kely 1 year ago
parent
commit
8be281a6db
  1. 1
      web-admin-app/README.md
  2. 14
      web-admin-app/src/app/app.component.ts
  3. 12
      web-admin-app/src/app/app.routes.ts
  4. 66
      web-admin-app/src/app/components/address-tree/address-tree.component.html
  5. 7
      web-admin-app/src/app/components/address-tree/address-tree.component.less
  6. 164
      web-admin-app/src/app/components/address-tree/address-tree.component.ts
  7. 12
      web-admin-app/src/app/components/asset-business-allot-form/asset-business-allot-form.component.html
  8. 2
      web-admin-app/src/app/components/asset-business-allot-form/asset-business-allot-form.component.ts
  9. 11
      web-admin-app/src/app/components/asset-business-borrow-form/asset-business-borrow-form.component.html
  10. 2
      web-admin-app/src/app/components/asset-business-borrow-form/asset-business-borrow-form.component.ts
  11. 11
      web-admin-app/src/app/components/asset-business-collection/asset-business-collection.component.html
  12. 1
      web-admin-app/src/app/components/asset-business-collection/asset-business-collection.component.ts
  13. 12
      web-admin-app/src/app/components/asset-business-retirement/asset-business-retirement.component.html
  14. 2
      web-admin-app/src/app/components/asset-business-retirement/asset-business-retirement.component.ts
  15. 11
      web-admin-app/src/app/components/asset-business-return-form/asset-business-return-form.component.html
  16. 1
      web-admin-app/src/app/components/asset-business-return-form/asset-business-return-form.component.ts
  17. 12
      web-admin-app/src/app/components/asset-business-revert-form/asset-business-revert-form.component.html
  18. 2
      web-admin-app/src/app/components/asset-business-revert-form/asset-business-revert-form.component.ts
  19. 13
      web-admin-app/src/app/components/asset-business-storage-form/asset-business-storage-form.component.html
  20. 3
      web-admin-app/src/app/components/asset-business-storage-form/asset-business-storage-form.component.ts
  21. 12
      web-admin-app/src/app/components/asset-business-transfer-form/asset-business-transfer-form.component.html
  22. 2
      web-admin-app/src/app/components/asset-business-transfer-form/asset-business-transfer-form.component.ts
  23. 67
      web-admin-app/src/app/components/asset-form/asset-form.component.html
  24. 40
      web-admin-app/src/app/components/asset-form/asset-form.component.ts
  25. 7
      web-admin-app/src/app/components/asset-inspection-record/asset-inspection-record.component.ts
  26. 7
      web-admin-app/src/app/components/asset-maintenance-record/asset-maintenance-record.component.ts
  27. 4
      web-admin-app/src/app/components/asset-operation-records/asset-operation-records.component.html
  28. 12
      web-admin-app/src/app/components/asset-operation-records/asset-operation-records.component.ts
  29. 5
      web-admin-app/src/app/components/asset-operational-statistics/asset-operational-statistics.component.ts
  30. 8
      web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.ts
  31. 7
      web-admin-app/src/app/components/asset-stocktaking-record/asset-stocktaking-record.component.ts
  32. 36
      web-admin-app/src/app/components/flow-list-by-type/flow-list-by-type.component.html
  33. 421
      web-admin-app/src/app/components/flow-list-by-type/flow-list-by-type.component.ts
  34. 2
      web-admin-app/src/app/components/plan-task/calendar-list/calendar-list.component.html
  35. 60
      web-admin-app/src/app/components/plan-task/handle-task-asset-item/handle-task-asset-item.component.html
  36. 72
      web-admin-app/src/app/components/plan-task/handle-task-asset-item/handle-task-asset-item.component.ts
  37. 2
      web-admin-app/src/app/components/plan-task/handle-task/handle-task.component.html
  38. 9
      web-admin-app/src/app/components/plan-task/handle-task/handle-task.component.ts
  39. 11
      web-admin-app/src/app/components/plan-task/plan-form/plan-form.component.html
  40. 1
      web-admin-app/src/app/components/plan-task/plan-form/plan-form.component.ts
  41. 12
      web-admin-app/src/app/components/plan-task/plan-list/plan-list.component.ts
  42. 21
      web-admin-app/src/app/components/plan-task/task-list/task-list.component.ts
  43. 35
      web-admin-app/src/app/constants/index.ts
  44. 46
      web-admin-app/src/app/pages/dashboard/dashboard.component.ts
  45. 2
      web-admin-app/src/app/pages/data-vis/data-vis.component.html
  46. 8
      web-admin-app/src/app/pages/data-vis/data-vis.component.less
  47. 72
      web-admin-app/src/app/pages/data-vis/data-vis.component.ts
  48. 3
      web-admin-app/src/app/pages/fixed-asset/alert/alert-borrow/alert-borrow.component.html
  49. 24
      web-admin-app/src/app/pages/fixed-asset/alert/alert-borrow/alert-borrow.component.ts
  50. 14
      web-admin-app/src/app/pages/fixed-asset/alert/alert-inventory-down/alert-inventory-down.component.ts
  51. 30
      web-admin-app/src/app/pages/fixed-asset/alert/alert-inventory-safety/alert-inventory-safety.component.ts
  52. 3
      web-admin-app/src/app/pages/fixed-asset/alert/alert-maintenance/alert-maintenance.component.html
  53. 18
      web-admin-app/src/app/pages/fixed-asset/alert/alert-maintenance/alert-maintenance.component.ts
  54. 37
      web-admin-app/src/app/pages/fixed-asset/asset-management/asset-management.component.html
  55. 45
      web-admin-app/src/app/pages/fixed-asset/asset-management/asset-management.component.ts
  56. 85
      web-admin-app/src/app/pages/fixed-asset/basic/basic-category/basic-category.component.html
  57. 35
      web-admin-app/src/app/pages/fixed-asset/basic/basic-category/basic-category.component.ts
  58. 74
      web-admin-app/src/app/pages/fixed-asset/basic/basic-flow-form-manage/basic-flow-form-manage.component.html
  59. 51
      web-admin-app/src/app/pages/fixed-asset/basic/basic-flow-form-manage/basic-flow-form-manage.component.ts
  60. 18
      web-admin-app/src/app/pages/fixed-asset/basic/basic-flow-form/basic-flow-form.component.ts
  61. 3
      web-admin-app/src/app/pages/fixed-asset/maintain/maintain-on-off/maintain-on-off.component.html
  62. 10
      web-admin-app/src/app/pages/fixed-asset/maintain/maintain-on-off/maintain-on-off.component.ts
  63. 21
      web-admin-app/src/app/pages/fixed-asset/maintain/on-off-records/on-off-records.component.html
  64. 21
      web-admin-app/src/app/pages/fixed-asset/maintain/on-off-records/on-off-records.component.ts
  65. 4
      web-admin-app/src/app/pages/fixed-asset/manage/fixed-asset-manage/fixed-asset-manage.component.ts
  66. 6
      web-admin-app/src/app/pages/fixed-asset/registration/registration.component.html
  67. 21
      web-admin-app/src/app/pages/fixed-asset/registration/registration.component.ts
  68. 6
      web-admin-app/src/app/pages/flow/flow-main/flow-main.component.html
  69. 6
      web-admin-app/src/app/pages/flow/flow-main/flow-main.component.ts
  70. 292
      web-admin-app/src/app/pages/flow/flow-report/flow-report.component.html
  71. 134
      web-admin-app/src/app/pages/flow/flow-report/flow-report.component.less
  72. 506
      web-admin-app/src/app/pages/flow/flow-report/flow-report.component.ts
  73. 4
      web-admin-app/src/app/pages/login/login.component.html
  74. 5
      web-admin-app/src/app/pages/login/login.component.less
  75. 10
      web-admin-app/src/app/pages/login/login.component.ts
  76. 19
      web-admin-app/src/app/pages/msg/flow-msg/flow-msg.component.ts
  77. 19
      web-admin-app/src/app/pages/msg/system-log/system-log.component.ts
  78. 54
      web-admin-app/src/app/pages/system/display-config/display-config.component.html
  79. 0
      web-admin-app/src/app/pages/system/display-config/display-config.component.less
  80. 59
      web-admin-app/src/app/pages/system/display-config/display-config.component.ts
  81. 14
      web-admin-app/src/app/pages/system/index/system.component.html
  82. 38
      web-admin-app/src/app/pages/system/system-address/system-address.component.html
  83. 12
      web-admin-app/src/app/pages/system/system-address/system-address.component.ts
  84. 126
      web-admin-app/src/app/services/api.service.ts
  85. 8
      web-admin-app/src/app/shared/components/header/header.component.html
  86. 7
      web-admin-app/src/app/shared/components/header/header.component.ts
  87. 18
      web-admin-app/src/app/shared/components/upload/upload.component.html
  88. 32
      web-admin-app/src/app/shared/components/upload/upload.component.ts
  89. 2
      web-admin-app/src/app/utils/index.ts
  90. BIN
      web-admin-app/src/assets/favicon.ico
  91. 1
      web-admin-app/src/index.html
  92. 41
      web-admin-app/src/styles.less
  93. 19
      web-admin-app/t.html

1
web-admin-app/README.md

@ -167,4 +167,3 @@ Excel导出 /api/v2/sysFormTemp/importByExcel
13、工作报表 api/flFormItem/workReport 13、工作报表 api/flFormItem/workReport
富文本 + html转word api/flFormItem/h52word 或者api/flFormItem/h5str2word 富文本 + html转word api/flFormItem/h52word 或者api/flFormItem/h5str2word

14
web-admin-app/src/app/app.component.ts

@ -1,5 +1,6 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { SharedModule } from './shared/shared.module' import { SharedModule } from './shared/shared.module'
import { ApiService } from './services'
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -8,4 +9,15 @@ import { SharedModule } from './shared/shared.module'
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrl: './app.component.less', styleUrl: './app.component.less',
}) })
export class AppComponent {} export class AppComponent {
constructor(private api: ApiService) {}
ngOnInit() {
this.api.getSysDisplayConfig().subscribe((res) => {
if (res.favicon) {
console.log('res.favicon', res.favicon)
;(document.querySelector('#favicon') as HTMLLinkElement).href = res.favicon
}
})
}
}

12
web-admin-app/src/app/app.routes.ts

@ -86,6 +86,7 @@ import { MsgLayoutComponent } from './pages/msg/msg-layout/msg-layout.component'
import { FlowManagementComponent } from './pages/flow/flow-management/flow-management.component' import { FlowManagementComponent } from './pages/flow/flow-management/flow-management.component'
import { FlowReportComponent } from './pages/flow/flow-report/flow-report.component' import { FlowReportComponent } from './pages/flow/flow-report/flow-report.component'
import { DataVisComponent } from './pages/data-vis/data-vis.component' import { DataVisComponent } from './pages/data-vis/data-vis.component'
import { DisplayConfigComponent } from './pages/system/display-config/display-config.component'
export const routes: Routes = [ export const routes: Routes = [
{ {
@ -202,6 +203,17 @@ export const routes: Routes = [
}, },
}, },
}, },
{
path: 'display',
component: DisplayConfigComponent,
canActivate: [permissionGuard],
title: '展示设置',
data: {
// permission: {
// only: ['system-display:view'],
// },
},
},
{ {
path: 'place', path: 'place',
title: '场所地址', title: '场所地址',

66
web-admin-app/src/app/components/address-tree/address-tree.component.html

@ -0,0 +1,66 @@
<div class="w-full overflow-auto">
<div class="flex items-center">
<div class="flex-1 pr-2">
<nz-input-group [nzSuffix]="suffixIcon">
<input type="text" nz-input placeholder="请输入关键字" [(ngModel)]="searchValue" />
</nz-input-group>
<ng-template #suffixIcon>
<span nz-icon nzType="search"></span>
</ng-template>
</div>
@if (createable) {
<button nz-button nzType="primary" (click)="onCreate(0)">添加</button>
}
</div>
<div class="py-4">
<nz-tree
class="tree"
nzBlockNode
[nzData]="nodes"
[nzExpandedKeys]="expandedKeys"
[(nzSelectedKeys)]="selectedKeys"
[nzSearchValue]="searchValue"
(nzClick)="nzEvent($event)"
(nzExpandChange)="onExpandChange($event)"
[nzTreeTemplate]="nzTreeTemplate"
>
<ng-template #nzTreeTemplate let-node let-origin="origin">
<div class="custom-node flex items-center overflow-hidden">
<div class="flex-1">
@switch (origin.organizationType) {
@case ('0') {
<span nz-icon nzType="bank" nzTheme="outline"></span>
}
@case ('1') {
<span nz-icon nzType="cluster" nzTheme="outline"></span>
}
@case ('2') {
<span nz-icon nzType="team" nzTheme="outline"></span>
}
}
<span class="ml-2 overflow-hidden text-ellipsis">{{ node.title }}</span>
</div>
@if (createable) {
<button
nz-button
nz-dropdown
[nzDropdownMenu]="menu"
nzType="text"
onclick="event.stopPropagation()"
>
<span nz-icon nzType="more"></span>
</button>
<nz-dropdown-menu #menu="nzDropdownMenu">
<ul nz-menu>
<li nz-menu-item (click)="onCreate(origin.parentId)">添加同级分类</li>
<li nz-menu-item (click)="onCreate(origin.positionId)">添加下级分类</li>
<li nz-menu-divider></li>
<li nz-menu-item (click)="onDelete(origin.positionId)">删除</li>
</ul>
</nz-dropdown-menu>
}
</div>
</ng-template>
</nz-tree>
</div>
</div>

7
web-admin-app/src/app/components/address-tree/address-tree.component.less

@ -0,0 +1,7 @@
.tree {
::ng-deep {
.ant-tree-switcher {
align-self: center;
}
}
}

164
web-admin-app/src/app/components/address-tree/address-tree.component.ts

@ -0,0 +1,164 @@
import { CommonModule } from '@angular/common'
import { Component, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core'
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'
import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module'
import { FormValidators } from 'app/utils'
import { NzButtonModule } from 'ng-zorro-antd/button'
import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer'
import { NzDropDownModule } from 'ng-zorro-antd/dropdown'
import { NzIconModule } from 'ng-zorro-antd/icon'
import { NzInputModule } from 'ng-zorro-antd/input'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzModalService } from 'ng-zorro-antd/modal'
import { NzFormatEmitEvent, NzTreeModule, NzTreeNodeOptions } from 'ng-zorro-antd/tree'
interface CateGoryInterface {
createTime: string
depth: string
name: string
parentId: number
positionId: number
}
export function buildCateTree(organizations: CateGoryInterface[]): NzTreeNodeOptions[] {
const map: { [parentId: number]: NzTreeNodeOptions[] } = {}
organizations.forEach((org) => {
if (!map[org.parentId]) {
map[org.parentId] = []
}
const treeNode: NzTreeNodeOptions = {
...org,
title: org.name,
key: org.positionId.toString(),
}
map[org.parentId].push(treeNode)
})
const build = (parentId: number): NzTreeNodeOptions[] => {
if (!map[parentId]) {
return []
}
return map[parentId].map((node) => {
const children = build(parseInt(node.key))
return {
...node,
isLeaf: children.length === 0,
children,
}
})
}
return build(0)
}
@Component({
selector: 'app-component-address-tree',
standalone: true,
imports: [
NzDropDownModule,
NzTreeModule,
NzInputModule,
NzIconModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
NzButtonModule,
],
templateUrl: './address-tree.component.html',
styleUrl: './address-tree.component.less',
})
export class AddressTreeComponent {
constructor(
private api: ApiService,
private drawer: NzDrawerService,
private fb: FormBuilder,
private msg: NzMessageService,
private modal: NzModalService,
) {}
@Input() createable = true
@Output() onSelectedChange = new EventEmitter<NzSafeAny>()
@Input() defaultName?: string = '新地址'
drawerRef?: NzDrawerRef
searchValue = ''
parentId?: number
nodes: NzSafeAny[] = []
expandedKeys: string[] = []
selectedKeys: string[] = []
initTree() {
this.api.getBasicPositionTree().subscribe((res) => {
this.nodes = buildCateTree(res.body)
this.expandedKeys = [...this.expandedKeys]
if (this.selectedKeys.length === 0) {
this.selectedKeys = [this.nodes[0].key]
} else {
this.selectedKeys = [...this.selectedKeys]
}
const node = res.body.find((node: NzSafeAny) => String(node.positionId) === this.selectedKeys[0])
this.onSelectedChange.emit(node)
})
}
ngOnInit(): void {
this.initTree()
}
nzEvent(event: NzFormatEmitEvent): void {
if (event.eventName === 'click') {
const { node } = event
this.selectedKeys = event.keys ?? []
this.onSelectedChange.emit(node?.origin)
}
}
onExpandChange(e: NzFormatEmitEvent) {
this.expandedKeys = e.keys ?? []
}
onSelectedKeysChange(e: string[]) {
console.log('e', e)
}
onCreate(parentId: number) {
this.api
.saveBasicPosition({
depth: '',
parentId,
name: this.defaultName,
})
.subscribe((res) => {
this.expandedKeys.push(String(parentId))
this.initTree()
this.msg.success(res.desc)
})
}
onDelete(id: number) {
this.modal.confirm({
nzTitle: '警告',
nzContent: '是否要删除该分类?',
nzOnOk: () => {
this.api.deleteBasicPosition([id]).subscribe((res) => {
if (this.selectedKeys.includes(String(id))) {
this.selectedKeys = []
}
this.msg.success(res.desc)
this.initTree()
})
},
})
}
}

12
web-admin-app/src/app/components/asset-business-allot-form/asset-business-allot-form.component.html

@ -42,7 +42,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

2
web-admin-app/src/app/components/asset-business-allot-form/asset-business-allot-form.component.ts

@ -54,7 +54,7 @@ export class AssetBusinessAllotFormComponent {
notes: this.fb.control(null, []), notes: this.fb.control(null, []),
inWarehouseId: this.fb.control(null, [FormValidators.required('请选择')]), inWarehouseId: this.fb.control(null, [FormValidators.required('请选择')]),
// outWarehouseId: this.fb.control(null, [FormValidators.required('请选择')]), // outWarehouseId: this.fb.control(null, [FormValidators.required('请选择')]),
urgency: this.fb.control(1, []),
attach: this.fb.control('', []), attach: this.fb.control('', []),
assetIdList: this.fb.control([], []), assetIdList: this.fb.control([], []),

11
web-admin-app/src/app/components/asset-business-borrow-form/asset-business-borrow-form.component.html

@ -50,6 +50,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>

2
web-admin-app/src/app/components/asset-business-borrow-form/asset-business-borrow-form.component.ts

@ -49,7 +49,7 @@ export class AssetBusinessBorrowFormComponent {
// useOrganizationId: this.fb.control(null, [FormValidators.required('请选择')]), // useOrganizationId: this.fb.control(null, [FormValidators.required('请选择')]),
businessGeneratedDate: this.fb.control(null, [FormValidators.required('请选择')]), businessGeneratedDate: this.fb.control(null, [FormValidators.required('请选择')]),
returnTime: this.fb.control(null, [FormValidators.required('请选择')]), returnTime: this.fb.control(null, [FormValidators.required('请选择')]),
urgency: this.fb.control(1, []),
notes: this.fb.control(null, []), notes: this.fb.control(null, []),
attach: this.fb.control('', []), attach: this.fb.control('', []),

11
web-admin-app/src/app/components/asset-business-collection/asset-business-collection.component.html

@ -58,6 +58,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

1
web-admin-app/src/app/components/asset-business-collection/asset-business-collection.component.ts

@ -55,6 +55,7 @@ export class AssetBusinessCollectionComponent {
notes: this.fb.control(null, []), notes: this.fb.control(null, []),
positionId: this.fb.control(null, []), positionId: this.fb.control(null, []),
urgency: this.fb.control(1, []),
attach: this.fb.control('', []), attach: this.fb.control('', []),
positionDetail: this.fb.control('', []), positionDetail: this.fb.control('', []),
applicant: this.fb.control({ value: '', disabled: true }, []), applicant: this.fb.control({ value: '', disabled: true }, []),

12
web-admin-app/src/app/components/asset-business-retirement/asset-business-retirement.component.html

@ -45,7 +45,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

2
web-admin-app/src/app/components/asset-business-retirement/asset-business-retirement.component.ts

@ -52,7 +52,7 @@ export class AssetBusinessRetirementComponent {
// useUserId: this.fb.control(null, [FormValidators.required('请选择')]), // useUserId: this.fb.control(null, [FormValidators.required('请选择')]),
type: this.fb.control(null, []), type: this.fb.control(null, []),
businessGeneratedDate: this.fb.control(null, [FormValidators.required('请选择')]), businessGeneratedDate: this.fb.control(null, [FormValidators.required('请选择')]),
urgency: this.fb.control(1, []),
expeditedStatus: this.fb.control(0, []), expeditedStatus: this.fb.control(0, []),
notes: this.fb.control(null, []), notes: this.fb.control(null, []),
// positionId: this.fb.control(null, []), // positionId: this.fb.control(null, []),

11
web-admin-app/src/app/components/asset-business-return-form/asset-business-return-form.component.html

@ -66,6 +66,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

1
web-admin-app/src/app/components/asset-business-return-form/asset-business-return-form.component.ts

@ -53,6 +53,7 @@ export class AssetBusinessReturnFormComponent {
warehouseId: this.fb.control(null, [FormValidators.required('请选择')]), warehouseId: this.fb.control(null, [FormValidators.required('请选择')]),
notes: this.fb.control(null, []), notes: this.fb.control(null, []),
urgency: this.fb.control(1, []),
positionId: this.fb.control(null, [FormValidators.required('请选择')]), positionId: this.fb.control(null, [FormValidators.required('请选择')]),
attach: this.fb.control('', []), attach: this.fb.control('', []),
positionDetail: this.fb.control('', []), positionDetail: this.fb.control('', []),

12
web-admin-app/src/app/components/asset-business-revert-form/asset-business-revert-form.component.html

@ -67,6 +67,18 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

2
web-admin-app/src/app/components/asset-business-revert-form/asset-business-revert-form.component.ts

@ -54,7 +54,7 @@ export class AssetBusinessRevertFormComponent {
positionId: this.fb.control(null, []), positionId: this.fb.control(null, []),
attach: this.fb.control('', []), attach: this.fb.control('', []),
positionDetail: this.fb.control('', []), positionDetail: this.fb.control('', []),
urgency: this.fb.control(1, []),
assetIdList: this.fb.control([], []), assetIdList: this.fb.control([], []),
applicant: this.fb.control({ value: '', disabled: true }, []), applicant: this.fb.control({ value: '', disabled: true }, []),
}) })

13
web-admin-app/src/app/components/asset-business-storage-form/asset-business-storage-form.component.html

@ -30,7 +30,7 @@
<nz-form-item> <nz-form-item>
<nz-form-label>业务日期</nz-form-label> <nz-form-label>业务日期</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl"> <nz-form-control [nzErrorTip]="errorTpl">
<nz-date-picker class="w-full" formControlName="createTime" /> <nz-date-picker class="w-full" formControlName="businessGeneratedDate" />
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
@ -42,6 +42,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

3
web-admin-app/src/app/components/asset-business-storage-form/asset-business-storage-form.component.ts

@ -51,7 +51,8 @@ export class AssetBusinessStorageFormComponent {
name: this.fb.control('', [FormValidators.required('请输入')]), name: this.fb.control('', [FormValidators.required('请输入')]),
warehouseId: this.fb.control('', [FormValidators.required('请输入')]), warehouseId: this.fb.control('', [FormValidators.required('请输入')]),
manager: this.fb.control(null, []), manager: this.fb.control(null, []),
createTime: this.fb.control(null, []), urgency: this.fb.control(1, []),
businessGeneratedDate: this.fb.control(null, []),
supplierVendorId: this.fb.control(null, []), supplierVendorId: this.fb.control(null, []),
notes: this.fb.control(null, []), notes: this.fb.control(null, []),
assetIdList: this.fb.control([], []), assetIdList: this.fb.control([], []),

12
web-admin-app/src/app/components/asset-business-transfer-form/asset-business-transfer-form.component.html

@ -66,7 +66,17 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="6">
<nz-form-item>
<nz-form-label>紧急程度</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-radio-group formControlName="urgency">
<label nz-radio [nzValue]="1">普通</label>
<label nz-radio [nzValue]="2">紧急</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="6"> <div nz-col [nzSpan]="6">
<nz-form-item> <nz-form-item>
<nz-form-label>附件</nz-form-label> <nz-form-label>附件</nz-form-label>

2
web-admin-app/src/app/components/asset-business-transfer-form/asset-business-transfer-form.component.ts

@ -55,7 +55,7 @@ export class AssetBusinessTransferFormComponent {
managerId: this.fb.control(null, [FormValidators.required('请选择')]), managerId: this.fb.control(null, [FormValidators.required('请选择')]),
inUseOrganizationId: this.fb.control(null, [FormValidators.required('请选择')]), inUseOrganizationId: this.fb.control(null, [FormValidators.required('请选择')]),
outUseOrganizationId: this.fb.control(null, [FormValidators.required('请选择')]), outUseOrganizationId: this.fb.control(null, [FormValidators.required('请选择')]),
urgency: this.fb.control(1, []),
attach: this.fb.control('', []), attach: this.fb.control('', []),
positionId: this.fb.control('', []), positionId: this.fb.control('', []),
positionDetail: this.fb.control('', []), positionDetail: this.fb.control('', []),

67
web-admin-app/src/app/components/asset-form/asset-form.component.html

@ -10,7 +10,7 @@
<nz-tab nzTitle="维修记录"></nz-tab> <nz-tab nzTitle="维修记录"></nz-tab>
<nz-tab nzTitle="保养记录"></nz-tab> <nz-tab nzTitle="保养记录"></nz-tab>
<nz-tab nzTitle="巡检记录"></nz-tab> --> <nz-tab nzTitle="巡检记录"></nz-tab> -->
<nz-tab nzTitle="历史记录"></nz-tab> <nz-tab nzTitle="变动记录"></nz-tab>
<nz-tab nzTitle="维修记录"></nz-tab> <nz-tab nzTitle="维修记录"></nz-tab>
<nz-tab nzTitle="巡检记录"></nz-tab> <nz-tab nzTitle="巡检记录"></nz-tab>
<nz-tab nzTitle="保养记录"></nz-tab> <nz-tab nzTitle="保养记录"></nz-tab>
@ -219,8 +219,8 @@
@if (extraFields.length > 0) { @if (extraFields.length > 0) {
<div class="text-lg mb-6">扩展信息</div> <div class="text-lg mb-6">扩展信息</div>
<div nz-row [nzGutter]="24"> <div nz-row [nzGutter]="24">
@for (item of extraFields; track item.key) { @for (item of extraFields; track item.key; let fid = $index) {
<div nz-col nzSpan="8" [formGroupName]="$index"> <div nz-col [nzSpan]="item.type === 'LIST' ? 24 : 8" [formGroupName]="fid">
<nz-form-item> <nz-form-item>
<nz-form-label>{{ item.name }}</nz-form-label> <nz-form-label>{{ item.name }}</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl"> <nz-form-control [nzErrorTip]="errorTpl">
@ -245,6 +245,63 @@
</nz-radio-group> </nz-radio-group>
</ng-container> </ng-container>
} }
@case ('LIST') {
<ng-container *ngIf="item?.value?.fields as fields">
<nz-table [nzBordered]="true" nzSize="small" nzTemplateMode>
<thead>
<tr>
@for (item of fields; track $index) {
<th>{{ item }}</th>
}
<th>操作</th>
</tr>
</thead>
<tbody formArrayName="value">
<tr
*ngFor="
let row of getListValue(fid).controls;
let r = index
"
>
<ng-container [formGroupName]="r">
<td
*ngFor="let tc of fields; let c = index"
>
<input
placeholder="请输入"
nz-input
[formControlName]="tc"
/>
</td>
<td>
<button
(click)="removeRow(fid, r)"
nz-button
nzType="link"
nzDanger
>
<i nz-icon nzType="delete"></i>
</button>
</td>
</ng-container>
</tr>
<tr>
<td [attr.colspan]="fields.length + 1">
<button
nz-button
nzType="dashed"
nzBlock
(click)="addRow(fid, fields)"
>
<i nz-icon nzType="plus"></i>
新增
</button>
</td>
</tr>
</tbody>
</nz-table>
</ng-container>
}
@case ('NUMBER') { @case ('NUMBER') {
<nz-input-number <nz-input-number
class="!w-full" class="!w-full"
@ -375,8 +432,8 @@
<div nz-col [nzSpan]="8"> <div nz-col [nzSpan]="8">
<nz-form-item> <nz-form-item>
<nz-form-label>财务分类</nz-form-label> <nz-form-label>财务分类</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl" formControlName="financialCategoryId"> <nz-form-control [nzErrorTip]="errorTpl">
<nz-select [nzPlaceHolder]="'请选择'"> <nz-select [nzPlaceHolder]="'请选择'" formControlName="financialCategoryId">
@for (item of financialCategory; track $index) { @for (item of financialCategory; track $index) {
<nz-option <nz-option
[nzLabel]="item.financialCategoryName" [nzLabel]="item.financialCategoryName"

40
web-admin-app/src/app/components/asset-form/asset-form.component.ts

@ -154,11 +154,22 @@ export class AssetFormComponent implements OnInit {
.sort((a, b) => a.sort - b.sort) .sort((a, b) => a.sort - b.sort)
.map((i) => { .map((i) => {
let val = i.value let val = i.value
if (i.type === 'RADIO') { if (i.type === 'RADIO' || i.type === 'LIST') {
val = i.value?.value val = i.value?.value
} else if (i.type === 'DATE') { } else if (i.type === 'DATE') {
val = new Date(i.value) val = new Date(i.value)
} }
const listValue =
i.type === 'LIST'
? (val ?? []).map((c: NzSafeAny) =>
this.fb.group(
i.value.fields.reduce((a: any, f: any) => {
a[f] = c[f]
return a
}, {}),
),
)
: []
this.extInfo.push( this.extInfo.push(
this.fb.group({ this.fb.group({
@ -167,12 +178,33 @@ export class AssetFormComponent implements OnInit {
remark: this.fb.control(i.remark), remark: this.fb.control(i.remark),
sort: this.fb.control(i.sort), sort: this.fb.control(i.sort),
type: this.fb.control(i.type), type: this.fb.control(i.type),
value: this.fb.control(val), value: i.type === 'LIST' ? this.fb.array(listValue) : this.fb.control(val),
fields: this.fb.control(i.type === 'RADIO' ? i.value?.fields : []), fields: this.fb.control(['RADIO', 'LIST'].includes(i.type) ? i.value?.fields : []),
}), }),
) )
return i return i
}) })
console.log('this.extInfo', this.extInfo)
}
getListValue(fid: number) {
return (this.extInfo.at(fid) as FormArray).get('value') as FormArray
}
addRow(fidx: number, fields: string[]) {
const row = this.getListValue(fidx)
row.push(
this.fb.group(
fields.reduce((a: any, f: any) => {
a[f] = this.fb.control('')
return a
}, {}),
),
)
}
removeRow(fidx: number, ridx: number) {
const row = this.getListValue(fidx)
row.removeAt(ridx)
} }
patchValues() { patchValues() {
@ -214,7 +246,7 @@ export class AssetFormComponent implements OnInit {
useOrganizationId: v.useOrganizationId, useOrganizationId: v.useOrganizationId,
responsiblePerson: v.responsiblePerson?.[0], responsiblePerson: v.responsiblePerson?.[0],
_extInfo: this.extInfo.value.map((v: any) => { _extInfo: this.extInfo.value.map((v: any) => {
if (v.type === 'RADIO') { if (v.type === 'RADIO' || v.type === 'LIST') {
return { return {
...v, ...v,
value: { value: {

7
web-admin-app/src/app/components/asset-inspection-record/asset-inspection-record.component.ts

@ -46,11 +46,10 @@ export class AssetInspectionRecordComponent {
cacheKey: 'asset-repair-records.component', cacheKey: 'asset-repair-records.component',
}) })
.setColumn([ .setColumn([
{ key: 'id', title: '主键', width: '100px' }, { key: 'idx', title: '编号', width: '100px' },
{ key: 'businessId', title: '业务编号', width: '170px' }, { key: 'businessId', title: '业务编号', width: '170px' },
{ key: 'name', title: '名称' }, { key: 'remark', title: '操作内容' },
{ key: '_repairType', title: '维修类型' }, { key: 'operationType', title: '操作类型' },
{ key: 'plannedDate', title: '计划完成时间' },
// { key: 'createTime', title: '创建时间' }, // { key: 'createTime', title: '创建时间' },
]) ])

7
web-admin-app/src/app/components/asset-maintenance-record/asset-maintenance-record.component.ts

@ -46,11 +46,10 @@ export class AssetMaintenanceRecordComponent {
cacheKey: 'asset-repair-records.component', cacheKey: 'asset-repair-records.component',
}) })
.setColumn([ .setColumn([
{ key: 'id', title: '主键', width: '100px' }, { key: 'idx', title: '编号', width: '100px' },
{ key: 'businessId', title: '业务编号', width: '170px' }, { key: 'businessId', title: '业务编号', width: '170px' },
{ key: 'name', title: '名称' }, { key: 'remark', title: '操作内容' },
{ key: '_repairType', title: '维修类型' }, { key: 'operationType', title: '操作类型' },
{ key: 'plannedDate', title: '计划完成时间' },
// { key: 'createTime', title: '创建时间' }, // { key: 'createTime', title: '创建时间' },
]) ])

4
web-admin-app/src/app/components/asset-operation-records/asset-operation-records.component.html

@ -15,7 +15,7 @@
} }
</ng-template> </ng-template>
<ng-container *appTableForm> <!-- <ng-container *appTableForm>
<div class="mr-3"> <div class="mr-3">
<div nz-row nzGutter="24"> <div nz-row nzGutter="24">
<div nz-col nzSpan="8"> <div nz-col nzSpan="8">
@ -44,6 +44,6 @@
</div> </div>
</div> </div>
</div> </div>
</ng-container> </ng-container> -->
</app-server-paginated-table> </app-server-paginated-table>
</div> </div>

12
web-admin-app/src/app/components/asset-operation-records/asset-operation-records.component.ts

@ -8,7 +8,7 @@ import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer' import { NzDrawerRef, NzDrawerService } from 'ng-zorro-antd/drawer'
import { lastValueFrom } from 'rxjs' import { lastValueFrom, tap } from 'rxjs'
import { FormValidators } from 'app/utils' import { FormValidators } from 'app/utils'
@Component({ @Component({
@ -47,9 +47,9 @@ export class AssetOperationRecordsComponent {
cacheKey: 'asset-operation-records.component', cacheKey: 'asset-operation-records.component',
}) })
.setColumn([ .setColumn([
{ key: 'id', title: '主键', width: '100px' }, { key: 'idx', title: '编号', width: '100px' },
{ key: 'businessId', title: '业务编号', width: '170px' }, { key: 'businessId', title: '业务编号', width: '170px' },
{ key: 'operationNotes', title: '操作内容' }, { key: 'remark', title: '操作内容' },
{ key: 'operationType', title: '操作类型' }, { key: 'operationType', title: '操作类型' },
// { key: 'createTime', title: '创建时间' }, // { key: 'createTime', title: '创建时间' },
@ -58,6 +58,10 @@ export class AssetOperationRecordsComponent {
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getAssetLog({ ...p, ...q, assetId: this.assetId }) return this.api.getAssetLog({ ...p, ...q, assetId: this.assetId }).pipe(
tap((res) => {
console.log(res)
}),
)
} }
} }

5
web-admin-app/src/app/components/asset-operational-statistics/asset-operational-statistics.component.ts

@ -91,6 +91,7 @@ export class AssetOperationalStatisticsComponent {
if (this.runningStatusChart?.nativeElement) { if (this.runningStatusChart?.nativeElement) {
if (!this.pieRef) { if (!this.pieRef) {
this.pieRef = init(this.runningStatusChart?.nativeElement) this.pieRef = init(this.runningStatusChart?.nativeElement)
}
let data: NzSafeAny[] = [] let data: NzSafeAny[] = []
const odata: NzSafeAny[] = this.data?.runLogs ?? [] const odata: NzSafeAny[] = this.data?.runLogs ?? []
const total = odata.reduce((a: number, b: any) => a + Math.abs(b.value), 0) const total = odata.reduce((a: number, b: any) => a + Math.abs(b.value), 0)
@ -105,6 +106,7 @@ export class AssetOperationalStatisticsComponent {
value, value,
} }
}) })
console.log('data', data)
this.pieRef.setOption({ this.pieRef.setOption({
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
@ -114,7 +116,7 @@ export class AssetOperationalStatisticsComponent {
formatter: function (name: string, d: any) { formatter: function (name: string, d: any) {
const item = data.find((i: NzSafeAny) => i.name === name) const item = data.find((i: NzSafeAny) => i.name === name)
return name + ' | ' + item?.percent + '%' + ' ' + item?.value + '' return name + ' | ' + item?.percent + '%' + ' ' + item?.value + '小时'
}, },
}, },
series: [ series: [
@ -149,5 +151,4 @@ export class AssetOperationalStatisticsComponent {
}) })
} }
} }
}
} }

8
web-admin-app/src/app/components/asset-repair-records/asset-repair-records.component.ts

@ -46,12 +46,10 @@ export class AssetRepairRecordsComponent {
cacheKey: 'asset-repair-records.component', cacheKey: 'asset-repair-records.component',
}) })
.setColumn([ .setColumn([
{ key: 'id', title: '主键', width: '100px' }, { key: 'idx', title: '编号', width: '100px' },
{ key: 'businessId', title: '业务编号', width: '170px' }, { key: 'businessId', title: '业务编号', width: '170px' },
{ key: 'name', title: '名称' }, { key: 'remark', title: '操作内容' },
{ key: '_repairType', title: '维修类型' }, { key: 'operationType', title: '操作类型' },
{ key: 'plannedDate', title: '计划完成时间' },
// { key: 'createTime', title: '创建时间' }, // { key: 'createTime', title: '创建时间' },
]) ])
this.initQueryForm() this.initQueryForm()

7
web-admin-app/src/app/components/asset-stocktaking-record/asset-stocktaking-record.component.ts

@ -46,11 +46,10 @@ export class AssetStocktakingRecordComponent {
cacheKey: 'asset-repair-records.component', cacheKey: 'asset-repair-records.component',
}) })
.setColumn([ .setColumn([
{ key: 'id', title: '主键', width: '100px' }, { key: 'idx', title: '编号', width: '100px' },
{ key: 'businessId', title: '业务编号', width: '170px' }, { key: 'businessId', title: '业务编号', width: '170px' },
{ key: 'name', title: '名称' }, { key: 'remark', title: '操作内容' },
{ key: '_repairType', title: '维修类型' }, { key: 'operationType', title: '操作类型' },
{ key: 'plannedDate', title: '计划完成时间' },
// { key: 'createTime', title: '创建时间' }, // { key: 'createTime', title: '创建时间' },
]) ])

36
web-admin-app/src/app/components/flow-list-by-type/flow-list-by-type.component.html

@ -30,3 +30,39 @@
</ng-template> </ng-template>
</app-server-paginated-table> </app-server-paginated-table>
</div> </div>
<ng-template #commentTpl>
<div nz-form nzLayout="vertical">
<nz-form-item>
<nz-form-label [nzRequired]="true"> 审批意见 </nz-form-label>
<nz-form-control>
<textarea nz-input rows="4" [(ngModel)]="comment" [nzAutosize]="{ minRows: 2, maxRows: 4 }"></textarea>
</nz-form-control>
</nz-form-item>
</div>
</ng-template>
<ng-template #zhipaiTpl>
<div nz-form nzLayout="vertical">
<nz-form-item>
<nz-form-label nzRequired> 任务处置人员 </nz-form-label>
<nz-form-control>
<nz-cascader [nzOptions]="teamList" [(ngModel)]="assignee" />
</nz-form-control>
</nz-form-item>
</div>
</ng-template>
<ng-template #shenheTpl>
<div nz-form nzLayout="vertical">
<nz-form-item>
<nz-form-label nzRequired> {{ shenhe ? '审批意见' : '驳回意见' }} </nz-form-label>
<nz-form-control>
<textarea
nz-input
[(ngModel)]="comment"
[placeholder]="'请输入' + shenhe ? '审批理由' : '驳回理由'"
></textarea>
</nz-form-control>
</nz-form-item>
</div>
</ng-template>

421
web-admin-app/src/app/components/flow-list-by-type/flow-list-by-type.component.ts

@ -7,12 +7,14 @@ import { SharedModule } from 'app/shared/shared.module'
import { last, lastValueFrom, map, of, tap } from 'rxjs' import { last, lastValueFrom, map, of, tap } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
import { FormValidators } from 'app/utils' import { FormValidators, Utils } from 'app/utils'
import { AssetEmployeeApplyComponent } from 'app/components' import { AssetEmployeeApplyComponent } from 'app/components'
import { FLOW_STATUS, flowIntStatus } from 'app/constants' import { FLOW_STATUS, flowIntStatus, flowIntStatusToStr } from 'app/constants'
import { comsMap } from 'app/pages/flow/flow-main/flow-main.component' import { comsMap } from 'app/pages/flow/flow-main/flow-main.component'
import { TaskFormComponent } from '../plan-task/task-form/task-form.component'
import { HandleTaskComponent } from '../plan-task/handle-task/handle-task.component'
@Component({ @Component({
selector: 'app-flow-list-by-type', selector: 'app-flow-list-by-type',
@ -43,6 +45,8 @@ export class FlowListByTypeComponent {
table = new TableOption(this.fetchData.bind(this)) table = new TableOption(this.fetchData.bind(this))
detailRef?: NzModalRef
assetTotal = 0 assetTotal = 0
deviceTotal = 0 deviceTotal = 0
@ -70,13 +74,278 @@ export class FlowListByTypeComponent {
.setRowOperate([ .setRowOperate([
{ title: '查看', onClick: this.onDetail.bind(this) }, { title: '查看', onClick: this.onDetail.bind(this) },
{ {
title: '作废', title: '撤回',
onClick: this.cancleFlow.bind(this), onClick: this.cancleFlow.bind(this),
visible: (v) => { visible: (v) => {
return this.page === 'apply' return this.page === 'apply' && [2, 9].includes(v.status)
},
},
{
title: '编辑',
onClick: (v) => {
this.onDetail(v, false)
},
visible: (v) => {
return this.page === 'apply' && [1, 4, 5].includes(v.status)
},
},
{
title: '删除',
onClick: (v) => {
this.onDelete(v)
},
visible: (v) => {
return this.page === 'apply' && [1, 4, 5].includes(v.status)
},
},
{
title: '受理',
onClick: this.shouli.bind(this),
visible: (v) => {
return this.page === 'todo' && this.type === 'device' && v.status === 'TO_BE_ASSIGNED'
},
},
{
title: '指派',
onClick: this.zhipai.bind(this),
premissions: ['ROOT'],
visible: (v) => {
return this.page === 'todo' && this.type === 'device' && v.status === 7
},
},
{
title: '处置',
onClick: this.onHandle.bind(this, true),
visible: (v) => {
return this.page === 'todo' && this.type === 'device' && v.status === 9
},
},
{
title: '审批',
onClick: this.onHandle.bind(this, false),
visible: (v) => {
return this.page === 'todo' && this.type === 'device' && v.status === 2
},
},
{
title: '报表',
onClick: this.onReport.bind(this),
visible: (v) => {
return this.page === 'todo' && this.type === 'device' && v.status === 3
}, },
}, },
]) ])
this.api.getAssetTeamAll().subscribe((res) => {
this.teamList = res.body.map((i: NzSafeAny) => {
let users = []
try {
users = JSON.parse(i.value)
} catch (error) {}
return {
...i,
label: i.teamName,
value: i.teamId,
children: users.map((c: NzSafeAny) => {
return {
label: c.userName,
value: c.userId,
isLeaf: true,
}
}),
}
})
})
}
zhipai(item?: NzSafeAny) {
this.modal.create({
nzTitle: '任务指派',
nzContent: this.zhipaiTpl,
nzOnOk: async () => {
if (!this.assignee) {
this.msg.error('请选择处理人')
return false
}
const res = await lastValueFrom(
this.api.assignTask({ instanceId: item.procInsId, taskId: item.taskId, assignee: this.assignee }),
)
this.msg.success(res.desc)
this.table.ref.reload()
return true
},
})
}
shouli(item?: NzSafeAny) {
this.modal.confirm({
nzTitle: '是否确定受理当前设备流程?',
nzContent: `受理后你将作为该任务的责任人,其他人员无法受理!`,
nzOnOk: async () => {
const res = await lastValueFrom(this.api.takeTask({ instanceId: item.procInsId, taskId: item.taskId }))
this.msg.success(res.desc)
this.table.ref.reload()
},
})
}
modalRef?: NzModalRef
assignee?: string
shenhe = false
onHandle(chuzhi: boolean, d: NzSafeAny) {
// console.log('chuzhi', chuzhi, data)
let nzTitle = chuzhi ? '处置任务' : '任务审批'
const { procVars: data } = d
// data.id = data.jobId
// console.log('data', data)
const footer: NzSafeAny[] = chuzhi
? [
{
label: '提交审核',
type: 'reject',
onClick: async (e: HandleTaskComponent) => {
const vals = e.getValues()
if (vals) {
const res = await lastValueFrom(
this.api.completeProcessFlow({
variables: {
...data,
...vals,
},
taskId: data.taskId,
instanceId: data.procInsId,
}),
)
this.msg.success(res.desc)
this.table.ref.reload()
this.modalRef?.close()
}
},
},
{
label: '保存',
type: 'primary',
onClick: async (e: HandleTaskComponent) => {
const vals = e.getValues()
if (vals) {
console.log('data', data, d)
const res = await lastValueFrom(
this.api.handleTaskAssetItem(
{
...data,
...vals,
taskId: d.taskId,
instanceId: d.procInsId,
},
d.taskId,
),
)
this.msg.success(res.desc)
this.table.ref.reload()
this.modalRef?.close()
}
},
},
]
: [
{
label: '驳回',
type: 'reject',
onClick: async (e: HandleTaskComponent) => {
this.shenhe = false
this.onShenpi(data)
},
},
{
label: '通过',
type: 'primary',
onClick: async (e: HandleTaskComponent) => {
this.shenhe = true
this.onShenpi(data)
},
},
]
this.modalRef = this.modal.create({
nzTitle,
nzContent: HandleTaskComponent,
nzWidth: '80vw',
nzWrapClassName: 'modal-lg modal-for-btn',
nzData: {
value: {
...data,
taskId: d.taskId,
status: flowIntStatusToStr.get(Number(d.status)),
},
chuzhi,
type: d.procDefKey.split('_').at(-1),
preview: !chuzhi,
},
nzFooter: footer.concat({
label: '取消',
onClick: () => {
this.modalRef?.close()
},
}),
})
}
@ViewChild('zhipaiTpl') zhipaiTpl!: TemplateRef<NzSafeAny>
@ViewChild('shenheTpl') shenheTpl!: TemplateRef<NzSafeAny>
teamList: NzSafeAny[] = []
onShenpi(item: NzSafeAny) {
const nzTitle = this.shenhe ? '请填写审批意见' : '请填写驳回意见'
this.modal.create({
nzTitle,
nzContent: this.shenheTpl,
nzOnOk: async () => {
if (!this.comment) {
this.msg.error(nzTitle)
return false
}
if (this.shenhe) {
const res = await lastValueFrom(
this.api.completeProcessFlow({
instanceId: item.procInsId,
taskId: item.taskId,
assignee: this.assignee,
comment: this.comment,
}),
)
this.msg.success(res.desc)
} else {
const res = await lastValueFrom(
this.api.rejectProcessFlow({
instanceId: item.procInsId,
taskId: item.taskId,
assignee: this.assignee,
comment: this.comment,
}),
)
this.msg.success(res.desc)
}
this.table.ref.reload()
this.modalRef?.close()
return true
},
})
}
onReport(i: NzSafeAny) {
this.msg.loading('下载中...')
this.api.downloadTaskReport(i.id).subscribe((res) => {
Utils.downLoadFile(
res,
'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8',
)
this.msg.remove()
this.msg.success('下载成功')
})
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
@ -101,25 +370,149 @@ export class FlowListByTypeComponent {
} }
} }
onDetail(model: NzSafeAny) { onDelete(model: NzSafeAny) {
console.log('model', model, comsMap[model.category]) this.modal.confirm({
this.modal.create({ nzTitle: '删除',
nzTitle: '查看', nzContent: '是否要删除该申请?',
nzContent: comsMap[model.category], nzOnOk: async () => {
const res = await lastValueFrom(
this.api.deleteAssetFlow({
instanceId: model.procInsId,
taskId: model.taskId,
}),
)
this.msg.success('删除成功')
this.table.ref.reload()
},
})
}
onDetail(model: NzSafeAny, preview = true) {
if (this.type === 'asset') {
// console.log('model', model, comsMap[model.category])
let footer: any = null
if (this.page === 'apply') {
if (!preview) {
footer = void 0
} else {
}
}
if (this.page === 'todo') {
footer = [
{
label: '通过',
type: 'primary',
onClick: async () => {
this.completeFlow(model)
},
},
{
label: '驳回',
danger: true,
type: 'primary',
onClick: async () => {
return this.rejectProcessFlow(model)
},
},
]
}
this.detailRef = this.modal.create({
nzTitle: preview ? '查看' : '编辑',
nzContent: comsMap[model.category ?? model.procDefKey],
nzWrapClassName: 'modal-lg', nzWrapClassName: 'modal-lg',
nzWidth: '80vw', nzWidth: '80vw',
nzFooter: null, // nzFooter: preview ? null : void 0,
nzFooter: footer,
nzData: { nzData: {
value: model, value: model,
preview,
},
nzOnOk: async (e: NzSafeAny) => {
const vals = e.getValues()
if (vals) {
const res = await lastValueFrom(this.api.startFlow(vals, model.procDefKey))
this.msg.success(res.desc)
return true
}
return false
},
})
} else {
let assetIdList = []
try {
assetIdList = JSON.parse(model?.procVars?.defects)
} catch (error) {}
this.modal.create({
nzTitle: '查看',
nzContent: TaskFormComponent,
nzWidth: '80vw',
nzWrapClassName: 'modal-lg',
nzData: {
value: {
...model.procVars,
assetIdList,
},
preview: true, preview: true,
type: model.procVars.jobType,
},
nzFooter: null,
})
}
}
completeFlow(d: NzSafeAny) {
this.modal.create({
nzTitle: '审核通过',
// nzContent: '是否要审核通过该申请?',
nzContent: this.commentTpl,
nzOnOk: async () => {
await lastValueFrom(
this.api.completeProcessFlow({
instanceId: d.procInsId,
taskId: d.taskId,
comment: this.comment,
}),
)
this.msg.success('通过成功')
this.table.ref.reload()
this.detailRef?.close()
},
})
}
@ViewChild('commentTpl') commentTpl!: TemplateRef<{}>
comment = ''
rejectProcessFlow(d: NzSafeAny) {
this.modal.create({
nzTitle: '驳回',
nzContent: this.commentTpl,
nzOnOk: async () => {
if (!this.comment) {
this.msg.error('请输入驳回意见')
return false
}
await lastValueFrom(
this.api.rejectProcessFlow({
instanceId: d.procInsId,
taskId: d.taskId,
comment: this.comment,
}),
)
this.msg.success('驳回成功')
this.table.ref.reload()
this.detailRef?.close()
return true
}, },
}) })
} }
cancleFlow(d: NzSafeAny) { cancleFlow(d: NzSafeAny) {
this.modal.confirm({ this.modal.confirm({
nzTitle: '作废', nzTitle: '撤回',
nzContent: '是否要作废该申请?', nzContent: '是否要撤回该申请?',
nzOnOk: async () => { nzOnOk: async () => {
const res = await lastValueFrom( const res = await lastValueFrom(
this.api.cancelFlow({ this.api.cancelFlow({
@ -127,7 +520,7 @@ export class FlowListByTypeComponent {
taskId: d.taskId, taskId: d.taskId,
}), }),
) )
this.msg.success('作废成功') this.msg.success('撤回成功')
this.table.ref.reload() this.table.ref.reload()
}, },
}) })

2
web-admin-app/src/app/components/plan-task/calendar-list/calendar-list.component.html

@ -8,7 +8,7 @@
<nz-form-label>任务状态</nz-form-label> <nz-form-label>任务状态</nz-form-label>
<nz-form-control> <nz-form-control>
<nz-select formControlName="status" nzShowSearch nzPlaceHolder="请选择" nzAllowClear> <nz-select formControlName="status" nzShowSearch nzPlaceHolder="请选择" nzAllowClear>
<nz-option nzLabel="全部" nzValue="全部"></nz-option> <nz-option nzLabel="全部" [nzValue]="-1"></nz-option>
<!-- (1-起草 2-审批中 3-已结束 4-已驳回 5-已废弃 6-流程异常 7-待指派 8-已挂起) --> <!-- (1-起草 2-审批中 3-已结束 4-已驳回 5-已废弃 6-流程异常 7-待指派 8-已挂起) -->
<nz-option nzLabel="起草" [nzValue]="1" /> <nz-option nzLabel="起草" [nzValue]="1" />
<nz-option nzLabel="审批中" [nzValue]="2" /> <nz-option nzLabel="审批中" [nzValue]="2" />

60
web-admin-app/src/app/components/plan-task/handle-task-asset-item/handle-task-asset-item.component.html

@ -90,8 +90,8 @@
@if (extraFields.length > 0) { @if (extraFields.length > 0) {
<div class="text-lg mb-6">{{ data.title }}项目</div> <div class="text-lg mb-6">{{ data.title }}项目</div>
<div nz-row [nzGutter]="24"> <div nz-row [nzGutter]="24">
@for (item of extraFields; track item.key) { @for (item of extraFields; track item.key; let fid = $index) {
<div nz-col nzSpan="8" [formGroupName]="$index"> <div nz-col [nzSpan]="item.type === 'LIST' ? 24 : 8" [formGroupName]="fid">
<nz-form-item> <nz-form-item>
<nz-form-label>{{ item.name }}</nz-form-label> <nz-form-label>{{ item.name }}</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl"> <nz-form-control [nzErrorTip]="errorTpl">
@ -103,6 +103,61 @@
[formControlName]="'value'" [formControlName]="'value'"
/> />
} }
@case ('LIST') {
<ng-container *ngIf="item?.value?.fields as fields">
<nz-table [nzBordered]="true" nzSize="small" nzTemplateMode>
<thead>
<tr>
@for (item of fields; track $index) {
<th>{{ item }}</th>
}
<th>操作</th>
</tr>
</thead>
<tbody formArrayName="value">
<tr
*ngFor="
let row of getListValue(fid).controls;
let r = index
"
>
<ng-container [formGroupName]="r">
<td *ngFor="let tc of fields; let c = index">
<input
placeholder="请输入"
nz-input
[formControlName]="tc"
/>
</td>
<td>
<button
(click)="removeRow(fid, r)"
nz-button
nzType="link"
nzDanger
>
<i nz-icon nzType="delete"></i>
</button>
</td>
</ng-container>
</tr>
<tr>
<td [attr.colspan]="fields.length + 1">
<button
nz-button
nzType="dashed"
nzBlock
(click)="addRow(fid, fields)"
>
<i nz-icon nzType="plus"></i>
新增
</button>
</td>
</tr>
</tbody>
</nz-table>
</ng-container>
}
@case ('RADIO') { @case ('RADIO') {
<ng-container *ngIf="item?.value?.fields as fields"> <ng-container *ngIf="item?.value?.fields as fields">
<nz-radio-group [formControlName]="'value'" class="radio"> <nz-radio-group [formControlName]="'value'" class="radio">
@ -116,6 +171,7 @@
</nz-radio-group> </nz-radio-group>
</ng-container> </ng-container>
} }
@case ('NUMBER') { @case ('NUMBER') {
<nz-input-number <nz-input-number
class="!w-full" class="!w-full"

72
web-admin-app/src/app/components/plan-task/handle-task-asset-item/handle-task-asset-item.component.ts

@ -22,10 +22,10 @@ import { AssetSelectBeijianComponent } from 'app/components/asset-select-beijian
// import { UploadComponent } from '../../shared/components/upload/upload.component' // import { UploadComponent } from '../../shared/components/upload/upload.component'
export const defectStatusText: Record<PlanTaskType, string[]> = { export const defectStatusText: Record<PlanTaskType, string[]> = {
inspection: ['待检', '正常', '异常', '取消'], inspection: ['待检', '正常', '异常', '取消'], // 巡检
stocktaking: ['待盘点', '正常', '盘赢', '盘亏'], stocktaking: ['待盘点', '正常', '盘赢', '盘亏'], // 盘点
maintenance: ['待保养', '正常', '异常', '取消'], maintenance: ['待保养', '正常', '异常', '取消'], // 保养
repair: [], repair: ['待保养', '正常', '异常', '取消'],
} }
@Component({ @Component({
selector: 'app-asset-form', selector: 'app-asset-form',
@ -94,6 +94,7 @@ export class HandleTaskAssetItemComponent {
sparePartsList: this.fb.control([], []), sparePartsList: this.fb.control([], []),
}) })
console.log('this.data', this.data)
this.patchValues() this.patchValues()
this.api.getBasicFinancialCategory({}).subscribe((res) => { this.api.getBasicFinancialCategory({}).subscribe((res) => {
@ -147,13 +148,51 @@ export class HandleTaskAssetItemComponent {
removeSpareParts(idx: number) { removeSpareParts(idx: number) {
// this.sparePartsList.removeAt(idx) // this.sparePartsList.removeAt(idx)
} }
setExtraFields(fields: NzSafeAny[]) { setExtraFields(fields: NzSafeAny[]) {
this.extInfo.clear() this.extInfo.clear()
this.extraFields = fields this.extraFields = fields
.sort((a, b) => a.sort - b.sort) .sort((a, b) => a.sort - b.sort)
.map((i) => { .map((i) => {
let val = i.value let val = i.value
if (i.type === 'RADIO') { if (i.type === 'RADIO' || i.type === 'LIST') {
val = i.value?.value
} else if (i.type === 'DATE') {
val = new Date(i.value)
}
const listValue =
i.type === 'LIST'
? (val ?? []).map((c: NzSafeAny) =>
this.fb.group(
i.value.fields.reduce((a: any, f: any) => {
a[f] = c[f]
return a
}, {}),
),
)
: []
this.extInfo.push(
this.fb.group({
key: this.fb.control(i.key),
name: this.fb.control(i.name),
remark: this.fb.control(i.remark),
sort: this.fb.control(i.sort),
type: this.fb.control(i.type),
value: i.type === 'LIST' ? this.fb.array(listValue) : this.fb.control(val),
fields: this.fb.control(['RADIO', 'LIST'].includes(i.type) ? i.value?.fields : []),
}),
)
return i
})
}
setExtraFields1(fields: NzSafeAny[]) {
this.extInfo.clear()
this.extraFields = fields
.sort((a, b) => a.sort - b.sort)
.map((i) => {
let val = i.value
if (i.type === 'RADIO' || i.type === 'LIST') {
val = i.value?.value val = i.value?.value
} else if (i.type === 'DATE') { } else if (i.type === 'DATE') {
val = i.value ? new Date(i.value) : null val = i.value ? new Date(i.value) : null
@ -167,7 +206,7 @@ export class HandleTaskAssetItemComponent {
sort: this.fb.control(i.sort), sort: this.fb.control(i.sort),
type: this.fb.control(i.type), type: this.fb.control(i.type),
value: this.fb.control(val), value: this.fb.control(val),
fields: this.fb.control(i.type === 'RADIO' ? i.value?.fields : []), fields: this.fb.control(['RADIO', 'LIST'].includes(i.type) ? i.value?.fields : []),
}), }),
) )
@ -198,7 +237,7 @@ export class HandleTaskAssetItemComponent {
...v, ...v,
_extInfo: this.extInfo.value.map((v: any) => { _extInfo: this.extInfo.value.map((v: any) => {
if (v.type === 'RADIO') { if (v.type === 'RADIO' || v.type === 'LIST') {
return { return {
...v, ...v,
value: { value: {
@ -213,4 +252,23 @@ export class HandleTaskAssetItemComponent {
} }
return values return values
} }
getListValue(fid: number) {
return (this.extInfo.at(fid) as FormArray).get('value') as FormArray
}
addRow(fidx: number, fields: string[]) {
const row = this.getListValue(fidx)
row.push(
this.fb.group(
fields.reduce((a: any, f: any) => {
a[f] = this.fb.control('')
return a
}, {}),
),
)
}
removeRow(fidx: number, ridx: number) {
const row = this.getListValue(fidx)
row.removeAt(ridx)
}
} }

2
web-admin-app/src/app/components/plan-task/handle-task/handle-task.component.html

@ -107,7 +107,7 @@
<span class="text-yellow-500">待分配</span> <span class="text-yellow-500">待分配</span>
} }
@default { @default {
{{ data }} {{ data.value.status | json }}
} }
} }
</nz-form-control> </nz-form-control>

9
web-admin-app/src/app/components/plan-task/handle-task/handle-task.component.ts

@ -9,7 +9,7 @@ import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NZ_MODAL_DATA, NzModalService } from 'ng-zorro-antd/modal' import { NZ_MODAL_DATA, NzModalService } from 'ng-zorro-antd/modal'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { STOCKTAKING_JOB_STATUS_MAP, taskTypeTitle } from 'app/constants' import { flowIntStatusToStr, STOCKTAKING_JOB_STATUS_MAP, taskTypeTitle } from 'app/constants'
import { import {
AssetSelectComponent, AssetSelectComponent,
OrgSelectComponent, OrgSelectComponent,
@ -94,6 +94,9 @@ export class HandleTaskComponent {
defectStatusText = defectStatusText defectStatusText = defectStatusText
defectStatusTextOnThis: string[] = [] defectStatusTextOnThis: string[] = []
flowIntStatusToStr = flowIntStatusToStr
defectStatus = { defectStatus = {
0: 'processing', 0: 'processing',
1: 'success', 1: 'success',
@ -137,9 +140,8 @@ export class HandleTaskComponent {
return i return i
}), }),
} }
console.log('val', val)
const res = await lastValueFrom(this.api.handleTaskAssetItem(val, this.data.value.id)) const res = await lastValueFrom(this.api.handleTaskAssetItem(val, this.data.value.taskId))
this.data.value = JSON.parse(JSON.stringify(val)) this.data.value = JSON.parse(JSON.stringify(val))
this.msg.success(res.desc) this.msg.success(res.desc)
// this.table.ref.reload() // this.table.ref.reload()
@ -153,6 +155,7 @@ export class HandleTaskComponent {
patchValues() { patchValues() {
const { value: data, preview, type } = this.data const { value: data, preview, type } = this.data
this.title = taskTypeTitle.get(type) this.title = taskTypeTitle.get(type)
console.log('type====', data)
this.defectStatusTextOnThis = this.defectStatusText[type as PlanTaskType] this.defectStatusTextOnThis = this.defectStatusText[type as PlanTaskType]
if (data) { if (data) {
this.formGroup.patchValue({ this.formGroup.patchValue({

11
web-admin-app/src/app/components/plan-task/plan-form/plan-form.component.html

@ -78,6 +78,16 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="8">
<nz-form-item>
<nz-form-label>重复间隔</nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-input-group nzAddOnAfter="天">
<nz-input-number class="!w-full" [nzMin]="0" formControlName="interval" />
</nz-input-group>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col [nzSpan]="8"> <div nz-col [nzSpan]="8">
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired>顺序巡检</nz-form-label> <nz-form-label nzRequired>顺序巡检</nz-form-label>
@ -95,6 +105,7 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col [nzSpan]="8"> <div nz-col [nzSpan]="8">
<nz-form-item> <nz-form-item>
<nz-form-label nzRequired>跳过周末</nz-form-label> <nz-form-label nzRequired>跳过周末</nz-form-label>

1
web-admin-app/src/app/components/plan-task/plan-form/plan-form.component.ts

@ -85,6 +85,7 @@ export class PlanFormComponent {
businessId: this.fb.control(null, []), businessId: this.fb.control(null, []),
remark: this.fb.control(null, []), remark: this.fb.control(null, []),
interval: this.fb.control(0, []),
formTempId: this.fb.control(null, [FormValidators.required('请选择')]), formTempId: this.fb.control(null, [FormValidators.required('请选择')]),

12
web-admin-app/src/app/components/plan-task/plan-list/plan-list.component.ts

@ -15,6 +15,7 @@ import { ASSET_TYPE } from 'app/constants'
import { AssetBasicTeamFormComponent } from 'app/components/asset-basic-team-form/asset-basic-team-form.component' import { AssetBasicTeamFormComponent } from 'app/components/asset-basic-team-form/asset-basic-team-form.component'
import { StatusTagComponent } from 'app/components/status-tag/status-tag.component' import { StatusTagComponent } from 'app/components/status-tag/status-tag.component'
import { PlanFormComponent } from '../plan-form/plan-form.component' import { PlanFormComponent } from '../plan-form/plan-form.component'
import { Utils } from 'app/utils'
@Component({ @Component({
selector: 'app-plan-list', selector: 'app-plan-list',
@ -82,7 +83,7 @@ export class PlanListComponent {
return v.status === '1' return v.status === '1'
}, },
}, },
{ title: '报表', onClick: this.deleteItem.bind(this) }, { title: '报表', onClick: this.baobiao.bind(this) },
]) ])
} }
@ -90,6 +91,15 @@ export class PlanListComponent {
return this.api.getPlanPage({ ...p, ...q, planType: this.type }) return this.api.getPlanPage({ ...p, ...q, planType: this.type })
} }
baobiao(i: NzSafeAny) {
this.msg.loading('下载中...')
this.api.exportPlanReport(i.jobId).subscribe((res) => {
Utils.downLoadFile(res, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8')
this.msg.remove()
this.msg.success('下载成功')
})
}
changeStatus(d: NzSafeAny) { changeStatus(d: NzSafeAny) {
const action = d.status === '0' ? '停用' : '启用' const action = d.status === '0' ? '停用' : '启用'
this.modal.confirm({ this.modal.confirm({

21
web-admin-app/src/app/components/plan-task/task-list/task-list.component.ts

@ -103,13 +103,13 @@ export class TaskListComponent {
return v.status === 'APPROVAL' return v.status === 'APPROVAL'
}, },
}, },
{ // {
title: '报表', // title: '报表',
onClick: this.onReport.bind(this), // onClick: this.onReport.bind(this),
visible(v) { // visible(v) {
return v.status === 'COMPLETED' // return v.status === 'COMPLETED'
}, // },
}, // },
]) ])
this.api.getAssetTeamAll().subscribe((res) => { this.api.getAssetTeamAll().subscribe((res) => {
this.teamList = res.body.map((i: NzSafeAny) => { this.teamList = res.body.map((i: NzSafeAny) => {
@ -263,6 +263,8 @@ export class TaskListComponent {
onHandle(chuzhi: boolean, data: NzSafeAny) { onHandle(chuzhi: boolean, data: NzSafeAny) {
// console.log('chuzhi', chuzhi, data) // console.log('chuzhi', chuzhi, data)
let nzTitle = chuzhi ? '处置任务' : '任务审批' let nzTitle = chuzhi ? '处置任务' : '任务审批'
console.log('data', data)
const footer: NzSafeAny[] = chuzhi const footer: NzSafeAny[] = chuzhi
? [ ? [
{ {
@ -296,14 +298,13 @@ export class TaskListComponent {
const res = await lastValueFrom( const res = await lastValueFrom(
this.api.handleTaskAssetItem( this.api.handleTaskAssetItem(
{ {
variables: {
...data, ...data,
...vals, ...vals,
},
taskId: data.taskId, taskId: data.taskId,
instanceId: data.procInsId, instanceId: data.procInsId,
}, },
data.id, data.taskId,
), ),
) )
this.msg.success(res.desc) this.msg.success(res.desc)

35
web-admin-app/src/app/constants/index.ts

@ -2,8 +2,10 @@ import { PlanTaskType } from 'app/types'
export const MAX_PAGE_SIZE = 10000000 export const MAX_PAGE_SIZE = 10000000
export const VERSION = 'V1'
export const LOCALSTORAGKEY = { export const LOCALSTORAGKEY = {
quickAction: 'QUICKACTION', quickAction: `QUICKACTION_${VERSION}`,
report: `REPORT_${VERSION}`,
} }
export const ASSET_STATUS = [ export const ASSET_STATUS = [
@ -17,12 +19,25 @@ export const ASSET_STATUS = [
{ label: '库存', value: 7 }, { label: '库存', value: 7 },
{ label: '已报废', value: 8 }, { label: '已报废', value: 8 },
] ]
// 1-起草 2-审批中 3-已结束 4-已驳回 5-已废弃 6-流程异常 7-待指派 8-已挂起, 9-待处置
export const ASSET_STATUS_V2 = [
{ label: '起草', value: 1 },
{ label: '审批中', value: 2 },
{ label: '已结束', value: 3 },
{ label: '已驳回', value: 4 },
{ label: '已废弃', value: 5 },
{ label: '流程异常', value: 6 },
{ label: '待指派', value: 7 },
{ label: '已挂起', value: 8 },
{ label: '待处置', value: 9 },
]
export const FLOW_FORM_TYPES = [ export const FLOW_FORM_TYPES = [
{ value: 'DATE', label: '日期' }, { value: 'DATE', label: '日期' },
{ value: 'NUMBER', label: '数字' }, { value: 'NUMBER', label: '数字' },
{ value: 'RADIO', label: '单选' }, { value: 'RADIO', label: '单选' },
{ value: 'STRING', label: '文本' }, { value: 'STRING', label: '文本' },
{ value: 'LIST', label: '列表' },
] ]
export const ASSET_STATUS_MAP = () => { export const ASSET_STATUS_MAP = () => {
return ASSET_STATUS.reduce( return ASSET_STATUS.reduce(
@ -170,11 +185,10 @@ export const flowStatus = new Map([
// REJECTED(4, "已驳回"), // REJECTED(4, "已驳回"),
// DISCARDED(5, "已废弃"), // DISCARDED(5, "已废弃"),
// EXCEPTION(6, "流程异常"), // EXCEPTION(6, "流程异常"),
// TO_BE_ASSIGNED(7,"待指派"), // TO_BE_ASSIGNED(7,"待指派"), 受理 | 指派
// SUSPENDED(8,"已挂起"), // SUSPENDED(8,"已挂起"),
// // // DISPOSE(9,"待处置"), 处置 | 挂起
// DISPOSE(9,"待处置"),
// ;
export const flowIntStatus = new Map([ export const flowIntStatus = new Map([
[1, '起草'], [1, '起草'],
[2, '审批中'], [2, '审批中'],
@ -186,3 +200,14 @@ export const flowIntStatus = new Map([
[8, '已挂起'], [8, '已挂起'],
[9, '待处置'], [9, '待处置'],
]) ])
export const flowIntStatusToStr = new Map([
[1, 'DRAFTING'],
[2, 'APPROVAL'],
[3, 'COMPLETED'],
[4, 'REJECTED'],
[5, 'DISCARDED'],
[6, 'EXCEPTION'],
[7, 'TO_BE_ASSIGNED'],
[8, 'SUSPENDED'],
[9, 'DISPOSE'],
])

46
web-admin-app/src/app/pages/dashboard/dashboard.component.ts

@ -23,19 +23,32 @@ const antvColor = [
] ]
const defaultAction = [ const defaultAction = [
{ icon: 'database', title: '资产管理', link: '/fixed-asset/manage/list' }, { icon: 'appstore', title: '资产管理', link: '/fixed-asset/management' },
{ icon: 'download', title: '资产入库', link: '/fixed-asset/manage/entry' }, { icon: 'appstore', title: '资产台账', link: '/fixed-asset/ledger/asset-search' },
{ icon: 'user-add', title: '资产领用', link: '/fixed-asset/manage/distribution' }, { icon: 'appstore', title: '资产登记', link: '/fixed-asset/registration' },
{ icon: 'import', title: '资产退库', link: '/fixed-asset/manage/return' }, { icon: 'appstore', title: '维修登记', link: '/fixed-asset/maintain/record' },
{ icon: 'node-expand', title: '资产借用', link: '/fixed-asset/manage/borrow' }, { icon: 'appstore', title: '开关机', link: '/fixed-asset/maintain/on-off' },
{ icon: 'node-collapse', title: '资产归还', link: '/fixed-asset/manage/revert' }, { icon: 'appstore', title: '巡检计划', link: '/fixed-asset/inspection/plan' },
{ icon: 'node-index', title: '资产调拨', link: '/fixed-asset/manage/allot' }, { icon: 'appstore', title: '巡检任务', link: '/fixed-asset/inspection/task' },
{ icon: 'sync', title: '资产转换', link: '/fixed-asset/manage/transfer' }, { icon: 'appstore', title: '巡检日历', link: '/fixed-asset/inspection/calendar' },
{ icon: 'delete', title: '资产报废', link: '/fixed-asset/manage/scrap' }, { icon: 'appstore', title: '保养计划', link: '/fixed-asset/maintenance/plan' },
{ icon: 'profile', title: '盘点计划', link: '/fixed-asset/stocktaking/plan' }, { icon: 'appstore', title: '保养任务', link: '/fixed-asset/maintenance/task' },
{ icon: 'file-protect', title: '盘点任务', link: '/fixed-asset/stocktaking/job/list' }, { icon: 'appstore', title: '保养日历', link: '/fixed-asset/maintenance/calendar' },
{ icon: 'carry-out', title: '维修登记', link: '/fixed-asset/repair/list' }, { icon: 'appstore', title: '盘点计划', link: '/fixed-asset/stocktaking/plan' },
{ icon: 'alert', title: '故障登记', link: '/fixed-asset/repair/fault' }, { icon: 'appstore', title: '盘点任务', link: '/fixed-asset/stocktaking/task' },
{ icon: 'appstore', title: '盘点日历', link: '/fixed-asset/stocktaking/calendar' },
// { icon: 'download', title: '资产入库', link: '/fixed-asset/manage/entry' },
// { icon: 'user-add', title: '资产领用', link: '/fixed-asset/manage/distribution' },
// { icon: 'import', title: '资产退库', link: '/fixed-asset/manage/return' },
// { icon: 'node-expand', title: '资产借用', link: '/fixed-asset/manage/borrow' },
// { icon: 'node-collapse', title: '资产归还', link: '/fixed-asset/manage/revert' },
// { icon: 'node-index', title: '资产调拨', link: '/fixed-asset/manage/allot' },
// { icon: 'sync', title: '资产转换', link: '/fixed-asset/manage/transfer' },
// { icon: 'delete', title: '资产报废', link: '/fixed-asset/manage/scrap' },
// { icon: 'profile', title: '盘点计划', link: '/fixed-asset/stocktaking/plan' },
// { icon: 'file-protect', title: '盘点任务', link: '/fixed-asset/stocktaking/job/list' },
// { icon: 'carry-out', title: '维修登记', link: '/fixed-asset/repair/list' },
// { icon: 'alert', title: '故障登记', link: '/fixed-asset/repair/fault' },
] ]
@Component({ @Component({
@ -131,6 +144,7 @@ export class DashboardComponent implements OnInit, AfterViewInit {
ngOnInit(): void { ngOnInit(): void {
this.api.getHomeData().subscribe((res) => { this.api.getHomeData().subscribe((res) => {
this.data = res.body this.data = res.body
this.count = res.body.todo
this.initChartBar(this.chart1, this.data.assetStatusChart, 1) this.initChartBar(this.chart1, this.data.assetStatusChart, 1)
this.initChartBar(this.chart2, this.data.assetPositionChart, 2) this.initChartBar(this.chart2, this.data.assetPositionChart, 2)
this.initChartBar(this.chart3, this.data.assetCategoryChart, 3) this.initChartBar(this.chart3, this.data.assetCategoryChart, 3)
@ -138,9 +152,9 @@ export class DashboardComponent implements OnInit, AfterViewInit {
this.initChartBar(this.chart5, this.data.assetOwnChart, 5) this.initChartBar(this.chart5, this.data.assetOwnChart, 5)
this.initChartBar(this.chart6, this.data.assetUseChart, 6) this.initChartBar(this.chart6, this.data.assetUseChart, 6)
}) })
this.api.getHomeTodocountData().subscribe((res) => { // this.api.getHomeTodocountData().subscribe((res) => {
this.count = res.body // this.count = res.body
}) // })
this.initQuickAction() this.initQuickAction()
} }

2
web-admin-app/src/app/pages/data-vis/data-vis.component.html

@ -3,7 +3,7 @@
<div class="vis-hd-left"> <div class="vis-hd-left">
{{ time | date: 'yyyy-MM-dd HH:mm:ss' }} {{ time | date: 'yyyy-MM-dd HH:mm:ss' }}
</div> </div>
<div class="vis-title">EAM数据可视化</div> <div class="vis-title">{{ data?.bigScreenName }}</div>
<div class="vis-hd-right"> <div class="vis-hd-right">
{{ data?.slogan }} {{ data?.slogan }}
</div> </div>

8
web-admin-app/src/app/pages/data-vis/data-vis.component.less

@ -7,11 +7,10 @@
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 0 0 / cover; background-position: 0 0 / cover;
background-color: #101129; background-color: #101129;
overflow: hidden;
} }
html {
font-size: 21.1375px !important;
}
* { * {
margin: 0; margin: 0;
@ -59,6 +58,7 @@
max-width: 1920px; max-width: 1920px;
min-height: 780px; min-height: 780px;
margin: 0 auto; margin: 0 auto;
background-color: #101129;
background: url(/assets/data-vis/images/logo.png) no-repeat 0 0 / contain; background: url(/assets/data-vis/images/logo.png) no-repeat 0 0 / contain;
display: flex; display: flex;
padding: 3.667rem 0.833rem 0; padding: 3.667rem 0.833rem 0;
@ -318,7 +318,7 @@
/* 地图 */ /* 地图 */
.map { .map {
height: 24.1rem; height: 23.1rem;
margin-bottom: 0.833rem; margin-bottom: 0.833rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

72
web-admin-app/src/app/pages/data-vis/data-vis.component.ts

@ -1,9 +1,10 @@
import { Component, ElementRef, ViewChild } from '@angular/core' import { Component, ElementRef, HostListener, Inject, Renderer2, ViewChild } from '@angular/core'
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { interval } from 'rxjs' import { debounceTime, fromEvent, interval, Subscription } from 'rxjs'
import { init, EChartsType } from 'echarts' import { init, EChartsType } from 'echarts'
import { DOCUMENT } from '@angular/common'
@Component({ @Component({
selector: 'app-data-vis', selector: 'app-data-vis',
@ -13,7 +14,11 @@ import { init, EChartsType } from 'echarts'
styleUrl: './data-vis.component.less', styleUrl: './data-vis.component.less',
}) })
export class DataVisComponent { export class DataVisComponent {
constructor(private api: ApiService) {} constructor(
private api: ApiService,
private renderer: Renderer2,
@Inject(DOCUMENT) private document: Document,
) {}
@ViewChild('cateTpl') cateTpl?: ElementRef<HTMLDivElement> @ViewChild('cateTpl') cateTpl?: ElementRef<HTMLDivElement>
@ViewChild('statusTpl') statusTpl?: ElementRef<HTMLDivElement> @ViewChild('statusTpl') statusTpl?: ElementRef<HTMLDivElement>
@ -30,7 +35,37 @@ export class DataVisComponent {
data: NzSafeAny data: NzSafeAny
time = new Date() time = new Date()
private setFontSize() {
const html = this.document.documentElement
// 计算基于视口宽度和高度的 font-size,取最小值并适当缩放
const fontSize = `${Math.min(window.innerWidth, window.innerHeight) / 44.5}px`
// 将计算后的 font-size 应用于根元素
this.renderer.setStyle(html, 'font-size', fontSize)
}
@HostListener('window:resize')
onResize() {
this.cateRef?.resize()
this.statusRef?.resize()
this.changeRef?.resize()
this.posRef?.resize()
this.flowRef?.resize()
this.setFontSize()
}
fullscreenSubscription!: Subscription
ngOnDestroy(): void {
this.fullscreenSubscription.unsubscribe()
}
ngOnInit(): void { ngOnInit(): void {
this.setFontSize()
this.fullscreenSubscription = fromEvent(this.document, 'fullscreenchange')
.pipe(debounceTime(100))
.subscribe(() => this.setFontSize())
this.api.bigScreen().subscribe((res) => { this.api.bigScreen().subscribe((res) => {
this.data = res.body this.data = res.body
setTimeout(() => { setTimeout(() => {
@ -64,7 +99,7 @@ export class DataVisComponent {
legend: { legend: {
bottom: 'bottom', bottom: 'bottom',
left: 'center', left: 'center',
type: 'scroll', // type: 'scroll',
textStyle: { textStyle: {
color: '#ffffff', color: '#ffffff',
}, },
@ -73,14 +108,16 @@ export class DataVisComponent {
series: [ series: [
{ {
type: 'pie', type: 'pie',
radius: [10, 100], // radius: [10, 100],
label: { label: {
formatter: '{b}-{c}', formatter: '{b}-{c}',
// position: 'inside', // position: 'inside',
color: '#fff',
}, },
itemStyle: { itemStyle: {
borderRadius: 8, // borderRadius: 8,
}, },
bottom: '40',
data: this.data.flowTypeChart.map((i: any) => { data: this.data.flowTypeChart.map((i: any) => {
return { return {
value: i.total, value: i.total,
@ -104,6 +141,8 @@ export class DataVisComponent {
name.push(i.name) name.push(i.name)
val.push(i.total) val.push(i.total)
}) })
console.log('name', name, val)
this.posRef.setOption({ this.posRef.setOption({
grid: { grid: {
top: '5%', top: '5%',
@ -113,7 +152,7 @@ export class DataVisComponent {
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, // boundaryGap: false,
data: name, data: name,
splitLine: { splitLine: {
show: false, show: false,
@ -134,8 +173,6 @@ export class DataVisComponent {
{ {
data: val, data: val,
type: 'bar', type: 'bar',
areaStyle: {},
smooth: true,
}, },
], ],
}) })
@ -201,7 +238,7 @@ export class DataVisComponent {
legend: { legend: {
bottom: 'bottom', bottom: 'bottom',
left: 'center', left: 'center',
type: 'scroll', // type: 'scroll',
textStyle: { textStyle: {
color: '#ffffff', color: '#ffffff',
}, },
@ -210,11 +247,11 @@ export class DataVisComponent {
series: [ series: [
{ {
type: 'pie', type: 'pie',
radius: [10, 100], // radius: [10, 100],
roseType: 'area', // roseType: 'area',
itemStyle: { itemStyle: {
borderRadius: 8, // borderRadius: 8,
}, },
data: this.data.assetStatusChart.map((i: any) => { data: this.data.assetStatusChart.map((i: any) => {
return { return {
@ -222,6 +259,10 @@ export class DataVisComponent {
name: i.name, name: i.name,
} }
}), }),
bottom: '30',
label: {
color: '#fff',
},
}, },
], ],
}) })
@ -235,7 +276,9 @@ export class DataVisComponent {
} }
const name: string[] = [] const name: string[] = []
const val: number[] = [] const val: number[] = []
this.data.assetCategoryChart.forEach((i: any) => { this.data.assetCategoryChart
// .sort((a: any, b: any) => a.total - b.total)
.forEach((i: any) => {
name.push(i.name) name.push(i.name)
val.push(i.total) val.push(i.total)
}) })
@ -255,6 +298,7 @@ export class DataVisComponent {
yAxis: { yAxis: {
type: 'category', type: 'category',
data: name, data: name,
inverse: true,
axisLabel: { axisLabel: {
show: true, show: true,
color: '#ffffff', color: '#ffffff',

3
web-admin-app/src/app/pages/fixed-asset/alert/alert-borrow/alert-borrow.component.html

@ -3,6 +3,9 @@
<app-server-paginated-table [options]="table" [formGroup]="queryForm" [renderColumn]="renderColumnTpl"> <app-server-paginated-table [options]="table" [formGroup]="queryForm" [renderColumn]="renderColumnTpl">
<ng-template #renderColumnTpl let-data let-key="key" let-row="row"> <ng-template #renderColumnTpl let-data let-key="key" let-row="row">
@switch (key) { @switch (key) {
@case ('alarmType') {
借用超期
}
@case ('_useUser') { @case ('_useUser') {
{{ data?.userName ?? '-' }} {{ data?.userName ?? '-' }}
} }

24
web-admin-app/src/app/pages/fixed-asset/alert/alert-borrow/alert-borrow.component.ts

@ -5,7 +5,7 @@ import { AnyObject, TableOption } from 'app/shared/components/server-paginated-t
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
@ -42,20 +42,34 @@ export class AlertBorrowComponent {
// rowKey: 'id', // rowKey: 'id',
// }) // })
.setColumn([ .setColumn([
{ key: 'index', title: '序号', visible: true, width: '60px' },
{ key: 'alarmType', title: '报警类型', visible: true },
{ key: 'createTime', title: '告警时间', visible: true },
{ key: 'returnTime', title: '归还时间', visible: true },
{ key: 'businessId', title: '借用业务编号', visible: true },
{ key: 'name', title: '名称', visible: true },
{ key: '_category', title: '资产分类', visible: true }, { key: '_category', title: '资产分类', visible: true },
{ key: 'assetCode', title: '资产编号', visible: true }, { key: 'assetCode', title: '资产编号', visible: true },
{ key: 'name', title: '名称', visible: true },
{ key: 'model', title: '规格型号', visible: true }, { key: 'model', title: '规格型号', visible: true },
{ key: 'serialNumber', title: '序列号', visible: true }, { key: 'serialNumber', title: '序列号', visible: true },
{ key: 'notes', title: '备注', visible: true }, { key: 'notes', title: '备注', visible: true },
{ key: 'returnTime', title: '归还时间', visible: true },
{ key: 'businessId', title: '借用业务编号', visible: true },
// { key: 'createTime', title: '创建时间', visible: true }, // { key: 'createTime', title: '创建时间', visible: true },
]) ])
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getAlertBorrow({ ...p, ...q }) return this.api.getAlertBorrow({ ...p, ...q }).pipe(
map((r) => {
r.body.rows = r.body.rows.map((item: NzSafeAny, idx: number) => {
item.index = idx + 1
return item
})
return r
}),
)
} }
} }

14
web-admin-app/src/app/pages/fixed-asset/alert/alert-inventory-down/alert-inventory-down.component.ts

@ -5,7 +5,7 @@ import { AnyObject, TableOption } from 'app/shared/components/server-paginated-t
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
@ -40,6 +40,7 @@ export class AlertInventoryDownComponent {
// rowKey: 'id', // rowKey: 'id',
// }) // })
.setColumn([ .setColumn([
{ key: 'index', title: '序号', visible: true, width: '60px' },
{ key: 'categoryName', title: '资产分类', visible: true }, { key: 'categoryName', title: '资产分类', visible: true },
{ key: 'assetCode', title: '资产编号', visible: true }, { key: 'assetCode', title: '资产编号', visible: true },
{ key: 'name', title: '名称', visible: true }, { key: 'name', title: '名称', visible: true },
@ -55,6 +56,15 @@ export class AlertInventoryDownComponent {
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getAlertSafetyDown({ ...p, ...q }) return this.api.getAlertSafetyDown({ ...p, ...q }).pipe(
map((r) => {
r.body.rows = r.body.rows.map((item: NzSafeAny, idx: number) => {
item.index = idx + 1
return item
})
return r
}),
)
} }
} }

30
web-admin-app/src/app/pages/fixed-asset/alert/alert-inventory-safety/alert-inventory-safety.component.ts

@ -5,7 +5,7 @@ import { AnyObject, TableOption } from 'app/shared/components/server-paginated-t
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
@ -40,21 +40,37 @@ export class AlertInventorySafetyComponent {
// rowKey: 'id', // rowKey: 'id',
// }) // })
.setColumn([ .setColumn([
{ key: 'categoryName', title: '资产分类', visible: true }, // 序号-报警类型-告警时间-资产信息-超期/数量等信息
{ key: 'assetCode', title: '资产编号', visible: true }, { key: 'index', title: '序号', visible: true, width: '60px' },
{ key: 'name', title: '名称', visible: true },
{ key: 'model', title: '规格型号', visible: true },
{ key: 'warehouseName', title: '仓库', visible: true }, { key: 'alarmType', title: '报警类型', visible: true },
{ key: 'createTime', title: '告警时间', visible: true },
{ key: 'count', title: '库存数量', visible: true, width: '100px' }, { key: 'count', title: '库存数量', visible: true, width: '100px' },
{ key: 'safetyLimit', title: '安全库存', visible: true, width: '100px' }, { key: 'safetyLimit', title: '安全库存', visible: true, width: '100px' },
{ key: 'upperLimit', title: '库存上限', visible: true, width: '100px' }, { key: 'upperLimit', title: '库存上限', visible: true, width: '100px' },
{ key: 'lowerLimit', title: '库存下限', visible: true, width: '100px' }, { key: 'lowerLimit', title: '库存下限', visible: true, width: '100px' },
{ key: 'name', title: '名称', visible: true },
{ key: 'categoryName', title: '资产分类', visible: true },
{ key: 'assetCode', title: '资产编号', visible: true },
{ key: 'model', title: '规格型号', visible: true },
{ key: 'warehouseName', title: '仓库', visible: true },
// { key: 'createTime', title: '创建时间', visible: true }, // { key: 'createTime', title: '创建时间', visible: true },
]) ])
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getAlertSafety({ ...p, ...q }) return this.api.getAlertSafety({ ...p, ...q }).pipe(
map((r) => {
r.body.rows = r.body.rows.map((item: NzSafeAny, idx: number) => {
item.index = idx + 1
return item
})
return r
}),
)
} }
} }

3
web-admin-app/src/app/pages/fixed-asset/alert/alert-maintenance/alert-maintenance.component.html

@ -3,6 +3,9 @@
<app-server-paginated-table [options]="table" [formGroup]="queryForm" [renderColumn]="renderColumnTpl"> <app-server-paginated-table [options]="table" [formGroup]="queryForm" [renderColumn]="renderColumnTpl">
<ng-template #renderColumnTpl let-data let-key="key" let-row="row"> <ng-template #renderColumnTpl let-data let-key="key" let-row="row">
@switch (key) { @switch (key) {
@case ('alarmType') {
维保到期
}
@case ('_useUser') { @case ('_useUser') {
{{ data?.userName ?? '-' }} {{ data?.userName ?? '-' }}
} }

18
web-admin-app/src/app/pages/fixed-asset/alert/alert-maintenance/alert-maintenance.component.ts

@ -5,7 +5,7 @@ import { AnyObject, TableOption } from 'app/shared/components/server-paginated-t
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
@ -39,7 +39,10 @@ export class AlertMaintenanceComponent {
// rowKey: 'id', // rowKey: 'id',
// }) // })
.setColumn([ .setColumn([
{ key: '_category', title: '资产分类', visible: true }, { key: 'index', title: '序号', visible: true, width: '60px' },
{ key: 'alarmType', title: '报警类型', visible: true },
{ key: 'createTime', title: '告警时间', visible: true },
{ key: 'maintenanceEndDate', title: '维保到期时间', visible: true },
{ key: 'assetCode', title: '资产编号', visible: true }, { key: 'assetCode', title: '资产编号', visible: true },
{ key: 'name', title: '名称', visible: true }, { key: 'name', title: '名称', visible: true },
{ key: 'model', title: '规格型号', visible: true }, { key: 'model', title: '规格型号', visible: true },
@ -50,6 +53,15 @@ export class AlertMaintenanceComponent {
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getAlertMaintenance({ ...p, ...q }) return this.api.getAlertMaintenance({ ...p, ...q }).pipe(
map((r) => {
r.body.rows = r.body.rows.map((item: NzSafeAny, idx: number) => {
item.index = idx + 1
return item
})
return r
}),
)
} }
} }

37
web-admin-app/src/app/pages/fixed-asset/asset-management/asset-management.component.html

@ -30,32 +30,20 @@
@switch (key) { @switch (key) {
@case ('status') { @case ('status') {
<nz-tag> <nz-tag>
{{ ASSET_STATUS_MAP[data] }} {{ ASSET_STATUS_V2_MAP(data) }}
</nz-tag> </nz-tag>
} }
@case ('type') { @case ('type') {
<nz-tag> <nz-tag nzColor="teal">
{{ businessType.get(data) }} {{ businessType.get(data) }}
</nz-tag> </nz-tag>
} }
@case ('_warehouse') { @case ('urgency') {
{{ data?.name ?? '-' }} <nz-tag [nzColor]="data === 2 ? 'error' : ''">
} {{ data === 2 ? '紧急' : '普通' }}
@case ('_position') { </nz-tag>
{{ data?.name ?? '-' }}
}
@case ('_head') {
{{ data?.userName ?? '-' }}
}
@case ('_ownCompany') {
{{ data?.organizationName ?? '-' }}
}
@case ('_useOrganization') {
{{ data?.organizationName ?? '-' }}
}
@case ('_category') {
{{ data?.categoryName ?? '-' }}
} }
@default { @default {
{{ data }} {{ data }}
} }
@ -77,7 +65,16 @@
</nz-select> </nz-select>
</app-query-item> </app-query-item>
<app-query-item label="流程状态"> <app-query-item label="流程状态">
<input nz-input placeholder="请输入" formControlName="assetCode" /> <nz-select
nzPlaceHolder="请选择"
nzPlacement="bottomRight"
class="!w-24"
[nzDropdownMatchSelectWidth]="false"
formControlName="status"
nzAllowClear
>
<nz-option *ngFor="let item of ASSET_STATUS" [nzLabel]="item.label" [nzValue]="item.value" />
</nz-select>
</app-query-item> </app-query-item>
<app-query-item label="流程名称"> <app-query-item label="流程名称">
<input nz-input placeholder="请输入" formControlName="name" /> <input nz-input placeholder="请输入" formControlName="name" />

45
web-admin-app/src/app/pages/fixed-asset/asset-management/asset-management.component.ts

@ -22,7 +22,7 @@ import {
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal' import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { ASSET_SOURCE_MAP, ASSET_STATUS, ASSET_STATUS_MAP, ASSET_TYPE, businessType } from 'app/constants' import { ASSET_STATUS, ASSET_STATUS_MAP, ASSET_STATUS_V2, ASSET_TYPE, businessType } from 'app/constants'
import { Utils } from 'app/utils' import { Utils } from 'app/utils'
@Component({ @Component({
@ -52,7 +52,11 @@ export class AssetManagementComponent {
ASSET_STATUS_MAP = ASSET_STATUS_MAP() ASSET_STATUS_MAP = ASSET_STATUS_MAP()
ASSET_SOURCE_MAP = ASSET_SOURCE_MAP ASSET_STATUS = ASSET_STATUS_V2
ASSET_STATUS_V2_MAP(v: number) {
return ASSET_STATUS_V2.find((f) => f.value === v)?.label ?? '-'
}
table = new TableOption(this.fetchData.bind(this)) table = new TableOption(this.fetchData.bind(this))
@ -71,18 +75,18 @@ export class AssetManagementComponent {
.setColumn([ .setColumn([
{ key: 'businessId', title: '业务编号', visible: true }, { key: 'businessId', title: '业务编号', visible: true },
{ key: 'name', title: '流程名称', visible: true }, { key: 'name', title: '流程名称', visible: true },
{ key: 'type', title: '流程类型', visible: true }, { key: 'type', title: '流程类型', visible: true, width: '120px' },
{ key: 'status', title: '流程状态', visible: true }, { key: 'status', title: '流程状态', visible: true, width: '100px' },
{ key: '_ownCompany', title: '紧急程度', visible: true }, { key: 'urgency', title: '紧急程度', visible: true, width: '100px' },
{ key: '_useOrganization', title: '发起人', visible: true }, { key: 'applicant', title: '发起人', visible: true },
{ key: 'createTime', title: '创建时间', visible: true }, { key: 'createTime', title: '创建时间', visible: true },
{ key: '_position', title: '当前节点', visible: true }, { key: 'currentNode', title: '当前节点', visible: true },
{ key: '_position', title: '备注', visible: true }, { key: 'notes', title: '备注', visible: true },
]) ])
.setRowOperate([ .setRowOperate([
{ title: '查看', onClick: this.itemAction.bind(this, 'preview') }, { title: '查看', onClick: this.itemAction.bind(this, 'preview') },
{ title: '修改', onClick: this.itemAction.bind(this, 'edit') }, // { title: '修改', onClick: this.itemAction.bind(this, 'edit') },
{ title: '删除', onClick: this.deleteItem.bind(this) }, // { title: '删除', onClick: this.deleteItem.bind(this) },
]) ])
} }
@ -137,7 +141,12 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessStorage(vals)) const res = await lastValueFrom(
this.api.assetAddByFlow({
...vals,
type: 'STORAGE',
}),
)
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -163,7 +172,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessCollection(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'COLLECTION' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -191,7 +200,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessReturnInventory(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'RETURN_INVENTORY' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -218,7 +227,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessBorrow(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'BORROW' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -246,7 +255,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessAllocate(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'ALLOCATE' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -274,7 +283,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessTransfer(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'TRANSFER' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -302,7 +311,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessRetirement(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'RETIREMENT' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true
@ -329,7 +338,7 @@ export class AssetManagementComponent {
nzOnOk: async (e) => { nzOnOk: async (e) => {
const vals = e.getValues() const vals = e.getValues()
if (vals) { if (vals) {
const res = await lastValueFrom(this.api.saveBusinessRevert(vals)) const res = await lastValueFrom(this.api.assetAddByFlow({ ...vals, type: 'RETURN' }))
this.msg.success(res.desc) this.msg.success(res.desc)
this.table.ref.reload() this.table.ref.reload()
return true return true

85
web-admin-app/src/app/pages/fixed-asset/basic/basic-category/basic-category.component.html

@ -100,8 +100,10 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@for (item of formValue.controls; track $index) { <tr
<tr [formGroupName]="$index"> *ngFor="let item of formValue.controls; let $index = index"
[formGroupName]="$index"
>
<td> <td>
<nz-input-number <nz-input-number
[nzStep]="1" [nzStep]="1"
@ -124,10 +126,7 @@
/> />
</td> </td>
<td> <td>
<nz-select <nz-select nzPlaceHolder="请选择" formControlName="type">
nzPlaceHolder="请选择"
formControlName="type"
>
@for (item of FLOW_FORM_TYPES; track $index) { @for (item of FLOW_FORM_TYPES; track $index) {
<nz-option <nz-option
[nzLabel]="item.label" [nzLabel]="item.label"
@ -182,16 +181,69 @@
class="ml-2" class="ml-2"
nzDanger nzDanger
(click)=" (click)="
removeRadioItem( removeRadioItem($index, i)
$index,
i
)
" "
> >
<i <i nz-icon nzType="delete"></i>
</button>
</div>
</div>
</nz-radio-group>
</ng-container>
<div class="mt-2">
<button
nz-button
nzSize="small"
(click)="addRadioItem($index)"
>
<span
nz-icon nz-icon
nzType="delete" nzType="plus"
></i> nzTheme="outline"
></span>
新增选项
</button>
</div>
}
@case ('LIST') {
<ng-container
*ngIf="getRadioFields($index) as fields"
>
<nz-radio-group
formControlName="value"
class="radio"
>
<div formArrayName="fields">
<div
class="flex items-center mb-2"
*ngFor="
let f of fields;
let i = index
"
>
<!-- <label
class="!flex"
nz-radio
[nzValue]="f.value"
>
</label> -->
<input
class="flex-1"
nz-input
nzSize="small"
[formControlName]="i"
/>
<button
nz-button
nzType="text"
nzSize="small"
class="ml-2"
nzDanger
(click)="
removeRadioItem($index, i)
"
>
<i nz-icon nzType="delete"></i>
</button> </button>
</div> </div>
</div> </div>
@ -245,15 +297,10 @@
nzDanger="" nzDanger=""
(click)="removeFormItem($index)" (click)="removeFormItem($index)"
> >
<span <span nz-icon nzType="delete" nzTheme="outline"></span>
nz-icon
nzType="delete"
nzTheme="outline"
></span>
</button> </button>
</td> </td>
</tr> </tr>
}
<tr> <tr>
<td colspan="6" class="text-right"></td> <td colspan="6" class="text-right"></td>

35
web-admin-app/src/app/pages/fixed-asset/basic/basic-category/basic-category.component.ts

@ -52,7 +52,7 @@ export class BasicCategoryComponent {
safetyLimit: [0, []], safetyLimit: [0, []],
lowerLimit: [0, []], lowerLimit: [0, []],
upperLimit: [0, []], upperLimit: [0, []],
_assetExtTemp: new FormArray([]), _assetExtTemp: this.fb.array([]),
}) })
} }
initQueryForm() { initQueryForm() {
@ -67,10 +67,9 @@ export class BasicCategoryComponent {
} }
onSelectedChange(v: NzSafeAny) { onSelectedChange(v: NzSafeAny) {
this.createForm.patchValue({ const { _assetExtTemp, ...r } = v
...v, this.createForm.patchValue(r)
}) this.patchFormValue(_assetExtTemp ?? [])
this.patchFormValue(v._assetExtTemp ?? [])
} }
get formValue(): FormArray { get formValue(): FormArray {
@ -80,12 +79,12 @@ export class BasicCategoryComponent {
onConfirm() { onConfirm() {
if (FormValidators.validateFormGroup(this.createForm)) { if (FormValidators.validateFormGroup(this.createForm)) {
const { value } = this.createForm const { value } = this.createForm
console.log('value', value)
this.api this.api
.updateBasicCategoryTree({ .updateBasicCategoryTree({
...value, ...value,
_assetExtTemp: this.formValue.value.map((v: any) => { _assetExtTemp: this.formValue.value.map((v: any) => {
if (v.type === 'RADIO') { if (v.type === 'RADIO' || v.type === 'LIST') {
return { return {
...v, ...v,
value: { value: {
@ -123,8 +122,9 @@ export class BasicCategoryComponent {
this.formValue.clear() this.formValue.clear()
e.forEach((v) => { e.forEach((v) => {
let value = v.value let value = v.value
// console.log('v', v)
const fieldsArrays = this.fb.array([]) const fieldsArrays = this.fb.array([])
if (v.type === 'RADIO') { if (v.type === 'RADIO' || v.type === 'LIST') {
let val = Object.create(null) let val = Object.create(null)
try { try {
val = typeof v.value === 'string' ? JSON.parse(v.value) : v.value val = typeof v.value === 'string' ? JSON.parse(v.value) : v.value
@ -134,18 +134,23 @@ export class BasicCategoryComponent {
}) })
value = val?.value value = val?.value
} }
if (v.type === 'DATE') {
value = new Date(v.value)
}
this.formValue.push( this.formValue.push(
new FormGroup({ this.fb.group({
key: new FormControl(v.key, []), key: this.fb.control(v.key, []),
value: new FormControl(value, []), value: this.fb.control(value, []),
name: new FormControl(v.name, []), name: this.fb.control(v.name, []),
type: new FormControl(v.type, []), type: this.fb.control(v.type, []),
remark: new FormControl(v.remark, []), remark: this.fb.control(v.remark, []),
sort: new FormControl(v.sort ?? 0, []), sort: this.fb.control(v.sort ?? 0, []),
fields: fieldsArrays, fields: fieldsArrays,
}), }),
) )
}) })
console.log('this.formValue', this.formValue)
} }
formatRadioValue(fields: string[], value: string) {} formatRadioValue(fields: string[], value: string) {}

74
web-admin-app/src/app/pages/fixed-asset/basic/basic-flow-form-manage/basic-flow-form-manage.component.html

@ -52,15 +52,11 @@
<nz-form-item> <nz-form-item>
<nz-form-label nzSpan="5" [nzRequired]="true">选择模板</nz-form-label> <nz-form-label nzSpan="5" [nzRequired]="true">选择模板</nz-form-label>
<nz-form-control nzSpan="14" [nzExtra]="tempalteTpl" [nzErrorTip]="formErrorTpl"> <nz-form-control nzSpan="14" [nzExtra]="tempalteTpl" [nzErrorTip]="formErrorTpl">
<app-upload <app-upload [drag]="true" [uploadFn]="api.uploadFormTpl" (onUpload)="onTplupload($event)" />
[drag]="true"
[uploadFn]="api.uploadFlowFormTpl"
(onUpload)="onTplupload($event)"
/>
</nz-form-control> </nz-form-control>
<ng-template #tempalteTpl> <ng-template #tempalteTpl>
<div class="mt-4"> <div class="mt-4">
<a (click)="downloadTemplate()"> <a (click)="downloadTemplate1()">
<i nz-icon nzType="cloud-download" class="mb-2"></i> <i nz-icon nzType="cloud-download" class="mb-2"></i>
点击下载模板示例 点击下载模板示例
</a> </a>
@ -85,14 +81,12 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@for (item of formValue.controls; track $index) { <tr
<tr [formGroupName]="$index"> [formGroupName]="$index"
*ngFor="let item of formValue.controls; let $index = index"
>
<td> <td>
<nz-input-number <nz-input-number [nzStep]="1" placeholder="请输入" formControlName="sort" />
[nzStep]="1"
placeholder="请输入"
formControlName="sort"
/>
</td> </td>
<td> <td>
<input nz-input placeholder="请输入" formControlName="key" /> <input nz-input placeholder="请输入" formControlName="key" />
@ -116,20 +110,14 @@
formControlName="value" formControlName="value"
/> />
} }
@case ('RADIO') { @case ('LIST') {
<ng-container *ngIf="getRadioFields($index) as fields"> <ng-container *ngIf="getRadioFields($index) as fields">
<nz-radio-group formControlName="value" class="radio"> <nz-radio-group formControlName="value" class="radio">
<div formArrayName="fields"> <div formArrayName="fields">
<div <div
class="flex items-center" class="mb-2 flex items-center"
*ngFor="let f of fields; let i = index" *ngFor="let f of fields; let i = index"
> >
<label
class="!flex"
nz-radio
[nzValue]="f.value"
>
</label>
<input <input
class="flex-1" class="flex-1"
nz-input nz-input
@ -151,11 +139,42 @@
</nz-radio-group> </nz-radio-group>
</ng-container> </ng-container>
<div class="mt-2"> <div class="mt-2">
<button nz-button nzSize="small" (click)="addRadioItem($index)">
<span nz-icon nzType="plus" nzTheme="outline"></span>
新增选项
</button>
</div>
}
@case ('RADIO') {
<ng-container *ngIf="getRadioFields($index) as fields">
<nz-radio-group formControlName="value" class="radio">
<div formArrayName="fields">
<div
class="flex mb-2 items-center"
*ngFor="let f of fields; let i = index"
>
<input
class="flex-1"
nz-input
nzSize="small"
[formControlName]="i"
/>
<button <button
nz-button nz-button
nzType="text"
nzSize="small" nzSize="small"
(click)="addRadioItem($index)" class="ml-2"
nzDanger
(click)="removeRadioItem($index, i)"
> >
<i nz-icon nzType="delete"></i>
</button>
</div>
</div>
</nz-radio-group>
</ng-container>
<div class="mt-2">
<button nz-button nzSize="small" (click)="addRadioItem($index)">
<span nz-icon nzType="plus" nzTheme="outline"></span> <span nz-icon nzType="plus" nzTheme="outline"></span>
新增选项 新增选项
</button> </button>
@ -194,7 +213,6 @@
</button> </button>
</td> </td>
</tr> </tr>
}
<tr> <tr>
<td colspan="6" class="text-right"></td> <td colspan="6" class="text-right"></td>
@ -211,20 +229,20 @@
</ng-template> </ng-template>
<ng-template #step3> <ng-template #step3>
<nz-form-item> <nz-form-item>
<nz-form-label nzSpan="5" nzRequired>模板示例</nz-form-label> <nz-form-label nzSpan="5" nzRequired>模板预览</nz-form-label>
<nz-form-control nzSpan="14" [nzErrorTip]="formErrorTpl"> <nz-form-control nzSpan="14" [nzErrorTip]="formErrorTpl">
<a nz-button nzType="link" (click)="downloadTemplate1()"> <a nz-button nzType="link" (click)="previewTpl()">
<i nz-icon nzType="cloud-download" class="mb-2"></i> <i nz-icon nzType="cloud-download" class="mb-2"></i>
点击下载模板示例 点击下载预览
</a> </a>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <!-- <nz-form-item>
<nz-form-label nzSpan="5" [nzRequired]="true">上传模板</nz-form-label> <nz-form-label nzSpan="5" [nzRequired]="true">上传模板</nz-form-label>
<nz-form-control nzSpan="14" [nzErrorTip]="formErrorTpl"> <nz-form-control nzSpan="14" [nzErrorTip]="formErrorTpl">
<app-upload [drag]="true" [uploadFn]="api.uploadFormTpl" formControlName="templatePath" /> <app-upload [drag]="true" [uploadFn]="api.uploadFormTpl" formControlName="templatePath" />
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item> -->
</ng-template> </ng-template>
<ng-template #radioTpl let-fields> </ng-template> <ng-template #radioTpl let-fields> </ng-template>

51
web-admin-app/src/app/pages/fixed-asset/basic/basic-flow-form-manage/basic-flow-form-manage.component.ts

@ -21,7 +21,7 @@ import { lastValueFrom } from 'rxjs'
export class BasicFlowFormManageComponent { export class BasicFlowFormManageComponent {
constructor(public api: ApiService) {} constructor(public api: ApiService) {}
step = 2 step = 0
formJsonData = [] formJsonData = []
@ -59,7 +59,7 @@ export class BasicFlowFormManageComponent {
this.formGroup.get(k)?.setValue(v) this.formGroup.get(k)?.setValue(v)
} }
}) })
console.log('this.formGroup', this.formGroup) // console.log('this.formGroup', this.formGroup)
}) })
} }
} }
@ -83,16 +83,17 @@ export class BasicFlowFormManageComponent {
} }
fb = inject(FormBuilder) fb = inject(FormBuilder)
onTplupload(e: NzSafeAny[]) { onTplupload(e: NzSafeAny) {
this.patchFormValue(e) this.patchFormValue(e?._formValue ?? [])
} }
patchFormValue(e: NzSafeAny[]) { patchFormValue(e: NzSafeAny[]) {
this.formValue.clear() this.formValue.clear()
e.forEach((v) => { e.forEach((v) => {
let value = v.value let value = v.value
const fieldsArrays = this.fb.array([]) const fieldsArrays = this.fb.array([])
if (v.type === 'RADIO') { if (v.type === 'RADIO' || v.type === 'LIST') {
let val = Object.create(null) let val = Object.create(null)
try { try {
val = typeof v.value === 'string' ? JSON.parse(v.value) : v.value val = typeof v.value === 'string' ? JSON.parse(v.value) : v.value
@ -101,7 +102,9 @@ export class BasicFlowFormManageComponent {
fieldsArrays.push(this.fb.control(i)) fieldsArrays.push(this.fb.control(i))
}) })
value = val?.value value = val?.value
// console.log('fieldsArrays', val)
} }
this.formValue.push( this.formValue.push(
new FormGroup({ new FormGroup({
key: new FormControl(v.key, []), key: new FormControl(v.key, []),
@ -125,12 +128,12 @@ export class BasicFlowFormManageComponent {
} }
if (currentStep === 1) { if (currentStep === 1) {
this.handleSubmit() this.handleSubmit()
} } else if (currentStep === 2) {
if (currentStep === 2) {
this.handleConfirm() this.handleConfirm()
} } else {
this.step = currentStep + 1 this.step = currentStep + 1
} }
}
handleSubmit() { handleSubmit() {
if (FormValidators.validateFormGroup(this.formGroup)) { if (FormValidators.validateFormGroup(this.formGroup)) {
@ -140,16 +143,27 @@ export class BasicFlowFormManageComponent {
nzContent: '确定提交表单?', nzContent: '确定提交表单?',
nzOnOk: async () => { nzOnOk: async () => {
const vals = this.formGroup.value const vals = this.formGroup.value
const _formValue = vals._formValue!.map((i: any) => {
return {
...i,
value: ['RADIO', 'LIST'].includes(i.type) ? { fields: i.fields, value: i.value } : i.value,
}
})
const res = await lastValueFrom( const res = await lastValueFrom(
this.id this.id
? this.api.updateFlowForm({ ? this.api.updateFlowForm({
...vals, ...vals,
_formValue,
id: this.id, id: this.id,
formTempId: this.id, formTempId: this.id,
}) })
: this.api.addFlowForm(vals), : this.api.addFlowForm(vals),
) )
this.msg.success(res.desc) this.msg.success(res.desc)
if (!this.id) {
this.id = res.body.formTempId
}
// this.router.navigate(['/fixed-asset/basic/flow-form/list']) // this.router.navigate(['/fixed-asset/basic/flow-form/list'])
this.step = 2 this.step = 2
}, },
@ -158,7 +172,7 @@ export class BasicFlowFormManageComponent {
} }
handleConfirm() { handleConfirm() {
if (FormValidators.validateFormGroup(this.formGroup)) { if (FormValidators.validateFormGroup(this.formGroup)) {
if (!this.formValue.value?.templatePath) { if (!this.formGroup.value?.templatePath) {
this.msg.error('请先上传模板') this.msg.error('请先上传模板')
return return
} }
@ -186,7 +200,25 @@ export class BasicFlowFormManageComponent {
getRadioFieldsFormArray(index: number): FormArray { getRadioFieldsFormArray(index: number): FormArray {
return this.formValue.at(index).get('fields') as FormArray return this.formValue.at(index).get('fields') as FormArray
} }
previewTpl() {
this.msg.loading('正在下载...', { nzDuration: 0 })
this.api.preview(this.id!).subscribe((res) => {
Utils.downLoadFile(res, 'application/pdf;charset=utf-8')
// const blob = new Blob([res as any], { type: 'application/pdf;charset=utf-8' })
// const url = URL.createObjectURL(blob)
// // 在新窗口打开 PDF 预览
// window.open(url, '_blank')
// // 释放 URL 资源,避免内存泄漏(延迟一点时间释放以确保预览完成)
// setTimeout(() => URL.revokeObjectURL(url), 10000)
this.msg.remove()
this.msg.success('下载成功')
})
}
getRadioFields(index: number): any[] { getRadioFields(index: number): any[] {
// console.log('this.getRadioFieldsFormArray(index).controls', this.getRadioFieldsFormArray(index).controls)
return this.getRadioFieldsFormArray(index).controls return this.getRadioFieldsFormArray(index).controls
} }
cancel(currentStep: number) { cancel(currentStep: number) {
@ -229,6 +261,7 @@ export class BasicFlowFormManageComponent {
removeFormItem(idx: number) { removeFormItem(idx: number) {
this.formValue.removeAt(idx) this.formValue.removeAt(idx)
// console.log('this.formValue', this.formValue.controls, idx)
} }
removeRadioItem(idx: number, idx2: number) { removeRadioItem(idx: number, idx2: number) {

18
web-admin-app/src/app/pages/fixed-asset/basic/basic-flow-form/basic-flow-form.component.ts

@ -74,7 +74,7 @@ export class BasicFlowFormComponent {
{ title: '编辑', onClick: this.onEdit.bind(this) }, { title: '编辑', onClick: this.onEdit.bind(this) },
{ title: '删除', onClick: this.onDelete.bind(this) }, { title: '删除', onClick: this.onDelete.bind(this) },
{ title: '停用', onClick: this.onSetApprover.bind(this) }, { title: '停用', onClick: this.onSetApprover.bind(this) },
{ title: '预览', onClick: this.onSetApprover.bind(this) }, { title: '预览', onClick: this.onPreview.bind(this) },
]) ])
} }
@ -100,6 +100,22 @@ export class BasicFlowFormComponent {
return this.api.getFlowFormsList({ ...p, ...q }).pipe() return this.api.getFlowFormsList({ ...p, ...q }).pipe()
} }
onPreview(data?: NzSafeAny) {
this.msg.loading('正在下载...', { nzDuration: 0 })
this.api.preview(data.formTempId).subscribe((res) => {
Utils.downLoadFile(res, 'application/pdf;charset=utf-8')
// const blob = new Blob([res as any], { type: 'application/pdf;charset=utf-8' })
// const url = URL.createObjectURL(blob)
// // 在新窗口打开 PDF 预览
// window.open(url, '_blank')
// // 释放 URL 资源,避免内存泄漏(延迟一点时间释放以确保预览完成)
// setTimeout(() => URL.revokeObjectURL(url), 10000)
this.msg.remove()
this.msg.success('下载成功')
})
}
onSetApprover(data?: NzSafeAny) { onSetApprover(data?: NzSafeAny) {
if (data) { if (data) {
this.createForm.patchValue({ this.createForm.patchValue({

3
web-admin-app/src/app/pages/fixed-asset/maintain/maintain-on-off/maintain-on-off.component.html

@ -63,7 +63,7 @@
</ng-template> </ng-template>
<ng-container *appTableForm> <ng-container *appTableForm>
<app-query-item label="业务分类"> <app-query-item label="设备分类">
<nz-select <nz-select
nzPlaceHolder="请选择" nzPlaceHolder="请选择"
nzPlacement="bottomRight" nzPlacement="bottomRight"
@ -72,7 +72,6 @@
formControlName="model" formControlName="model"
nzAllowClear nzAllowClear
> >
<nz-option nzLabel="所有分类" nzValue=""></nz-option>
<nz-option *ngFor="let item of ASSET_TYPE" [nzLabel]="item.label" [nzValue]="item.value" /> <nz-option *ngFor="let item of ASSET_TYPE" [nzLabel]="item.label" [nzValue]="item.value" />
</nz-select> </nz-select>
</app-query-item> </app-query-item>

10
web-admin-app/src/app/pages/fixed-asset/maintain/maintain-on-off/maintain-on-off.component.ts

@ -50,15 +50,13 @@ export class MaintainOnOffComponent {
rowKey: 'assetId', rowKey: 'assetId',
}) })
.setColumn([ .setColumn([
{ key: 'serialNumber', title: '序号', visible: true },
{ key: 'assetCode', title: '资产编号', visible: true }, { key: 'assetCode', title: '资产编号', visible: true },
{ key: 'name', title: '资产名称', visible: true }, { key: 'name', title: '资产名称', visible: true },
{ key: 'deviceStatus', title: '当前状态', visible: true },
{ key: '_category', title: '资产分类', visible: true }, { key: '_category', title: '资产分类', visible: true },
{ key: 'status', title: '资产状态', visible: true }, { key: 'deviceStatus', title: '当前状态', visible: true, width: '120px' },
{ key: '_ownCompany', title: '所属公司', visible: true }, { key: 'serialNumber', title: '序列号', visible: true },
{ key: '_useOrganization', title: '使用组织', visible: true }, { key: 'status', title: '资产状态', visible: true, width: '120px' },
{ key: '_position', title: '位置信息', visible: true }, { key: 'lastTime', title: '最后操作时间', visible: true },
]) ])
.setRowOperate([ .setRowOperate([
// { title: '修改', onClick: this.onCreate.bind(this) }, // { title: '修改', onClick: this.onCreate.bind(this) },

21
web-admin-app/src/app/pages/fixed-asset/maintain/on-off-records/on-off-records.component.html

@ -1,12 +1,23 @@
<div class="max-h-[60vh] mt-6"> <div class="max-h-[60vh] overflow-y-auto overflow-x-hidden">
<div>
<nz-range-picker [(ngModel)]="range" nzShowTime (ngModelChange)="onDateChange()" />
</div>
<div class="mt-6">
@if (records.length > 0) {
<nz-timeline> <nz-timeline>
@for (item of records; track $index) { @for (item of records; track $index) {
<nz-timeline-item <nz-timeline-item [nzColor]="item.operationType.includes('开机') ? 'green' : 'red'">
[nzLabel]="item.createTime" <div>
[nzColor]="item.operationType.includes('开机') ? 'green' : 'red'" {{ item.createTime }}
> </div>
<div>
{{ item.operationType }} {{ item.operationType }}
</div>
</nz-timeline-item> </nz-timeline-item>
} }
</nz-timeline> </nz-timeline>
} @else {
<nz-empty />
}
</div>
</div> </div>

21
web-admin-app/src/app/pages/fixed-asset/maintain/on-off-records/on-off-records.component.ts

@ -3,6 +3,7 @@ import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NZ_MODAL_DATA } from 'ng-zorro-antd/modal' import { NZ_MODAL_DATA } from 'ng-zorro-antd/modal'
import { format } from 'date-fns'
@Component({ @Component({
selector: 'app-on-off-records', selector: 'app-on-off-records',
@ -17,9 +18,27 @@ export class OnOffRecordsComponent implements OnInit {
data = inject(NZ_MODAL_DATA) data = inject(NZ_MODAL_DATA)
records: NzSafeAny[] = [] records: NzSafeAny[] = []
range: Date[] = []
onDateChange() {
this.getRecords()
}
ngOnInit(): void { ngOnInit(): void {
this.getRecords()
}
getRecords() {
if (this.data) { if (this.data) {
this.api.onOffRecord(this.data.assetId).subscribe((res) => { let d = {}
if (this.range.length > 1) {
let startTime = null
let endTime = null
startTime = this.range[0].getTime()
endTime = this.range[1].getTime()
d = { startTime, endTime }
}
this.api.onOffRecord({ id: this.data.assetId, ...d }).subscribe((res) => {
this.records = res.body this.records = res.body
}) })
} }

4
web-admin-app/src/app/pages/fixed-asset/manage/fixed-asset-manage/fixed-asset-manage.component.ts

@ -131,7 +131,9 @@ export class FixedAssetManageComponent {
const ids = item ? [item.assetId] : Array.from(this.table.ref.selected) const ids = item ? [item.assetId] : Array.from(this.table.ref.selected)
this.modal.confirm({ this.modal.confirm({
nzTitle: '警告', nzTitle: '警告',
nzContent: `是否要删除${ids.length}个资产?`, nzContent: `是否要删除当前选中资产?`,
nzOkDanger: true,
nzIconType: '',
nzOnOk: async () => { nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteAsset(ids)) const res = await lastValueFrom(this.api.deleteAsset(ids))
this.msg.success(res.desc) this.msg.success(res.desc)

6
web-admin-app/src/app/pages/fixed-asset/registration/registration.component.html

@ -257,11 +257,7 @@
<nz-form-item> <nz-form-item>
<nz-form-label [nzSpan]="6" nzRequired> 扩展资产表单 </nz-form-label> <nz-form-label [nzSpan]="6" nzRequired> 扩展资产表单 </nz-form-label>
<nz-form-control [nzSpan]="12"> <nz-form-control [nzSpan]="12">
<nz-select nzPlaceHolder="请选择扩展资产表单" [(ngModel)]="extendFormId"> <app-asset-category-select [(ngModel)]="extendFormId" />
@for (item of flowForms; track $index) {
<nz-option [nzLabel]="item.formName" [nzValue]="item.formTempId" />
}
</nz-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
} }

21
web-admin-app/src/app/pages/fixed-asset/registration/registration.component.ts

@ -6,7 +6,12 @@ import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, of } from 'rxjs'
import { AssetFormComponent, ManufacturerSelectComponent, PositionSelectComponent } from 'app/components' import {
AssetCategorySelectComponent,
AssetFormComponent,
ManufacturerSelectComponent,
PositionSelectComponent,
} from 'app/components'
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal' import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
@ -16,7 +21,13 @@ import { Utils } from 'app/utils'
@Component({ @Component({
selector: 'app-fixed-asset-registration', selector: 'app-fixed-asset-registration',
standalone: true, standalone: true,
imports: [SharedModule, AssetFormComponent, PositionSelectComponent, ManufacturerSelectComponent], imports: [
SharedModule,
AssetFormComponent,
PositionSelectComponent,
ManufacturerSelectComponent,
AssetCategorySelectComponent,
],
templateUrl: './registration.component.html', templateUrl: './registration.component.html',
styleUrl: './registration.component.less', styleUrl: './registration.component.less',
}) })
@ -119,6 +130,7 @@ export class RegistrationComponent {
nzContent: AssetFormComponent, nzContent: AssetFormComponent,
nzWidth: '80vw', nzWidth: '80vw',
nzWrapClassName: 'modal-lg', nzWrapClassName: 'modal-lg',
nzFooter: preview ? null : undefined,
nzData: { nzData: {
value: data, value: data,
preview, preview,
@ -141,7 +153,10 @@ export class RegistrationComponent {
const ids = item ? [item.assetId] : Array.from(this.table.ref.selected) const ids = item ? [item.assetId] : Array.from(this.table.ref.selected)
this.modal.confirm({ this.modal.confirm({
nzTitle: '警告', nzTitle: '警告',
nzContent: `是否要删除${ids.length}个资产?`,
nzContent: `是否要删除当前选中资产?`,
nzOkDanger: true,
nzIconType: 'exclamation-circle',
nzOnOk: async () => { nzOnOk: async () => {
const res = await lastValueFrom(this.api.deleteAsset(ids)) const res = await lastValueFrom(this.api.deleteAsset(ids))
this.msg.success(res.desc) this.msg.success(res.desc)

6
web-admin-app/src/app/pages/flow/flow-main/flow-main.component.html

@ -35,8 +35,8 @@
<nz-card [nzBordered]="false" nzTitle="资管流程"> <nz-card [nzBordered]="false" nzTitle="资管流程">
<nz-spin [nzSpinning]="loading"> <nz-spin [nzSpinning]="loading">
<div nz-row [nzGutter]="[24, 24]"> <div nz-row [nzGutter]="[24, 24]">
@for (item of assetFlows; track $index) { @for (i of assetFlows; track $index) {
<div nz-col nzSpan="8" [nzXl]="4" (click)="onStart(item)" class="cursor-pointer"> <div nz-col nzSpan="8" [nzXl]="4" (click)="onStart(i)" class="cursor-pointer">
<div> <div>
<div class="h-22 flex flex-col items-center justify-center text-center overflow-hidden"> <div class="h-22 flex flex-col items-center justify-center text-center overflow-hidden">
<div class="flex-shrink-0"> <div class="flex-shrink-0">
@ -46,7 +46,7 @@
</div> </div>
<div class="flex-1 pt-3 text-base overflow-hidden"> <div class="flex-1 pt-3 text-base overflow-hidden">
<div> <div>
{{ item.name }} {{ i.name }}
</div> </div>
</div> </div>
</div> </div>

6
web-admin-app/src/app/pages/flow/flow-main/flow-main.component.ts

@ -75,7 +75,7 @@ export class FlowMainComponent implements OnInit {
res.body.forEach((i: NzSafeAny) => { res.body.forEach((i: NzSafeAny) => {
const enabled = Boolean(comsMap[i.formKey as keyof typeof comsMap]) const enabled = Boolean(comsMap[i.formKey as keyof typeof comsMap])
const formType = (i.formKey as string).split('_').splice(-1)[0] const formType = (i.formKey as string).split('_').splice(-1)[0]
console.log('formType', formType)
const item = { ...i, enabled, formType } const item = { ...i, enabled, formType }
if (i.type === '设备流程') { if (i.type === '设备流程') {
this.deviceFlows.push(item) this.deviceFlows.push(item)
@ -83,6 +83,8 @@ export class FlowMainComponent implements OnInit {
this.assetFlows.push(item) this.assetFlows.push(item)
} }
}) })
console.log('this.deviceFlows', this.deviceFlows, this.assetFlows)
}) })
} }
@ -92,7 +94,7 @@ export class FlowMainComponent implements OnInit {
if (i.type === '设备流程') { if (i.type === '设备流程') {
this.devicecounter = i this.devicecounter = i
} else { } else {
this.assetFlows = i this.assetcounter = i
} }
}) })
}) })

292
web-admin-app/src/app/pages/flow/flow-report/flow-report.component.html

@ -1,19 +1,20 @@
<app-page> <app-page>
<div nz-form nz-row [nzGutter]="12"> <div nz-form nz-row [nzGutter]="12" class="no-print">
<div nz-col nzFlex="400px"> <div nz-col nzFlex="300px">
<nz-form-item> <nz-form-item>
<nz-form-label> 任务类型 </nz-form-label> <nz-form-label> 任务类型 </nz-form-label>
<nz-form-control> <nz-form-control>
<nz-select <nz-select
nzPlaceHolder="请选择类型" nzPlaceHolder="请选择类型"
class="!w-full" class="!w-full"
(ngModelChange)="onChange()" nzMode="multiple"
[nzAllowClear]="true"
[(ngModel)]="formKeys" [(ngModel)]="formKeys"
> >
<nz-option nzLabel="维保" nzValue="1"></nz-option> <nz-option nzLabel="维保" nzValue="eam_device_repair"></nz-option>
<nz-option nzLabel="巡检" nzValue="2"></nz-option> <nz-option nzLabel="巡检" nzValue="eam_device_inspection"></nz-option>
<nz-option nzLabel="保养" nzValue="3"></nz-option> <nz-option nzLabel="保养" nzValue="eam_device_maintenance"></nz-option>
<nz-option nzLabel="盘点" nzValue="4"></nz-option> <!-- <nz-option nzLabel="盘点" nzValue="eam_device_stocktaking"></nz-option> -->
</nz-select> </nz-select>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
@ -35,82 +36,265 @@
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col nzFlex="400px"> <div nz-col nzFlex="200px">
<nz-form-item>
<nz-form-label> 开始时间 </nz-form-label>
<nz-form-control>
<nz-date-picker
[nzAllowClear]="false"
nzFormat="YYYY-MM-dd"
[(ngModel)]="date"
(ngModelChange)="onStartDateChange()"
/>
</nz-form-control>
</nz-form-item>
</div>
<div nz-col nzFlex="200px">
<nz-form-item> <nz-form-item>
<nz-form-label> 自定义时段 </nz-form-label> <nz-form-label> 结束时间 </nz-form-label>
<nz-form-control> <nz-form-control>
<nz-range-picker [(ngModel)]="range" (ngModelChange)="onChange()" /> <nz-date-picker nzFormat="YYYY-MM-dd" [ngModel]="range[1]" [nzDisabled]="true" />
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
</div> </div>
<div nz-col nzFlex="auto"> <div nz-col nzFlex="auto">
<div class="flex justify-end"> <div class="flex justify-end">
<nz-space> <nz-space>
<button *nzSpaceItem nz-button>编辑</button> <!-- <button *nzSpaceItem nz-button>编辑</button>
<button *nzSpaceItem nz-button>复制</button> <button *nzSpaceItem nz-button>复制</button> -->
<button *nzSpaceItem nz-button>打印</button> <button *nzSpaceItem nzType="primary" nz-button (click)="onCreate()">生成报告</button>
<button *nzSpaceItem nz-button>导出</button> <button *nzSpaceItem nz-button (click)="edit()">{{ edited ? '保存' : '编辑' }}</button>
<button *nzSpaceItem nz-button (click)="print()">打印</button>
<button *nzSpaceItem nz-button (click)="export()">下载</button>
</nz-space> </nz-space>
</div> </div>
</div> </div>
</div> </div>
<div class="mt-2"> <div class="mt-2">
<nz-spin [nzSpinning]="loading"> <nz-spin [nzSpinning]="loading">
<div class="report" *ngIf="data"> @if (data) {
<div
class="report"
[ngClass]="{ uneditable: !edited }"
style="position: relative; background: #fff; width: 100%; padding: 24px; margin: 0 auto"
#reportTpl
>
<div class="report-title"> <div class="report-title">
<div class="report-title-left"> <div class="report-title-left">
<span>工作报表</span> <input
class="print-textarea"
[(ngModel)]="title"
style="width: 100%; text-align: center; font-size: 24px"
/>
</div> </div>
<div class="report-title-right"> <div style="text-align: right; margin-top: 12px">
日期:{{ data.startDate | date: 'yyyy-MM-dd' }} ~ {{ data.endDate | date: 'yyyy-MM-dd' }} 报告周期:{{ data.startDate | date: 'yyyy-MM-dd' }} ~
{{ data.endDate | date: 'yyyy-MM-dd' }}
</div> </div>
</div> </div>
<div class="report-content"> <div class="report-content">
<div class="report-content-row"> <div class="report-content-row">
<h2>{{ reportTypeText.get(reportType) }}工作概述</h2> <h3>当期工作概述</h3>
<div class="report-content-row-content"> <div class="report-content-row-content">
<div class="report-content-row-left"> <textarea
<textarea [(ngModel)]="gaishu"></textarea> style="width: 100%; resize: vertical; min-height: 100px"
[(ngModel)]="gaishu"
></textarea>
</div> </div>
<div class="report-content-row-right"> <div class="report-content-row-content">
<ul class="counter"> <div style="display: flex; gap: 12px; margin-top: 18px">
<li class="info"> <div style="flex: 1">
<p>{{ data.taskCount ?? 0 }}</p> <div style="border: 2px dashed #ccc; padding: 12px">
<p>累计处理任务数</p> <div style="font-size: 18px; margin-bottom: 16px">报修维修任务简报</div>
<ul
class="counter"
style="
display: flex;
align-items: center;
justify-content: center;
text-align: center;
gap: 12px;
"
>
<li
class="info"
style="padding: 12px 0; flex: 1; border: 1px dashed #027db4"
>
<div style="font-size: 22px; font-weight: bold; color: #027db4">
{{ heji.weibao.total }}
</div>
<div style="font-size: 10px">维修任务数</div>
</li> </li>
<li class="success"> <li
<p>{{ data.taskCount ?? 0 }}</p> class="success"
<p>已完成任务数</p> style="padding: 12px 0; flex: 1; border: 1px dashed #70b603"
>
<div style="font-size: 22px; font-weight: bold; color: #70b603">
{{ heji.weibao.deviceComplete }}
</div>
<div style="font-size: 10px">已修复设备</div>
</li> </li>
<li class="error"> <li
<p>{{ data.taskCount ?? 0 }}</p> class="error"
<p>未完成任务数</p> style="padding: 12px 0; flex: 1; border: 1px dashed #d9001b"
>
<div style="font-size: 22px; font-weight: bold; color: #d9001b">
{{ heji.weibao.deviceUnComplete }}
</div>
<div style="font-size: 10px">未修复设备</div>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<div style="flex: 1">
<div style="border: 2px dashed #ccc; padding: 12px">
<div style="font-size: 18px; margin-bottom: 16px">设备巡检任务简报</div>
<ul
class="counter"
style="
display: flex;
align-items: center;
justify-content: center;
text-align: center;
gap: 12px;
"
>
<li
class="info"
style="padding: 12px 0; flex: 1; border: 1px dashed #027db4"
>
<div style="font-size: 22px; font-weight: bold; color: #027db4">
{{ heji.xunjian.total }}
</div> </div>
@for (item of data.taskList; track $index) { <div style="font-size: 10px">巡检任务数</div>
<div class="report-content-row" #itemElement> </li>
<h2>任务执行情况</h2> <li
<div class="report-content-row-content"> class="success"
<div class="report-content-row-left"> style="padding: 12px 0; flex: 1; border: 1px dashed #70b603"
>
<div style="font-size: 22px; font-weight: bold; color: #70b603">
{{ heji.xunjian.deviceComplete }}
</div>
<div style="font-size: 10px">已巡设备</div>
</li>
<li
class="error"
style="padding: 12px 0; flex: 1; border: 1px dashed #d9001b"
>
<div style="font-size: 22px; font-weight: bold; color: #d9001b">
{{ heji.xunjian.deviceUnComplete }}
</div>
<div style="font-size: 10px">未巡设备</div>
</li>
</ul>
</div>
</div>
<div style="flex: 1">
<div style="border: 2px dashed #ccc; padding: 12px">
<div style="font-size: 18px; margin-bottom: 16px">设备保养任务简报</div>
<ul
class="counter"
style="
display: flex;
align-items: center;
justify-content: center;
text-align: center;
gap: 12px;
"
>
<li
class="info"
style="padding: 12px 0; flex: 1; border: 1px dashed #027db4"
>
<div style="font-size: 22px; font-weight: bold; color: #027db4">
{{ heji.baoyang.total }}
</div>
<div style="font-size: 10px">保养任务数</div>
</li>
<li
class="success"
style="padding: 12px 0; flex: 1; border: 1px dashed #70b603"
>
<div style="font-size: 22px; font-weight: bold; color: #70b603">
{{ heji.baoyang.deviceComplete }}
</div>
<div style="font-size: 10px">保养设备</div>
</li>
<li
class="error"
style="padding: 12px 0; flex: 1; border: 1px dashed #d9001b"
>
<div style="font-size: 22px; font-weight: bold; color: #d9001b">
{{ heji.baoyang.deviceUnComplete }}
</div>
<div style="font-size: 10px">未处理设备</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
@for (item of taskTypeData | keyvalue; track $index) {
@if (item.value.length) {
<div style="margin-top: 24px" #itemElement [attr.data-type]="item.key">
<div>
<h3>{{ taskTypeNameMap.get(item.key) }}任务执行情况</h3>
<div
style="
border: 1px dashed #ccc;
padding: 12px;
margin-top: 12px;
display: flex;
"
class="report-content-row-content"
>
<div
class="report-content-row-left"
style="flex-basis: 60%; flex-shrink: 0"
>
<p>任务执行数据分析</p> <p>任务执行数据分析</p>
<div class="pie echart"></div> <div style="display: flex">
<div class="line echart"></div> <div style="height: 205px; width: 200px" class="pie echart"></div>
<img
style="height: 205px; width: 200px; display: none"
class="echartImg"
[src]="echartsImgMap.get(item.key)?.pie"
/>
<div style="height: 205px; flex: 1" class="line echart"></div>
<img
style="height: 205px; flex: 1; display: none"
class="echartImg"
[src]="echartsImgMap.get(item.key)?.line"
/>
</div>
</div>
<div
class="report-content-row-right"
style="flex-shrink: 0; padding-left: 24px; flex: 1"
>
<textarea
[(ngModel)]="$any(taskTypeText)[item.key]"
style="width: 100%; min-height: 200px"
></textarea>
</div> </div>
<div class="report-content-row-right">
<textarea></textarea>
</div> </div>
</div> </div>
</div> </div>
} }
}
<div class="report-content-row"> <div class="report-content-row" style="margin-top: 18px">
<h2>工作计划</h2> <h2>工作计划</h2>
<div class="report-content-row-content"> <div class="report-content-row-content">
<div class="report-content-row-left"> <div class="report-content-row-left">
<textarea [(ngModel)]="plan"></textarea> <textarea
class="print-textarea"
style="width: 100%; min-height: 200px"
[(ngModel)]="plan"
></textarea>
</div> </div>
</div> </div>
</div> </div>
@ -118,18 +302,28 @@
<h2>总结</h2> <h2>总结</h2>
<div class="report-content-row-content"> <div class="report-content-row-content">
<div class="report-content-row-left"> <div class="report-content-row-left">
<textarea [(ngModel)]="zongjie"></textarea> <textarea
class="print-textarea"
style="width: 100%; min-height: 200px"
[(ngModel)]="zongjie"
></textarea>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="report-footer"> <div class="report-footer" style="margin-top: 18px; display: flex; justify-content: end">
<div> <textarea
{{ data.organizationName }} class="print-textarea"
</div> style="width: 100%; min-height: 100px; text-align: right"
<div>{{ today }}</div> [(ngModel)]="footer"
></textarea>
</div> </div>
</div> </div>
} @else {
<nz-card>
<nz-empty></nz-empty>
</nz-card>
}
</nz-spin> </nz-spin>
</div> </div>
</app-page> </app-page>

134
web-admin-app/src/app/pages/flow/flow-report/flow-report.component.less

@ -1,127 +1,27 @@
.report { ::ng-deep {
.uneditable {
padding: 24px;
background-color: #fff;
h1 {
font-size: 22px;
}
h2 {
font-size: 18x;
}
.report-title {
position: relative;
}
.echart {
height: 205px;
}
.pie {
width: 200px;
}
.line {
flex: 1;
}
.report-title-left {
font-size: 24px;
text-align: center;
}
.report-title-right {
position: absolute;
bottom: 5px;
right: 0;
}
.report-footer {
text-align: right;
&>div {
margin-top: 12px;
}
}
.report-content-row {
min-height: 220px;
textarea { pointer-events: none;
width: 100%;
min-height: 150px;
border: 1px solid #ccc;
&:focus, textarea,
&:active, input {
&:hover { border: none;
outline: none; outline: none;
border: 1px solid #ccc; resize: none !important;
} }
}
}
.report-content-row-content {
display: flex;
.report-content-row-left {
display: flex;
flex-basis: 60%;
flex-shrink: 0;
}
.report-content-row-right {
padding-left: 24px;
flex: 1;
}
}
.counter {
display: flex;
justify-content: center;
li {
margin: 0 12px;
padding: 24px 0;
flex: 1;
text-align: center;
border: 1px dashed #027db4;
&.error {
border-color: #d9001b;
p { .readonly {
color: #d9001b; position: absolute;
} inset: 0;
} pointer-events: none;
z-index: 100;
&.success { background-color: red;
border-color: #70b603; opacity: .5;
p {
color: #70b603;
} }
} }
}
p { .report {
margin-bottom: 6px; width: 793.92px !important;
color: #027db4;
&:first-child {
font-size: 20px;
font-weight: bold;
}
}
}
}
} }

506
web-admin-app/src/app/pages/flow/flow-report/flow-report.component.ts

@ -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 } },
}
taskTypeText: Record<'weibao' | 'xunjian' | 'baoyang', string> = {
weibao: '',
xunjian: '',
baoyang: '',
}
zongjie = ` gaishu = ''
001
` 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)]
} }
onChange() {
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
}
}
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('下载成功')
})
}
} }

4
web-admin-app/src/app/pages/login/login.component.html

@ -1,9 +1,9 @@
<div class="flex items-center justify-center fixed inset-0 z-10 login-page"> <div class="flex items-center justify-center fixed inset-0 z-10 login-page">
<div class="bg fixed inset-0"></div> <div class="bg fixed inset-0" [ngStyle]="{ 'background-image': 'url(' + loginBackground + ')' }"></div>
<div class="w-[450px] relative z-10 login-form p-8 bg-white rounded-md shadow-2xl"> <div class="w-[450px] relative z-10 login-form p-8 bg-white rounded-md shadow-2xl">
<div class="px-4"> <div class="px-4">
<div class="text-center"> <div class="text-center">
<h1>固资系统</h1> <h1>{{ systemName }}</h1>
<p class="text-lg mb-6">登录</p> <p class="text-lg mb-6">登录</p>
</div> </div>
<form nz-form [formGroup]="loginForm" class="mt-12"> <form nz-form [formGroup]="loginForm" class="mt-12">

5
web-admin-app/src/app/pages/login/login.component.less

@ -2,13 +2,14 @@
.bg { .bg {
background-image: url(/assets/images/login-bg.jpg);
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: bottom; background-position: bottom;
background-size: cover;
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
justify-content: center; justify-content: center;
background-color: #3d62f1; // background-color: #3d62f1;
} }

10
web-admin-app/src/app/pages/login/login.component.ts

@ -23,11 +23,21 @@ export class LoginComponent {
loading = false loading = false
systemName = ''
loginBackground = ''
loginForm = new FormGroup({ loginForm = new FormGroup({
loginName: new FormControl('', [FormValidators.required('请输入用户名')]), loginName: new FormControl('', [FormValidators.required('请输入用户名')]),
password: new FormControl('', [FormValidators.required('请输入密码')]), password: new FormControl('', [FormValidators.required('请输入密码')]),
}) })
ngOnInit() {
this.api.getSysDisplayConfig().subscribe((res) => {
this.systemName = res.systemName || '固资系统'
this.loginBackground = res.loginBackground ?? '/assets/images/login-bg.jpg'
})
}
onLogin() { onLogin() {
if (FormValidators.validateFormGroup(this.loginForm)) { if (FormValidators.validateFormGroup(this.loginForm)) {
this.loading = true this.loading = true

19
web-admin-app/src/app/pages/msg/flow-msg/flow-msg.component.ts

@ -5,7 +5,7 @@ import { AnyObject, TableOption } from 'app/shared/components/server-paginated-t
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
@ -44,14 +44,25 @@ export class FlowMsgComponent {
// }) // })
.setColumn([ .setColumn([
// { key: 'logId', title: '序号', visible: true }, // { key: 'logId', title: '序号', visible: true },
{ key: 'createTime', title: '时间', visible: true }, { key: 'index', title: '序号', visible: true, width: '60px' },
// { key: 'logType', title: '类型', visible: true },
{ key: 'createTime', title: '时间', width: '120px', visible: true },
{ key: 'type', title: '类型', width: '220px', visible: true },
{ key: 'content', title: '内容', visible: true }, { key: 'content', title: '内容', visible: true },
// { key: 'logContent', title: '待我处理', visible: true }, // { key: 'logContent', title: '待我处理', visible: true },
]) ])
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getFlowMsg({ ...p, ...q }) return this.api.getFlowMsg({ ...p, ...q }).pipe(
map((r) => {
r.body.rows = r.body.rows.map((item: NzSafeAny, idx: number) => {
item.index = idx + 1
return item
})
return r
}),
)
} }
} }

19
web-admin-app/src/app/pages/msg/system-log/system-log.component.ts

@ -5,7 +5,7 @@ import { AnyObject, TableOption } from 'app/shared/components/server-paginated-t
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { format } from 'date-fns' import { format } from 'date-fns'
import { lastValueFrom, of } from 'rxjs' import { lastValueFrom, map, of } from 'rxjs'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
import { NzModalService } from 'ng-zorro-antd/modal' import { NzModalService } from 'ng-zorro-antd/modal'
import { NzMessageService } from 'ng-zorro-antd/message' import { NzMessageService } from 'ng-zorro-antd/message'
@ -30,8 +30,8 @@ export class SystemLogComponent {
queryForm = new FormGroup({ queryForm = new FormGroup({
logContent: new FormControl(''), logContent: new FormControl(''),
logType: new FormControl(''), // logType: new FormControl(''),
createTime: new FormControl(''), // createTime: new FormControl(''),
}) })
table = new TableOption(this.fetchData.bind(this)) table = new TableOption(this.fetchData.bind(this))
@ -43,7 +43,7 @@ export class SystemLogComponent {
// rowKey: 'id', // rowKey: 'id',
// }) // })
.setColumn([ .setColumn([
{ key: 'logId', title: '序号', visible: true }, { key: 'index', title: '序号', visible: true },
{ key: 'createTime', title: '时间', visible: true }, { key: 'createTime', title: '时间', visible: true },
{ key: 'logType', title: '类型', visible: true }, { key: 'logType', title: '类型', visible: true },
{ key: 'logContent', title: '内容', visible: true }, { key: 'logContent', title: '内容', visible: true },
@ -51,6 +51,15 @@ export class SystemLogComponent {
} }
fetchData(p: {}, q: AnyObject) { fetchData(p: {}, q: AnyObject) {
return this.api.getSysLog({ ...p, ...q }) return this.api.getSysLog({ ...p, ...q }).pipe(
map((r) => {
r.body.rows = r.body.rows.map((item: NzSafeAny, idx: number) => {
item.index = idx + 1
return item
})
return r
}),
)
} }
} }

54
web-admin-app/src/app/pages/system/display-config/display-config.component.html

@ -0,0 +1,54 @@
<app-page>
<form nz-form [formGroup]="formGroup" nzLayout="vertical">
<div>
<nz-card nzTitle="系统展示管理">
<nz-form-item>
<nz-form-label>系统名称</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input formControlName="systemName" placeholder="请输入系统名称" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>Logo图片</nz-form-label>
<!-- logo -->
<nz-form-control nzSpan="8">
<app-upload formControlName="logo" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>favicon</nz-form-label>
<!-- favicon -->
<nz-form-control nzSpan="8">
<app-upload formControlName="favicon" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>登录背景图</nz-form-label>
<!-- loginBackground -->
<nz-form-control nzSpan="8">
<app-upload formControlName="loginBackground" />
</nz-form-control>
</nz-form-item>
</nz-card>
</div>
<div class="mt-4 mb-48">
<nz-card nzTitle="大屏展示管理">
<nz-form-item>
<nz-form-label>大屏名称</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input formControlName="bigScreenName" placeholder="请输入大屏名称" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>欢迎语</nz-form-label>
<nz-form-control nzSpan="8">
<input nz-input formControlName="bigScreenSlogan" placeholder="请输入大屏欢迎语" />
</nz-form-control>
</nz-form-item>
</nz-card>
</div>
<div class="flex items-center p-4 bg-white fixed bottom-0 right-0 left-0 pl-56">
<button nz-button nzType="primary" [nzLoading]="loading" (click)="setConfig()">保存</button>
</div>
</form>
</app-page>

0
web-admin-app/src/app/pages/system/display-config/display-config.component.less

59
web-admin-app/src/app/pages/system/display-config/display-config.component.ts

@ -0,0 +1,59 @@
import { Component, inject } from '@angular/core'
import { FormControl, FormGroup } from '@angular/forms'
import { SharedModule } from 'app/shared/shared.module'
import { UploadComponent } from '../../../shared/components/upload/upload.component'
import { ApiService } from 'app/services'
import { FormValidators } from 'app/utils'
import { NzMessageService } from 'ng-zorro-antd/message'
import { finalize } from 'rxjs'
@Component({
selector: 'app-display-config',
standalone: true,
imports: [SharedModule, UploadComponent],
templateUrl: './display-config.component.html',
styleUrl: './display-config.component.less',
})
export class DisplayConfigComponent {
constructor(private api: ApiService) {}
msg = inject(NzMessageService)
displayConfig: any
loading = false
formGroup = new FormGroup({
bigScreenName: new FormControl(),
bigScreenSlogan: new FormControl(),
favicon: new FormControl('/assets/favicon.ico'),
loginBackground: new FormControl('/assets/images/login-bg.jpg'),
logo: new FormControl(),
systemName: new FormControl(),
})
ngOnInit() {
this.getConfig()
}
getConfig(force = false) {
this.api.getSysDisplayConfig(force).subscribe((data) => {
this.displayConfig = data
this.formGroup.patchValue(data)
})
}
setConfig() {
if (FormValidators.validateFormGroup(this.formGroup)) {
this.loading = true
this.api
.setSysDisplayConfig(this.formGroup.value)
.pipe(finalize(() => (this.loading = false)))
.subscribe(() => {
this.msg.success('设置成功').onClose.subscribe(() => {
window.location.reload()
})
})
}
}
}

14
web-admin-app/src/app/pages/system/index/system.component.html

@ -45,18 +45,8 @@
> >
授权证书 授权证书
</li> </li>
<li <!-- *appPermission="['system-display:view']" -->
*appPermission="['system-flow-form:view']" <li nz-menu-item [nzPaddingLeft]="12" [routerLink]="['/system/display']" nzMatchRouter>展示设置</li>
nzMatchRouter
[nzPaddingLeft]="12"
nz-submenu
nzTitle="流程管理"
[nzOpen]="openedSubmenu.startsWith('/system/flow/')"
>
<ul>
<li nz-menu-item [nzPaddingLeft]="24" [routerLink]="['/system/flow/form']" nzMatchRouter>表单定义</li>
</ul>
</li>
</ul> </ul>
</div> </div>

38
web-admin-app/src/app/pages/system/system-address/system-address.component.html

@ -1,7 +1,7 @@
<app-page class="p-3"> <app-page class="p-3">
<div class="flex flex-1"> <div class="flex flex-1">
<nz-card [nzBordered]="false" class="org shadow" nzSize="small"> <nz-card [nzBordered]="false" class="org shadow" nzSize="small">
<app-component-basic-category-tree <app-component-address-tree
#treeEl #treeEl
[defaultName]="'新地址'" [defaultName]="'新地址'"
(onSelectedChange)="onSelectedChange($event)" (onSelectedChange)="onSelectedChange($event)"
@ -13,42 +13,10 @@
<nz-form-item> <nz-form-item>
<nz-form-label [nzRequired]="true"> 名称 </nz-form-label> <nz-form-label [nzRequired]="true"> 名称 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl"> <nz-form-control [nzErrorTip]="errorTpl">
<input type="text" nz-input formControlName="categoryName" placeholder="请输入名称" /> <input type="text" nz-input formControlName="name" placeholder="请输入名称" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 安全库存 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-input-number
nzPlaceHolder="请输入"
[nzMin]="0"
class="!w-full"
formControlName="safetyLimit"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 安全库存上限 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-input-number
nzPlaceHolder="请输入"
[nzMin]="0"
class="!w-full"
formControlName="upperLimit"
/>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label> 安全库存下限 </nz-form-label>
<nz-form-control [nzErrorTip]="errorTpl">
<nz-input-number
nzPlaceHolder="请输入"
[nzMin]="0"
class="!w-full"
formControlName="lowerLimit"
/>
</nz-form-control> </nz-form-control>
</nz-form-item> </nz-form-item>
<nz-form-item> <nz-form-item>
<nz-form-control> <nz-form-control>
<nz-space> <nz-space>

12
web-admin-app/src/app/pages/system/system-address/system-address.component.ts

@ -1,6 +1,7 @@
import { Component, TemplateRef, ViewChild } from '@angular/core' import { Component, TemplateRef, ViewChild } from '@angular/core'
import { FormBuilder, FormGroup } from '@angular/forms' import { FormBuilder, FormGroup } from '@angular/forms'
import { ComponentBasicCategoryTreeComponent } from 'app/components' import { ComponentBasicCategoryTreeComponent } from 'app/components'
import { AddressTreeComponent } from 'app/components/address-tree/address-tree.component'
import { ApiService } from 'app/services' import { ApiService } from 'app/services'
import { SharedModule } from 'app/shared/shared.module' import { SharedModule } from 'app/shared/shared.module'
import { FormValidators } from 'app/utils' import { FormValidators } from 'app/utils'
@ -12,7 +13,7 @@ import { NzModalService } from 'ng-zorro-antd/modal'
@Component({ @Component({
selector: 'app-system-address', selector: 'app-system-address',
standalone: true, standalone: true,
imports: [SharedModule, ComponentBasicCategoryTreeComponent], imports: [SharedModule, AddressTreeComponent],
templateUrl: './system-address.component.html', templateUrl: './system-address.component.html',
styleUrl: './system-address.component.less', styleUrl: './system-address.component.less',
}) })
@ -39,12 +40,9 @@ export class SystemAddressComponent {
initCreateForm() { initCreateForm() {
this.createForm = this.fb.group({ this.createForm = this.fb.group({
categoryId: [], positionId: [],
parentId: ['', [FormValidators.required('请输入')]], parentId: ['', [FormValidators.required('请输入')]],
categoryName: ['', [FormValidators.required('请输入')]], name: ['', [FormValidators.required('请输入')]],
safetyLimit: [0, []],
lowerLimit: [0, []],
upperLimit: [0, []],
}) })
} }
initQueryForm() { initQueryForm() {
@ -67,7 +65,7 @@ export class SystemAddressComponent {
const { value } = this.createForm const { value } = this.createForm
this.api this.api
.updateBasicCategoryTree({ .saveBasicPosition({
...value, ...value,
}) })
.subscribe((res) => { .subscribe((res) => {

126
web-admin-app/src/app/services/api.service.ts

@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { JwResponse } from 'app/types' import { JwResponse } from 'app/types'
import { Utils } from 'app/utils' import { Utils } from 'app/utils'
import { of, tap } from 'rxjs' import { map, of, tap } from 'rxjs'
import { AuthDTO } from './api.dto' import { AuthDTO } from './api.dto'
import { PermissionService } from 'app/shared/permission/permission.service' import { PermissionService } from 'app/shared/permission/permission.service'
import { NzSafeAny } from 'ng-zorro-antd/core/types' import { NzSafeAny } from 'ng-zorro-antd/core/types'
@ -48,6 +48,24 @@ export class ApiService {
return this.http.post<JwResponse>('/api/common/upload', data) return this.http.post<JwResponse>('/api/common/upload', data)
} }
_displayConfig: any
setSysDisplayConfig(d: {}) {
return this.http.post<JwResponse>(`/api/sysConfig/update/displaySettings`, d)
}
getSysDisplayConfig(force: boolean = false) {
if (force || !this._displayConfig) {
return this.http.post<JwResponse>(`/api/sysConfig/query/displaySettings`, null).pipe(
map((i) => i.body),
tap((res) => {
this._displayConfig = res.body
}),
)
}
return of(this._displayConfig)
}
getLicenseInfo() { getLicenseInfo() {
return this.http.post<JwResponse>('/api/license/info', null) return this.http.post<JwResponse>('/api/license/info', null)
} }
@ -59,7 +77,7 @@ export class ApiService {
return this.http.post<JwResponse>('/api/v2/sysFormTemp/importByExcel', formData) return this.http.post<JwResponse>('/api/v2/sysFormTemp/importByExcel', formData)
} }
uploadFormTpl(formData: FormData) { uploadFormTpl = (formData: FormData) => {
return this.http.post<JwResponse>(`/api/v2/sysFormTemp/upload`, formData) return this.http.post<JwResponse>(`/api/v2/sysFormTemp/upload`, formData)
} }
@ -178,7 +196,27 @@ export class ApiService {
return this.http.post<JwResponse>('/api/eamAsset/warehouse/listByIds', ids) return this.http.post<JwResponse>('/api/eamAsset/warehouse/listByIds', ids)
} }
getAssetLog(data: {}) { getAssetLog(data: {}) {
return this.http.post<JwResponse>('/api/eamAssetLog/list', data) return this.http.post<JwResponse>('/api/eamAssetLog/list', data).pipe(
map((res) => {
return {
...res,
body: {
...res.body,
rows: res.body.rows
.sort((a: any, b: any) => {
return a.id - b.id
})
.map((i: any, idx: number) => {
return {
idx: idx + 1,
...i,
}
}),
},
}
}),
)
} }
getAssetRepairLog(data: {}, id: number) { getAssetRepairLog(data: {}, id: number) {
return this.http.post<JwResponse>(`/api/eamAsset/repair/list?id=${id}`, data) return this.http.post<JwResponse>(`/api/eamAsset/repair/list?id=${id}`, data)
@ -383,6 +421,10 @@ export class ApiService {
return this.http.post<JwResponse>(`/api/eamStocktakingJob/complete`, ids) return this.http.post<JwResponse>(`/api/eamStocktakingJob/complete`, ids)
} }
assetAddByFlow(val: {}) {
return this.http.post<JwResponse>('/api/v2/eamManager/add', val)
}
getBusinessStoragePage(data: {}) { getBusinessStoragePage(data: {}) {
return this.http.post<JwResponse>('/api/eamBusinessStorage/list', data) return this.http.post<JwResponse>('/api/eamBusinessStorage/list', data)
} }
@ -580,7 +622,7 @@ export class ApiService {
return this.http.post<JwResponse>(`/api/flowable/task/myProcess`, data) return this.http.post<JwResponse>(`/api/flowable/task/myProcess`, data)
} }
deleteAssetFlow(data: {}) { deleteAssetFlow(data: {}) {
return this.http.delete<JwResponse>(`/api/flowable/task/delete`, data) return this.http.delete<JwResponse>(`/api/flowable/task/delete`, { body: data })
} }
getMyTodoAssetFlow(data: {}) { getMyTodoAssetFlow(data: {}) {
return this.http.post<JwResponse>(`/api/flowable/task/todoList`, data) return this.http.post<JwResponse>(`/api/flowable/task/todoList`, data)
@ -596,14 +638,15 @@ export class ApiService {
return this.http.post<JwResponse>(`/api/flowable/task/reject`, data) return this.http.post<JwResponse>(`/api/flowable/task/reject`, data)
} }
completeProcessFlow(data: {}) { completeProcessFlow(data: {}) {
// 通过 // 通过 & 重新发起?
return this.http.post<JwResponse>(`/api/flowable/task/complete`, data) return this.http.post<JwResponse>(`/api/flowable/task/complete`, data)
} }
handleTaskAssetItem(data: {}, id: string) { handleTaskAssetItem(data: {}, taskId: string) {
return this.http.post<JwResponse>(`/api/v2/flowable/device/update/${id}`, { variables: data }) return this.http.post<JwResponse>(`/api/v2/flowable/device/update/${taskId}`, { variables: data })
} }
cancelFlow(data: {}) { cancelFlow(data: {}) {
return this.http.post<JwResponse>(`/api/flowable/task/stopProcess`, data) // return this.http.post<JwResponse>(`/api/flowable/task/stopProcess`, data)
return this.http.post<JwResponse>(`/api/flowable/task/revokeProcess`, data)
} }
startFlow(json: {}, form_key: string) { startFlow(json: {}, form_key: string) {
return this.http.post<JwResponse>(`/api/flowable/definition/start/${form_key}`, json) return this.http.post<JwResponse>(`/api/flowable/definition/start/${form_key}`, json)
@ -639,7 +682,7 @@ export class ApiService {
return this.http.post<JwResponse>(`/api/v2/sysFormTemp/update`, data) return this.http.post<JwResponse>(`/api/v2/sysFormTemp/update`, data)
} }
confirmFlowForm(data: NzSafeAny) { confirmFlowForm(data: NzSafeAny) {
return this.http.post<JwResponse>(` /api/v2/sysFormTemp/confirm`, data) return this.http.post<JwResponse>(`/api/v2/sysFormTemp/confirm`, data)
} }
deleteFlowForm(idList: NzSafeAny) { deleteFlowForm(idList: NzSafeAny) {
@ -656,8 +699,11 @@ export class ApiService {
getFlowFormList() { getFlowFormList() {
return this.http.post<JwResponse>(`/api/v2/sysFormTemp/all`, null) return this.http.post<JwResponse>(`/api/v2/sysFormTemp/all`, null)
} }
// getAssetManagerPage(data: {}) {
// return this.http.post<JwResponse>(`/api/v2/eamManager/list`, data)
// }
getAssetManagerPage(data: {}) { getAssetManagerPage(data: {}) {
return this.http.post<JwResponse>(`/api/v2/eamManager/list`, data) return this.http.post<JwResponse>(`/api/v2/eamManager/query`, data)
} }
getAssetTeamPage(data: {}) { getAssetTeamPage(data: {}) {
return this.http.post<JwResponse>(`/api/v2/eamBasicTeam/list`, data) return this.http.post<JwResponse>(`/api/v2/eamBasicTeam/list`, data)
@ -727,7 +773,27 @@ export class ApiService {
return this.http.post<JwResponse>('/api/flForm/update', d) return this.http.post<JwResponse>('/api/flForm/update', d)
} }
deviceLog(d: {}) { deviceLog(d: {}) {
return this.http.post<JwResponse>('/api/eamAssetLog/list/device', d) return this.http.post<JwResponse>('/api/eamAssetLog/list/device', d).pipe(
map((res) => {
return {
...res,
body: {
...res.body,
rows: res.body.rows
.sort((a: any, b: any) => {
return a.id - b.id
})
.map((i: any, idx: number) => {
return {
idx: idx + 1,
...i,
}
}),
},
}
}),
)
} }
assetFlowRecord(d: {}) { assetFlowRecord(d: {}) {
return this.http.post<JwResponse>('/api/flowable/task/flowRecord', d) return this.http.post<JwResponse>('/api/flowable/task/flowRecord', d)
@ -749,16 +815,48 @@ export class ApiService {
responseType: 'blob' as 'json', responseType: 'blob' as 'json',
}) })
} }
onOffRecord(id: string) { onOffRecord(q: {}) {
return this.http.post<JwResponse>(`/api/v2/device/record`, null, { return this.http.post<JwResponse>(`/api/v2/device/record`, null, {
params: { id }, params: q,
}) })
} }
getReportData(data: {}) { getReportData(data: {}) {
return this.http.post<JwResponse>(`/api/flFormItem/workReport`, data) return this.http.post<JwResponse>(`/api/flFormItem/workReport`, data)
} }
saveReport(content: string) { saveReport(content: string) {
return this.http.post<JwResponse>(`api/flFormItem/h5str2word`, null, { params: { content } }) return this.http.post<JwResponse>(
`/api/flFormItem/h5str2word`,
{ content },
{
observe: 'response',
responseType: 'blob' as 'json',
},
)
}
downloadWord(content: {}) {
return this.http.post<JwResponse>(`/api/flFormItem/downloadWord`, content, {
observe: 'response',
responseType: 'blob' as 'json',
})
}
preview(id: string) {
return this.http.post<JwResponse>(`/api/v2/sysFormTemp/preview`, null, {
params: { id },
observe: 'response',
responseType: 'blob' as 'json',
})
}
exportPlanReport(id: string) {
return this.http.post<JwResponse>(
`/api/v2/plan/export`,
{
idList: [id],
},
{
observe: 'response',
responseType: 'blob' as 'json',
},
)
} }
bigScreen() { bigScreen() {
return this.http.post<JwResponse>(`/api/home/bigScreen`, null) return this.http.post<JwResponse>(`/api/home/bigScreen`, null)

8
web-admin-app/src/app/shared/components/header/header.component.html

@ -1,8 +1,10 @@
<header class="fixed z-20 left-0 top-0 right-0 shadow-md header"> <header class="fixed z-20 left-0 top-0 right-0 shadow-md header">
<div class="flex h-full px-4 app-width mx-auto"> <div class="flex h-full px-4 app-width mx-auto">
@if (logo) {
<a class="logo flex items-center"> <a class="logo flex items-center">
<img src="/assets/images/logo.png" class="h-full" /> <img [src]="logo" class="h-10" />
</a> </a>
}
<ul class="ml-8 nav flex"> <ul class="ml-8 nav flex">
<li class="nav-item" *appPermission="['dashboard:view']"> <li class="nav-item" *appPermission="['dashboard:view']">
@ -87,9 +89,9 @@
<a nz-tooltip="消息中心" nz-button nzType="text" routerLink="/message" *nzSpaceItem> <a nz-tooltip="消息中心" nz-button nzType="text" routerLink="/message" *nzSpaceItem>
<span nz-icon nzType="bell" nzTheme="outline"></span> <span nz-icon nzType="bell" nzTheme="outline"></span>
</a> </a>
<a nz-tooltip="主题色" nz-button nzType="text" routerLink="/message" *nzSpaceItem> <!-- <a nz-tooltip="主题色" nz-button nzType="text" routerLink="/message" *nzSpaceItem>
<span nz-icon nzType="bg-colors" nzTheme="outline"></span> <span nz-icon nzType="bg-colors" nzTheme="outline"></span>
</a> </a> -->
<a nz-tooltip="退出登录" nz-button nzType="text" (click)="logout()" *nzSpaceItem> <a nz-tooltip="退出登录" nz-button nzType="text" (click)="logout()" *nzSpaceItem>
<span nz-icon nzType="poweroff" nzTheme="outline"></span> <span nz-icon nzType="poweroff" nzTheme="outline"></span>
</a> </a>

7
web-admin-app/src/app/shared/components/header/header.component.ts

@ -19,7 +19,12 @@ export class HeaderComponent implements OnInit {
public api: ApiService, public api: ApiService,
) {} ) {}
ngOnInit(): void {} logo = ''
ngOnInit(): void {
this.api.getSysDisplayConfig().subscribe((res) => {
this.logo = res.logo
})
}
permission = inject(PermissionService) permission = inject(PermissionService)

18
web-admin-app/src/app/shared/components/upload/upload.component.html

@ -21,25 +21,23 @@
} }
} }
@if (preview) { @if (preview) {
<ul class="mt-2"> <ul class="mt-2 flex">
<li> <li>
<nz-card [nzBordered]="true" nzSize="small"> <nz-card [nzBordered]="true" nzSize="small" [nzBodyStyle]="{ padding: '6px' }">
<a class="flex items-center" [href]="preview.url" target="_blank"> <a class="flex items-center" [href]="preview.url" target="_blank">
<div class="w-16 h-16 overflow-hidden flex-shrink-0 flex items-center justify-center"> <div class="w-32 h-32 overflow-hidden flex-shrink-0 flex items-center justify-center">
@if (isImage(preview.name)) { @if (isImage(preview.name)) {
<img class="h-full object-cover" [src]="preview.url" /> <img class="w-full h-full object-contain" [src]="preview.url" />
} @else { } @else {
<i nz-icon nzType="file" class="text-4xl"></i> <i nz-icon nzType="file" class="text-4xl"></i>
} }
</div> </div>
<div class="flex-1 pl-2"> <!-- <div class="flex-1 pl-2 break-all">
<div>{{ preview.name || preview.url }}</div> <div>{{ preview.name || preview.url }}</div>
</div> </div> -->
<div class="flex-shrink-0"> <button nz-button class="!absolute top-3 right-3" (click)="remove($event)">
<a (click)="remove()">
<i nz-icon nzType="delete"></i> <i nz-icon nzType="delete"></i>
</a> </button>
</div>
</a> </a>
</nz-card> </nz-card>
</li> </li>

32
web-admin-app/src/app/shared/components/upload/upload.component.ts

@ -32,6 +32,8 @@ export class UploadComponent implements ControlValueAccessor {
@Input() placeholder = '选择文件' @Input() placeholder = '选择文件'
@Input() maxSize = 5
@Input() uploadFn: (data: FormData) => Observable<JwResponse> = (d) => { @Input() uploadFn: (data: FormData) => Observable<JwResponse> = (d) => {
return this.api.upload(d) return this.api.upload(d)
} }
@ -54,22 +56,10 @@ export class UploadComponent implements ControlValueAccessor {
this.msg.error('文件不存在') this.msg.error('文件不存在')
return return
} }
if (file.size / 1024 / 1024 >= 2) { if (file.size / 1024 / 1024 >= this.maxSize) {
this.msg.error('文件大小不能超过2M') this.msg.error(`文件大小不能超过${this.maxSize}}M`)
return return
} }
if (this.isImage(file.name)) {
const fileReader = new FileReader()
fileReader.onload = () => {
const base64 = fileReader.result as string
this.preview = {
name: file.name,
url: base64,
}
}
fileReader.readAsDataURL(file)
} else {
}
const formdata = new FormData() const formdata = new FormData()
formdata.append('file', file) formdata.append('file', file)
@ -82,6 +72,16 @@ export class UploadComponent implements ControlValueAccessor {
name: res.body.fileName ?? file.name, name: res.body.fileName ?? file.name,
url: res.body.url, url: res.body.url,
} }
} else {
const fileReader = new FileReader()
fileReader.onload = () => {
const base64 = fileReader.result as string
this.preview = {
name: file.name,
url: base64,
}
}
fileReader.readAsDataURL(file)
} }
}) })
} }
@ -120,7 +120,9 @@ export class UploadComponent implements ControlValueAccessor {
} }
} }
remove() { remove(e: MouseEvent) {
e.stopPropagation()
e.preventDefault()
this.preview = null this.preview = null
this.onChange(null) this.onChange(null)
this.onUpload.emit(null) this.onUpload.emit(null)

2
web-admin-app/src/app/utils/index.ts

@ -98,7 +98,7 @@ export class Utils {
} }
static downLoadFile(response: HttpResponse<Object>, type: string, ext: string = 'pdf') { static downLoadFile(response: HttpResponse<Object>, type: string, ext: string = 'pdf') {
const fileNameFromHeader = response.headers.get('Content-Disposition') const fileNameFromHeader = response.headers.get('Content-Disposition')
console.log('fileNameFromHeader', fileNameFromHeader) console.log('fileNameFromHeader', fileNameFromHeader, response.headers)
let fileName = '' let fileName = ''
if (fileNameFromHeader) { if (fileNameFromHeader) {
fileName = fileNameFromHeader.trim().split('=')[1].replace(/"/g, '') fileName = fileNameFromHeader.trim().split('=')[1].replace(/"/g, '')

BIN
web-admin-app/src/assets/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

1
web-admin-app/src/index.html

@ -4,6 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>固资系统</title> <title>固资系统</title>
<base href="/" /> <base href="/" />
<link rel="icon" id="favicon" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
</head> </head>

41
web-admin-app/src/styles.less

@ -23,6 +23,47 @@
} }
} }
@media print {
@page {
margin: 0;
/* 取消页面边距 */
}
body {
width: 793.92px !important;
/* 设置为 A4 宽度 */
margin: 0 auto;
/* 居中 */
padding: 0;
}
.report {
padding: 0;
}
.no-print,
app-header,
app-flow-layout>.menu,
.page-header {
display: none !important;
width: 0;
height: 0;
opacity: 0;
}
app-flow-layout>.menu+.pl-48 {
padding-left: 0;
}
.print-textarea {
border: none !important;
outline: none !important;
resize: none !important;
}
}
.app-width { .app-width {
width: var(--container-width); width: var(--container-width);

19
web-admin-app/t.html

@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>cccc</title>
</head>
<body>
<h1 style="text-align: center">报表</h1>
<div style="display: flex; border: 1px solid">
<div style="padding: 24px; flex: 1">1</div>
<div style="padding: 24px; flex: 1">2</div>
</div>
<div style="margin-top: 24px; display: flex; border: 1px solid red">
<div style="padding: 24px; flex: 1">1</div>
<div style="padding: 24px; flex: 1">2</div>
</div>
</body>
</html>
Loading…
Cancel
Save