15 changed files with 638 additions and 4 deletions
@ -0,0 +1,23 @@
|
||||
<div class="box"> |
||||
<form nz-form [formGroup]="validateForm"> |
||||
<nz-form-item> |
||||
<nz-form-control> |
||||
<nz-input-group> |
||||
<input nz-input type="text" formControlName="name" placeholder="请输入名称" /> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
<!-- <nz-form-item> |
||||
<nz-form-control> |
||||
<nz-input-group> |
||||
<input nz-input type="text" formControlName="code" placeholder="请输入编码" /> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
</nz-form-item> --> |
||||
<nz-form-item> |
||||
<nz-form-control> |
||||
<label nz-checkbox formControlName="isGasStation">是否为加油站</label> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</form> |
||||
</div> |
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
||||
|
||||
import { AddmenuComponent } from './addmenu.component'; |
||||
|
||||
describe('AddmenuComponent', () => { |
||||
let component: AddmenuComponent; |
||||
let fixture: ComponentFixture<AddmenuComponent>; |
||||
|
||||
beforeEach(async(() => { |
||||
TestBed.configureTestingModule({ |
||||
declarations: [ AddmenuComponent ] |
||||
}) |
||||
.compileComponents(); |
||||
})); |
||||
|
||||
beforeEach(() => { |
||||
fixture = TestBed.createComponent(AddmenuComponent); |
||||
component = fixture.componentInstance; |
||||
fixture.detectChanges(); |
||||
}); |
||||
|
||||
it('should create', () => { |
||||
expect(component).toBeTruthy(); |
||||
}); |
||||
}); |
@ -0,0 +1,27 @@
|
||||
import { Component, OnInit } from '@angular/core'; |
||||
import { NzModalRef } from 'ng-zorro-antd/modal'; |
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
||||
import { HttpClient } from '@angular/common/http'; |
||||
|
||||
@Component({ |
||||
selector: 'app-addmenu', |
||||
templateUrl: './addmenu.component.html', |
||||
styleUrls: ['./addmenu.component.scss'] |
||||
}) |
||||
export class AddmenuComponent implements OnInit { |
||||
|
||||
validateForm!: FormGroup; |
||||
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { } |
||||
|
||||
ngOnInit(): void { |
||||
this.validateForm = this.fb.group({ |
||||
name: [null, [Validators.required]], |
||||
// code: [null, [Validators.required]],
|
||||
isGasStation: [false] |
||||
}); |
||||
} |
||||
destroyModal(): void { |
||||
this.modal.destroy({ data: 'this the result data' }); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@
|
||||
<div class="box"> |
||||
<form nz-form [formGroup]="validateForm"> |
||||
<nz-form-item> |
||||
<nz-form-control nzErrorTip="请输入名称"> |
||||
<nz-input-group> |
||||
<input [(ngModel)]="datacopy.displayName" nz-input type="text" formControlName="name" placeholder="请输入名称" /> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
<!-- <nz-form-item> |
||||
<nz-form-control> |
||||
<nz-input-group> |
||||
<input [(ngModel)]="datacopy.code" nz-input type="text" formControlName="code" placeholder="请输入编码" /> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
</nz-form-item> --> |
||||
<nz-form-item> |
||||
<nz-form-control> |
||||
<label [(ngModel)]="datacopy.isGasStation" nz-checkbox formControlName="isGasStation">是否为加油站</label> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</form> |
||||
</div> |
||||
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
||||
|
||||
import { EditmenuComponent } from './editmenu.component'; |
||||
|
||||
describe('EditmenuComponent', () => { |
||||
let component: EditmenuComponent; |
||||
let fixture: ComponentFixture<EditmenuComponent>; |
||||
|
||||
beforeEach(async(() => { |
||||
TestBed.configureTestingModule({ |
||||
declarations: [ EditmenuComponent ] |
||||
}) |
||||
.compileComponents(); |
||||
})); |
||||
|
||||
beforeEach(() => { |
||||
fixture = TestBed.createComponent(EditmenuComponent); |
||||
component = fixture.componentInstance; |
||||
fixture.detectChanges(); |
||||
}); |
||||
|
||||
it('should create', () => { |
||||
expect(component).toBeTruthy(); |
||||
}); |
||||
}); |
@ -0,0 +1,30 @@
|
||||
import { Component, OnInit, Input } from '@angular/core'; |
||||
import { NzModalRef } from 'ng-zorro-antd/modal'; |
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
||||
import { HttpClient } from '@angular/common/http'; |
||||
@Component({ |
||||
selector: 'app-editmenu', |
||||
templateUrl: './editmenu.component.html', |
||||
styleUrls: ['./editmenu.component.scss'] |
||||
}) |
||||
export class EditmenuComponent implements OnInit { |
||||
|
||||
@Input() data?: any; |
||||
validateForm!: FormGroup; |
||||
constructor(private modal: NzModalRef, private fb: FormBuilder, private http: HttpClient) { } |
||||
|
||||
datacopy:any |
||||
ngOnInit(): void { |
||||
this.validateForm = this.fb.group({ |
||||
name: [null, [Validators.required]], |
||||
// code: [null, [Validators.required]],
|
||||
isGasStation: [] |
||||
}); |
||||
this.datacopy = JSON.parse(JSON.stringify(this.data))
|
||||
} |
||||
destroyModal(): void { |
||||
this.modal.destroy({ data: 'this the result data' }); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,53 @@
|
||||
<div class="orbox" id="orbox"> |
||||
<div class="topbox"> |
||||
<div class="lefttop"> |
||||
<span>组织机构列表</span> |
||||
<span><img style="vertical-align: top;" src="../../../assets/images/icon/orgrey.png" alt=""> |
||||
{{totalCount}}个单位</span> |
||||
</div> |
||||
<div class="righttop"> |
||||
<!-- <form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()"> |
||||
<nz-form-item> |
||||
<nz-form-control> |
||||
<nz-input-group nzPrefixIcon="search"> |
||||
<input type="text" nz-input placeholder="请输入单位" formControlName="search" [(ngModel)]="searchValue"/> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
<button style="display: none;" type="submit"></button> |
||||
</nz-form-item> |
||||
</form> --> |
||||
<nz-input-group nzPrefixIcon="search"> |
||||
<input type="text" nz-input placeholder="请输入单位" [(ngModel)]="searchValue" /> |
||||
</nz-input-group> |
||||
<button nz-button nzType="primary" (click)="addOr()"><i nz-icon nzType="plus-circle" |
||||
nzTheme="outline"></i>新增</button> |
||||
</div> |
||||
</div> |
||||
<div class="treeTitle"> |
||||
<span>组织机构</span> |
||||
<span>操作</span> |
||||
</div> |
||||
<nz-tree [nzHideUnMatched]='true' [nzSearchValue]="searchValue" #nzTreeComponent [nzData]="nodes" |
||||
[nzExpandAll]="nzExpandAll" [nzExpandedKeys]="defaultExpandedKeys" [nzTreeTemplate]="nzTreeTemplate" nzDraggable |
||||
nzBlockNode (nzOnDrop)="nzEvent($event)" [nzBeforeDrop]="beforeDrop" [nzExpandedIcon]="multiExpandedIconTpl"> |
||||
</nz-tree> |
||||
<ng-template #nzTreeTemplate let-node let-origin="origin"> |
||||
<div class="nodebox"> |
||||
<span class="name">{{ node.title }}</span> |
||||
<span class="operation"> |
||||
<span (click)="addOr(node)" *ngIf="!node.origin.isGasStation">新增</span> |
||||
<span (click)="editOr(node)">编辑</span> |
||||
<span [ngClass]="{'grey':node.origin.children && node.origin.children.length != 0}" |
||||
(click)="deleteOr(node)">删除</span> |
||||
</span> |
||||
</div> |
||||
</ng-template> |
||||
<ng-template #multiExpandedIconTpl let-node let-origin="origin"> |
||||
<ng-container *ngIf="node.children.length == 0; else elseTemplate"> |
||||
|
||||
</ng-container> |
||||
<ng-template #elseTemplate> |
||||
<i nz-icon [nzType]="node.isExpanded ? 'caret-down' : 'caret-right'" class="ant-tree-switcher-line-icon"></i> |
||||
</ng-template> |
||||
</ng-template> |
||||
</div> |
@ -0,0 +1,80 @@
|
||||
.orbox { |
||||
width: 100%; |
||||
height: 100%; |
||||
overflow-y: auto; |
||||
background: #fff; |
||||
box-sizing: border-box; |
||||
padding: 20px; |
||||
font-size: 15px; |
||||
} |
||||
|
||||
.topbox { |
||||
width: 700px; |
||||
height: 36px; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
|
||||
.lefttop { |
||||
span:nth-child(1) { |
||||
color: #000D21; |
||||
margin-right: 16px; |
||||
} |
||||
|
||||
span:nth-child(2) { |
||||
color: rgba(36, 36, 36, 0.24); |
||||
} |
||||
} |
||||
|
||||
.righttop { |
||||
height: 36px; |
||||
display: flex; |
||||
|
||||
button { |
||||
margin-left: 16px; |
||||
} |
||||
|
||||
nz-input-group { |
||||
height: 32px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.treeTitle { |
||||
width: 700px; |
||||
height: 36px; |
||||
line-height: 36px; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
color: #000D21; |
||||
box-sizing: border-box; |
||||
padding-left: 30px; |
||||
padding-right: 180px; |
||||
background: rgba(145, 204, 255, 0.2); |
||||
margin: 12px 0; |
||||
} |
||||
|
||||
.nodebox { |
||||
font-size: 15px; |
||||
|
||||
} |
||||
|
||||
.operation { |
||||
position: absolute; |
||||
right: 0; |
||||
|
||||
span { |
||||
margin-left: 40px; |
||||
} |
||||
|
||||
span:nth-child(1), |
||||
span:nth-child(2), |
||||
span:nth-child(3) { |
||||
color: #2399FF; |
||||
} |
||||
|
||||
.grey{ |
||||
color: rgba(0, 13, 33, 0.48)!important; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; |
||||
|
||||
import { MenuComponent } from './menu.component'; |
||||
|
||||
describe('MenuComponent', () => { |
||||
let component: MenuComponent; |
||||
let fixture: ComponentFixture<MenuComponent>; |
||||
|
||||
beforeEach(async(() => { |
||||
TestBed.configureTestingModule({ |
||||
declarations: [ MenuComponent ] |
||||
}) |
||||
.compileComponents(); |
||||
})); |
||||
|
||||
beforeEach(() => { |
||||
fixture = TestBed.createComponent(MenuComponent); |
||||
component = fixture.componentInstance; |
||||
fixture.detectChanges(); |
||||
}); |
||||
|
||||
it('should create', () => { |
||||
expect(component).toBeTruthy(); |
||||
}); |
||||
}); |
@ -0,0 +1,317 @@
|
||||
import { HttpClient } from '@angular/common/http'; |
||||
import { Component, OnInit, AfterViewInit, ViewChild, ViewContainerRef } from '@angular/core'; |
||||
import { TreeService } from 'src/app/service/tree.service'; |
||||
import { NzFormatEmitEvent, NzTreeComponent, NzTreeNodeOptions } from 'ng-zorro-antd/tree'; |
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
||||
import { NzModalService } from 'ng-zorro-antd/modal'; |
||||
import { NzMessageService } from 'ng-zorro-antd/message'; |
||||
import { AddmenuComponent } from './addmenu/addmenu.component'; |
||||
import { EditmenuComponent } from './editmenu/editmenu.component'; |
||||
|
||||
import { NzFormatBeforeDropEvent } from 'ng-zorro-antd/tree'; |
||||
import { Observable, of } from 'rxjs'; |
||||
import { delay } from 'rxjs/operators'; |
||||
@Component({ |
||||
selector: 'app-menu', |
||||
templateUrl: './menu.component.html', |
||||
styleUrls: ['./menu.component.scss'] |
||||
}) |
||||
export class MenuComponent implements OnInit { |
||||
validateForm!: FormGroup; |
||||
constructor(private fb: FormBuilder, private http: HttpClient, private toTree: TreeService, private modal: NzModalService, private message: NzMessageService, private viewContainerRef: ViewContainerRef) { } |
||||
|
||||
ngOnInit(): void { |
||||
this.validateForm = this.fb.group({ |
||||
search: [null] |
||||
}); |
||||
this.getAllOrganization() |
||||
} |
||||
//搜索框提交
|
||||
submitForm(): void { |
||||
for (const i in this.validateForm.controls) { |
||||
this.validateForm.controls[i].markAsDirty(); |
||||
this.validateForm.controls[i].updateValueAndValidity(); |
||||
} |
||||
} |
||||
|
||||
//获取所有组织机构
|
||||
searchValue = ''; |
||||
nzExpandAll = false; |
||||
totalCount: string |
||||
|
||||
allOrList: any |
||||
getAllOrganization() { |
||||
let OrganizationUnitId = sessionStorage.getItem('isGasStation') == 'true' ? JSON.parse(sessionStorage.getItem('userdataOfgasstation')).organization.id : JSON.parse(sessionStorage.getItem('userdata')).organization.id |
||||
let params = { |
||||
OrganizationUnitId: OrganizationUnitId, |
||||
IsContainsChildren: "true" |
||||
} |
||||
this.http.get('/api/services/app/Organization/GetAll', { |
||||
params: params |
||||
}).subscribe((data: any) => { |
||||
this.totalCount = data.result.totalCount |
||||
data.result.items.forEach(element => { |
||||
element.key = element.id |
||||
element.title = element.displayName |
||||
element.selectable = false |
||||
}); |
||||
this.allOrList = data.result.items |
||||
this.nodes = [...this.toTree.toTree(data.result.items)] |
||||
this.defaultExpandedKeys = [this.nodes[0].id] |
||||
this.defaultExpandedKeys = [...this.defaultExpandedKeys] |
||||
}) |
||||
} |
||||
|
||||
|
||||
@ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent; |
||||
|
||||
defaultExpandedKeys = []; |
||||
|
||||
nodes: any[] = [] |
||||
|
||||
|
||||
addOr(node?: any) { |
||||
console.log(node) |
||||
const modal = this.modal.create({ |
||||
nzTitle: node ? '新增组织机构' : '新增一级组织机构', |
||||
nzContent: AddmenuComponent, |
||||
nzViewContainerRef: this.viewContainerRef, |
||||
nzWidth: 288, |
||||
nzComponentParams: {}, |
||||
nzOnOk: async () => { |
||||
console.log('hhhhhhh', instance.validateForm) |
||||
if (instance.validateForm.valid) { |
||||
await new Promise(resolve => { |
||||
let body = { |
||||
parentId: node ? Number(node.key) : null, |
||||
// code: instance.validateForm.value.code,
|
||||
displayName: instance.validateForm.value.name, |
||||
isGasStation: instance.validateForm.value.isGasStation |
||||
} |
||||
this.http.post('/api/services/app/Organization/Create', body).subscribe(data => { |
||||
resolve(data) |
||||
this.message.create('success', '创建成功!'); |
||||
this.nzTreeComponent.getExpandedNodeList().forEach((item) => { |
||||
this.defaultExpandedKeys.push(item.key) |
||||
}) |
||||
this.getAllOrganization() |
||||
return true |
||||
}, err => { |
||||
resolve(err) |
||||
this.message.create('warning', '创建失败'); |
||||
return false |
||||
}) |
||||
}) |
||||
} else { |
||||
this.message.create('warning', '请填写完整!'); |
||||
return false |
||||
} |
||||
} |
||||
}); |
||||
const instance = modal.getContentComponent(); |
||||
|
||||
} |
||||
editOr(node) { |
||||
// console.log(node)
|
||||
const modal = this.modal.create({ |
||||
nzTitle: '编辑组织机构', |
||||
nzContent: EditmenuComponent, |
||||
nzViewContainerRef: this.viewContainerRef, |
||||
nzWidth: 288, |
||||
nzComponentParams: { |
||||
data: node.origin, |
||||
}, |
||||
nzOnOk: async () => { |
||||
console.log('hhhhhhh', instance.validateForm) |
||||
if (instance.validateForm.valid) { |
||||
await new Promise(resolve => { |
||||
let body = { |
||||
id: node.origin.id, |
||||
parentId: node.origin.parentId, |
||||
// code: instance.validateForm.value.code,
|
||||
displayName: instance.validateForm.value.name, |
||||
isGasStation: instance.validateForm.value.isGasStation |
||||
} |
||||
this.http.put('/api/services/app/Organization/Update', body).subscribe(data => { |
||||
resolve(data) |
||||
this.message.create('success', '编辑成功!'); |
||||
this.nzTreeComponent.getExpandedNodeList().forEach((item) => { |
||||
this.defaultExpandedKeys.push(item.key) |
||||
}) |
||||
this.getAllOrganization() |
||||
return true |
||||
}, err => { |
||||
resolve(err) |
||||
this.message.create('warning', '编辑失败'); |
||||
return false |
||||
}) |
||||
}) |
||||
} else { |
||||
this.message.create('warning', '请填写完整!'); |
||||
return false |
||||
} |
||||
} |
||||
}); |
||||
const instance = modal.getContentComponent(); |
||||
} |
||||
deleteOr(item) { |
||||
console.log(item) |
||||
if (item.origin.children && item.origin.children.length != 0) { |
||||
this.message.create('warning', '请先删除所有子节点'); |
||||
} else { |
||||
this.modal.confirm({ |
||||
nzTitle: `确定要删除${item.title}这个机构吗?`, |
||||
nzOkText: '确定', |
||||
nzOkType: 'danger', |
||||
nzOnOk: () => { |
||||
this.http.delete('/api/services/app/Organization/Delete', { |
||||
params: { |
||||
Id: item.origin.id |
||||
} |
||||
}).subscribe(data => { |
||||
this.nzTreeComponent.getExpandedNodeList().forEach((item) => { |
||||
this.defaultExpandedKeys.push(item.key) |
||||
}) |
||||
this.getAllOrganization() |
||||
this.message.create('success', '删除成功!'); |
||||
}) |
||||
}, |
||||
nzCancelText: '取消', |
||||
nzOnCancel: () => { |
||||
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
nzEvent(event: NzFormatEmitEvent): void { |
||||
console.log('event', event) |
||||
if (this.isDrag) { |
||||
let parentId |
||||
if (this.pos == 0) {//目标节点内部
|
||||
parentId = event.node.key |
||||
} else { |
||||
if (event.node.level == 0) { |
||||
parentId = null |
||||
} else { |
||||
parentId = event.node.origin.parentId |
||||
} |
||||
} |
||||
|
||||
let body = { |
||||
id: event.dragNode.key, |
||||
parentId: parentId, |
||||
// code: instance.validateForm.value.code,
|
||||
displayName: event.dragNode.origin.displayName, |
||||
isGasStation: event.dragNode.origin.isGasStation |
||||
} |
||||
this.http.put('/api/services/app/Organization/Update', body).subscribe(data => { |
||||
this.message.create('success', '拖拽成功!'); |
||||
this.nzTreeComponent.getExpandedNodeList().forEach((item) => { |
||||
this.defaultExpandedKeys.push(item.key) |
||||
}) |
||||
this.getAllOrganization() |
||||
return true |
||||
}, err => { |
||||
this.message.create('warning', '拖拽失败'); |
||||
return false |
||||
}) |
||||
|
||||
|
||||
// console.log('this.allOrList', this.allOrList)
|
||||
// let orders = {}
|
||||
// let originalData = JSON.parse(JSON.stringify(this.allOrList || [])) //tree原始数据
|
||||
// let targetNodeData = []//拖动移入节点的数据,用于遍历求出放在该数组的第几位
|
||||
//找到需要重新排序的数组
|
||||
// if (this.pos == 0) {
|
||||
// originalData.forEach(item => {
|
||||
// if (item.parentId == event.node.key) {
|
||||
// targetNodeData.push(item)
|
||||
// }
|
||||
// })
|
||||
// } else {
|
||||
// if (event.node.origin.parentId) {//如果拖动目标为非一级节点
|
||||
// originalData.forEach(item => {
|
||||
// if (item.parentId == event.node.origin.parentId) {
|
||||
// targetNodeData.push(item)
|
||||
// }
|
||||
// })
|
||||
// } else {//如果拖动目标为一级节点
|
||||
// originalData.forEach(item => {
|
||||
// if (!item.parentId) {
|
||||
// targetNodeData.push(item)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// let idArr = []
|
||||
// targetNodeData.forEach(i => {
|
||||
// idArr.push(i.id)
|
||||
// })
|
||||
// if (this.pos == 0 && event.node.origin.children.length == 1) {
|
||||
// // console.log("移入,没有兄弟")
|
||||
// let key = event.dragNode.key
|
||||
// orders[key] = 0
|
||||
// parentId = event.node.key
|
||||
// } else {
|
||||
|
||||
// let array = []
|
||||
// targetNodeData.forEach(item => {
|
||||
// if (item.id != event.dragNode.key) { //将拖动项先移除掉
|
||||
// array.push(item)
|
||||
// }
|
||||
// })
|
||||
// if (event.dragNode.isEnd[event.dragNode.isEnd.length - 1]) { //如果移入到最后一个
|
||||
// // console.log("最后")
|
||||
// array.push(event.dragNode.origin)
|
||||
// } else if (event.dragNode.isStart[event.dragNode.isStart.length - 1]) {//如果移入到第一个
|
||||
// // console.log("第一")
|
||||
// array.unshift(event.dragNode.origin)
|
||||
// } else {//如果移入中间位置
|
||||
// // console.log("中间")
|
||||
// array.splice(event.node.origin.order, 0, event.dragNode.origin)
|
||||
// }
|
||||
// array.forEach((item, key) => {
|
||||
// orders[item.id] = key
|
||||
// })
|
||||
// console.log("移入,多个兄弟",orders)
|
||||
// }
|
||||
|
||||
// let obj = {
|
||||
// id: event.dragNode.origin.id,
|
||||
// parentId: parentId,
|
||||
// orders: orders
|
||||
// }
|
||||
|
||||
// this.http.put("/api/DisposalNodes/Sort", obj).subscribe(data => {
|
||||
// const config = new MatSnackBarConfig();
|
||||
// config.verticalPosition = 'top';
|
||||
// config.duration = 3000
|
||||
// this.snackBar.open('排序成功', '确定', config)
|
||||
// this.refurbishTreeData()
|
||||
// })
|
||||
|
||||
|
||||
|
||||
} |
||||
} |
||||
isDrag //是否可以拖动
|
||||
pos//放置位置
|
||||
beforeDrop = (arg: NzFormatBeforeDropEvent) => { |
||||
console.log('arg', arg) |
||||
if (arg.node.level === 0) {//如果为数据节点则不允许拖到一级节点
|
||||
this.message.create('warning', '不允许拖拽到一级节点'); |
||||
this.isDrag = false |
||||
return of(false); |
||||
} else { |
||||
this.isDrag = true |
||||
this.pos = arg.pos |
||||
return of(true) |
||||
} |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue