mirror of
https://gitee.com/eolink_admin/postcat.git
synced 2024-12-02 11:47:57 +08:00
refator: move api operation to group
This commit is contained in:
parent
6a22e79508
commit
4eb639d392
@ -2,11 +2,7 @@
|
||||
<nz-sider nzTheme="light" nzWidth="250">
|
||||
<nz-content>
|
||||
<div class="inner-content">
|
||||
<eo-api-group-tree
|
||||
[treeNodes]="treeNodes"
|
||||
(groupTreeEvent)="groupTreeEvent($event)"
|
||||
(updateGroupTreeEvent)="updateGroupTreeEvent($event)"
|
||||
></eo-api-group-tree>
|
||||
<eo-api-group-tree></eo-api-group-tree>
|
||||
</div>
|
||||
</nz-content>
|
||||
</nz-sider>
|
||||
@ -14,7 +10,7 @@
|
||||
<nz-content>
|
||||
<div class="inner-content">
|
||||
<div class="tabs-bar f_row">
|
||||
<eo-api-tab class="fg1" [apiDataItems]="apiDataItems"></eo-api-tab>
|
||||
<eo-api-tab class="fg1"></eo-api-tab>
|
||||
<div class="env">
|
||||
<eo-env></eo-env>
|
||||
</div>
|
||||
|
@ -1,48 +1,13 @@
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd/tree';
|
||||
import { Message, MessageService } from '../../shared/services/message';
|
||||
import { GroupService } from '../../shared/services/group/group.service';
|
||||
import { NzModalService } from 'ng-zorro-antd/modal';
|
||||
import { ApiDataService } from '../../shared/services/api-data/api-data.service';
|
||||
import { listToTree } from '../../utils/tree';
|
||||
|
||||
import { GroupApiDataModel, GroupTreeItem } from '../../shared/models';
|
||||
import { ApiData } from '../../shared/services/api-data/api-data.model';
|
||||
import { Group } from '../../shared/services/group/group.model';
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { ApiTabService } from './tab/api-tab.service';
|
||||
@Component({
|
||||
selector: 'eo-api',
|
||||
templateUrl: './api.component.html',
|
||||
styleUrls: ['./api.component.scss'],
|
||||
})
|
||||
export class ApiComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Default projectID.
|
||||
*/
|
||||
projectID = 1;
|
||||
/**
|
||||
* All group items.
|
||||
*/
|
||||
groupByID: { [key: number | string]: Group };
|
||||
/**
|
||||
* All api data items.
|
||||
*/
|
||||
apiDataItems: { [key: number | string]: ApiData };
|
||||
|
||||
/**
|
||||
* All Tree items.
|
||||
*/
|
||||
treeItems: Array<GroupTreeItem>;
|
||||
/**
|
||||
* Level Tree nodes.
|
||||
*/
|
||||
treeNodes: Array<GroupTreeItem>;
|
||||
|
||||
export class ApiComponent implements OnInit {
|
||||
/**
|
||||
* API uuid
|
||||
*/
|
||||
@ -62,68 +27,16 @@ export class ApiComponent implements OnInit, OnDestroy {
|
||||
title: '测试',
|
||||
},
|
||||
];
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private groupService: GroupService,
|
||||
private apiDataService: ApiDataService,
|
||||
private messageService: MessageService,
|
||||
private modalService: NzModalService,
|
||||
private tabSerive: ApiTabService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.watchChangeRouter();
|
||||
this.buildGroupTreeData();
|
||||
this.watchGroupTreeData();
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
/**
|
||||
* Load all group and apiData items.
|
||||
*/
|
||||
buildGroupTreeData(): void {
|
||||
this.groupByID = {};
|
||||
this.treeItems = [];
|
||||
this.getGroups();
|
||||
}
|
||||
getGroups() {
|
||||
this.groupService.loadAllByProjectID(this.projectID).subscribe((items: Array<Group>) => {
|
||||
items.forEach((item) => {
|
||||
delete item.updatedAt;
|
||||
this.groupByID[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: item.uuid,
|
||||
weight: item.weight || 0,
|
||||
parentID: item.parentID || 0,
|
||||
isLeaf: false,
|
||||
});
|
||||
});
|
||||
this.getApis();
|
||||
});
|
||||
}
|
||||
getApis() {
|
||||
this.apiDataService.loadAllByProjectID(this.projectID).subscribe((items: Array<ApiData>) => {
|
||||
let apiItems = {};
|
||||
items.forEach((item) => {
|
||||
delete item.updatedAt;
|
||||
apiItems[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: item.uuid,
|
||||
weight: item.weight || 0,
|
||||
parentID: item.groupID || 0,
|
||||
method: item.method,
|
||||
isLeaf: true,
|
||||
});
|
||||
});
|
||||
this.apiDataItems = apiItems;
|
||||
this.generateGroupTreeData();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current API ID to show content tab
|
||||
*/
|
||||
@ -136,173 +49,4 @@ export class ApiComponent implements OnInit, OnDestroy {
|
||||
clickContentMenu(data) {
|
||||
this.tabSerive.apiEvent$.next({ action: 'beforeChangeRouter', data: data });
|
||||
}
|
||||
/**
|
||||
* Event emit from group tree component.
|
||||
*
|
||||
* @param event NzFormatEmitEvent
|
||||
*/
|
||||
groupTreeEvent(event: NzFormatEmitEvent | any): void {
|
||||
switch (event.eventName) {
|
||||
case 'deleteGroup':
|
||||
this.deleteGroupTreeItems(event.node);
|
||||
break;
|
||||
case 'loadAllGroup':
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
case 'copyApi':
|
||||
this.copyApi(event.node);
|
||||
break;
|
||||
case 'deleteApi':
|
||||
this.deleteApi(event.node);
|
||||
break;
|
||||
default: {
|
||||
this.tabSerive.apiEvent$.next({ action: event.eventName, data: event.node });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch group and apiData change event.
|
||||
*/
|
||||
watchGroupTreeData(): void {
|
||||
this.messageService
|
||||
.get()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((data: Message) => {
|
||||
switch (data.type) {
|
||||
case 'addApi':
|
||||
case 'editApi':
|
||||
{
|
||||
this.tabSerive.apiEvent$.next({ action: `${data.type}Finish`,data:data.data});
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
}
|
||||
case 'groupAdd':
|
||||
case 'groupEdit':
|
||||
case 'groupDelete':
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
case 'apiDelete':
|
||||
let tmpApi = data.data;
|
||||
this.tabSerive.apiEvent$.next({ action: 'removeApiDataTabs', data: [tmpApi.uuid] });
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
case 'apiBatchDelete':
|
||||
this.tabSerive.apiEvent$.next({ action: 'removeApiDataTabs', data: data.data.uuids });
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generate group tree nodes.
|
||||
*/
|
||||
generateGroupTreeData(): void {
|
||||
this.treeItems.sort((a, b) => a.weight - b.weight);
|
||||
this.treeNodes = [];
|
||||
listToTree(this.treeItems, this.treeNodes, 0);
|
||||
}
|
||||
/**
|
||||
* Copy api data.
|
||||
*
|
||||
* @param node NzTreeNode
|
||||
*/
|
||||
copyApi(node: NzTreeNode): void {
|
||||
const data = this.apiDataItems[node.key];
|
||||
delete data.uuid;
|
||||
delete data.createdAt;
|
||||
data.name += ' Copy';
|
||||
window.sessionStorage.setItem('apiDataWillbeSave', JSON.stringify(data));
|
||||
this.tabSerive.apiEvent$.next({
|
||||
action: 'newApi',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete api data.
|
||||
*
|
||||
* @param node NzTreeNode
|
||||
*/
|
||||
deleteApi(node: NzTreeNode): void {
|
||||
this.modalService.confirm({
|
||||
nzTitle: '删除确认?',
|
||||
nzContent: `确认要删除数据<strong>${node.title}</strong>吗?删除后不可恢复!`,
|
||||
nzOnOk: () => {
|
||||
this.apiDataService.remove(node.key).subscribe((result: boolean) => {
|
||||
this.messageService.send({ type: 'apiDelete', data: { uuid: node.key } });
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get all child items belong to parentID
|
||||
*
|
||||
* @param list
|
||||
* @param tree
|
||||
* @param parentID
|
||||
*/
|
||||
getChildrenFromTree(list: Array<GroupTreeItem>, tree: GroupApiDataModel, parentID: number | string): void {
|
||||
list.forEach((data) => {
|
||||
if (data.parentID === parentID) {
|
||||
if (!data.isLeaf) {
|
||||
tree.group.push(data.key);
|
||||
this.getChildrenFromTree(list, tree, data.key);
|
||||
} else {
|
||||
tree.api.push(data.key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Delete all tree items of parent node.
|
||||
*
|
||||
* @param data GroupApiDataModel
|
||||
*/
|
||||
deleteGroupTreeItems(group: Group) {
|
||||
const data: GroupApiDataModel = { group: [], api: [] };
|
||||
this.getChildrenFromTree(this.treeItems, data, group.uuid);
|
||||
if (data.group.length > 0 && data.api.length > 0) {
|
||||
this.groupService.bulkRemove(data.group).subscribe((result) => {
|
||||
this.apiDataService.bulkRemove(data.api).subscribe((result) => {
|
||||
this.buildGroupTreeData();
|
||||
this.messageService.send({ type: 'apiBatchDelete', data: { uuids: data.api } });
|
||||
});
|
||||
});
|
||||
} else if (data.group.length > 0) {
|
||||
this.groupService.bulkRemove(data.group).subscribe((result) => {
|
||||
this.buildGroupTreeData();
|
||||
});
|
||||
} else if (data.api.length > 0) {
|
||||
this.apiDataService.bulkRemove(data.api).subscribe((result) => {
|
||||
this.buildGroupTreeData();
|
||||
this.messageService.send({ type: 'apiBatchDelete', data: { uuids: data.api } });
|
||||
});
|
||||
} else {
|
||||
this.buildGroupTreeData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tree items after drag.
|
||||
*
|
||||
* @param data GroupApiDataModel
|
||||
*/
|
||||
updateGroupTreeEvent(data: GroupApiDataModel) {
|
||||
if (data.group.length > 0 && data.api.length > 0) {
|
||||
this.groupService.bulkUpdate(data.group).subscribe((result) => {
|
||||
console.log(result);
|
||||
this.apiDataService.bulkUpdate(data.api).subscribe((result) => {
|
||||
console.log(result);
|
||||
});
|
||||
});
|
||||
} else if (data.group.length > 0) {
|
||||
this.groupService.bulkUpdate(data.group).subscribe((result) => {
|
||||
console.log(result);
|
||||
});
|
||||
} else if (data.api.length > 0) {
|
||||
this.apiDataService.bulkUpdate(data.api).subscribe((result) => {
|
||||
console.log(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import { ApiTabService } from './tab/api-tab.service';
|
||||
import { MessageService } from '../../shared/services/message';
|
||||
import { ApiGroupTreeComponent } from './group/tree/api-group-tree.component';
|
||||
import { ApiTabComponent } from './tab/api-tab.component';
|
||||
import { ApiService } from './api.service';
|
||||
|
||||
const COMPONENTS = [ApiComponent, ApiGroupEditComponent, ApiGroupTreeComponent];
|
||||
@NgModule({
|
||||
@ -54,6 +55,6 @@ const COMPONENTS = [ApiComponent, ApiGroupEditComponent, ApiGroupTreeComponent];
|
||||
],
|
||||
declarations: [...COMPONENTS, ApiTabComponent],
|
||||
exports: [],
|
||||
providers: [ApiDataService, GroupService, MessageService, ApiTabService],
|
||||
providers: [ApiDataService, GroupService, MessageService, ApiTabService,ApiService],
|
||||
})
|
||||
export class ApiModule {}
|
||||
|
45
src/app/pages/api/api.service.ts
Normal file
45
src/app/pages/api/api.service.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { NzModalService } from 'ng-zorro-antd/modal';
|
||||
import { ApiDataService } from '../../shared/services/api-data/api-data.service';
|
||||
import { MessageService } from '../../shared/services/message';
|
||||
|
||||
@Injectable()
|
||||
export class ApiService {
|
||||
constructor(
|
||||
private apiDataService: ApiDataService,
|
||||
private modalService: NzModalService,
|
||||
private messageService: MessageService
|
||||
) {}
|
||||
/**
|
||||
* Copy api data.
|
||||
*
|
||||
* @param node NzTreeNode
|
||||
*/
|
||||
copy(apiData): void {
|
||||
delete apiData.uuid;
|
||||
delete apiData.createdAt;
|
||||
apiData.name += ' Copy';
|
||||
window.sessionStorage.setItem('apiDataWillbeSave', JSON.stringify(apiData));
|
||||
this.messageService.send({ type: 'copyApi', data: apiData });
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete api data.
|
||||
*
|
||||
* @param node NzTreeNode
|
||||
*/
|
||||
delete(apiData): void {
|
||||
this.modalService.confirm({
|
||||
nzTitle: '删除确认?',
|
||||
nzContent: `确认要删除数据 <strong title="${apiData.title}">${
|
||||
apiData.title.length > 50 ? apiData.title.slice(0, 50) + '...' : apiData.title
|
||||
}</strong> 吗?删除后不可恢复!`,
|
||||
nzOnOk: () => {
|
||||
this.apiDataService.remove(apiData.key).subscribe((result: boolean) => {
|
||||
this.messageService.send({ type: 'deleteApi', data: { uuid: apiData.key } });
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
@ -2,9 +2,9 @@
|
||||
<div class="t-1">
|
||||
<nz-tag [nzColor]="'#108ee9'">{{ apiData.protocol | uppercase }}</nz-tag>
|
||||
<nz-tag [nzColor]="'#0aa07a'">{{ apiData.method | uppercase }}</nz-tag>
|
||||
<span>{{ apiData.uri }}</span>
|
||||
<span class="mt10 dp_b text_omit">{{ apiData.uri }}</span>
|
||||
</div>
|
||||
<p class="api_name">{{ apiData.name }}</p>
|
||||
<p class="api_name text_omit">{{ apiData.name }}</p>
|
||||
<div *ngIf="apiData.requestHeaders && apiData.requestHeaders.length">
|
||||
<p class="api_line">请求头部</p>
|
||||
<eo-api-detail-header [model]="apiData.requestHeaders"></eo-api-detail-header>
|
||||
|
@ -29,7 +29,7 @@ export class ApiDetailComponent implements OnInit {
|
||||
BODY_TYPE: reverseObj(ApiBodyType),
|
||||
JSON_ROOT_TYPE: reverseObj(JsonRootType)
|
||||
};
|
||||
constructor(private apiService: ApiDataService, private route: ActivatedRoute) {
|
||||
constructor(private apiDataService: ApiDataService, private route: ActivatedRoute) {
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.subscribe((params) => {
|
||||
@ -41,7 +41,7 @@ export class ApiDetailComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
getApiByUuid(id: number) {
|
||||
this.apiService.load(id).subscribe((result: ApiData) => {
|
||||
this.apiDataService.load(id).subscribe((result: ApiData) => {
|
||||
['requestBody', 'responseBody'].forEach((tableName) => {
|
||||
if (['xml', 'json'].includes(result[`${tableName}Type`])) {
|
||||
result[tableName] = treeToListHasLevel(result[tableName]);
|
||||
|
@ -7,11 +7,14 @@
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
||||
<div *ngIf="isDelete">
|
||||
删除<strong>{{ group.name }}</strong>后,该分组下的数据都会删除。该操作无法撤销,确认删除吗?
|
||||
</div>
|
||||
<p *ngIf="isDelete">
|
||||
删除 <strong title="{{ group.name }}">{{
|
||||
group.name.length > 50 ? group.name.slice(0, 50) + '...' : group.name
|
||||
}}</strong
|
||||
> 后,该分组下的数据都会删除。该操作无法撤销,确认删除吗?
|
||||
</p>
|
||||
</div>
|
||||
<footer class="group_edit_footer">
|
||||
<button nz-button nzType="primary" (click)='submit()' [nzLoading]="showLoading">确定</button>
|
||||
<button nz-button nzType="primary" (click)="submit()" [nzLoading]="showLoading">确定</button>
|
||||
<button nz-button (click)="close()">取消</button>
|
||||
</footer>
|
||||
|
@ -36,7 +36,7 @@
|
||||
[nzSearchValue]="searchValue"
|
||||
[nzExpandedKeys]="expandedKeys"
|
||||
(nzClick)="treeItemClick($event)"
|
||||
(nzExpandChange)="nzEvent($event)"
|
||||
(nzExpandChange)="groupTreeEvent($event)"
|
||||
nzDraggable
|
||||
nzBlockNode
|
||||
(nzOnDrop)="treeItemDrop($event)"
|
||||
|
@ -1,35 +1,185 @@
|
||||
import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
|
||||
import { GroupTreeItem, GroupApiDataModel } from '../../../../shared/models';
|
||||
import { Group } from '../../../../shared/services/group/group.model';
|
||||
import { Message } from '../../../../shared/services/message/message.model';
|
||||
import { ApiData } from '../../../../shared/services/api-data/api-data.model';
|
||||
|
||||
import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
|
||||
import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd/tree';
|
||||
|
||||
import { ApiGroupEditComponent } from '../edit/api-group-edit.component';
|
||||
import { Message } from '../../../../shared/services/message/message.model';
|
||||
|
||||
import { GroupService } from '../../../../shared/services/group/group.service';
|
||||
import { ApiService } from '../../api.service';
|
||||
import { ApiTabService } from '../../tab/api-tab.service';
|
||||
import { ApiDataService } from '../../../../shared/services/api-data/api-data.service';
|
||||
import { MessageService } from '../../../../shared/services/message';
|
||||
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
import { listToTree } from '../../../../utils/tree';
|
||||
@Component({
|
||||
selector: 'eo-api-group-tree',
|
||||
templateUrl: './api-group-tree.component.html',
|
||||
styleUrls: ['./api-group-tree.component.scss'],
|
||||
})
|
||||
export class ApiGroupTreeComponent implements OnInit {
|
||||
@Input() treeNodes: Array<GroupTreeItem> | any;
|
||||
@Output() groupTreeEvent = new EventEmitter();
|
||||
@Output() updateGroupTreeEvent = new EventEmitter();
|
||||
export class ApiGroupTreeComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Expanded keys of tree.
|
||||
*/
|
||||
expandedKeys: Array<string | number>;
|
||||
|
||||
searchValue = '';
|
||||
constructor(private modalService: NzModalService) {}
|
||||
/**
|
||||
* Default projectID.
|
||||
*/
|
||||
projectID = 1;
|
||||
/**
|
||||
* All group items.
|
||||
*/
|
||||
groupByID: { [key: number | string]: Group };
|
||||
/**
|
||||
* All api data items.
|
||||
*/
|
||||
apiDataItems: { [key: number | string]: ApiData };
|
||||
|
||||
ngOnInit(): void {}
|
||||
nzEvent(event: NzFormatEmitEvent): void {
|
||||
console.log(event);
|
||||
this.groupTreeEvent.emit(event);
|
||||
/**
|
||||
* All Tree items.
|
||||
*/
|
||||
treeItems: Array<GroupTreeItem>;
|
||||
/**
|
||||
* Level Tree nodes.
|
||||
*/
|
||||
treeNodes: Array<GroupTreeItem>;
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
constructor(
|
||||
private modalService: NzModalService,
|
||||
private groupService: GroupService,
|
||||
private apiDataService: ApiDataService,
|
||||
private apiService: ApiService,
|
||||
private tabSerive: ApiTabService,
|
||||
private messageService: MessageService
|
||||
) {}
|
||||
ngOnInit(): void {
|
||||
this.buildGroupTreeData();
|
||||
this.watchGroupTreeData();
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
/**
|
||||
* Watch group and apiData change event.
|
||||
*/
|
||||
watchGroupTreeData(): void {
|
||||
this.messageService
|
||||
.get()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((data: Message) => {
|
||||
switch (data.type) {
|
||||
case 'addApi':
|
||||
case 'editApi': {
|
||||
this.tabSerive.apiEvent$.next({ action: `${data.type}Finish`, data: data.data });
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
}
|
||||
case 'copyApi': {
|
||||
this.tabSerive.apiEvent$.next({
|
||||
action: 'copyApi',
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'groupAdd':
|
||||
case 'groupEdit':
|
||||
case 'groupDelete':
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
case 'deleteApi':
|
||||
let tmpApi = data.data;
|
||||
this.tabSerive.apiEvent$.next({ action: 'removeApiDataTabs', data: [tmpApi.uuid] });
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
case 'apiBatchDelete':
|
||||
this.tabSerive.apiEvent$.next({ action: 'removeApiDataTabs', data: data.data.uuids });
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Generate group tree nodes.
|
||||
*/
|
||||
generateGroupTreeData(): void {
|
||||
this.treeItems.sort((a, b) => a.weight - b.weight);
|
||||
this.treeNodes = [];
|
||||
listToTree(this.treeItems, this.treeNodes, 0);
|
||||
}
|
||||
/**
|
||||
* Load all group and apiData items.
|
||||
*/
|
||||
buildGroupTreeData(): void {
|
||||
this.groupByID = {};
|
||||
this.treeItems = [];
|
||||
this.getGroups();
|
||||
}
|
||||
getGroups() {
|
||||
this.groupService.loadAllByProjectID(this.projectID).subscribe((items: Array<Group>) => {
|
||||
items.forEach((item) => {
|
||||
delete item.updatedAt;
|
||||
this.groupByID[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: item.uuid,
|
||||
weight: item.weight || 0,
|
||||
parentID: item.parentID || 0,
|
||||
isLeaf: false,
|
||||
});
|
||||
});
|
||||
this.getApis();
|
||||
});
|
||||
}
|
||||
getApis() {
|
||||
this.apiDataService.loadAllByProjectID(this.projectID).subscribe((items: Array<ApiData>) => {
|
||||
let apiItems = {};
|
||||
items.forEach((item) => {
|
||||
delete item.updatedAt;
|
||||
apiItems[item.uuid] = item;
|
||||
this.treeItems.push({
|
||||
title: item.name,
|
||||
key: item.uuid,
|
||||
weight: item.weight || 0,
|
||||
parentID: item.groupID || 0,
|
||||
method: item.method,
|
||||
isLeaf: true,
|
||||
});
|
||||
});
|
||||
this.apiDataItems = apiItems;
|
||||
this.tabSerive.apiEvent$.next({ action: 'afterLoadApi', data: this.apiDataItems });
|
||||
this.generateGroupTreeData();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Event emit from group tree component.
|
||||
*
|
||||
* @param event NzFormatEmitEvent
|
||||
*/
|
||||
groupTreeEvent(event: NzFormatEmitEvent | any): void {
|
||||
switch (event.eventName) {
|
||||
case 'deleteGroup':
|
||||
this.deleteGroupTreeItems(event.node);
|
||||
break;
|
||||
case 'loadAllGroup':
|
||||
this.buildGroupTreeData();
|
||||
break;
|
||||
case 'copyApi':
|
||||
this.apiService.copy(this.apiDataItems[event.node.key]);
|
||||
break;
|
||||
case 'deleteApi':
|
||||
this.apiService.delete(this.apiDataItems[event.node.key]);
|
||||
break;
|
||||
default: {
|
||||
this.tabSerive.apiEvent$.next({ action: event.eventName, data: event.node });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +192,7 @@ export class ApiGroupTreeComponent implements OnInit {
|
||||
event.node.isExpanded = !event.node.isExpanded;
|
||||
} else {
|
||||
event.eventName = 'detailApi';
|
||||
this.groupTreeEvent.emit(event);
|
||||
this.groupTreeEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,12 +262,12 @@ export class ApiGroupTreeComponent implements OnInit {
|
||||
if (res) {
|
||||
if ('deleteGroup' === res.type) {
|
||||
const group: Group = res.data.group;
|
||||
this.groupTreeEvent.emit({
|
||||
this.groupTreeEvent({
|
||||
eventName: 'deleteGroup',
|
||||
node: group,
|
||||
});
|
||||
} else {
|
||||
this.groupTreeEvent.emit({
|
||||
this.groupTreeEvent({
|
||||
eventName: 'loadAllGroup',
|
||||
});
|
||||
}
|
||||
@ -148,7 +298,23 @@ export class ApiGroupTreeComponent implements OnInit {
|
||||
groupApiData.group.push({ uuid: dragNode.key, weight: 0, parentID: 0 });
|
||||
}
|
||||
}
|
||||
this.updateGroupTreeEvent.emit(groupApiData);
|
||||
this.updateGroupTreeEvent(groupApiData);
|
||||
}
|
||||
/**
|
||||
* Update tree items after drag.
|
||||
*
|
||||
* @param data GroupApiDataModel
|
||||
*/
|
||||
updateGroupTreeEvent(data: GroupApiDataModel) {
|
||||
if (data.group.length > 0 && data.api.length > 0) {
|
||||
this.groupService.bulkUpdate(data.group).subscribe((result) => {
|
||||
this.apiDataService.bulkUpdate(data.api).subscribe((result) => {});
|
||||
});
|
||||
} else if (data.group.length > 0) {
|
||||
this.groupService.bulkUpdate(data.group).subscribe((result) => {});
|
||||
} else if (data.api.length > 0) {
|
||||
this.apiDataService.bulkUpdate(data.api).subscribe((result) => {});
|
||||
}
|
||||
}
|
||||
private nodeToGroup(node: NzTreeNode): Group {
|
||||
return {
|
||||
@ -159,8 +325,56 @@ export class ApiGroupTreeComponent implements OnInit {
|
||||
weight: node.origin.weight,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all child items belong to parentID
|
||||
*
|
||||
* @param list
|
||||
* @param tree
|
||||
* @param parentID
|
||||
*/
|
||||
getChildrenFromTree(list: Array<GroupTreeItem>, tree: GroupApiDataModel, parentID: number | string): void {
|
||||
list.forEach((data) => {
|
||||
if (data.parentID === parentID) {
|
||||
if (!data.isLeaf) {
|
||||
tree.group.push(data.key);
|
||||
this.getChildrenFromTree(list, tree, data.key);
|
||||
} else {
|
||||
tree.api.push(data.key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Delete all tree items of parent node.
|
||||
*
|
||||
* @param data GroupApiDataModel
|
||||
*/
|
||||
deleteGroupTreeItems(group: Group) {
|
||||
const data: GroupApiDataModel = { group: [], api: [] };
|
||||
this.getChildrenFromTree(this.treeItems, data, group.uuid);
|
||||
if (data.group.length > 0 && data.api.length > 0) {
|
||||
this.groupService.bulkRemove(data.group).subscribe((result) => {
|
||||
this.apiDataService.bulkRemove(data.api).subscribe((result) => {
|
||||
this.buildGroupTreeData();
|
||||
this.messageService.send({ type: 'apiBatchDelete', data: { uuids: data.api } });
|
||||
});
|
||||
});
|
||||
} else if (data.group.length > 0) {
|
||||
this.groupService.bulkRemove(data.group).subscribe((result) => {
|
||||
this.buildGroupTreeData();
|
||||
});
|
||||
} else if (data.api.length > 0) {
|
||||
this.apiDataService.bulkRemove(data.api).subscribe((result) => {
|
||||
this.buildGroupTreeData();
|
||||
this.messageService.send({ type: 'apiBatchDelete', data: { uuids: data.api } });
|
||||
});
|
||||
} else {
|
||||
this.buildGroupTreeData();
|
||||
}
|
||||
}
|
||||
onClick(event: NzFormatEmitEvent) {
|
||||
event.event.stopPropagation();
|
||||
this.groupTreeEvent.emit(event);
|
||||
this.groupTreeEvent(event);
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,32 @@
|
||||
<nz-tabset
|
||||
[(nzSelectedIndex)]="selectedIndex"
|
||||
nzType="editable-card"
|
||||
(nzAdd)="newTab()"
|
||||
nzHideAdd="true"
|
||||
(nzClose)="closeTab($event)"
|
||||
(nzSelectChange)="switchTab()"
|
||||
(nzSelectChange)="pickTab()"
|
||||
[nzTabBarExtraContent]="extraTemplate"
|
||||
>
|
||||
<nz-tab *ngFor="let tab of tabs; let i = index" nzClosable [nzTitle]="titleTemplate">
|
||||
<ng-template #titleTemplate>
|
||||
<span class="mr5 method_text_{{ tab.method }}" *ngIf="tab.method">{{ tab.method.slice(0, 4) }}</span>
|
||||
{{ tab.title }}
|
||||
<span class="text_omit tab_text"> {{ tab.title }}</span>
|
||||
</ng-template>
|
||||
</nz-tab>
|
||||
</nz-tabset>
|
||||
<ng-template #extraTemplate>
|
||||
<button (click)="newTab()" class="ant-tabs-nav-add {{ tabs.length >= MAX_TAB_LIMIT ? 'hidden' : '' }}">
|
||||
<i nz-icon nzType="plus"></i>
|
||||
</button>
|
||||
<a nz-dropdown nzTrigger="click" [nzDropdownMenu]="menu">
|
||||
<button class="ant-tabs-nav-more"><i nz-icon nzType="ellipsis" nzTheme="outline"></i></button>
|
||||
</a>
|
||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item>关闭其它标签页</li>
|
||||
<li nz-menu-item>关闭所有标签</li>
|
||||
<li nz-menu-item (click)="operateTab('closeOther')">关闭所有标签(当前标签除外)</li>
|
||||
<li nz-menu-item (click)="operateTab('closeAll')">关闭所有标签</li>
|
||||
<!-- <li nz-menu-item>关闭已保存</li> -->
|
||||
<li nz-menu-item>关闭左侧标签页</li>
|
||||
<li nz-menu-item>关闭右侧标签页</li>
|
||||
<li nz-menu-item (click)="operateTab('closeLeft')">关闭左侧标签页</li>
|
||||
<li nz-menu-item (click)="operateTab('closeRight')">关闭右侧标签页</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</ng-template>
|
||||
|
@ -1,3 +1,6 @@
|
||||
.tab_text{
|
||||
max-width: 100px;
|
||||
}
|
||||
::ng-deep {
|
||||
eo-api-tab {
|
||||
width: calc(100% - 160px);
|
||||
@ -18,7 +21,7 @@
|
||||
}
|
||||
.ant-tabs-tab-btn {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.ant-tabs-nav-wrap {
|
||||
|
@ -1,18 +1,20 @@
|
||||
import { Component, OnInit, Input, OnChanges, SimpleChanges, OnDestroy } from '@angular/core';
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
|
||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { TabItem } from './tab.model';
|
||||
import { ApiData } from '../../../shared/services/api-data/api-data.model';
|
||||
|
||||
import { ApiTabService } from './api-tab.service';
|
||||
import { filter, Subject, takeUntil } from 'rxjs';
|
||||
|
||||
import { min, Subject, takeUntil } from 'rxjs';
|
||||
@Component({
|
||||
selector: 'eo-api-tab',
|
||||
templateUrl: './api-tab.component.html',
|
||||
styleUrls: ['./api-tab.component.scss'],
|
||||
})
|
||||
export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input() apiDataItems;
|
||||
id: number;
|
||||
export class ApiTabComponent implements OnInit, OnDestroy {
|
||||
apiDataItems: { [key: number | string]: ApiData };
|
||||
/**
|
||||
* Tab items.
|
||||
*/
|
||||
@ -30,7 +32,7 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
test: { path: '/home/api/test', title: '新 API' },
|
||||
detail: { path: '/home/api/detail', title: 'API 详情' },
|
||||
};
|
||||
MAX_LIMIT = 15;
|
||||
MAX_TAB_LIMIT = 15;
|
||||
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
constructor(private router: Router, private route: ActivatedRoute, private tabSerive: ApiTabService) {}
|
||||
@ -38,11 +40,6 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
ngOnInit(): void {
|
||||
this.watchApiAction();
|
||||
}
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.apiDataItems && !changes.apiDataItems.previousValue && changes.apiDataItems.currentValue) {
|
||||
this.initTab();
|
||||
}
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
@ -58,12 +55,13 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
*/
|
||||
initTab() {
|
||||
let apiID = Number(this.route.snapshot.queryParams.uuid);
|
||||
let hasApiExist = this.apiDataItems[apiID];
|
||||
//delete api
|
||||
if (!hasApiExist) {
|
||||
this.closeTab({ index: this.selectedIndex });
|
||||
return;
|
||||
}
|
||||
if (apiID) {
|
||||
let hasApiExist = this.apiDataItems[apiID];
|
||||
if (!hasApiExist) {
|
||||
this.closeTab({ index: this.selectedIndex });
|
||||
return;
|
||||
}
|
||||
const tab = this.getTabInfo({
|
||||
id: apiID,
|
||||
});
|
||||
@ -81,7 +79,7 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
* @param tab TabItem
|
||||
*/
|
||||
appendTab(which = 'test', apiData: any = {}): void {
|
||||
if (this.tabs.length >= this.MAX_LIMIT) return;
|
||||
if (this.tabs.length >= this.MAX_TAB_LIMIT) return;
|
||||
let tab: TabItem = Object.assign(
|
||||
{
|
||||
uuid: new Date().getTime(),
|
||||
@ -89,20 +87,20 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
which === 'unset' ? {} : this.defaultTabs[which],
|
||||
apiData
|
||||
);
|
||||
let existTabIndex = this.tabs.findIndex((val) => val.key === tab.key);
|
||||
if (tab.key && existTabIndex !== -1) {
|
||||
this.selectedIndex = existTabIndex;
|
||||
if (this.tabs[existTabIndex].path !== tab.path) {
|
||||
//exist api(same tab) change page
|
||||
this.tabs[existTabIndex].path = tab.path;
|
||||
this.switchTab();
|
||||
let existApiIndex = this.tabs.findIndex((val) => val.key === tab.key);
|
||||
if (tab.key && existApiIndex !== -1) {
|
||||
this.selectedIndex = existApiIndex;
|
||||
if (this.tabs[existApiIndex].path !== tab.path) {
|
||||
//* exist api in same tab change route,such as edit page to detail
|
||||
this.tabs[existApiIndex].path = tab.path;
|
||||
this.pickTab();
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.tabs.push(tab);
|
||||
// if index no change,manual change reflesh content
|
||||
if (this.selectedIndex === this.tabs.length - 1) {
|
||||
this.switchTab();
|
||||
this.pickTab();
|
||||
return;
|
||||
}
|
||||
this.selectedIndex = this.tabs.length - 1;
|
||||
@ -123,32 +121,68 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.closeTab(item);
|
||||
});
|
||||
}
|
||||
removeTabCache(index) {
|
||||
if (!this.tabs[index]) return;
|
||||
this.tabSerive.removeData(this.tabs[index].uuid);
|
||||
}
|
||||
/**
|
||||
* Close Tab and keep tab status
|
||||
*
|
||||
* @param index number
|
||||
*/
|
||||
closeTab({ index }: { index: number }): void {
|
||||
if (this.tabs[index]) {
|
||||
this.tabSerive.removeData(this.tabs[index].uuid);
|
||||
}
|
||||
this.tabs.splice(index, 1);
|
||||
//no tab left
|
||||
let selectIndex = this.selectedIndex <= index ? index - 1 : this.selectedIndex;
|
||||
this.batchCloseTab([index], selectIndex);
|
||||
}
|
||||
batchCloseTab(closeTabs, selectIndex?) {
|
||||
closeTabs.forEach((index) => {
|
||||
this.removeTabCache(index);
|
||||
});
|
||||
this.tabs = this.tabs.filter((val, index) => !closeTabs.includes(index));
|
||||
if (0 === this.tabs.length) {
|
||||
this.newTab();
|
||||
return;
|
||||
}
|
||||
//selectedIndex no change
|
||||
if (this.selectedIndex < this.tabs.length) {
|
||||
this.switchTab();
|
||||
if (selectIndex !== this.selectedIndex) {
|
||||
this.selectedIndex = selectIndex;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* router change after switch the tab or tab content
|
||||
* Tab Close operate
|
||||
* @param action closeOther|closeAll|closeLeft|closeRight
|
||||
*/
|
||||
oeprateCloseTab(action) {
|
||||
let closeTabs = [...new Array(this.tabs.length).keys()],
|
||||
tmpSelectIndex = 0;
|
||||
switch (action) {
|
||||
case 'closeOther':
|
||||
closeTabs.splice(this.selectedIndex, 1);
|
||||
break;
|
||||
case 'closeLeft':
|
||||
closeTabs = closeTabs.slice(0, this.selectedIndex);
|
||||
break;
|
||||
case 'closeRight':
|
||||
closeTabs = closeTabs.slice(this.selectedIndex + 1);
|
||||
tmpSelectIndex = this.selectedIndex;
|
||||
break;
|
||||
}
|
||||
this.batchCloseTab(closeTabs, tmpSelectIndex);
|
||||
}
|
||||
/**
|
||||
* Tab operate
|
||||
* @param action closeOther|closeAll|closeLeft|closeRight
|
||||
*/
|
||||
operateTab(action) {
|
||||
if (action.includes('close')) {
|
||||
this.oeprateCloseTab(action);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Pick tab after switch the tab or tab content
|
||||
* @param {TabItem} inArg.tab
|
||||
* @param inArg.index
|
||||
*/
|
||||
switchTab() {
|
||||
pickTab() {
|
||||
let tab = this.tabs[this.selectedIndex];
|
||||
this.tabSerive.tabChange$.next(tab);
|
||||
this.activeRoute(tab);
|
||||
@ -170,6 +204,7 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
case 'editApi':
|
||||
this.appendTab('edit', inArg.data.origin);
|
||||
break;
|
||||
case 'copyApi':
|
||||
case 'newApi':
|
||||
this.appendTab('edit', inArg.data ? { groupID: inArg.data.key } : {});
|
||||
break;
|
||||
@ -180,6 +215,7 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
apiData: inArg.data,
|
||||
})
|
||||
);
|
||||
this.pickTab();
|
||||
break;
|
||||
}
|
||||
case 'addApiFinish':
|
||||
@ -190,13 +226,18 @@ export class ApiTabComponent implements OnInit, OnChanges, OnDestroy {
|
||||
apiData: inArg.data,
|
||||
})
|
||||
);
|
||||
this.switchTab();
|
||||
this.pickTab();
|
||||
break;
|
||||
}
|
||||
case 'removeApiDataTabs': {
|
||||
this.removeApiDataTabs(inArg.data);
|
||||
break;
|
||||
}
|
||||
case 'afterLoadApi': {
|
||||
this.apiDataItems = inArg.data;
|
||||
this.initTab();
|
||||
break;
|
||||
}
|
||||
case 'beforeChangeRouter': {
|
||||
this.changeCurrentTab(
|
||||
this.getTabInfo({
|
||||
|
Loading…
Reference in New Issue
Block a user