diff --git a/build/SetupScripts/nim/skin/form/pic.png b/build/SetupScripts/nim/skin/form/pic.png index cb1dcd243..54bfc0375 100644 Binary files a/build/SetupScripts/nim/skin/form/pic.png and b/build/SetupScripts/nim/skin/form/pic.png differ diff --git a/build/SetupScripts/nim/skin/pic.png b/build/SetupScripts/nim/skin/pic.png index 1d1f8a8de..54bfc0375 100644 Binary files a/build/SetupScripts/nim/skin/pic.png and b/build/SetupScripts/nim/skin/pic.png differ diff --git a/src/app/pages/api/api.component.ts b/src/app/pages/api/api.component.ts index 041a8a4ef..aef5621d0 100644 --- a/src/app/pages/api/api.component.ts +++ b/src/app/pages/api/api.component.ts @@ -76,7 +76,6 @@ export class ApiComponent implements OnInit, OnDestroy { */ buildGroupTreeData(): void { this.groupByID = {}; - this.apiDataItems = {}; this.treeItems = []; this.getGroups(); } @@ -98,9 +97,10 @@ export class ApiComponent implements OnInit, OnDestroy { } getApis() { this.apiDataService.loadAllByProjectID(this.projectID).subscribe((items: Array) => { + let apiItems={}; items.forEach((item) => { delete item.updatedAt; - this.apiDataItems[item.uuid] = item; + apiItems[item.uuid] = item; this.treeItems.push({ title: item.name, key: item.uuid, @@ -110,8 +110,8 @@ export class ApiComponent implements OnInit, OnDestroy { isLeaf: true, }); }); + this.apiDataItems=apiItems; this.generateGroupTreeData(); - this.apiTabComponent.initTab(); }); } /** @@ -211,7 +211,6 @@ export class ApiComponent implements OnInit, OnDestroy { generateGroupTreeData(): void { this.treeItems.sort((a, b) => a.weight - b.weight); this.treeNodes = []; - console.log('generateGroupTreeData=>',this.treeItems) listToTree(this.treeItems, this.treeNodes, 0); } diff --git a/src/app/pages/api/api.module.ts b/src/app/pages/api/api.module.ts index 15923411b..f27b8df9f 100644 --- a/src/app/pages/api/api.module.ts +++ b/src/app/pages/api/api.module.ts @@ -11,8 +11,7 @@ import { EouiModule } from '../../eoui/eoui.module'; import { ParamsImportModule } from '../../shared/components/params-import/params-import.module'; import { ApiComponent } from './api.component'; -import { ApiGroupEditComponent} from './group/edit/api-group-edit.component'; - +import { ApiGroupEditComponent } from './group/edit/api-group-edit.component'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzIconModule } from 'ng-zorro-antd/icon'; @@ -25,6 +24,7 @@ import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; import { ApiDataService } from '../../shared/services/api-data/api-data.service'; import { GroupService } from '../../shared/services/group/group.service'; +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'; @@ -54,6 +54,6 @@ const COMPONENTS = [ApiComponent, ApiGroupEditComponent, ApiGroupTreeComponent]; ], declarations: [...COMPONENTS, ApiTabComponent], exports: [], - providers: [ApiDataService, GroupService, MessageService], + providers: [ApiDataService, GroupService, MessageService, ApiTabService], }) export class ApiModule {} diff --git a/src/app/pages/api/tab/api-tab.component.html b/src/app/pages/api/tab/api-tab.component.html index 6251c02f3..b129b9fb1 100644 --- a/src/app/pages/api/tab/api-tab.component.html +++ b/src/app/pages/api/tab/api-tab.component.html @@ -1,19 +1,18 @@ - - {{ tab.method | uppercase }} + {{ tab.method | uppercase }} {{ tab.title }} diff --git a/src/app/pages/api/tab/api-tab.component.ts b/src/app/pages/api/tab/api-tab.component.ts index 88503e2e4..d11a5aa7d 100644 --- a/src/app/pages/api/tab/api-tab.component.ts +++ b/src/app/pages/api/tab/api-tab.component.ts @@ -1,16 +1,17 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; -import { filter } from 'rxjs/operators'; import { TabItem } from './tab.model'; +import { ApiTabService } from './api-tab.service'; +import { filter } from 'rxjs'; @Component({ selector: 'eo-api-tab', templateUrl: './api-tab.component.html', styleUrls: ['./api-tab.component.scss'], }) -export class ApiTabComponent implements OnInit { +export class ApiTabComponent implements OnInit, OnChanges { @Input() apiDataItems; id: number; /** @@ -31,20 +32,26 @@ export class ApiTabComponent implements OnInit { detail: { path: '/home/api/detail', title: 'API 详情' }, }; - constructor(private router: Router, private route: ActivatedRoute) {} + constructor(private router: Router, private route: ActivatedRoute, private tabSerive: ApiTabService) {} ngOnInit(): void { - this.id = Number(this.route.snapshot.queryParams.uuid); this.watchChangeRouter(); } + ngOnChanges(changes: SimpleChanges): void { + if (changes.apiDataItems && changes.apiDataItems.currentValue) { + this.initTab(); + } + } /** - * Get current path to update tab + * path change */ watchChangeRouter() { this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => { this.id = Number(this.route.snapshot.queryParams.uuid); if (!this.id) return; - this.tabs[this.selectedIndex] = this.getCurrentTabByID(this.id); + this.tabs[this.selectedIndex] =Object.assign({ + uuid:this.tabs[this.selectedIndex].uuid + }, this.getTabInfoByID(this.id)); }); } /** @@ -57,19 +64,14 @@ export class ApiTabComponent implements OnInit { * Init tab data after load or update. */ initTab() { - if (!this.apiDataItems[this.id]) { + this.id = Number(this.route.snapshot.queryParams.uuid); + let apiHasDelete = !this.apiDataItems[this.id]; + if (apiHasDelete) { this.closeTab({ index: this.selectedIndex }); return; } - let module = Object.keys(this.defaultTabs).find((keyName) => - this.router.url.split('?')[0].includes(this.defaultTabs[keyName].path) - ); - const tab = this.getCurrentTabByID(this.id); - if (this.tabs.length < 1) { - this.appendTab(module, tab); - } else { - this.tabs[this.selectedIndex] = tab; - } + const tab = this.getTabInfoByID(this.id); + this.appendTab('unset', tab); } /** * Push new tab. @@ -77,15 +79,37 @@ export class ApiTabComponent implements OnInit { * @param tab TabItem */ appendTab(which = 'test', apiData = {}): void { - let tab: TabItem = Object.assign({}, this.defaultTabs[which], apiData); + let tab: TabItem = Object.assign( + { + uuid: new Date().getTime(), + }, + which === 'unset' ? {} : this.defaultTabs[which], + apiData + ); let existTabIndex = this.tabs.findIndex((val) => val.key === tab.key); if (tab.key && existTabIndex !== -1) { - this.tabSelect({ index: existTabIndex, tab: tab }); + this.selectedIndex = existTabIndex; } else { this.tabs.push(tab); - this.tabSelect({ index: this.tabs.length - 1, tab: tab }); + this.selectedIndex = this.tabs.length - 1; } } + /** + * Remove api data tabs. + * + * @param uuids Array + */ + removeApiDataTabs(uuids: Array): void { + const items = []; + this.tabs.forEach((tab: TabItem, index: number) => { + if (uuids.indexOf(tab.key)) { + items.push({ index }); + } + }); + items.reverse().forEach((item) => { + this.closeTab(item); + }); + } /** * Close current tab. * @@ -99,13 +123,13 @@ export class ApiTabComponent implements OnInit { } /** * Switch the tab. - * * @param {TabItem} inArg.tab * @param inArg.index */ - tabSelect(inArg) { - this.selectedIndex = inArg.index; - this.activeRoute(inArg.tab); + switchTab() { + let tab = this.tabs[this.selectedIndex]; + this.tabSerive.tabChange$.next(tab); + this.activeRoute(tab); } /** @@ -113,28 +137,15 @@ export class ApiTabComponent implements OnInit { * * @param tab */ - activeRoute(tab) { + private activeRoute(tab) { this.router - .navigate([tab.path], { queryParams: { uuid: tab.key, groupID: tab.groupID, projectID: tab.projectID } }) + .navigate([tab.path], { + queryParams: { uuid: tab.key, groupID: tab.groupID, projectID: tab.projectID }, + }) .finally(); } - /** - * Remove api data tabs. - * - * @param uuids Array - */ - removeApiDataTabs(uuids: Array): void { - const items = []; - this.tabs.forEach((tab: TabItem, index: number) => { - if (uuids.indexOf(tab.key)) { - items.push({ index }); - } - }); - items.reverse().forEach((item) => { - this.closeTab(item); - }); - } - private getCurrentTabByID(id) { + + private getTabInfoByID(id) { const result = { path: this.router.url.split('?')[0], title: this.apiDataItems[id].name, diff --git a/src/app/pages/api/tab/api-tab.service.spec.ts b/src/app/pages/api/tab/api-tab.service.spec.ts new file mode 100644 index 000000000..77000eb64 --- /dev/null +++ b/src/app/pages/api/tab/api-tab.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ApiTabService } from './api-tab.service'; + +describe('ApiTabService', () => { + let service: ApiTabService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ApiTabService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/pages/api/tab/api-tab.service.ts b/src/app/pages/api/tab/api-tab.service.ts new file mode 100644 index 000000000..bed1eee8f --- /dev/null +++ b/src/app/pages/api/tab/api-tab.service.ts @@ -0,0 +1,17 @@ +import { ReplaySubject, Subject } from 'rxjs'; +import { TabItem } from './tab.model'; + +export class ApiTabService { + currentTab: TabItem; + tabs = {}; + tabChange$: ReplaySubject = new ReplaySubject(1); + saveTabData$: Subject<{ tab: TabItem; data: any }> = new Subject(); + constructor() { + this.saveTabData$.subscribe((inData) => { + this.tabs[inData.tab.uuid] = inData.data; + }); + this.tabChange$.subscribe((tab) => { + this.currentTab = tab; + }); + } +} diff --git a/src/app/pages/api/tab/tab.model.ts b/src/app/pages/api/tab/tab.model.ts index c29b64ad0..03a1624e2 100644 --- a/src/app/pages/api/tab/tab.model.ts +++ b/src/app/pages/api/tab/tab.model.ts @@ -1,54 +1,54 @@ /** * Tab item. */ - export interface TabItem { - /** - * 标签标题 - * - * @type {string} - */ - title: string; - - /** - * 标签对应的路径 - * - * @type {string} - */ - path: string; - - /** - * 路径的主键参数 - * - * @type {string | number} - */ - key?: string|number; - - /** - * 路径的分组参数 - * - * @type {string | number} - */ - groupID?: string|number; - - /** - * 路径的项目参数 - * - * @type {string | number} - */ - projectID?: string|number; - - /** - * 标签路径的请求类型,用于显示 - * - * @type {string | number} - */ - method?: string; - - /** - * 实体类型,为后期加上其他类型到Tab预留,如Group - * - * @type {string} - */ - entity?: string; - } - \ No newline at end of file +export interface TabItem { + uuid: number; + /** + * 标签标题 + * + * @type {string} + */ + title: string; + + /** + * 标签对应的路径 + * + * @type {string} + */ + path: string; + + /** + * 路径的主键参数 + * + * @type {string | number} + */ + key?: string | number; + + /** + * 路径的分组参数 + * + * @type {string | number} + */ + groupID?: string | number; + + /** + * 路径的项目参数 + * + * @type {string | number} + */ + projectID?: string | number; + + /** + * 标签路径的请求类型,用于显示 + * + * @type {string | number} + */ + method?: string; + + /** + * 实体类型,为后期加上其他类型到Tab预留,如Group + * + * @type {string} + */ + entity?: string; +} diff --git a/src/app/pages/api/test/api-test.component.ts b/src/app/pages/api/test/api-test.component.ts index f58657aca..66fa58d31 100644 --- a/src/app/pages/api/test/api-test.component.ts +++ b/src/app/pages/api/test/api-test.component.ts @@ -1,20 +1,21 @@ import { Component, OnInit, OnDestroy, ChangeDetectorRef, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { Store, Select } from '@ngxs/store'; +import { Select } from '@ngxs/store'; import { ApiData, RequestMethod, RequestProtocol } from '../../../shared/services/api-data/api-data.model'; -import { Message, MessageService } from '../../../shared/services/message'; +import { MessageService } from '../../../shared/services/message'; import { interval, Subscription, Observable, of, Subject } from 'rxjs'; -import { switchMap, take, takeUntil, distinctUntilChanged } from 'rxjs/operators'; +import { take, takeUntil, distinctUntilChanged, pairwise } from 'rxjs/operators'; import { ApiTestHistoryComponent } from './history/api-test-history.component'; import { TestServerService } from '../../../shared/services/api-test/test-server.service'; import { ApiDataService } from '../../../shared/services/api-data/api-data.service'; import { ApiTestService } from './api-test.service'; +import { ApiTabService } from '../tab/api-tab.service'; import { objectToArray } from '../../../utils'; import { EnvState } from '../../../shared/store/env.state'; @@ -26,13 +27,12 @@ import { EnvState } from '../../../shared/store/env.state'; }) export class ApiTestComponent implements OnInit, OnDestroy { @ViewChild('historyComponent') historyComponent: ApiTestHistoryComponent; - @Select(EnvState) - env$: Observable; + @Select(EnvState) env$: Observable; validateForm!: FormGroup; apiData: any; env: any = { - parameters:[], - hostUri:'' + parameters: [], + hostUri: '', }; status: 'start' | 'testing' | 'tested' = 'start'; waitSeconds = 0; @@ -57,7 +57,8 @@ export class ApiTestComponent implements OnInit, OnDestroy { private route: ActivatedRoute, private messageService: MessageService, private ref: ChangeDetectorRef, - private apiTest: ApiTestService + private apiTest: ApiTestService, + private apiTab: ApiTabService ) { this.testServer = this.testServerService.getService(); this.testServer.init((message) => { @@ -120,15 +121,10 @@ export class ApiTestComponent implements OnInit, OnDestroy { }).query; } ngOnInit(): void { - this.resetApi(); - this.initBasicForm(); - this.watchApiChange(); - this.env$.subscribe((data) => { - const { env } = data; - if (env) { - this.env = env; - } - }); + console.log('ngOnInit'); + this.initApi(Number(this.route.snapshot.queryParams.uuid)); + this.watchTabChange(); + this.watchEnvChange(); } ngOnDestroy() { this.destroy$.next(); @@ -187,6 +183,42 @@ export class ApiTestComponent implements OnInit, OnDestroy { } } } + private initApi(id) { + this.resetApi(); + this.initBasicForm(); + //recovery from tab + if (this.apiTab.currentTab && this.apiTab.tabs[this.apiTab.currentTab.uuid]) { + this.apiData = this.apiTab.tabs[this.apiTab.currentTab.uuid]; + return; + } + if (!id) { + Object.assign(this.apiData, { + uuid: 0, + requestBodyType: 'json', + requestBodyJsonType: 'object', + requestBody: [], + queryParams: [], + restParams: [], + requestHeaders: [], + }); + } else { + this.getApi(id); + } + } + private watchEnvChange() { + this.env$.pipe(takeUntil(this.destroy$)).subscribe((data) => { + const { env } = data; + if (env) { + this.env = env; + } + }); + } + private watchTabChange() { + this.apiTab.tabChange$.pipe(pairwise(), takeUntil(this.destroy$)).subscribe(([nowTab, nextTab]) => { + this.apiTab.saveTabData$.next({ tab: nowTab, data: this.apiData }); + this.initApi(nextTab.key); + }); + } /** * Init API data structure */ @@ -208,31 +240,4 @@ export class ApiTestComponent implements OnInit, OnDestroy { }); this.validateForm = this.fb.group(controls); } - private watchApiChange() { - if (!this.route.snapshot.queryParams.uuid) { - Object.assign(this.apiData, { - requestBodyType: 'json', - requestBodyJsonType: 'object', - requestBody: [], - queryParams: [], - restParams: [], - requestHeaders: [], - }); - } - this.api$ = this.route.queryParamMap.pipe( - switchMap((params) => { - const id = Number(params.get('uuid')); - return of({ id }); - }), - takeUntil(this.destroy$) - ); - this.api$.subscribe((inArg: any = {}) => { - if (inArg.id) { - this.getApi(inArg.id); - } else { - //add history need - this.apiData.uuid = 0; - } - }); - } } diff --git a/src/app/pages/env/env.component.ts b/src/app/pages/env/env.component.ts index 10eaa359e..a9a0dd721 100644 --- a/src/app/pages/env/env.component.ts +++ b/src/app/pages/env/env.component.ts @@ -37,7 +37,11 @@ export class EnvComponent implements OnInit, OnDestroy { } set envUuid(value) { this.activeUuid = value || 0; - localStorage.setItem('env:selected', value.toString()); + if(value){ + localStorage.setItem('env:selected', value.toString()); + }else{ + localStorage.removeItem('env:selected'); + } this.changeStoreEnv(value); } diff --git a/src/app/shared/components/page-not-found/page-not-found.component.html b/src/app/shared/components/page-not-found/page-not-found.component.html index 56885df3b..d47d2eac9 100644 --- a/src/app/shared/components/page-not-found/page-not-found.component.html +++ b/src/app/shared/components/page-not-found/page-not-found.component.html @@ -1,5 +1,5 @@ - +
- +
-
\ No newline at end of file +
diff --git a/src/app/shared/components/page-not-found/page-not-found.component.ts b/src/app/shared/components/page-not-found/page-not-found.component.ts index a207a7a6b..3d4573383 100644 --- a/src/app/shared/components/page-not-found/page-not-found.component.ts +++ b/src/app/shared/components/page-not-found/page-not-found.component.ts @@ -1,14 +1,18 @@ import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; @Component({ selector: 'eo-page-not-found', templateUrl: './page-not-found.component.html', - styleUrls: ['./page-not-found.component.scss'] + styleUrls: ['./page-not-found.component.scss'], }) export class PageNotFoundComponent implements OnInit { - constructor() {} + constructor(private router: Router) {} ngOnInit(): void { console.log('PageNotFoundComponent INIT'); } + backHome() { + this.router.navigate(['/home']); + } } diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg index b02824428..507e9555b 100644 --- a/src/assets/images/logo.svg +++ b/src/assets/images/logo.svg @@ -1 +1 @@ -eolinkeolink \ No newline at end of file +eoapi \ No newline at end of file