diff options
Diffstat (limited to 'usecaseui-portal/src/app/views')
59 files changed, 11964 insertions, 0 deletions
diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.css b/usecaseui-portal/src/app/views/alarm/alarm.component.css new file mode 100644 index 00000000..25bf187e --- /dev/null +++ b/usecaseui-portal/src/app/views/alarm/alarm.component.css @@ -0,0 +1,164 @@ +/* + Copyright (C) 2018 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.select { + margin-bottom: 20px; +} +.select span { + display: inline-block; + font: 700 14px "Arial"; + color: #4c5e70; +} +.select nz-dropdown { + vertical-align: middle; +} +.select nz-dropdown :hover { + border-color: #147dc2; +} +.select nz-dropdown button { + width: 165px; + height: 30px; + background-color: #eceff4; + text-align: left; + border-color: #9fa9ab; +} +.select nz-dropdown button span { + font-weight: 400; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; +} +.select nz-dropdown button i { + position: absolute; + top: 10px; + right: 10px; +} +.select .search { + margin-left: 20px; + height: 30px; + padding: 0 10px; +} +.select .search span { + color: #fff; + font-weight: 400; +} +.content .title { + border-radius: 5px 5px 0 0; + background-color: #fff; + height: 106px; + border-bottom: 1px solid #f0f0f0; + margin-bottom: 0; +} +.content .title ul { + display: flex; + display: -webkit-flex; + justify-content: space-around; + align-items: center; + padding: 0; + margin: 0; + height: 100%; +} +.content .title ul li { + list-style: none; + padding-left: 32px; + width: 100%; + border-left: 1px solid #eceff4; +} +.content .title ul li h5 { + font: 500 14px "Arial"; + color: #3d4d65; +} +.content .title ul li p { + font: 500 24px "Arial"; + color: #3fa8eb; + margin-bottom: 0; +} +.content .title ul li:nth-child(1) { + border: none; +} +.content .chart { + background-color: #fff; + position: relative; + padding-bottom: 24px; +} +.content .chart h3 { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + padding: 20px 15px; + margin: 0; + width: 12%; + display: inline-block; +} +.content .chart .AlarmChart { + height: 0px; + overflow: hidden; + border-bottom: 1px solid #f5f5f5; + transition: all 0.3s linear; +} +.content .chart .alarmChart-active { + height: 386px; +} +.content .chart .open-close { + width: 50px; + height: 25px; + position: absolute; + left: 50%; + bottom: 0px; + transform: translate(-25px, 0); + border: none; + outline: none; + cursor: pointer; + background-color: #fff; + background: url(../../../assets/images/open-close.png) no-repeat center -27px; +} +.content .chart .open-close:hover { + background: url(../../../assets/images/open-close.png) no-repeat center -79px; +} +.content .chart .open-close-active { + background: url(../../../assets/images/open-close.png) center -1px; +} +.content .chart .open-close-active:hover { + background: url(../../../assets/images/open-close.png) no-repeat center -53px; +} +.content .tablelist { + background-color: #fff; + padding: 24px 10px 0px; + border-radius: 0 0 5px 5px; +} +.content .tablelist .action { + padding: 10px 0 0 20px; +} +.content .tablelist .action .details { + display: inline-block; + width: 16px; + height: 16px; + background: url(../../../assets/images/icon.png) center -113px; +} +.content .tablelist .action .details:hover { + background: url(../../../assets/images/icon.png) no-repeat center -128px; +} diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.html b/usecaseui-portal/src/app/views/alarm/alarm.component.html new file mode 100644 index 00000000..312ec236 --- /dev/null +++ b/usecaseui-portal/src/app/views/alarm/alarm.component.html @@ -0,0 +1,138 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<h3 class="title"> <span (click)="detailHide()" style="cursor:pointer; float:right;" *ngIf="detailshow">Alarm</span> <span *ngIf="detailshow">Device Alarm Details</span> </h3> +<div style="padding:0px 20px 20px 20px;"> + <div class="charts" [@showHideAnimate]="state"> + <div class="chartsleft"> + <div class="active sctive_closed"> + <div>Active</div> + <div>13,980</div> + <div><nz-progress [nzPercent]="30" [nzShowInfo]="false"></nz-progress></div> + <div>There are 13980 faults waiting to be solved</div> + </div> + <div class="closed sctive_closed"> + <div>Closed</div> + <div>23,980</div> + <div><nz-progress [nzPercent]="50" [nzShowInfo]="false"></nz-progress></div> + <div>23,980 faults have been fixed</div> + </div> + </div> + <div class="chartsright"> + <span>Daily Total</span> + <app-line [initData]="alarmChartInit" [chartData]="alarmChartData"></app-line> + </div> + </div> + <div class="select" [@showHideAnimate]="state"> + <div class="query_criteria"> + <div class="query_item"> + <span>Source Name: </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="choseSourceName(item)" *ngFor="let item of sourceNameList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + </div> + <div class="query_item" style="margin-left: 1.5%;"> + <span>Priority: </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{prioritySelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="chosePriority(item)" *ngFor="let item of priorityList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + </div> + <div class="query_item" style="margin-left:-2%;"> + <span>Status: </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{statusSelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="choseStatus(item)" *ngFor="let item of statusList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + </div> + <div class="query_time" style="margin-left: -3%;"> + <span>Report Time: </span> + <nz-range-picker [(ngModel)]="dateRange" (ngModelChange)="onChange($event)" + ></nz-range-picker> + <!-- <nz-range-picker [nzFormat]="dateFormat"></nz-range-picker> --> + </div> + <button class="search" nz-button [nzType]="'primary'" (click)="getAlarmFormData()"><i class="anticon anticon-search"></i><span>Search</span></button> + </div> + </div> + <div class="content" [@showHideAnimate]="state"> + <!-- <div class="title"> + <ul> + <li> + <h5>All</h5> + <p>{{alarmList.all }}</p> + </li> + <li> + <h5>Closed</h5> + <p>{{alarmList.closed }}</p> + </li> + <li> + <h5>Active</h5> + <p>{{alarmList.activeNum }}</p> + </li> + </ul> + </div> --> + <!-- <div class="chart"> + <h3>Alarm Chart</h3> + <div class="AlarmChart" [ngClass]="{'alarmChart-active':alarmShow}"> + <app-line [initData]="alarmChartInit" [chartData]="alarmChartData"></app-line> + </div> + </div> --> + <div class="tablelist"> + <nz-table #nzTable [nzData]="list" [(nzPageSize)]="pageSize" nzShowSizeChanger nzShowQuickJumper + [nzPageSizeOptions]="[5,10,15,20]" nzSize="middle"> + <thead (nzSortChange)="sort($event)" nzSingleSort> + <tr> + <th nzWidth="5%" style="padding-left:20px;">NO</th> + <th nzWidth="12%">Source Name</th> + <th nzWidth="7%">Priority</th> + <th nzWidth="18%">SpecificProblem</th> + <th nzWidth="15%">Report Time</th> + <th nzWidth="15%">Clear Time</th> + <th nzWidth="8%">Status</th> + <th nzWidth="10%">Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of nzTable.data; let i = index;"> + <td style="padding-left: 20px;">{{i+1}}</td> + <td>{{item.sourceName}}</td> + <td>{{item.priority}}</td> + <td>{{item.specificProblem}}</td> + <td>{{item.startEpochMicrosec | date:'yyyy-MM-dd HH:mm:ss'}}</td> + <td>{{item.startEpochMicrosecCleared | date:'yyyy-MM-dd HH:mm:ss'}}</td> + <td>{{item.status}}</td> + <td class="action"><a (click)="detailShow(item)"><i class="details"></i></a></td> + </tr> + </tbody> + </nz-table> + </div> + </div> + <div [@showHideAnimate]="state2"> + <app-details [detailId]="detailId"></app-details> + </div> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.less b/usecaseui-portal/src/app/views/alarm/alarm.component.less new file mode 100644 index 00000000..92c9b7a4 --- /dev/null +++ b/usecaseui-portal/src/app/views/alarm/alarm.component.less @@ -0,0 +1,244 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 500 16px/16px "ArialMT"; + color: #3C4F8C; + margin: 20px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.select { + margin-bottom: 15px; + width: 100%; + .query_criteria { + width: 100%; + .query_item { + width: 20%; + display: inline-block; + span { + display: inline-block; + font: 500 13px "ArialMT"; + color: #3C4F8C; + } + nz-dropdown { + vertical-align: middle; + width: 55%; + :hover{ + border-color: #48C6EF; + } + button { + width: 100%; + height: 30px; + background-color: #fff; + text-align: left; + border-color: #EEEEEE ; + border-radius: 2px; + span { + font-weight: 400; + color:rgba(60,79,140,0.5); + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; + } + i { + position: absolute; + top: 10px; + right: 10px; + } + } + } + } + + .query_time{ + display: inline-block; + span { + font: 500 13px "ArialMT"; + color: #3C4F8C; + } + } + .search { + margin-left: 0.8%; + height: 30px; + padding: 0 10px; + span { + color: #fff; + font-weight: 400; + } + } + } +} +.charts{ + width: 100%; + height: 250px; + margin-bottom: 25px; + .chartsleft { + width: 30%; + height: 100%; + float: left; + margin-right: 2%; + color: #fff; + font-family:"ArialMT"; + .sctive_closed { + height: 48.75%; + padding: 12px; + width: 100%; + :first-child{ + font-size: 14px; + } + :nth-child(2) { + font-size: 18px; + } + :nth-child(3) { + font-size: 12px; + } + } + .active { + margin-bottom: 5px; + background: -webkit-linear-gradient(left, #FB7788 , #FB93C2); /* Safari 5.1 - 6.0 */ + background: -o-linear-gradient(right, #FB7788, #FB93C2); /* Opera 11.1 - 12.0 */ + background: -moz-linear-gradient(right, #FB7788, #FB93C2); /* Firefox 3.6 - 15 */ + background: linear-gradient(to right, #FB7788 , #FB93C2); /* 标准的语法(必须放在最后) */ + } + .closed { + margin-top: 2px; + background: -webkit-linear-gradient(left, #7A8BAE , #A6BFE4); /* Safari 5.1 - 6.0 */ + background: -o-linear-gradient(right, #7A8BAE , #A6BFE4); /* Opera 11.1 - 12.0 */ + background: -moz-linear-gradient(right, #7A8BAE , #A6BFE4); /* Firefox 3.6 - 15 */ + background: linear-gradient(to right, #7A8BAE , #A6BFE4); /* 标准的语法(必须放在最后) */ + } + + } + .chartsright { + background-color: #fff; + width: 68%; + padding: 20px; + float: left; + height: 100%; + .picker { + float: right; margin-right: 3%; + } + .datapicker { + padding-left: 700px; + } + } +} +.content { + .title { + border-radius: 5px 5px 0 0; + background-color: #fff; + height: 106px; + border-bottom: 1px solid #f0f0f0; + margin-bottom: 0; + ul { + display: flex; + display: -webkit-flex; + justify-content: space-around; + align-items: center; + padding: 0; + margin: 0; + height: 100%; + li { + list-style: none; + padding-left: 32px; + width: 100%; + border-left: 1px solid #eceff4; + h5 { + font: 500 14px "Arial"; + color: #3d4d65; + } + p { + font: 500 24px "Arial"; + color: #3fa8eb; + margin-bottom: 0; + } + } + li:nth-child(1){ + border: none; + } + } + } + .chart { + background-color: #fff; + position: relative; + padding-bottom: 24px; + h3 { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + padding: 20px 15px; + margin: 0; + width: 12%; + display: inline-block; + } + .AlarmChart { + height: 0px; + overflow: hidden; + border-bottom: 1px solid #f5f5f5; + transition: all 0.3s linear; + } + .alarmChart-active { + height: 386px; + } + .open-close { + width: 50px; + height: 25px; + position: absolute; + left: 50%; + bottom: 0px; + transform: translate(-25px,0); + border: none; + outline: none; + cursor: pointer; + background-color: #fff; + background: url(../../../assets/images/open-close.png) no-repeat center -27px; + &:hover { + background: url(../../../assets/images/open-close.png) no-repeat center -79px; + } + } + .open-close-active { + background: url(../../../assets/images/open-close.png) center -1px; + &:hover { + background: url(../../../assets/images/open-close.png) no-repeat center -53px; + } + } + } + .tablelist { + // background-color: #fff; + // padding: 24px 10px 0px; + border-radius: 0 0 5px 5px; + .action{ + padding: 10px 0 0 20px; + .details{ + display: inline-block; + width: 16px; + height: 16px; + background: url(../../../assets/images/icon.png) center -113px; + &:hover { + background: url(../../../assets/images/icon.png) no-repeat center -128px; + } + } + } + } +} + + + + + diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts b/usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts new file mode 100644 index 00000000..9f01597e --- /dev/null +++ b/usecaseui-portal/src/app/views/alarm/alarm.component.spec.ts @@ -0,0 +1,66 @@ +import { async, ComponentFixture, TestBed, inject, fakeAsync } from '@angular/core/testing'; +import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { NgxEchartsModule } from 'ngx-echarts'; +import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader } from '@ngx-translate/core'; +import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { NZ_I18N, en_US } from 'ng-zorro-antd'; + +import { AlarmComponent } from './alarm.component'; +import { DetailsComponent } from '../../shared/components/details/details.component'; +import { LineComponent } from '../../shared/components/charts/line/line.component'; +import { HomesService } from '../../core/services/homes.service'; + +fdescribe('AlarmComponent', () => { + let component: AlarmComponent; + let fixture: ComponentFixture<AlarmComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [AlarmComponent, DetailsComponent, LineComponent], + imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }), + NgZorroAntdModule.forRoot(), + NgxEchartsModule, + HttpClientModule, + BrowserAnimationsModule, + HttpClientTestingModule], + providers: [TranslateService, HomesService, + { provide: NZ_I18N, useValue: en_US }], + schemas: [ + CUSTOM_ELEMENTS_SCHEMA, + NO_ERRORS_SCHEMA + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AlarmComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', inject([HttpTestingController, HomesService], + (httpMock: HttpTestingController, service: HomesService) => { + expect(component).toBeTruthy(); + })); + + it('expects service to fetch data with proper sorting', + inject([HttpTestingController, HomesService], + (httpMock: HttpTestingController, service: HomesService) => { + // We call the service + service.getqueryAllSourceNames().subscribe(data => { + expect(data.pageInfo.totalRecordCount).toBe(21); + expect(data.pageInfo.pageNumber).toBe(0); + expect(data.data.length).toBe(7); + }); + // We set the expectations for the HttpClient mock + const req = httpMock.expectOne('http://.../data/contacts'); + expect(req.request.method).toEqual('GET'); + // Then we set the fake data to be returned by the mock + req.flush({ data: ...}); + }) + ); +}); diff --git a/usecaseui-portal/src/app/views/alarm/alarm.component.ts b/usecaseui-portal/src/app/views/alarm/alarm.component.ts new file mode 100644 index 00000000..32e3456f --- /dev/null +++ b/usecaseui-portal/src/app/views/alarm/alarm.component.ts @@ -0,0 +1,301 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, Input, Output, EventEmitter, HostBinding, Pipe, PipeTransform } from '@angular/core'; +import { HomesService } from '../../core/services/homes.service'; +import { showHideAnimate, slideToRight } from '../../animates'; +import { DatePipe } from '@angular/common'; +@Component({ + selector: 'app-alarm', + templateUrl: './alarm.component.html', + styleUrls: ['./alarm.component.less'], + animations: [ + showHideAnimate, slideToRight + ], + providers: [DatePipe] +}) +export class AlarmComponent implements OnInit { + size = 'day'; + @HostBinding('@routerAnimate') routerAnimateState; //Routing animation + public currentPage: number = 1; + public pageSize: number = 10; + public sourceName: string = ''; + public priority: string = ''; + public startTime: string = this.myhttp.dateformater(Date.now() - 30 * 24 * 60 * 60 * 1000); + public endTime: string = this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss'); + public vfStatus: string = ''; + public sourceNameList: Array<any> = ['---auto---']; + list: any; + sourcenames: any; + constructor( + private datePipe: DatePipe, + private myhttp: HomesService) { } + ngOnInit() { + this.getAlarmFormData(); + this.getSourceNames(); + + // this.getstatuscount(); + } + + // Filter box + sourceNameSelected = this.sourceNameList[0]; + + priorityList = ['---auto---', 'Critical', 'Major', 'Minor', 'Warning']; + prioritySelected = this.priorityList[0]; + + + statusList = ['---auto---', 'active', 'Close']; + statusSelected = this.statusList[0]; + + choseSourceName(item) { + if (item == "---auto---") { + this.sourceName = ''; + } else { + this.sourceName = item; + } + this.sourceNameSelected = item; + + } + chosePriority(item) { + this.prioritySelected = item; + if (item == "---auto---") { + this.priority = ''; + } else { + this.priority = item; + } + } + choseStatus(item) { + this.statusSelected = item; + if (item == "---auto---") { + this.vfStatus = ''; + } else { + this.vfStatus = item; + } + } + getSourceNames() { + this.myhttp.getSourceNames().subscribe((data) => { + for (let i = 0; i < data.length; i++) { + this.sourceNameList.push(data[i]); + } + this.sourceNameSelected = this.sourceNameList[0]; + }) + } + + // Date screening + dateRange = [(new Date(), -30), new Date()]; + onChange(result: Date): void { + this.startTime = this.datePipe.transform(result[0], 'yyyy-MM-dd'); + this.endTime = this.datePipe.transform(result[1], 'yyyy-MM-dd'); + } + dateRange2 = [(new Date(), -30), new Date()]; + onChange2(result: Date): void { + this.startTime = this.datePipe.transform(result[0], 'yyyy-MM-dd'); + this.endTime = this.datePipe.transform(result[1], 'yyyy-MM-dd'); + } + + // total + alarmList = { + all: 0, + closed: 0, + activeNum: 0 + } + // total data + // getstatuscount() { + // this.myhttp.getstatuscount().subscribe((data) => { + // this.alarmList.activeNum = data[0]; + // this.alarmList.closed = data[1]; + // this.alarmList.all = (data[0] - 0) + (data[1] - 0); + + // }) + // } + getAlarmFormData() { + this.myhttp.getAlarmFormData(this.currentPage, this.pageSize, this.sourceName, this.priority, this.startTime, this.endTime, this.vfStatus).subscribe((data) => { + this.list = data.alarms; + }) + // this.getAlarmChartData(event); + } + getAlarmChartData() { + let paramsObj = { + // sourceName: this.sourceName, + // startTime: this.startTime, + // endTime: this.endTime, + // format: 'day' + } + this.myhttp.getHomeAlarmChartData(paramsObj) + .subscribe((data) => { + this.alarmChartData = { + xAxis: { + data: data.dateList + }, + series: [ + { data: data.allList }, + { data: data.ActiveList }, + ] + } + }, (err) => { + console.log(err); + }) + } + // day alarmchartdata + // day() { + // let paramsObj = { + // sourceName: this.sourceName, + // startTime: this.startTime, + // endTime: this.endTime, + // format: "day" + // } + // this.myhttp.getHomeAlarmChartData(paramsObj) + // .subscribe((data) => { + // this.alarmChartData = { + // xAxis: { + // data: data.dateList + // }, + // series: [ + // { data: data.allList }, + // { data: data.ActiveList }, + // { data: data.closedList } + // ] + // } + // }, (err) => { + // console.log(err); + // }) + // } + // month() { + // let paramsObj = { + // sourceName: this.sourceName, + // startTime: this.startTime, + // endTime: this.endTime, + // format: "month" + // } + // this.myhttp.getHomeAlarmChartData(paramsObj) + // .subscribe((data) => { + // this.alarmChartData = { + // xAxis: { + // data: data.dateList + // }, + // series: [ + // { data: data.allList }, + // { data: data.ActiveList }, + // { data: data.closedList } + // ] + // } + // }, (err) => { + // console.log(err); + // }) + // } + //Line chart + alarmShow = false; + alarmChartData: Object; + alarmChartInit: Object = { + height: 200, + option: { + legend: { + icon: "circle", + itemWidth: 10, + itemHeight: 10, + bottom: '-5px', + data: ['Active', 'Fixed'] + }, + tooltip: { + trigger: 'axis', + }, + dataZoom: [ + { + type: 'slider', + show: true, + start: 1, + height: 10, + end: 60, + bottom: '9%' + } + ], + xAxis: { + data: [] + }, + series: [ + { + name: 'Active', + type: 'bar', + data: [], + barWidth: 10, + barGap: 1, + itemStyle: { + normal: { + barBorderRadius: [5], + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [{ + offset: 0, color: '#FB7788' + }, { + offset: 1, color: '#FB93C2' + }], + }, + opacity: 1, + } + } + }, + { + name: 'Fixed', + type: 'bar', + data: [], + barWidth: 10, + barGap: 1, + itemStyle: { + normal: { + barBorderRadius: [5], + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [{ + offset: 0, color: '#7A8BAE' + }, { + offset: 1, color: '#A6BFE4' + }], + }, + opacity: 1, + } + } + }, + ] + } + }; + sort(e) { + + } + //Detail page title display + detailshow = false; + // Show hidden animation + state = "show"; + state2 = "hide"; + detailId: string; + detailShow(item) { + this.state = 'hide'; + this.state2 = 'show'; + this.detailshow = true; + this.detailId = item.id; + } + detailHide() { + this.state = 'show'; + this.state2 = 'hide'; + this.detailshow = false; + } +} diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css new file mode 100644 index 00000000..efeec683 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.css @@ -0,0 +1,321 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 10px; +} +.model { + background-color: #F7F8FC; + overflow-y: auto; +} +.creation-model{ + position: relative; +} +.top-title{ + width: 100%; + padding: 20px; + position: relative; + display: inline-block; +} +.model .back,.model .back:hover{ + position: absolute; + top: 10px; + right: 20px; + display: inline-block; + width: 35px; + height: 35px; + background:url("../../../assets/images/Return-icon.png") no-repeat!important; + background-size: 100%!important; + border-radius:4px; + color: #D7D7D7; + cursor: pointer; +} +.model .back:hover{ + background: url("../../../assets/images/Return-icon-active.png")!important; + background-size: 100%!important; +} +.top-title h3.title { + height: 35px; + width: 80%; + font-size:16px; + font-family:ArialMT; + color:#3C4F8C; + line-height:35px; + display: inline-block; + +} +.model .submit{ + position: absolute; + width:90px; + height: 35px; + top: 10px; + right: 85px; + color: #fff; + font-size: 18px; + background:#0DA9E2; + border-radius:4px; + border: none!important; + border-color:rgba(0,0,0,0)!important; +} +.model .submit:hover{ + background:#09C6E2; + border: none; +} +.model .creation { + width: 100%; + overflow-y: auto; + border-radius: 5px; + padding: 15px; +} +.model .creation h3 { + height: 20px; + font: 700 16px/20px "Arial"; + margin: 5px 0px; + color: #000; +} +/* SOTN VPN */ +.model .creation .service-title{ + margin:60px 50px; +} +.model .creation .service-title .info-inputs{ + width:400px; + height: 42px; + display: inline-block; +} +.model .creation .service-title span{ + height: 42px; + line-height: 42px; + vertical-align: middle; +} +.model .creation .service-title .lable{ + display: inline-block; + width: 100px; + font: 700 14px "Arial"; + color: #3C4F8C; + height: 42px; + line-height: 42px; + vertical-align: middle; + margin-left: 5px; +} +.model .creation .service-title input { + width: 230px; + height: 42px; + border-radius:4px; + outline: none; + margin-right: 50px; +} +/* Site List */ +/* addsite model */ +.model .sitemodel,.model .sotnnpnmodel{ + position: absolute; + z-index: 1001; + left: 50px; + top: 60px; + background-color: #fff; + width:1500px; + height: 81%; + border-radius:2px; + overflow:auto; +} +.model .sotnnpnmodel{ + width: 1000px; + height: 53%; + top:200px; + left: 50%; + margin-left: -500px; +} +.model .sitemodel h3,.model .sotnnpnmodel h3{ + width: 96%; + height: 40px; + line-height: 35px; + font-size: 18px; + font-weight: 500; + margin: 10px auto; + color: #06A7E2; + border-bottom: 2px solid; + border-image: -webkit-linear-gradient(#07A9E1,#30D9C4) 100 100; + border-image: -moz-linear-gradient(#07A9E1,#30D9C4) 100 100; + border-image: linear-gradient(#07A9E1,#30D9C4) 100 100; + border-radius:2px; +} +.model .sitemodel .inputs,.model .sotnnpnmodel .inputs { + padding: 10px 20px 0; +} +.model .sitemodel .inputs ul li,.model .sotnnpnmodel .inputs ul li { + display: inline-block; + height: 35px; + line-height: 35px; + width: 24.5%; + margin-bottom: 20px; +} +.model .sotnnpnmodel .inputs ul li{ + width: 31%; +} +.model .sitemodel .inputs ul li span,.model .sotnnpnmodel .inputs ul li span { + display: inline-block; + line-height: 35px; + font-size: 14px; + font-weight: 500; + color: #3C4F8C; + margin-left: 10px; + vertical-align: middle; + float: left; +} +.model .sitemodel .inputs input,.model .sitemodel .inputs nz-select { + width: 186px; + float: right; + margin-right: 60px; +} +.model .sotnnpnmodel .inputs input{ + width: 186px; + float: left; + margin-left: 20px; +} +.model .sitemodel .action,.model .sotnnpnmodel .action { + text-align: center; + margin-top: 30px; + margin-bottom: 20px; + cursor: pointer +} +.model .sotnnpnmodel .action{ + margin-top: 70px; +} +.model .sitemodel .action button,.model .sotnnpnmodel .action button{ + width: 126px; + height:40px; + background:#EEEEEE; + border-radius:2px; + border: none!important; + color: #9DA7C5; + font-size: 16px; + margin: 0 15px; +} +.model .sitemodel .action button:nth-child(2),.model .sotnnpnmodel .action button:nth-child(2){ + background: #0DA9E2; + color: #fff; +} +.model .sitemodel .action button:nth-child(2):hover,.model .sotnnpnmodel .action button:nth-child(2):hover{ + background:#09C6E2; +} + +.model nz-table tbody td i.anticon:hover { + color: #3fa8eb; + cursor: pointer; +} + +/* site table */ +.sitemodel h3 button,.sotnnpnmodel h3 button{ + color: #D7D7D7; + width:32px; + height:32px; + background:#ffffff; + border-radius:4px; + border:1px solid #D7D7D7; +} +.sitemodel h3 button:hover,.sotnnpnmodel h3 button:hover{ + background:#ffffff; + color: #0DA9E2; + border:1px solid #0DA9E2; +} +.sitemodel h3>button,.sotnnpnmodel h3>button{ + float: right; + width: 30px; + height: 30px; + margin-right: 15px; +} +.model nz-table tbody th{ + color:rgba(60,79,140,0.5); + font-size: 16px; +} +.model .site nz-table tbody td i.anticon:hover { + color: #3fa8eb; + cursor: pointer; +} +/* WAN Port */ + +.mask{ + width: 100%; + height: 100%; + position: absolute; + z-index: 1000; + background: rgba(0, 0, 0, 0.65); + top:0; +} + + +/* chart */ +.model .chart { + width: 98%; + padding: 10px; + margin: 0 auto; + color: #06A7E2; + font-size: 16px; + font-weight: 500; + margin-bottom: 30px; + background: #EEF9FF; + border-radius:4px; +} +.model .chart #createChart { + width: 100%; + height: 220px; + margin-top: 20px; + position: relative; +} +.model .chart #createChart .siteNameP { + position: fixed; + border: 5px; + padding: 3px 5px; + color: #fff; + background: #999; + box-shadow: 0px 0px 20px #000; + max-width: 100px; + overflow: hidden; + text-overflow: ellipsis; +} +.model .creation .sotnvpn,.model .creation .site{ + background: #fff; + padding: 30px 30px 0 30px; +} +.siteWanTab{ + width: 96%; + margin: 0 auto; + margin-top: 10px; +} +.siteWanTab th{ + padding: 10px 8px; + color: #3C4F8C; + font-size: 16px; +} +.siteWanTab tr td{ + padding: 10px 5px; +} +.siteWanTab .tr-border{ + border-bottom: 1px solid #EDEDED; +} +.addListBtn{ + margin-right: 30px; + color: #06A7E2; + border: none; + background: rgba(229,238,252,0.8); + cursor: pointer; +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html new file mode 100644 index 00000000..1fc9a500 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.html @@ -0,0 +1,275 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<div class="model creation-model"> + + <div class="top-title"> + <h3 class="title fl">{{createParams.commonParams.templateType}} + {{"i18nTextDefine_InstanceCreation" | translate}} </h3> + <div class="fl" style="width: 20%"> + <button class="submit" nz-button (click)="submit()"><span> {{"i18nTextDefine_Create" | translate}} </span> + </button> + <button class="back" nz-button (click)="goback()"></button> + </div> + </div> + <!-- chart --> + <div class="chart"> + <span style="padding: 25px;display: inline-block;"> + {{"i18nTextDefine_InstanceTopology" | translate}} + </span> + <div id="createChart"> + <svg width="100%" height="100%"> + <image id="domain" xlink:href="assets/images/domain1.png" style="width: 15%" x="40%" y="0" /> + </svg> + </div> + </div> + <!--Template resolution : Three major items--> + <div class="creation"> + <nz-tabset [nzTabPosition]="'top'" [nzShowPagination]=false [nzTabBarGutter]="'2'" [nzTabBarStyle]=tabBarStyle> + <nz-tab nzTitle="Service Info"> + <div class="service-title" style="clear: both"> + <span style="color: red;">*</span><span class="lable" style="width: 60px">name:</span> + <input nz-input [(ngModel)]="this.templateParameters.service['name']" required="required"> + <span style="color: red;">*</span><span class="lable">description:</span> + <input nz-input [(ngModel)]="this.templateParameters.service['description']"> + </div> + </nz-tab> + <nz-tab nzTitle="Sdwanvpnresource List"> + <div class="sotnvpn clearfix"> + <div style="clear: both;height: 10px"> + <h3 style="float: left;color: #3C4F8C">sdwanVPN List</h3> + <button nz-button (click)="addSotnvpn()" class="addListBtn" + style="float: right;margin-right: 10px"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700"></i> {{"i18nTextDefine_Add" | translate}} + </button> + </div> + <nz-table #sotnVpnTable [nzData]="sotnVpnTableData" [nzShowPagination]="false" nzSize="small"> + <thead> + <tr> + <th width="30%"> NO.</th> + <th *ngFor="let key of getKeys(this.sotnInfo)">{{key.split("_")[1] || key}}</th> + <th width="10%"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of sotnVpnTable.data; let i = index; "> + <td>{{i+1}}</td> + <td *ngFor="let keys of getKeys(this.sotnInfo);let a = index;"> + {{item[keys]}} + </td> + <td> + <span class="action" (click)="editSotnVpn(i+1)"><i + class="anticon anticon-edit"></i></span> + + <span class="action" (click)="deleteSotnVpn(i+1)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </nz-table> + </div> + </nz-tab> + <nz-tab nzTitle="Sdwansiteresource List"> + <div class="site"> + <div style="height: 10px"> + <h3 style="float: left;color: #3C4F8C">Site List</h3> + <button nz-button (click)="addSite()" class="addListBtn" + style="float: right;margin-right: 10px"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <nz-table #siteTable [nzData]="siteTableData" [nzShowPagination]="false" nzSize="small"> + <thead> + <tr> + <th nzWidth="10%"> NO.</th> + <th *ngFor="let key of getKeys(this.siteBaseData)">{{key.split("_")[1] || key}}</th> + <th nzWidth="20%" style="text-align: center"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of siteTable.data; let i = index; "> + <td>{{i+1}}</td> + <td *ngFor="let keys of getKeys(this.siteBaseData);let a = index;"> + {{item[keys]}} + </td> + <td style="text-align: center"> + <span class="action" (click)="editSite(i+1)"><i + class="anticon anticon-edit"></i></span> + + <span class="action" (click)="deleteSite(i+1)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </nz-table> + </div> + </nz-tab> + </nz-tabset> + </div> + <!-- sotnVpnmodel --> + <div class="sotnnpnmodel" *ngIf="sotnVpnModelShow"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.sotnvpn.sdwanvpnresource_list"> + <span *ngIf="item.required" + style="color: red;margin: 0;margin-right: -5px;">*</span><span>{{item.lableShow}}:</span> + <input nz-input [(ngModel)]="sotnInfo[item.lable]" + title="{{item.description ? item.description:null }}" + required="{{item.required==true ? 'required':null}}"></li> + </ul> + </div> + <div> + <h3>Sdwansitelan List</h3> + <div> + <div style="width: 100%;text-align: right"> + <button nz-button (click)="addSotnSdwansitelan()" class="addListBtn"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.sotnSdwansitelanParams)">{{key}}</th> + <th width="7%"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of sotnSdwansitelanData; let i = index;" + [ngClass]="{'tr-border':item.tabInputShowSdwansitelan ==false}"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);let a = index;"> + <span *ngIf="!tabInputShowSdwansitelan[i]" + title="{{this.templateParameters.sotnvpn.sdwansitelan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}">{{item[key]}}</span> + <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowSdwansitelan[i] " + title="{{this.templateParameters.sotnvpn.sdwansitelan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}" + required="{{item.required==true ? 'required':null}}"> + </td> + <td> + <span class="action" (click)="editSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i + class="anticon anticon-edit" style="margin: 0 5px;"></i></span> + <span class="action" (click)="deleteSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + + <div class="action"> + <button nz-button nzType="primary" + (click)="addSotnVpn_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button> + <button nz-button nzType="primary" (click)="addSotnVpn_OK()">{{"i18nTextDefine_Add" | translate}}</button> + </div> + </div> + <!-- sitemodel --> + <div class="sitemodel" *ngIf="siteModelShow"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.site.sdwansiteresource_list"> + <span *ngIf="item.required" + style="color: red;margin: 0;margin-right: -5px;">*</span><span>{{item.lableShow}}:</span> + <input nz-input [(ngModel)]="siteBaseData[item.lable]" title="{{item.description}}" + required="{{item.required==true ? 'required':null}}"></li> + </ul> + </div> + <div> + <h3>Sdwandevice</h3> + <div> + <div style="width: 100%;text-align: right"> + <button nz-button (click)="addSdwanDevice()" class="addListBtn"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.siteCpeData)">{{key}}</th> + <th width="7%"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of siteSdwanDevice; let i = index;" + [ngClass]="{'tr-border':item.tabInputShowDevice ==false}"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);let a = index;"> + <span *ngIf="!tabInputShowDevice[i]" + title="{{this.templateParameters.site.sdwandevice_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwandevice_list[a].description:null}}">{{item[key]}}</span> + <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowDevice[i] " + title="{{this.templateParameters.site.sdwandevice_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwandevice_list[a].description:null}}" + required="{{item.required==true ? 'required':null}}"> + </td> + <td> + <span class="action" (click)="editDevicePort(i+1,item,siteSdwanDevice)"><i + class="anticon anticon-edit" style="margin: 0 5px;"></i></span> + <span class="action" (click)="deleteDevicePort(i+1,item,siteSdwanDevice)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </table> + </div> + + + <h3>Sdwansitewan List</h3> + <div> + <div style="width: 100%;text-align: right"> + <button nz-button (click)="addSiteWan()" class="addListBtn"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th> + <th width="7%"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of siteWanData; let i = index;" + [ngClass]="{'tr-border':item.tabInputShowWanPort ==false}"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);let a = index;"> + <span *ngIf="!tabInputShowWanPort[i]" + title="{{this.templateParameters.site.sdwansitewan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}">{{item[key]}}</span> + <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowWanPort[i] " + title="{{this.templateParameters.site.sdwansitewan_list[a]['lable']==getKeys(item)[a] ? this.templateParameters.site.sdwansitewan_list[a].description:null}}" + required="{{item.required==true ? 'required':null}}"> + </td> + <td> + <span class="action" (click)="editWanPort(i+1,item,siteWanData)"><i + class="anticon anticon-edit" style="margin: 0 5px;"></i></span> + <span class="action" (click)="deleteWanPort(i+1,item,siteWanData)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + + <div class="action"> + <button nz-button nzType="primary" + (click)="addsite_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button> + <button nz-button nzType="primary" (click)="addsite_OK()">{{"i18nTextDefine_Add" | translate}}</button> + </div> + </div> + <div class="mask" *ngIf="siteModelShow || sotnVpnModelShow"></div> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts new file mode 100644 index 00000000..30402412 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CcvpnCreationComponent } from './ccvpn-creation.component'; +describe('CcvpnCreationComponent', () => { + let component: CcvpnCreationComponent; + let fixture: ComponentFixture<CcvpnCreationComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CcvpnCreationComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CcvpnCreationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts new file mode 100644 index 00000000..214afbb7 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-creation/ccvpn-creation.component.ts @@ -0,0 +1,723 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import * as d3 from 'd3'; +import * as $ from 'jquery'; +import { MyhttpService } from '../../core/services/myhttp.service'; +import { el } from "@angular/platform-browser/testing/src/browser_util"; + +@Component({ + selector: 'app-ccvpn-creation', + templateUrl: './ccvpn-creation.component.html', + styleUrls: ['./ccvpn-creation.component.css'] +}) +export class CcvpnCreationComponent implements OnInit { + + constructor(private myhttp: MyhttpService) { } + @Input() createParams; + @Input() ccvpn_temParametersContent; + @Output() closeCreate = new EventEmitter(); + + ngOnInit() { + this.getccvpnTemParameters(this.ccvpn_temParametersContent); + } + + //tabBarStyle + tabBarStyle = { + "height": "58px", + "width": "694px", + "box-shadow": "none", + "margin": "0", + "border-radius": "4px 4px 0px 0px" + }; + templateParameters = { + service: {}, + sotnvpn: { + info: {}, + sdwanvpnresource_list: [], + sdwansitelan_list: [] + }, + site: { + info: {}, + sdwansiteresource_list: [], + sdwandevice_list: [], + sdwansitewan_list: [] + } + }; + + bodyTemplateParameter = {}; + + // SOTN VPN List + sotnVpnTableData = []; + sotnInfo = {};//sotnmodel The first part of sotnInfo + sotnSdwansitelanData = [];//sotnmodel The second part of the data sdwansitelan Table + sotnSdwansitelanParams = {};//sdwansitelan Table Detailed parameters of each line of data + tabInputShowSdwansitelan = [];//sdwansitelan Table input&span The status identifier of the label switching display + // Site List + siteTableData = []; + siteBaseData = {}; //sitemodel one sdwansiteresource_list + // cpe + siteSdwanDevice = []; //sitemodel SdwanDevice port Table data + siteCpeData = {}; //sitemodel two sdwandevice_list + tabInputShowDevice = [];//Device port Table input和span The status identifier of the label switching display + // Wan Port + siteWanData = []; //sitemodel three wan port Table data + siteWanParams = {}; //wan port Table Detailed parameters of each line of data + tabInputShowWanPort = [];//wan port Table input和span The status identifier of the label switching display + getKeys(item) { + return Object.keys(item); + } + + getccvpnTemParameters(data) { //Get template parameters + console.log(this.createParams); + if (typeof data["model"] == 'string') { + data = JSON.parse(data["model"]); + } + console.log(data); + let inputss = data["inputs"]; + let inputs = {}; + this.templateParameters.service = { + name: data.metadata["name"], + description: data.metadata.description, + serviceInvariantUuid: data.metadata.invariantUUID, + serviceUuid: data.metadata.UUID + }; + + //Screening separation sotnvpn data + Object.keys(inputss).map((items) => { + if (items.search("vpn") != -1) { + this.bodyTemplateParameter[items] = []; + inputss[items].map((item, index) => { + if (item["required"] != undefined) { + this.templateParameters["sotnvpn"]["sdwanvpnresource_list"].push(item); + } + if (item["required"] == undefined && Object.keys(item).length == 1 && Object.keys(item)[0].search("site") != -1 && item[Object.keys(item)[0]] instanceof Array === true) { + this.templateParameters["sotnvpn"]["sdwansitelan_list"] = item[Object.keys(item)[0]] + let sitelanKey = {}; + sitelanKey[Object.keys(item)[0]] = []; + this.bodyTemplateParameter[items].push(sitelanKey); + } + }); + } + if (items.search("site") != -1) { + this.bodyTemplateParameter[items] = []; + inputss[items].map((item, index) => { + if (item["required"] != undefined) { + this.templateParameters["site"]["sdwansiteresource_list"].push(item); + } + if (item["required"] == undefined && Object.keys(item).length == 1 && Object.keys(item)[0].search("device") != -1 && item[Object.keys(item)[0]] instanceof Array === true) { + this.templateParameters["site"]["sdwandevice_list"] = item[Object.keys(item)[0]]; + let sitelanKey = {}; + sitelanKey[Object.keys(item)[0]] = []; + this.bodyTemplateParameter[items].push(sitelanKey); + } + if (item["required"] == undefined && Object.keys(item).length == 1 && Object.keys(item)[0].search("site") != -1 && Object.keys(item)[0].search("device") == -1 && item[Object.keys(item)[0]] instanceof Array === true) { + this.templateParameters["site"]["sdwansitewan_list"] = item[Object.keys(item)[0]]; + let sitelanKey = {}; + sitelanKey[Object.keys(item)[0]] = []; + this.bodyTemplateParameter[items].push(sitelanKey); + } + }); + } + }); + this.showTemParametersSotnVpn(); + this.showTemParametersSite(); + console.log(this.bodyTemplateParameter, this.templateParameters) + } + + //sotnVpn data, after combining the structure, rendering the template data to the page + showTemParametersSotnVpn() { + //sotn Data analysis, structure assembly + this.templateParameters.sotnvpn.sdwanvpnresource_list.map((item, index) => { + let input = {}; + for (var keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + item["lableShow"] = keys.split("_")[1]; + this.sotnInfo = Object.assign(this.sotnInfo, input); + } + } + }); + + this.templateParameters.sotnvpn.sdwansitelan_list.map((item, index) => { + let input = {}; + for (var keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + this.sotnSdwansitelanParams = Object.assign(this.sotnSdwansitelanParams, this.sotnSdwansitelanParams, input); + } + } + }); + this.sotnSdwansitelanData.push(this.sotnSdwansitelanParams); + this.sotnSdwansitelanData.map((item, index) => { + this.tabInputShowSdwansitelan[index] = true; + }); + } + + //Site data, after combining the structure, rendering the template to the page + showTemParametersSite() { + //site Data analysis, structure assembly + this.templateParameters.site.sdwansiteresource_list.map((item, index) => { + let input = {}; + for (var keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + item["lableShow"] = keys.split("_")[1]; + this.siteBaseData = Object.assign(this.siteBaseData, input); + } + } + }); + + this.templateParameters.site.sdwandevice_list.map((item, index) => { + let input = {}; + for (var keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + this.siteCpeData = Object.assign(this.siteCpeData, input); + } + } + }); + this.templateParameters.site.sdwandevice_list.map((item, index) => { + if (this.getKeys(item).indexOf("lable") == -1) { + this.templateParameters.site.sdwandevice_list.splice(index, 1) + } + }); + this.templateParameters.site.sdwansitewan_list.push( + { + ipMode: "", + description: "" + }, + { + publicIP: "", + description: "" + } + ); + + this.templateParameters.site.sdwansitewan_list.map((item, index) => { + let input = {}; + for (var keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + this.siteWanParams = Object.assign(this.siteWanParams, this.siteWanParams, input); + } + } + }); + this.siteSdwanDevice.push(this.siteCpeData); + this.siteWanData.push(this.siteWanParams); + this.siteWanData.map((item, index) => { + this.tabInputShowDevice[index] = true; + }); + this.siteWanData.map((item, index) => { + this.tabInputShowWanPort[index] = true; + }); + + } + + //add,edit,delete sotnSdwansitelan + addSotnSdwansitelan() { + if (this.tabInputShowSdwansitelan.indexOf(true) > -1) {//Adding new rows is not allowed when there is a row of data being edited + return false; + } + let addNum = this.sotnSdwansitelanData.length; + let inputsData = Object.assign({}, this.sotnSdwansitelanParams); + Object.keys(inputsData).forEach((item) => {//Add a new line of empty data + if (item != "description") { + inputsData[item] = null; + } + }); + this.sotnSdwansitelanData[addNum] = inputsData; + this.tabInputShowSdwansitelan[addNum] = true; + this.sotnSdwansitelanData = [...this.sotnSdwansitelanData]; //Table refresh + } + editSotnSdwansitelan(num, item, sotnSdwansitelanData) { + if (this.tabInputShowSdwansitelan[num - 1] == false) { + this.tabInputShowSdwansitelan[num - 1] = true; + } else { + this.tabInputShowSdwansitelan[num - 1] = false; + } + } + deleteSotnSdwansitelan(num, item, sotnSdwansitelanData) { + if (this.sotnSdwansitelanData.length <= 1) { + return false; + } else { + + } + this.sotnSdwansitelanData = this.sotnSdwansitelanData.filter((d, i) => i !== num - 1); + } + + //add,edit,delete SdwanDevice + addSdwanDevice() { + if (this.tabInputShowDevice.indexOf(true) > -1) {//当有正在编辑的一行数据时,不允许添加新的行 + return false; + } + let addNum = this.siteSdwanDevice.length; + let inputsData = Object.assign({}, this.siteCpeData); + Object.keys(inputsData).forEach((item) => {//新增一行空数据 + if (item != "description") { + inputsData[item] = null; + } + }); + this.siteSdwanDevice[addNum] = inputsData; + this.tabInputShowDevice[addNum] = true; + this.siteSdwanDevice = [...this.siteSdwanDevice]; //表格刷新 + } + + editDevicePort(num, item, siteSdwanDevice) { + if (this.tabInputShowDevice[num - 1] == false) { + this.tabInputShowDevice[num - 1] = true; + } else { + this.tabInputShowDevice[num - 1] = false; + } + } + + deleteDevicePort(num, item, siteSdwanDevice) { + if (this.siteSdwanDevice.length <= 1) { + return false; + } + this.siteSdwanDevice = this.siteSdwanDevice.filter((d, i) => i !== num - 1); + } + + //add,edit,delete siteWanPort + addSiteWan() { + if (this.tabInputShowWanPort.indexOf(true) > -1) {//Adding new rows is not allowed when there is a row of data being edited + return false; + } + let addNum = this.siteWanData.length; + let inputsData = Object.assign({}, this.siteWanParams); + Object.keys(inputsData).forEach((item) => {//Add a new line of empty data + if (item != "description") { + inputsData[item] = null; + } + }); + this.siteWanData[addNum] = inputsData; + this.tabInputShowWanPort[addNum] = true; + this.siteWanData = [...this.siteWanData]; //Table refresh + } + editWanPort(num, item, siteWanData) { + if (this.tabInputShowWanPort[num - 1] == false) { + this.tabInputShowWanPort[num - 1] = true; + } else { + this.tabInputShowWanPort[num - 1] = false; + } + } + deleteWanPort(num, item, siteWanData) { + if (this.siteWanData.length <= 1) { + return false; + } + this.siteWanData = this.siteWanData.filter((d, i) => i !== num - 1); + } + + //siteModel,sotnVpnModel Display sign + siteModelShow = false; + sotnVpnModelShow = false; + addSotnvpn() { + this.sotnVpnModelShow = true; + this.isEditSotnVpn = 0; + } + addSite() { + this.siteModelShow = true; + this.isEditSite = 0; + } + + //add sotnVpn model + isEditSotnVpn = 0;//Edit serial number, No value, 0 means increase + addSotnVpn_OK() { + let inputs = { + "sdwansitelan_list": [] + }; + inputs = Object.assign(inputs, this.sotnInfo); + inputs["sdwansitelan_list"] = this.sotnSdwansitelanData.map((item) => { + return Object.assign({}, item); + }); + if (this.isEditSotnVpn) { + // Edit status does not increase + this.sotnVpnTableData[this.isEditSotnVpn - 1] = inputs; + this.sotnVpnTableData = [...this.sotnVpnTableData]; //Table refresh + } else { + this.sotnVpnTableData = [...this.sotnVpnTableData, inputs]; + } + Object.keys(this.sotnInfo).forEach((item) => { //Clear modal box + this.sotnInfo[item] = null; + }); + this.sotnSdwansitelanData.forEach((item, index) => { + if (index > 0) { + this.sotnSdwansitelanData.splice(index, 1); + this.tabInputShowSdwansitelan.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowSdwansitelan[index] = true; + } + + }); + this.sotnVpnModelShow = false; + } + + addSotnVpn_cancel() { + Object.keys(this.sotnInfo).forEach((item) => { //Clear modal box + this.sotnInfo[item] = null; + }); + this.sotnSdwansitelanData.forEach((item, index) => { + if (index > 0) { + this.sotnSdwansitelanData.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowSdwansitelan[index] = true; + } + + }); + this.sotnVpnModelShow = false; + } + + editSotnVpn(num) { + this.sotnVpnModelShow = true; + this.isEditSotnVpn = num; + Object.keys(this.sotnInfo).forEach((item) => { //Clear modal box + this.sotnInfo[item] = this.sotnVpnTableData[num - 1][item]; + }); + this.sotnSdwansitelanData = this.sotnVpnTableData[num - 1].sdwansitelan_list.map((item) => { + return Object.assign({}, {}, item) + }); + this.sotnSdwansitelanData.forEach((item, index) => { + this.tabInputShowSdwansitelan[index] = false; + }); + } + + deleteSotnVpn(num) { + this.sotnVpnTableData = this.sotnVpnTableData.filter((d, i) => i !== num - 1); + } + + // addsite model + isEditSite = 0; //Edit serial number, No value, 0 means increase + addsite_OK() { + let inputs = { + "sdwandevice_list": [], + "sdwansitewan_list": [] + }; + inputs = Object.assign(inputs, this.siteBaseData); + inputs["sdwandevice_list"] = this.siteSdwanDevice.map((item) => { + return Object.assign({}, item); + }); + inputs["sdwansitewan_list"] = this.siteWanData.map((item) => { + return Object.assign({}, item); + }); + if (this.isEditSite) { + // Edit status does not increase + this.siteTableData[this.isEditSite - 1] = inputs; + this.siteTableData = [...this.siteTableData]; //Table refresh + } else { + this.siteTableData = [...this.siteTableData, inputs]; + } + + Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box + this.siteBaseData[item] = null; + }); + this.siteSdwanDevice.forEach((item, index) => { + if (index > 0) { + this.siteSdwanDevice.splice(index, 1); + this.tabInputShowDevice.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowDevice[index] = true; + } + }); + this.siteWanData.forEach((item, index) => { + if (index > 0) { + this.siteWanData.splice(index, 1); + this.tabInputShowWanPort.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowWanPort[index] = true; + } + }); + console.log(this.siteTableData); + this.drawImage(this.siteTableData); + this.siteModelShow = false; + } + + addsite_cancel() { + Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box + this.siteBaseData[item] = null; + }) + this.siteSdwanDevice.forEach((item, index) => { + if (index > 0) { + this.siteSdwanDevice.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowDevice[index] = true; + } + + }); + this.siteWanData.forEach((item, index) => { + if (index > 0) { + this.siteWanData.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowWanPort[index] = true; + } + + }); + this.siteModelShow = false; + } + + editSite(num) { //Edit and modify the selected site information + this.siteModelShow = true; + this.isEditSite = num; + Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box + this.siteBaseData[item] = this.siteTableData[num - 1][item]; + }); + this.siteSdwanDevice = this.siteTableData[num - 1].sdwandevice_list.map((item) => { + return Object.assign({}, item) + }); + this.siteSdwanDevice.forEach((item, index) => { + this.tabInputShowDevice[index] = false; + }); + this.siteWanData = this.siteTableData[num - 1].sdwansitewan_list.map((item) => { + return Object.assign({}, item) + }); + this.siteWanData.forEach((item, index) => { + this.tabInputShowWanPort[index] = false; + }); + } + + deleteSite(num) { + this.siteTableData = this.siteTableData.filter((d, i) => i !== num - 1); + this.drawImage(this.siteTableData); + } + + // Site node graphic depiction + lines = []; + siteImage = []; + tpImage = []; + imgmap = { + '1': '../../../assets/images/domain1.png', + '2': '../../../assets/images/site.png' + }; + + drawImage(sitelist) { + let cx = 550; + let cy = 40; + let innerx1 = 720; //Left site pattern coordinate position + let innery1 = 40; + let ox = 950; + let oy = 50; + let innerx2 = 780;//Right site pattern coordinate position + let innery2 = 50; + let lateX1 = Math.random() * 30 + 55; + let lateX2 = 10; + let lateY1 = 15; + this.lines = sitelist.map((item, index) => { + let step = index + 1; + let x = cx; + let y = cy; + let innerX = innerx1; + let innerY = innery1; + if (step % 2 != 0) { //Left site pattern coordinate position + x = cx; + y = cy; + innerX = innerx1; + innerY = innery1; + if (step == 1) { + innerX = innerx1; + innerY = innery1; + } else { + x = cx - lateX1 * Math.ceil((step / 2)) >= 0 ? cx - lateX1 * Math.ceil((step / 2)) : -(cx - lateX1 * Math.ceil((step / 2))); + y = cy + lateY1 * Math.floor((step / 2)); + innerX = this.lines[step - 3].innerX - lateX2; + innerY = y; + } + } else { //Right site pattern coordinate position + x = ox; + y = oy; + innerX = innerx2; + innerY = innery2; + if (step / 2 == 1) { + innerX = innerx2; + innerY = innery2; + } else { + x = ox + lateX1 * (step / 2) >= 0 ? ox + lateX1 * (step / 2) : -(ox + lateX1 * (step / 2)); + y = oy + lateY1 * (step / 2 - 1); + innerX = this.lines[step - 3].innerX - lateX2; + innerY = y; + } + } + return { + img: "line", + site: item.sdwandevice_list[0].name, + x1: x, + y1: y, + x2: innerX, + y2: innerY, + innerX: innerX, + innerY: innerY + } + }); + this.render(this.imgmap, this.lines); + } + + render(imgmap, lines) { + + //enter + var svg = d3.select("svg"), + _g_lines = svg.selectAll('line.line') + .data(lines) + .enter() + .append('line') + .style('stroke', '#3fa8eb' + ) + .style('stroke-width', 2) + .attr('class', 'line') + .attr("x1", function (d) { + return d.x1; + }) + .attr("y1", function (d) { + return d.y1; + }) + .attr("x2", function (d) { + return d.x2; + }) + .attr("y2", function (d) { + return d.y2; + }), + _g_site = svg.selectAll('g.g-site') + .data(lines) + .enter() + .append('g') + .style('cursor', 'pointer') + .attr('class', 'g-site'); + _g_site.append('image') + .style("width", "50px") + .attr('xlink:href', function (d) { + return imgmap[2]; + }) + .attr("x", function (d) { + return d.x1 - 25; + }) + .attr("y", function (d) { + return d.y1 - 25; + }) + + //quit + svg.selectAll("g.g-site") + .data(lines) + .exit() //Select a picture without bound data + .remove(); + svg.selectAll("line.line") + .data(lines) + .exit() //Select the connection without binding data + .remove(); + + } + + modifyJosnKey(json, oddkey, newkey) { + + let val = json[oddkey]; + delete json[oddkey]; + json[newkey] = val; + } + + // submit createData + submit() { + let globalCustomerId = this.createParams.commonParams.customer.id; + let globalServiceType = this.createParams.commonParams.serviceType.name; + let servicebody = { + service: { + name: this.templateParameters.service["name"], + description: this.templateParameters.service["description"], + serviceInvariantUuid: this.templateParameters.service["serviceInvariantUuid"], + serviceUuid: this.templateParameters.service["serviceUuid"], + globalSubscriberId: globalCustomerId, //customer.id + serviceType: globalServiceType, //serviceType.value + parameters: { + locationConstraints: [], + resources: [], + requestInputs: {} + }, + } + }; + let siteresource = null, sitewan = null, device = null, vpnresource = null, sitelan = null; + Object.keys(this.bodyTemplateParameter).map((item, index) => { + if (item.search("site") != -1) { + siteresource = item; + this.bodyTemplateParameter[item].map((items, index) => { + if (Object.keys(items)[0].search("site") != -1 && Object.keys(items)[0].search("device") == -1) { + sitewan = Object.keys(items)[0] + } + if (Object.keys(items)[0].search("device") != -1) { + device = Object.keys(items)[0] + } + }); + } + if (item.search("vpn") != -1) { + vpnresource = item; + this.bodyTemplateParameter[item].map((items, index) => { + if (Object.keys(items)[0].search("site") != -1) { + sitelan = Object.keys(items)[0] + } + }); + } + }); + this.sotnVpnTableData.forEach((item, index) => { + Object.keys(item).map((items, index) => { + if (items.search("site") != -1 && item[items] instanceof Array === true) { + this.modifyJosnKey(item, items, sitelan) + } + }); + }); + this.siteTableData.forEach((item, index) => { + Object.keys(item).map((items, index) => { + if (items.search("site") != -1 && Object.keys(item)[0].search("device") == -1 && item[items] instanceof Array === true) { + this.modifyJosnKey(item, items, sitewan) + } + if (items.search("device") != -1) { + this.modifyJosnKey(item, items, device) + } + }); + }); + Object.keys(this.bodyTemplateParameter).map((item, index) => { + if (item.search("site") != -1) { + servicebody.service.parameters.requestInputs[item] = [].concat(this.siteTableData); + } + if (item.search("vpn") != -1) { + servicebody.service.parameters.requestInputs[item] = [].concat(this.sotnVpnTableData); + } + }); + console.log(servicebody); + + this.closeCreate.emit(servicebody); + + } + + goback() { + this.closeCreate.emit(); + } +} diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css new file mode 100644 index 00000000..d5ad960d --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.css @@ -0,0 +1,365 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 10px; +} +.model { + background-color: #F7F8FC; + overflow-y: auto; +} +.creation-model{ + position: relative; + height: 100%; +} +.top-title{ + width: 100%; + padding: 20px; + position: relative; + display: inline-block; +} +.model .submit{ + position: absolute; + width: 90px; + height: 35px; + top: 10px; + right: 85px; + color: #fff; + font-size: 18px; + background: #0DA9E2; + border-radius: 4px; + border: none!important; + border-color: rgba(0,0,0,0)!important; +} +.model .back,.model .back:hover{ + position: absolute; + top: 10px; + right: 20px; + display: inline-block; + width: 35px; + height: 35px; + background:url("../../../assets/images/Return-icon.png") no-repeat!important; + background-size: 100%!important; + border-radius:4px; + color: #D7D7D7; + cursor: pointer; +} +.model .back:hover{ + background: url("../../../assets/images/Return-icon-active.png")!important; + background-size: 100%!important; +} +.top-title h3.title { + height: 35px; + width: 80%; + font-size:16px; + font-family:ArialMT; + color:#3C4F8C; + line-height:35px; + display: inline-block; +} + + +.model .detaildata { + width: 100%; + overflow-y: auto; + border-radius: 5px; + padding: 15px; +} +.model .detaildata h3.title { + height: 20px; + font: 700 20px/20px "Arial"; + color: #666; +} +.model .detaildata h3 { + height: 20px; + font: 700 16px/20px "Arial"; + margin: 5px 0; + color: #000; +} +.model .detaildata .service-title{ + margin:60px 50px; +} +.model .detaildata .service-title .info-inputs{ + width:400px; + height: 42px; + display: inline-block; +} +.model .detaildata .service-title span{ + height: 42px; + line-height: 42px; + vertical-align: middle; +} +.model .detaildata .service-title .lable{ + display: inline-block; + width: 100px; + font: 700 14px "Arial"; + color: #3C4F8C; + height: 42px; + line-height: 42px; + vertical-align: middle; + margin-left: 5px; +} +.model .detaildata .service-title .service-title-input { + width: 230px; + height: 42px; + border-radius:4px; + margin-right: 30px; + display: inline-block; +} +/* SOTN VPN */ +.model .detaildata .sotnvpn ul li { + display: inline-block; + height: 40px; + width: 24.5%; + margin-bottom: 40px; + float: left; +} +.model .detaildata .sotnvpn ul li span { + display: inline-block; + font-size: 14px; + font-weight: 500; + color:rgba(60,79,140,0.5); + margin-left: 10px; + vertical-align: middle; + float: left; + width: 110px; +} + +.model .sitemodel .inputs ul li span,.model .sotnnpnmodel .inputs ul li span { + display: inline-block; + line-height: 35px; + font-size: 14px; + font-weight: 500; + color: #3C4F8C; + margin-left: 10px; + vertical-align: middle; + float: left; +} +.model .sitemodel .inputs input,.model .sitemodel .inputs nz-select{ + width: 186px; + float: right; + margin-right: 60px; +} +.model .sotnnpnmodel .inputs input{ + width: 186px; + float: left; + margin-left: 20px; +} + +/* addsite model */ +.model .sitemodel,.model .sotnnpnmodel{ + position: absolute; + z-index: 1001; + left: 50px; + top: 60px; + background-color: #fff; + width:1500px; + height: 81%; + border-radius:2px; + overflow:auto; +} +.model .sotnnpnmodel{ + width: 1000px; + height: 53%; + top:200px; + left: 50%; + margin-left: -500px; +} +.model .sitemodel h3,.model .sotnnpnmodel h3{ + width: 96%; + height: 40px; + line-height: 35px; + font-size: 18px; + font-weight: 500; + margin: 10px auto; + color: #06A7E2; + border-bottom: 2px solid; + border-image: -webkit-linear-gradient(#07A9E1,#30D9C4) 100 100; + border-image: -moz-linear-gradient(#07A9E1,#30D9C4) 100 100; + border-image: linear-gradient(#07A9E1,#30D9C4) 100 100; + border-radius:2px; +} +.model .sitemodel .inputs,.model .sotnnpnmodel .inputs { + padding: 10px 20px 0; +} +.model .sitemodel .inputs ul li,.model .sotnnpnmodel .inputs ul li { + display: inline-block; + height: 35px; + line-height: 35px; + width: 24.5%; + margin-bottom: 20px; +} +.model .sotnnpnmodel .inputs ul li{ + width: 31%; +} +.model .sitemodel .inputs ul li span,.model .sotnnpnmodel .inputs ul li span { + display: inline-block; + line-height: 35px; + font-size: 14px; + font-weight: 500; + color: #3C4F8C; + margin-left: 10px; + vertical-align: middle; + float: left; +} +.model .sitemodel .inputs input,.model .sitemodel .inputs nz-select{ + width: 186px; + float: right; + margin-right: 60px; +} +.model .sotnnpnmodel .inputs div{ + width: 186px; + float: left; + margin-left: 20px; +} +.model .sitemodel .action,.model .sotnnpnmodel .action { + text-align: center; + margin-top: 30px; + margin-bottom: 20px; + cursor: pointer +} +.model .sotnnpnmodel .action{ + margin-top: 70px; +} +.model .sitemodel .action button,.model .sotnnpnmodel .action button{ + width: 126px; + height:40px; + background:#EEEEEE; + border-radius:2px; + border: none!important; + color: #9DA7C5; + font-size: 16px; + margin: 0 15px; +} +.model .sitemodel .action button:nth-child(2),.model .sotnnpnmodel .action button:nth-child(2){ + background: #0DA9E2; + color: #fff; +} +.model .sitemodel .action button:nth-child(2):hover,.model .sotnnpnmodel .action button:nth-child(2):hover{ + background:#09C6E2; +} + +.model nz-table tbody td i.anticon:hover { + color: #3fa8eb; + cursor: pointer; +} + +/* site table */ +.sitemodel h3 button,.sotnnpnmodel h3 button{ + color: #D7D7D7; + width:32px; + height:32px; + background:#ffffff; + border-radius:4px; + border:1px solid #D7D7D7; +} +.sitemodel h3 button:hover,.sotnnpnmodel h3 button:hover{ + background:#ffffff; + color: #0DA9E2; + border:1px solid #0DA9E2; +} +.sitemodel h3>button,.sotnnpnmodel h3>button{ + float: right; + width: 30px; + height: 30px; + margin-right: 15px; +} + +/* site Detail */ + +.model .detaildata .site h3 .closeDetail { + cursor: pointer; + padding: 2px 15px; + color: #3fa8eb; +} + +.model .detaildata .sotnvpn,.model .detaildata .site{ + background: #fff; + padding: 30px 30px 0 30px; +} + +.mask{ + width: 100%; + height: 100%; + position: absolute; + z-index: 1000; + background: rgba(0, 0, 0, 0.65); + top:0; +} + +/* charts */ +.model .chart { + width: 98%; + padding: 10px; + margin: 0 auto; + color: #06A7E2; + font-size: 16px; + font-weight: 500; + margin-bottom: 30px; + background: #EEF9FF; + border-radius: 4px; +} +.model .chart #detailChart { + width: 100%; + height: 254px; + margin-top: 20px; + position: relative; +} +.model .chart #detailChart .cloudcounty { + cursor: pointer; +} + +.model .chart #detailChart .couldDetail { + position: absolute; + left: 50%; + top: 10px; + width: 80%; + transform: translate(-50%,0); + height: 160px; + background-color: #aaa; + border-radius: 5px; + box-shadow: 0px 0px 20px #000; +} +.siteWanTab{ + width: 96%; + margin: 0 auto; + margin-top: 10px; +} +.siteWanTab th{ + padding: 10px 8px; + color: #3C4F8C; + font-size: 16px; +} +.siteWanTab tr td{ + padding: 10px 5px; +} +.siteWanTab .tr-border{ + border-bottom: 1px solid #EDEDED; +} +.addListBtn{ + margin-right: 30px; + color: #06A7E2; + border: none; + background: rgba(229,238,252,0.8); + cursor: pointer; +} diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html new file mode 100644 index 00000000..e2b5159e --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.html @@ -0,0 +1,421 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<div class="model creation-model" style="background: #F7F8FC;"> + <!-- top title --> + <div class="top-title"> + <h3 class="title fl">{{detailParams['service-instance-name']}} Instance Detail</h3> + <div class="fl" style="width: 20%"> + <button class="submit" nz-button (click)="submitUpdate()" *ngIf="upDateShow"><span> + {{"i18nTextDefine_Update" | translate}} </span> + </button> + <button class="back" nz-button (click)="goback()"></button> + </div> + </div> + <!-- chart --> + <div class="chart"> + + <div id="detailChart"> + <svg width="100%" height="100%" style="position: relative"> + <!--local domain--> + <g class="clouds" *ngIf="vpns[0].domain!=''"> + <image xlink:href="assets/images/domain1.png" id="domain1" width="14%" x="17%" y="14%"></image> + <text dx="24%" dy="51%" style="font-size: 14px; fill:#ffffff;width: 20px;"> + {{vpns[0].domain}} + </text> + </g> + <g *ngIf="vpns[1]" class="clouds"> + <image xlink:href="assets/images/domain1.png" id="domain2" width="14%" x="40%" y="40%"></image> + <text dx="43%" dy="19%" style="font-size: 14px; fill: #ffffff;width: 20px;"> + {{vpns[1].domain}} + </text> + </g> + <!--domain1 tp--> + <g class="clouds" *ngIf="vpns[0].sitetpname!=''"> + <image xlink:href="assets/images/tp.png" class="tp" id="tp1" height="16" width="20" x="21%" y="37%"></image> + <text dx="21%" dy="34%" style="font-size: 14px; fill: #666;width: 20px;"> + {{vpns[0].sitetpname}} + </text> + </g> + <g class="clouds" *ngIf="vpns[0].othertpname!=''"> + <image xlink:href="assets/images/tp.png" class="tp" id="tp2" height="16" width="20" x="29%" y="52%"></image> + <text dx="29%" dy="49%" style="font-size: 14px; fill: #666;width: 20px;"> + {{vpns[0].othertpname}} + </text> + </g> + <!--domain2 tp--> + <g *ngIf="vpns[1]" class="clouds"> + <image xlink:href="assets/images/tp.png" class="tp" id="tp3" height="16" width="20" x="44%" y="52%"></image> + <text dx="44%" dy="49%" style="font-size: 14px; fill: #666;width: 20px;"> + {{vpns[1].othertpname}} + </text> + </g> + <g *ngIf="vpns[1]" class="clouds"> + <image xlink:href="assets/images/tp.png" class="tp" id="tp4" height="16" width="20" x="51%" y="78%"></image> + <text dx="51%" dy="75%" style="font-size: 14px; fill: #666;width: 20px;"> + {{vpns[1].sitetpname}} + </text> + </g> + <!--clouds--> + <g class="clouds"> + <image xlink:href="assets/images/cloud-out.png" id="extent-cloud" width="14%" x="70%" y="11%"></image> + <text dx="75%" dy="39%" style="font-size: 14px; fill: #666;width: 20px;"> + SP Partent Network + </text> + </g> + <!--local site--> + <g class="clouds" *ngIf="localSite.length>0"> + <image xlink:href="assets/images/site.png" id="site1" height="59" width="100" x="6%" y="29%"></image> + <text dx="8%" dy="26%" style="font-size: 14px; fill: #666;width: 20px;"> + {{localSite[0] && localSite[0]["service-instance-name"]}} + </text> + </g> + <g *ngIf="!detailSites && localSite.length>0" class="clouds"> + <image xlink:href="assets/images/site.png" id="site2" height="59" width="100" x="61%" y="70%" + *ngIf="this.vpns.length == 2"></image> + <text dx="62%" dy="66%" style="font-size: 14px; fill: #666;width: 20px;" *ngIf="this.vpns.length == 2"> + {{ localSite[1] && localSite[1]["service-instance-name"]}} + </text> + <image xlink:href="assets/images/site.png" id="site2" height="59" width="100" x="40%" y="44%" + *ngIf="this.vpns.length == 1"></image> + <text dx="41%" dy="40%" style="font-size: 14px; fill: #666;width: 20px;" *ngIf="this.vpns.length == 1"> + {{ localSite[1] && localSite[1]["service-instance-name"]}} + </text> + </g> + <!--cloud site--> + <g *ngIf="!detailSites && outerSite.length>0" class="clouds"> + <image xlink:href="assets/images/site.png" id="site3" height="59" width="100" x="89%" y="10%"></image> + <text dx="90%" dy="7%" style="font-size: 14px; fill: #666;width: 20px;"> + {{outerSite[1] && outerSite[1]["service-instance-name"]}} + </text> + </g> + <g class="clouds" *ngIf="outerSite.length>0"> + <image xlink:href="assets/images/site.png" id="site4" height="59" width="100" x="89%" y="40%"></image> + <text dx="90%" dy="37%" style="font-size: 14px; fill: #666;width: 20px;"> + {{outerSite[0] && outerSite[0]["service-instance-name"]}} + </text> + </g> + <!--tp,site,domain---line --> + <line *ngFor="let item of detailLines" [attr.x1]="item.x1" [attr.y1]="item.y1" [attr.x2]="item.x2" + [attr.y2]="item.y2" style="stroke:#2F8BF7; stroke-width:2"></line> + <line *ngIf="detailSites" x1="45%" y1="30%" x2="75%" y2="20%" style="stroke:#FFC000; stroke-width:2"></line> + </svg> + </div> + </div> + <div class="detaildata"> + <nz-tabset [nzTabPosition]="'top'" [nzShowPagination]=false [nzTabBarGutter]="'2'" [nzTabBarStyle]=tabBarStyle + [nzSelectedIndex]="upDateShow == false?0:1"> + <nz-tab nzTitle="Service Info"> + <div class="service-title" style="clear: both"> + <span class="lable" style="width: 60px">name:</span> + <div class="service-title-input">{{templateParameters.service["name"]}}</div> + <span class="lable">description:</span> + <div class="service-title-input">{{templateParameters.service["description"]}}</div> + </div> + </nz-tab> + <nz-tab nzTitle="Sdwanvpnresource List"> + <div class="sotnvpn clearfix"> + <div style="clear: both;height: 10px"> + <h3 style="float: left;color: #3C4F8C">sdwanVPN List</h3> + <button nz-button *ngIf="upDateShow" (click)="updateSotnvpn()" class="addListBtn" + style="float: right;margin-right: 10px"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700"></i> {{"i18nTextDefine_Add" | translate}} + </button> + </div> + <nz-table #sotnVpnTable [nzData]="sotnVpnTableData" [nzShowPagination]="false" nzSize="small"> + <thead> + <tr> + <th width="30%"> NO.</th> + <th width="30%"> Name</th> + <th width="30%"> topology</th> + <th nzWidth="10%"> Action </th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of sotnVpnTable.data; let i = index; "> + <td>{{i+1}}</td> + <td>{{item.sdwanvpn_name}}</td> + <td>{{item.sdwanvpn_topology}}</td> + <td> + <span class="action" (click)="showstonVpnDetail(i+1)"><i class="anticon anticon-bars"></i></span> + <span class="action" (click)="editUpdateSotnVpn(i+1)" *ngIf="sotnvpnnum[i]"><i + class="anticon anticon-edit"></i></span> + + <span class="action" (click)="deleteUpdateSotnVpn(i+1)" *ngIf="upDateShow"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </nz-table> + </div> + </nz-tab> + <nz-tab nzTitle="Sdwansiteresource List"> + <div class="site"> + <div style="height: 10px"> + <h3 style="float: left;color: #3C4F8C">Site List</h3> + <button nz-button *ngIf="upDateShow" (click)="updateSite()" class="addListBtn" + style="float: right;margin-right: 10px"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <nz-table #nzTable [nzData]="siteTableData" [nzShowPagination]="false" nzSize="small"> + <thead> + <tr> + <th nzWidth="10%"> NO. </th> + <th nzWidth="15%"> Name </th> + <th nzWidth="20%"> Description </th> + <th nzWidth="15%"> Post Code </th> + <th nzWidth="15%"> Address </th> + <th nzWidth="15%"> VLAN </th> + <th nzWidth="10%"> Action </th> + </tr> + </thead> + <tbody> + + <tr *ngFor="let item of nzTable.data; let i = index; "> + <td>{{i+1}}</td> + <td>{{item.sdwandevice_list[0].name}}</td> + <td>{{item.sdwansite_description}}</td> + <td>{{item.sdwansite_postcode}}</td> + <td>{{item.sdwansite_address}}</td> + <td>{{item.sdwansite_emails}}</td> + <td> + <span class="action" (click)="showSiteDetail(i+1)"><i class="anticon anticon-bars"></i></span> + + <span class="action" (click)="editUpdateSite(i+1)" *ngIf="sitenum[i]"><i + class="anticon anticon-edit"></i></span> + + <span class="action" (click)="deleteUpdateSite(i+1)" *ngIf="upDateShow"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + + </tbody> + </nz-table> + </div> + </nz-tab> + </nz-tabset> + </div> + <!-- sotnVpn model --> + <div class="sotnnpnmodel" *ngIf="sotnVpnDetailShow"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.sotnvpn.sdwanvpnresource_list"> + <span>{{item.lableShow}}:</span> + <span class="input-info">{{sotnInfo[item.lable]}}</span> + </li> + </ul> + </div> + <div> + <h3>Sdwansitelan List</h3> + <div> + <div style="width: 100%;text-align: right"> + </div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.sotnSdwansitelanParams)">{{key}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of sotnSdwansitelanData; let i = index;" class="tr-border"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);let a = index;"> + <span *ngIf="key != 'lable' ">{{item[key]}}</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + <div class="action"> + <button nz-button nzType="primary" + (click)="detailSotnVpn_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button> + </div> + </div> + <!-- site model --> + <div class="sitemodel" *ngIf="siteDetail"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.site.sdwansiteresource_list"> + <span>{{item.lableShow}}:</span> + <span class="input-info">{{siteBaseData[item.lable]}}</span> + </li> + </ul> + </div> + <div> + <h3>Sdwandevice</h3> + <div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.siteCpeData)">{{key}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of siteSdwanDevice; let i = index;" class="tr-border"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);"> + <span *ngIf="key != 'lable' ">{{item[key]}}</span> + </td> + </tr> + </tbody> + </table> + </div> + <h3>Sdwansitewan List</h3> + <div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of siteWanData; let i = index;" class="tr-border"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);"> + <span *ngIf="key != 'lable' ">{{item[key]}}</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + + <div class="action"> + <button nz-button nzType="primary" (click)="detailsite_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button> + </div> + </div> + <!-- sotnVpn update model --> + <div class="sotnnpnmodel" *ngIf="sotnVpnAddModelShow"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.sotnvpn.sdwanvpnresource_list"> + <span>{{item.lableShow}}:</span> + <input nz-input [(ngModel)]="sotnInfo[item.lable]"></li> + </ul> + </div> + <div> + <h3>Sdwansitelan List</h3> + <div> + <div style="width: 100%;text-align: right"> + <button nz-button (click)="updateSotnSdwansitelan()" class="addListBtn"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.sotnSdwansitelanParams)">{{key}}</th> + <th width="7%"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of sotnSdwansitelanData; let i = index;" + [ngClass]="{'tr-border':item.tabInputShowSdwansitelan ==false}"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);let a = index;"> + <span *ngIf="!tabInputShowSdwansitelan[i]">{{item[key]}}</span> + <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowSdwansitelan[i] "> + </td> + <td> + <span class="action" (click)="editUpdateSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i + class="anticon anticon-edit" style="margin: 0 5px;"></i></span> + <span class="action" (click)="deleteUpdateSotnSdwansitelan(i+1,item,sotnSdwansitelanData)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + + <div class="action"> + <button nz-button nzType="primary" + (click)="updateSotnVpn_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button> + <button nz-button nzType="primary" (click)="updateSotnVpn_OK()">{{"i18nTextDefine_Add" | translate}}</button> + </div> + </div> + <!-- site update Model --> + <div class="sitemodel" *ngIf="siteAddModelShow"> + <h3> {{"i18nTextDefine_Base" | translate}} </h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.site.sdwansiteresource_list"> + <span>{{item.lableShow}}:</span> + <input nz-input [(ngModel)]="siteBaseData[item.lable]"></li> + </ul> + </div> + <div> + <h3>Sdwandevice</h3> + <div class="inputs"> + <ul> + <li *ngFor="let item of this.templateParameters.site.sdwandevice_list"> + <span>{{item.lable}}:</span> + <input nz-input [(ngModel)]="siteCpeData[item.lable]"> + </li> + </ul> + </div> + <h3>Sdwansitewan List</h3> + <div> + <div style="width: 100%;text-align: right"> + <button nz-button (click)="updateSiteWan()" class="addListBtn"><i class="anticon anticon-plus" + style="transform: scale(1.2);font-weight: 700;"></i>{{"i18nTextDefine_Add" | translate}} + </button> + </div> + <table class="siteWanTab"> + <thead> + <tr> + <th width="4%"> NO.</th> + <th *ngFor="let key of getKeys(this.siteWanParams)">{{key}}</th> + <th width="7%"> Action</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of siteWanData; let i = index;" + [ngClass]="{'tr-border':item.tabInputShowWanPort ==false}"> + <td>{{i+1}}</td> + <td *ngFor="let key of getKeys(item);let a = index;"> + <span *ngIf="!tabInputShowWanPort[i]">{{item[key]}}</span> + <input nz-input [(ngModel)]="item[key]" *ngIf="tabInputShowWanPort[i] "> + </td> + <td> + <span class="action" (click)="editUpdateWanPort(i+1,item,siteWanData)"><i class="anticon anticon-edit" + style="margin: 0 5px;"></i></span> + <span class="action" (click)="deleteUpdateWanPort(i+1,item,siteWanData)"><i + class="anticon anticon-delete"></i></span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + + <div class="action"> + <button nz-button nzType="primary" (click)="updatesite_cancel()">{{"i18nTextDefine_Cancel" | translate}}</button> + <button nz-button nzType="primary" (click)="updatesite_OK()">{{"i18nTextDefine_Add" | translate}}</button> + </div> + </div> + <div class="mask" *ngIf="sotnVpnDetailShow || siteDetail || sotnVpnAddModelShow || siteAddModelShow" + (click)="hiddenModel()"></div> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts new file mode 100644 index 00000000..3d112bf8 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.spec.ts @@ -0,0 +1,69 @@ +/* + Copyright (C) 2018 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { HttpClientModule } from '@angular/common/http'; +import { NZ_I18N, en_US } from 'ng-zorro-antd'; +import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader } from '@ngx-translate/core'; + +import { CcvpnDetailComponent } from './ccvpn-detail.component'; +import { MyhttpService } from '../../core/services/myhttp.service'; + +describe('CcvpnDetailComponent', () => { + let component: CcvpnDetailComponent; + let fixture: ComponentFixture<CcvpnDetailComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [CcvpnDetailComponent], + imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }), + NgZorroAntdModule.forRoot(), HttpClientModule], + providers: [MyhttpService, { provide: NZ_I18N, useValue: en_US }] + }) + .compileComponents(); + })); + + beforeEach(() => { + let detailshow = false; + detailData: Object; + let serviceDetail = (service) => { + service["siteSer"] = []; + service["sdwanSer"] = []; + service["customer"] = this.customerSelected; + service["serviceType"] = this.serviceTypeSelected; + + service.childServiceInstances.forEach((item) => { + if (item.serviceDomain == "SITE") { + service.siteSer.push(item); + } else if (item.serviceDomain == "SDWAN") { + service.sdwanSer.push(item); + } + }) + this.detailshow = true; + this.detailData = service; + component.detailParams = this.detailData + fixture = TestBed.createComponent(CcvpnDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }; + + it('should create', () => { + console.log(component); + expect(component).toBeTruthy(); + }); + }); + +}); diff --git a/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts new file mode 100644 index 00000000..109c143b --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-detail/ccvpn-detail.component.ts @@ -0,0 +1,815 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { MyhttpService } from '../../core/services/myhttp.service'; +import * as d3 from 'd3'; + +@Component({ + selector: 'app-ccvpn-detail', + templateUrl: './ccvpn-detail.component.html', + styleUrls: ['./ccvpn-detail.component.css'] +}) +export class CcvpnDetailComponent implements OnInit { + + constructor(private myhttp: MyhttpService) { } + + ngOnInit() { + this.dataInit(); + this.drawImages(); + } + + @Input() detailParams; + @Input() upDateShow; + @Output() closeDetail = new EventEmitter(); + @Output() closeUpdate = new EventEmitter(); + + tabBarStyle = { + "height": "58px", + "width": "694px", + "box-shadow": "none", + "margin": "0", + "border-radius": "4px 4px 0px 0px" + }; + input_parameters: any; + templateParameters = { + service: {}, + sotnvpn: { + // info: {}, + sdwanvpnresource_list: [], + sdwansitelan_list: [] + }, + site: { + // info: {}, + sdwansiteresource_list: [], + sdwandevice_list: [], + sdwansitewan_list: [] + } + }; + bodyTemplateParameter = {}; + + // SOTN VPN List + sotnVpnTableData = []; + sotnInfo = {};//sotnmodel The first part of sotnInfo + sotnSdwansitelanData = [];//sotnmodel The second part of the data sdwansitelan Table + sotnSdwansitelanParams = {};//sdwansitelan Table Detailed parameters of each line of data + tabInputShowSdwansitelan = [];//sdwansitelan table input and span + // Site List + siteTableData = []; + siteBaseData = {}; //sitemodel one sdwansiteresource_list + // cpe + siteSdwanDevice = []; //sitemodel SdwanDevice port Table data + siteCpeData = {}; //sitemodel two sdwandevice_list + tabInputShowDevice = [];//Device port input and span + // Wan Port + siteWanData = []; //sitemodel three wan port Table data + siteWanParams = {}; //wan port Table Detailed parameters of each line of data + tabInputShowWanPort = [];//wan port table input and span + sitenum = []; + sotnvpnnum = []; + + getKeys(item) { + return Object.keys(item); + } + //tabBarStyle + dataInit() { + console.log(this.detailParams); + // this.input_parameters = JSON.stringify(this.detailParams['input-parameters']) + if (this.detailParams['input-parameters']) { + this.input_parameters = JSON.parse(this.detailParams['input-parameters']); + } else { + return false; + } + console.log(this.input_parameters); + this.templateParameters.service = { + name: this.input_parameters.service.name, + description: this.input_parameters.service.description, + serviceInvariantUuid: this.input_parameters.service["serviceInvariantUuid"], + serviceUuid: this.input_parameters.service["serviceUuid"] + }; + let inputs = this.input_parameters.service.parameters.requestInputs; + + Object.keys(inputs).map((items) => { + if (items.search("vpn") != -1) { + this.bodyTemplateParameter[items] = []; + inputs[items].map((item, index) => { + this.sotnVpnTableData.push(item); + this.sotnvpnnum.push(false); + }); + let sdwanvpnresource_list = inputs[items][0]; + Object.keys(sdwanvpnresource_list).forEach((its) => { + let input = {}; + if (its.search("site") != -1 && sdwanvpnresource_list[its] instanceof Array === true) { + Object.keys(sdwanvpnresource_list[its][0]).forEach((i) => { + let input1 = {}; + input1[i] = sdwanvpnresource_list[its][i]; + this.templateParameters["sotnvpn"]["sdwansitelan_list"].push(input1); + }) + let sitelanKey = {}; + sitelanKey[its] = []; + this.bodyTemplateParameter[items].push(sitelanKey); + } + if (its.search("sitelan") == -1 && sdwanvpnresource_list[its] instanceof Array === false) { + input[its] = sdwanvpnresource_list[its]; + this.templateParameters["sotnvpn"]["sdwanvpnresource_list"].push(input); + } + }); + } + if (items.search("site") != -1) { + this.bodyTemplateParameter[items] = []; + inputs[items].map((item, index) => { + this.siteTableData.push(item); + this.sitenum.push(false); + }); + let sdwansiteresource_list = inputs[items][0]; + Object.keys(sdwansiteresource_list).forEach((its) => { + let input2 = {}; + if (its.search("device") != -1 && sdwansiteresource_list[its] instanceof Array === true) { + this.templateParameters["site"]["sdwandevice_list"][0] = sdwansiteresource_list[its][0]; + let sitelanKey = {}; + sitelanKey[its] = []; + this.bodyTemplateParameter[items].push(sitelanKey); + } + if (its.search("site") != -1 && its.search("device") == -1 && sdwansiteresource_list[its] instanceof Array === true) { + this.templateParameters["site"]["sdwansitewan_list"][0] = sdwansiteresource_list[its][0]; + let sitelanKey = {}; + sitelanKey[its] = []; + this.bodyTemplateParameter[items].push(sitelanKey); + } + if (its.search("device") == -1 && sdwansiteresource_list[its] instanceof Array === false) { + input2[its] = sdwansiteresource_list[its]; + this.templateParameters["site"]["sdwansiteresource_list"].push(input2); + } + }); + + } + }); + + console.log(this.templateParameters.site); + console.log(this.siteTableData); + + this.showTemParametersSotnVpn(); + this.showTemParametersSite(); + + } + + //sotnVpn data, after combining the structure, rendering the template data to the page + showTemParametersSotnVpn() { + //sotn Data analysis, structure assembly + this.templateParameters.sotnvpn.sdwanvpnresource_list.map((item, index) => { + let input = {}; + for (let keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + item["lableShow"] = keys.split("_")[1]; + this.sotnInfo = Object.assign(this.sotnInfo, input); + } + } + }); + + this.templateParameters.sotnvpn.sdwansitelan_list.map((item, index) => { + let input = {}; + for (let keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + this.sotnSdwansitelanParams = Object.assign(this.sotnSdwansitelanParams, this.sotnSdwansitelanParams, input); + } + } + }); + this.sotnSdwansitelanData.push(this.sotnSdwansitelanParams); + this.sotnSdwansitelanData.map((item, index) => { + this.tabInputShowSdwansitelan[index] = true; + }); + } + + //Site data, after combining the structure, rendering the template to the page + showTemParametersSite() { + //site Data analysis, structure assembly + this.templateParameters.site.sdwansiteresource_list.map((item, index) => { + let input = {}; + for (let keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + item["lableShow"] = keys.split("_")[1]; + this.siteBaseData = Object.assign(this.siteBaseData, input); + } + } + }); + + this.templateParameters.site.sdwandevice_list.map((item, index) => { + let input = {}; + for (let keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + this.siteCpeData = Object.assign(this.siteCpeData, input); + } + } + }); + this.templateParameters.site.sdwandevice_list.map((item, index) => { + if (this.getKeys(item).indexOf("lable") == -1) { + this.templateParameters.site.sdwandevice_list.splice(index, 1) + } + }); + this.templateParameters.site.sdwansitewan_list.map((item, index) => { + let input = {}; + for (let keys in item) { + if (keys != "required" && keys != "type" && keys != "description") { + input[keys] = item[keys]; + item["lable"] = keys; + this.siteWanParams = Object.assign(this.siteWanParams, this.siteWanParams, input); + } + } + }); + this.siteSdwanDevice.push(this.siteCpeData); + this.siteSdwanDevice.map((item, index) => { + this.tabInputShowDevice[index] = true; + }); + this.siteWanData.push(this.siteWanParams); + this.siteWanData.map((item, index) => { + this.tabInputShowWanPort[index] = true; + }); + } + + //sotnVpn detail show + sotnVpnDetailShow = false; + isEditSotnVpn = 0; + showstonVpnDetail(num) { + this.sotnVpnDetailShow = true; + this.isEditSotnVpn = num; + Object.keys(this.sotnInfo).forEach((item) => { + this.sotnInfo[item] = this.sotnVpnTableData[num - 1][item]; + }); + this.sotnSdwansitelanData = this.sotnVpnTableData[num - 1].sdwansitelan_list.map((item) => { + return Object.assign({}, {}, item) + }); + } + detailSotnVpn_cancel() { + this.sotnVpnDetailShow = false; + } + + // site detail show + siteDetail = false; + isEditSite = 0; + showSiteDetail(num) { + this.siteDetail = true; + this.isEditSite = num; + console.log(this.siteTableData[num - 1]); + Object.keys(this.siteBaseData).forEach((item) => { + this.siteBaseData[item] = this.siteTableData[num - 1][item]; + }); + this.siteSdwanDevice = this.siteTableData[num - 1].sdwandevice_list.map((item) => { + return Object.assign({}, {}, item) + }); + this.siteWanData = this.siteTableData[num - 1].sdwansitewan_list.map((item) => { + return Object.assign({}, {}, item) + }); + } + detailsite_cancel() { + this.siteDetail = false; + } + deleteUpdateSite(num) { + this.siteTableData = this.siteTableData.filter((d, i) => i !== num - 1); + this.sitenum.splice(num - 1, 1); + } + + //sotnVpn addModel + sotnVpnAddModelShow = false; + + updateSotnVpn_OK() { + let inputs = { + "sdwansitelan_list": [] + }; + inputs = Object.assign(inputs, this.sotnInfo); + inputs["sdwansitelan_list"] = this.sotnSdwansitelanData.map((item) => { + return Object.assign({}, item); + }); + if (this.isEditSotnVpn) { + + this.sotnVpnTableData[this.isEditSotnVpn - 1] = inputs; + this.sotnVpnTableData = [...this.sotnVpnTableData]; + } else { + // this.siteTableData.push(inputs); + this.sotnVpnTableData = [...this.sotnVpnTableData, inputs]; + this.sotnvpnnum = [...this.sotnvpnnum, true]; + } + Object.keys(this.sotnInfo).forEach((item) => { + this.sotnInfo[item] = null; + }); + this.sotnSdwansitelanData.forEach((item, index) => { + if (index > 0) { + this.sotnSdwansitelanData.splice(index, 1); + this.tabInputShowSdwansitelan.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowSdwansitelan[index] = true; + } + + }); + this.sotnVpnAddModelShow = false; + } + + updateSotnVpn_cancel() { + Object.keys(this.sotnInfo).forEach((item) => { + this.sotnInfo[item] = null; + }); + this.sotnSdwansitelanData.forEach((item, index) => { + if (index > 0) { + this.sotnSdwansitelanData.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowSdwansitelan[index] = true; + } + + }); + this.sotnVpnAddModelShow = false; + } + + editUpdateSotnVpn(num) { + this.sotnVpnAddModelShow = true; + this.isEditSotnVpn = num; + Object.keys(this.sotnInfo).forEach((item) => { + this.sotnInfo[item] = this.sotnVpnTableData[num - 1][item]; + }); + this.sotnSdwansitelanData = this.sotnVpnTableData[num - 1].sdwansitelan_list.map((item) => { + return Object.assign({}, {}, item) + }); + this.sotnSdwansitelanData.forEach((item, index) => { + this.tabInputShowSdwansitelan[index] = false; + }); + } + + deleteUpdateSotnVpn(num) { + this.sotnVpnTableData = this.sotnVpnTableData.filter((d, i) => i !== num - 1); + this.sotnvpnnum.splice(num - 1, 1); + } + updateSotnSdwansitelan() { + if (this.tabInputShowSdwansitelan.indexOf(true) > -1) { + return false; + } + let addNum = this.sotnSdwansitelanData.length; + let inputsData = Object.assign({}, this.sotnSdwansitelanParams); + Object.keys(inputsData).forEach((item) => { + if (item != "description") { + inputsData[item] = null; + } + }); + this.sotnSdwansitelanData[addNum] = inputsData; + this.tabInputShowSdwansitelan[addNum] = true; + this.sotnSdwansitelanData = [...this.sotnSdwansitelanData]; + } + editUpdateSotnSdwansitelan(num, item, sotnSdwansitelanData) { + if (this.tabInputShowSdwansitelan[num - 1] == false) { + this.tabInputShowSdwansitelan[num - 1] = true; + } else { + this.tabInputShowSdwansitelan[num - 1] = false; + } + } + deleteUpdateSotnSdwansitelan(num, item, sotnSdwansitelanData) { + if (this.sotnSdwansitelanData.length <= 1) { + return false; + } else { + + } + this.sotnSdwansitelanData = this.sotnSdwansitelanData.filter((d, i) => i !== num - 1); + } + + // site addModel + siteAddModelShow = false; + + updateSotnvpn() { + this.sotnVpnAddModelShow = true; + this.isEditSotnVpn = 0; + } + + updateSite() { + this.siteAddModelShow = true; + this.isEditSite = 0; + } + + editUpdateSite(num) { + this.siteAddModelShow = true; + this.isEditSite = num; + Object.keys(this.siteBaseData).forEach((item) => { + this.siteBaseData[item] = this.siteTableData[num - 1][item]; + }); + this.siteSdwanDevice = this.siteTableData[num - 1].sdwandevice_list.map((item) => { + return Object.assign({}, item) + }); + this.siteSdwanDevice.forEach((item, index) => { + this.tabInputShowDevice[index] = false; + }); + this.siteWanData = this.siteTableData[num - 1].sdwansitewan_list.map((item) => { + return Object.assign({}, item) + }); + this.siteWanData.forEach((item, index) => { + this.tabInputShowWanPort[index] = false; + }); + } + + updatesite_cancel() { + Object.keys(this.siteBaseData).forEach((item) => { + this.siteBaseData[item] = null; + }) + this.siteSdwanDevice.forEach((item, index) => { + if (index > 0) { + this.siteSdwanDevice.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowDevice[index] = true; + } + + }); + this.siteWanData.forEach((item, index) => { + if (index > 0) { + this.siteWanData.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowWanPort[index] = true; + } + + }); + this.siteAddModelShow = false; + } + + updatesite_OK() { + let inputs = { + "sdwandevice_list": [], + "sdwansitewan_list": [] + }; + inputs = Object.assign(inputs, this.siteBaseData); + inputs["sdwandevice_list"] = this.siteSdwanDevice.map((item) => { + return Object.assign({}, item); + }); + inputs["sdwansitewan_list"] = this.siteWanData.map((item) => { + return Object.assign({}, item); + }); + if (this.isEditSite) { + // Edit status does not increase + this.siteTableData[this.isEditSite - 1] = inputs; + this.siteTableData = [...this.siteTableData]; //Table refresh + } else { + // this.siteTableData.push(inputs); + this.siteTableData = [...this.siteTableData, inputs]; + this.sitenum = [...this.sitenum, true]; + } + + Object.keys(this.siteBaseData).forEach((item) => { //Clear modal box + this.siteBaseData[item] = null; + }); + this.siteSdwanDevice.forEach((item, index) => { + if (index > 0) { + this.siteSdwanDevice.splice(index, 1); + this.tabInputShowDevice.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowDevice[index] = true; + } + + }); + this.siteWanData.forEach((item, index) => { + if (index > 0) { + this.siteWanData.splice(index, 1); + this.tabInputShowWanPort.splice(index, 1); + } else { + Object.keys(item).forEach((item2) => { + item[item2] = null; + }); + this.tabInputShowWanPort[index] = true; + } + + }); + console.log(this.siteTableData); + this.siteAddModelShow = false; + } + + //add.edit,detele siteWanPort + updateSiteWan() { + if (this.tabInputShowWanPort.indexOf(true) > -1) {//Adding new rows is not allowed when there is a row of data being edited + return false; + } + let addNum = this.siteWanData.length; + let inputsData = Object.assign({}, this.siteWanParams); + Object.keys(inputsData).forEach((item) => {//Add a new line of empty data + if (item != "description") { + inputsData[item] = null; + } + }); + this.siteWanData[addNum] = inputsData; + this.tabInputShowWanPort[addNum] = true; + this.siteWanData = [...this.siteWanData]; //Table refresh + console.log(this.siteWanData) + } + + editUpdateWanPort(num, item, siteWanData) { + if (this.tabInputShowWanPort[num - 1] == false) { + this.tabInputShowWanPort[num - 1] = true; + } else { + this.tabInputShowWanPort[num - 1] = false; + } + } + + deleteUpdateWanPort(num, item, siteWanData) { + if (this.siteWanData.length <= 1) { + return false; + } + this.siteWanData = this.siteWanData.filter((d, i) => i !== num - 1); + } + + // site节点图形描绘 + // site分类,根据site查tp pnf --> allotted-resource + localSite = [];//本地site + outerSite = [];//外部site + + getSiteAResource() { + return new Promise((res, rej) => { + this.detailParams.siteSer.forEach((site) => { + site["relationship-list"]["relationship"].find((item) => { return item["related-to"] == "site-resource" }) ? this.localSite.push(site) : this.outerSite.push(site); + }); + + if (this.localSite[0] && this.localSite[0]["service-instance-name"].startsWith("Dc")) { + this.localSite.reverse(); + } + + if (this.outerSite[0] && this.outerSite[0]["service-instance-name"].startsWith("Dc")) { + this.outerSite.reverse(); + } + if (this.localSite.length > 0) { + this.detailLines = [].concat(this.detailLiness); + this.localSite.forEach((site) => { + let obj = { + customerId: this.detailParams.customer.id, + serviceType: this.detailParams.serviceType, + serviceId: site["service-instance-id"] + }; + this.myhttp.getAllottedResource(obj) + .subscribe((data) => { + let resource = data["allotted-resource"].find((item) => { return item["allotted-resource-name"] == "sotn ar" }); + let tps_pnfs = resource["relationship-list"]["relationship"].find((item) => { return item["related-to"] == "p-interface" })["relationship-data"]; + site.tpsitename = tps_pnfs.find((item) => { return item["relationship-key"] == "p-interface.interface-name" })["relationship-value"]; + res("sites-domain"); + }) + }) + } else { + return false; + } + }) + } + + + vpns = [{ name: "", tps: [], domain: "", sitetpname: "", othertpname: "" }]; + + + getSotnAresource() { + return new Promise((res, rej) => { + let connectivityId = this.detailParams["relationship-list"]["relationship"] + .find((item) => { + return item["related-to"] == "connectivity" + })["relationship-data"] + .find((item2) => { + return item2["relationship-key"] == "connectivity.connectivity-id" + })["relationship-value"]; + this.myhttp.getSotnConnectivity(connectivityId) + .subscribe((data) => { + let vpns = data.connectivity[0]["relationship-list"]["relationship"] + .filter((item) => { + return item["related-to"] == "vpn-binding" + }) + .map((item2) => { + return item2["relationship-data"].find((item3) => { + return item3["relationship-key"] == "vpn-binding.vpn-id" + })["relationship-value"] + }); + console.log(vpns); + this.detailParams.vpns = vpns.map((item) => { + return { name: item } + }); + this.detailParams.vpns.forEach((vpn, index) => { + this.myhttp.getVpnBinding(vpn.name) + .subscribe((data2) => { + let tps_pnfs = data2["vpn-binding"][0]["relationship-list"]["relationship"] + .filter((item) => { + return item["related-to"] == "p-interface" + }) + .map((item2) => { + return item2["relationship-data"] + }); + let pnfname = tps_pnfs.map((item) => { + return item.find((item2) => { + return item2["relationship-key"] == "pnf.pnf-name" + })["relationship-value"] + }); + let tpnames = tps_pnfs.map((item) => { + return item.find((item2) => { + return item2["relationship-key"] == "p-interface.interface-name" + })["relationship-value"] + }); + vpn.tps = tpnames; + this.myhttp.getPnfDetail(pnfname[0]) + .subscribe((data2) => { + let networkRelation = data2["relationship-list"]["relationship"].find((item) => { + return item["related-to"] == "network-resource" + })["relationship-data"]; + vpn.domain = networkRelation.find((item) => { + return item["relationship-key"] == "network-resource.network-id" + })["relationship-value"]; + if (this.localSite[index]) { + vpn.sitetpname = this.localSite.find((site) => { + return tpnames.includes(site.tpsitename) + }).tpsitename; + console.log(tpnames); + console.log(vpn.sitetpname); + vpn.othertpname = tpnames.find((name) => { + return name != vpn.sitetpname + }); + } else { + vpn.sitetpname = this.localSite[0].tpsitename; + vpn.othertpname = tpnames.find((name) => { + return name != vpn.sitetpname + }); + } + + this.vpns = this.detailParams.vpns; + console.log(this.vpns) + res(this.detailParams.vpns) + }) + console.log(this.detailParams.vpns) + }) + }) + }) + }) + } + + + drawImages() { + + this.getSiteAResource().then((data) => { + return this.getSotnAresource() + }).then((data) => { + this.detailSites = this.detailParams.serviceDomain == "CCVPN" ? false : true; + // When there is only one vpn + if (this.detailParams.serviceDomain == "CCVPN" && this.vpns.length == 1) { + this.detailLines.length = this.detailLines.length - 3; + // this.detailLines.push(line); + // when local site have 2 + if (this.localSite.length == 2) { + let line = { + "x1": "30%", "y1": "55%", "x2": "42%", "y2": "55%"//tp2--tp3 + } + this.detailLines.push(line); + } + // when cloud site have 2 + if (this.outerSite.length == 2) { + let line = { + "x1": "81%", "y1": "21%", "x2": "90%", "y2": "21%"//out-domain--site3 + }; + this.detailLines.push(line); + } + } + }) + let allnodes = [this.getSiteAResource(), this.getSotnAresource()]; + Promise.all(allnodes).then((data) => { + console.log(data); + console.log(this.localSite); + + + }) + } + + detailSites = false; + detailLines = []; + detailLiness = [ //Details of the topology map connection coordinates + { + "x1": "9%", "y1": "40%", "x2": "21%", "y2": "40%"//site1--tp1 + }, + + { + "x1": "83%", "y1": "51%", "x2": "91%", "y2": "51%"//out-domain--site4 + }, + + { + "x1": "52%", "y1": "81%", "x2": "63%", "y2": "81%"//site2--tp4 + }, + { + "x1": "81%", "y1": "21%", "x2": "90%", "y2": "21%"//out-domain--site3 + }, + { + "x1": "30%", "y1": "55%", "x2": "44%", "y2": "55%"//tp2--tp3 + } + ]; + + modifyJosnKey(json, oddkey, newkey) { + + let val = json[oddkey]; + delete json[oddkey]; + json[newkey] = val; + } + + // ccvpn update + submitUpdate() { + let globalCustomerId = this.detailParams.customer.id; + let globalServiceType = this.detailParams.serviceType.name; + let servicebody = { + service: { + name: this.templateParameters.service["name"], + description: this.templateParameters.service["description"], + serviceInvariantUuid: this.templateParameters.service["serviceInvariantUuid"], + serviceUuid: this.templateParameters.service["serviceUuid"], + globalSubscriberId: globalCustomerId, //customer.id + serviceType: globalServiceType, //serviceType.value + parameters: { + locationConstraints: [], + resources: [], + requestInputs: { + sdwanvpnresource_list: [], + sdwansiteresource_list: [] + } + } + } + }; + let siteresource = null, sitewan = null, device = null, vpnresource = null, sitelan = null; + Object.keys(this.bodyTemplateParameter).map((item, index) => { + if (item.search("site") != -1) { + siteresource = item; + this.bodyTemplateParameter[item].map((items, index) => { + if (Object.keys(items)[0].search("site") != -1 && Object.keys(items)[0].search("device") == -1) { + sitewan = Object.keys(items)[0] + } + if (Object.keys(items)[0].search("device") != -1) { + device = Object.keys(items)[0] + } + }); + } + if (item.search("vpn") != -1) { + vpnresource = item; + this.bodyTemplateParameter[item].map((items, index) => { + if (Object.keys(items)[0].search("site") != -1) { + sitelan = Object.keys(items)[0] + } + }); + } + }); + this.sotnVpnTableData.forEach((item, index) => { + Object.keys(item).map((items, index) => { + if (items.search("site") != -1 && item[items] instanceof Array === true) { + this.modifyJosnKey(item, items, sitelan) + } + }); + }); + this.siteTableData.forEach((item, index) => { + Object.keys(item).map((items, index) => { + if (items.search("site") != -1 && items.search("device") == -1 && item[items] instanceof Array === true) { + this.modifyJosnKey(item, items, sitewan) + } + if (items.search("device") != -1) { + this.modifyJosnKey(item, items, device) + } + }); + }); + Object.keys(this.bodyTemplateParameter).map((item, index) => { + if (item.search("site") != -1) { + servicebody.service.parameters.requestInputs[item] = [].concat(this.siteTableData); + } + if (item.search("vpn") != -1) { + servicebody.service.parameters.requestInputs[item] = [].concat(this.sotnVpnTableData); + } + }); + console.log(servicebody); + this.closeUpdate.emit(servicebody); + } + + goback() { + this.closeDetail.emit(); + } + + hiddenModel() { + this.sotnVpnDetailShow = false; + this.siteDetail = false; + } + +} diff --git a/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css new file mode 100644 index 00000000..5055205d --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.css @@ -0,0 +1,119 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.outer{ + width: 20%; + float: left; +} +.content{ + width: 100px; + margin: 30px 0; +} + +.submit,.delete,.add{ + padding:10px 20px; + width: 100px; + margin: 0 auto; + background: dodgerblue; + border: none; + border-radius: 10px; + color: #fff; + cursor: pointer; +} + +#tpContainer{ + position: relative; + width:100%; + height: 95%; + margin-top: 15px; + float: left; + background: #EEF9FF; +} +#tpContainer .no-network{ + width: 300px; + margin: 0 auto; + height: 280px; + position: absolute; + top: 50%; + left: 50%; + margin-top: -140px; + margin-left: -150px; +} +.no-network img{ + width: 100%; +} +.no-network p{ + text-align: center; + color: #A0AACD; + font-size: 18px; + margin-top: 20px; +} +.model { + position: relative; + padding: 15px; + height: 100vh; + width: 100%; +} +.model h2{ + display: inline-block; + margin: 0; + color: #3C4F8C; + margin-left: 10px; + display: inline-block; +} +.model .title-modelshow{ + color: #A0AACD; +} +.model .creation { + /*margin-top:-4%;*/ + background-color: #fff; + /*float: left;*/ + width: 20%; + position: absolute; + left: 0; + margin-top: 30px; + margin-left: 30px; + border-radius: 5px; + box-shadow: 0 0 10px #9e9e9e; + padding: 10px; + height: 80vh; + overflow: auto; +} +.model .creation .v_color{ + height: 17px; + float: left; + margin-left: -11px; + margin-top: 5px; + border-left: 4px #3fa8eb solid; +} +.w_font4{ + font-weight: 400; +} +.title-span{ + margin-left: 10%; + font-size: 12px; +} +.red-span{ + color: red; + margin-right: 3px; +} +.choose li nz-select,.choose li input{ + display: block !important; + margin: 5px 10% 15px; + width: 80%; +} + + + diff --git a/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.html b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.html new file mode 100644 index 00000000..25687f67 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.html @@ -0,0 +1,152 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<nz-spin [nzSpinning]="isSpinning" nzSize="large"> +<div class="model"> + <!--chart--> + <button nz-button nzType="primary" *ngIf="!nonetwork" style="margin-top: 2px;display: inline-block" (click)="showForm()" + [disabled]='isVisible' [attr.disabled] ='isVisible?true:undefined'> + {{"i18nTextDefine_CreateLink" | translate}} + </button> + <h2 *ngIf="!nonetwork" [ngClass]="{'title-modelshow':isVisible == true}"> + Please configure network links for registered devices and partner system. + </h2> + <div id="tpContainer" style="overflow: hidden;"> + <div *ngIf="nonetwork" style="padding: 20px"> + <h2> + There is not any terminal device can be used for configuration + </h2> + <br> + <h2> + please register external network into ONAP. + </h2> + </div> + <div class="no-network" *ngIf="nonetwork"> + <img src="assets/images/no-network-available.png" alt="No network available"> + <p>No network available</p> + </div> + </div> + <!--Popup--> + <div class="creation" id="d3_form" *ngIf="isVisible==true"> + <span class="v_color"></span> + <h3 class="w_font4"> {{"i18nTextDefine_SetAttribtes" | translate}} </h3> + <ul class="choose"> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_LinkName" | translate}} </span> + <input nz-input [(ngModel)]="linkName" maxlength="20"> + </li> + </ul> + <h4> {{"i18nTextDefine_LeftPort" | translate}} </h4> + <ul class="choose"> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_Network" | translate}} </span> + <nz-select [(ngModel)]="networkVal1" nzShowSearch nzAllowClear (ngModelChange)="network1Change($event)"> + <nz-option *ngFor="let option of networkOption" [nzLabel]="option.network" [nzValue]="option.network"></nz-option> + </nz-select> + </li> + <li> + <span class="title-span"> <span class="red-span">*</span> {{"i18nTextDefine_Node" | translate}} </span> + <nz-select [(ngModel)]="selectedNode1" nzShowSearch nzAllowClear (ngModelChange)="node1Change($event)"> + <nz-option *ngFor="let node of nodeOption1[networkVal1]" [nzValue]="node" [nzLabel]="node"></nz-option> + </nz-select> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <!-- <input nz-input id="city-one" value=""> --> + <nz-select [(ngModel)]="selecteTpName1" nzShowSearch nzAllowClear> + <nz-option *ngFor="let tp of tpOption1" [nzValue]="tp" [nzLabel]="tp"></nz-option> + </nz-select> + </li> + </ul> + <h4> {{"i18nTextDefine_RightPort" | translate}} </h4> + <label nz-checkbox [(ngModel)]="inputshow"> {{"i18nTextDefine_PartnerNetwork" | translate}} </label> + <ul class="choose"> + <li> + <span class="title-span"><span *ngIf="inputshow" class="red-span">*</span> {{"i18nTextDefine_HostUrl" | translate}} </span> + <input nz-input [(ngModel)]="cloudUrl" [disabled]='!inputshow' [attr.disabled] ='!inputshow?true:undefined'> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_Network" | translate}} </span> + <input nz-input *ngIf="inputshow" [(ngModel)]="cloudNetwork"> + <nz-select *ngIf="!inputshow" [(ngModel)]="networkVal2" nzShowSearch nzAllowClear (ngModelChange)="network2Change($event)"> + <nz-option *ngFor="let option of networkOption" [nzLabel]="option.network" [nzValue]="option.network"> </nz-option> + </nz-select> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_Node" | translate}} </span> + <input nz-input *ngIf="inputshow" [(ngModel)]="cloudNode"> + <nz-select *ngIf="!inputshow" [(ngModel)]="selectedNode2" nzShowSearch nzAllowClear (ngModelChange)="node2Change($event)"> + <nz-option *ngFor="let node of nodeOption1[networkVal2]" [nzValue]="node" [nzLabel]="node"></nz-option> + </nz-select> + </li> + <li> + <span class="title-span"><span class="red-span">*</span> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <input nz-input *ngIf="inputshow" [(ngModel)]="cloudTp"> + <nz-select *ngIf="!inputshow" [(ngModel)]="selecteTpName2" nzShowSearch nzAllowClear> + <nz-option *ngFor="let tp of tpOption2" [nzValue]="tp" [nzLabel]="tp"></nz-option> + </nz-select> + </li> + </ul> + <button nz-button nzType="primary" nzSize="small" style="width: 60px;" (click)="submitForm()"> {{"i18nTextDefine_modelOk" | translate}} </button> + <button nz-button nzType="default" nzSize="small" style="width: 60px;" (click)="hideForm()"> {{"i18nTextDefine_Cancel" | translate}} </button> + </div> + <div class="creation" id="delbox" *ngIf="delBoxisVisible==true"> + <span class="v_color"></span> + <ul class="choose"> + <li> + <span class="title-span"> {{"i18nTextDefine_LinkName" | translate}} </span> + <input nz-input [(ngModel)]="delLinkname" disabled="disabled"> + </li> + </ul> + <h4> {{"i18nTextDefine_LeftPort" | translate}} </h4> + <ul class="choose"> + <li> + <span class="title-span"> {{"i18nTextDefine_Network" | translate}} </span> + <input nz-input [(ngModel)]="delNetwork1" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_Node" | translate}} </span> + <input nz-input [(ngModel)]="delNode1" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <input nz-input [(ngModel)]="delTp1" disabled="disabled"> + </li> + </ul> + <h4> {{"i18nTextDefine_RightPort" | translate}} </h4> + <ul class="choose"> + <li *ngIf="delcloud"> + <span class="title-span"> {{"i18nTextDefine_HostUrl" | translate}} </span> + <input nz-input [(ngModel)]="delcloudUrl" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_Network" | translate}} </span> + <input nz-input [(ngModel)]="delNetwork2" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_Node" | translate}} </span> + <input nz-input [(ngModel)]="delNode2" disabled="disabled"> + </li> + <li> + <span class="title-span"> {{"i18nTextDefine_TerminalPoint" | translate}} </span> + <input nz-input [(ngModel)]="delTp2" disabled="disabled"> + </li> + </ul> + <button nz-button nzType="primary" nzSize="small" class="del-button" style="width: 90px;" (click)="delLink()" *ngIf="!delcloud"> {{"i18nTextDefine_DeleteLink" | translate}} </button> + <button nz-button nzType="primary" nzSize="small" class="del-button" style="width: 90px;" (click)="delCloudLink()" *ngIf="delcloud"> {{"i18nTextDefine_deleteLink" | translate}} </button> + <button nz-button nzType="default" nzSize="small" class="del-button" style="width: 60px;" (click)="hideForm()"> {{"i18nTextDefine_Cancel" | translate}} </button> + </div> +</div> +</nz-spin> diff --git a/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.spec.ts b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.spec.ts new file mode 100644 index 00000000..9ec321c5 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.spec.ts @@ -0,0 +1,40 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CcvpnNetworkComponent } from './ccvpn-network.component'; + +describe('CcvpnNetworkComponent', () => { + let component: CcvpnNetworkComponent; + let fixture: ComponentFixture<CcvpnNetworkComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CcvpnNetworkComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CcvpnNetworkComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.ts b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.ts new file mode 100644 index 00000000..8a56d885 --- /dev/null +++ b/usecaseui-portal/src/app/views/ccvpn-network/ccvpn-network.component.ts @@ -0,0 +1,1270 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import * as d3 from 'd3'; +import * as $ from 'jquery'; +import { networkHttpservice } from '../../core/services/networkHttpservice.service'; + +@Component({ + selector: 'app-ccvpn-network', + templateUrl: './ccvpn-network.component.html', + styleUrls: ['./ccvpn-network.component.css'] +}) +export class CcvpnNetworkComponent implements OnInit { + + constructor(private myhttp: networkHttpservice) { + } + + ngOnInit() { + let thisNg = this; + thisNg.getD3Data(); + + + //Local cloud TP port connection, click on the right to expand the details + $('#tpContainer').on('click', '.line-port', function () { + thisNg.isVisible = false; + thisNg.delBoxisVisible = true; + thisNg.delcloud = false; + + thisNg.delTp1 = $(this).attr('data-tp1'); + thisNg.delTp2 = $(this).attr('data-tp2'); + thisNg.delNode1 = $(this).attr('data-node1'); + thisNg.delNode2 = $(this).attr('data-node2'); + thisNg.delVersion = $(this).attr('data-version'); + thisNg.delLinkname = $(this).attr('data-link'); + thisNg.delcloudUrl = null; + thisNg.delLinkIndex = $(this); + + let dataD3 = thisNg.d3Data; + for (let p = 0; p < dataD3.length; p++) {//Determine which Domain network the two tp ports belong to + if (dataD3[p]['name'] == thisNg.delTp1) { + thisNg.network.push(dataD3[p]['source']['name']); + } + if (dataD3[p]['name'] == thisNg.delTp2) { + thisNg.network.push(dataD3[p]['source']['name']); + } + } + thisNg.delNetwork1 = thisNg.network[0]; + thisNg.delNetwork2 = thisNg.network[1]; + }); + + //External cloud connection, click on the right to expand the details + $('#tpContainer').on('click', '.cloudline', function () { + thisNg.isVisible = false; + thisNg.delBoxisVisible = true; + thisNg.delcloud = true; + + thisNg.delTp1 = $(this).attr('data-tp1'); + thisNg.delTp2 = $(this).attr('data-tp2'); + thisNg.delNode1 = $(this).attr('data-node1'); + thisNg.delNode2 = $(this).attr('data-node2'); + thisNg.delVersion = $(this).attr('data-version'); + thisNg.delNetwork1 = $(this).attr('data-network'); + thisNg.delNetwork2 = $(this).attr('data-cloudnetwork'); + thisNg.delcloudUrl = $(this).attr('data-url'); + thisNg.delLinkname = $(this).attr('data-link'); + thisNg.aaiId = $(this).attr('data-aaiid'); + thisNg.getCloudUrl(thisNg.aaiId); + }); + } + + addLinkDisabled = true; + nonetwork = false; + isVisible = false; + outCloudShow = false; + inputshow = false; + delBoxisVisible = false; + isSpinning = true; + + d3Data = [];//D3Render the required data + logicalLinks = [];//logicalLinks Existing connection data returned by the interface + linkName = null;//Linked name link-name + networkOption = [];//Form network drop-down box filled data + nodeOption1 = {};//Node drop-down box filled data + tpOption1 = [];//Node drop-down box filled data + tpOption2 = [];//Node drop-down box filled data + networkVal1 = null;//network1 Drop-down box default data + networkVal2 = null;//network2 Drop-down box default data + selectedNode1 = null;//node1 Drop-down box default data + selectedNode2 = null;//node2 Drop-down box default data + selecteTpName1 = null;//TP1 Drop-down box default data + selecteTpName2 = null;//TP2 Drop-down box default data + cloudUrl = null;//External cloud URL address + cloudNetwork = null;//External cloud network name + cloudNode = null;//External cloud Node name + cloudTp = null;//External cloud Tp name + + dataCloud = [];//External cloud information + dataCloudLink = []; + aaiId = ''; + + + //When the connection is deleted, the data displayed in the right frame + delLinkname = null; + delNetwork1 = null; + delNode1 = null; + delTp1 = null; + delcloudUrl = null; + delNetwork2 = null; + delNode2 = null; + delTp2 = null; + delVersion = null; + delLinkIndex = null; + network = []; + delcloud = false; + + winWidth = $('#tpContainer').width(); + winHeight = $('#tpContainer').height(); + charge = -300; + + imgmap = { + '1': 'assets/images/cloud-county1.png', + '2': 'assets/images/tp.png', + '3': 'assets/images/cloud-out.png', + }; + tpoption = { + container: '#tpContainer', + data: '', + width: 1000, + height: this.winHeight + }; + + showForm(): void { + if (this.addLinkDisabled == false) { + this.isVisible = true; + this.delBoxisVisible = false; + } + } + + hideForm(): void { + this.isVisible = false; + this.delBoxisVisible = false; + this.linkName = null; + this.networkVal1 = null;//Initialize the default data of the network1 drop-down box + this.networkVal2 = null;//Initialize the network2 drop-down box default data + this.selectedNode1 = null;//Initialize the default data of the node1 drop-down box + this.selectedNode2 = null;//Initialize the default data of the node2 drop-down box + this.selecteTpName1 = null;//Initialize the default data of the TP1 drop-down box + this.selecteTpName2 = null;//Initialize the default data of the TP2 drop-down box + this.cloudUrl = null;//External cloud URL address + this.cloudNetwork = null;//External cloud network name + this.cloudNode = null;//External cloud Node name + this.cloudTp = null;//External cloud Tp name + } + + //Get cloud image data + getD3Data() { + this.isSpinning = true; + this.myhttp.getNetworkD3Data() + .subscribe((data) => { + this.isSpinning = false; + if (data.length == 0) { + this.addLinkDisabled = false; + this.nonetwork = true; + return; + } + this.nonetwork = false; + for (let ii = 0; ii < data.length; ii++) {//Determine if there is external cloud information in the data, and kick it out. + if (data[ii]['aaiId'] != null) { + this.dataCloud = data.splice(ii, 1); + } + } + + for (let i = 0; i < data.length; i++) { + let name1 = {}, name2 = {}; + let nodess = []; + name1['name'] = name2['network'] = data[i]['networkId']; + name1['type'] = '1'; + name1['source'] = i; + this.d3Data.push(name1); + for (let c = 0; c < data[i]["pnfs"].length; c++) { + nodess.push(data[i]['pnfs'][c]['pnfName']); + this.nodeOption1[name2['network']] = nodess; + } + this.networkOption.push(name2); + } + console.log(this.networkOption); + for (let i = 0; i < data.length; i++) { + let tp_length = data[i]['tps'].length; + for (let h = 0; h < tp_length; h++) { + let name2 = {}; + let interface_name = data[i]['tps'][h]['interface-name']; + name2['name'] = interface_name; + name2['type'] = '2'; + name2['source'] = i; + this.d3Data.push(name2); + } + } + for (let b = 0; b < this.d3Data.length; b++) { + this.d3Data[b]['target'] = b; + } + this.initPosition(this.d3Data); + setTimeout(this.render(this.d3Data, this.imgmap, this.dataCloud, this.charge, data), 0); + }, (err) => { + console.log(err); + }); + + } + + //Get the initial connection status of the cloud image getlogicalLinksData + getLinksData() { + this.myhttp.getLogicalLinksData() + .subscribe((data) => { + if (data["status"] == "FAILED") { + return; + } + for (let i = 0; i < data["logical-link"].length; i++) {//Determine whether there is an external cloud connection in the obtained connection, and kick it out. + if (data['logical-link'][i]['relationship-list']['relationship'].length > 2) { + this.dataCloudLink = data['logical-link'].splice(i, 1); + } + } + + for (let i = 0; i < data["logical-link"].length; i++) { + let textval = []; + textval[0] = data['logical-link'][i]['relationship-list']['relationship'][0]['relationship-data'][1]['relationship-value'];//tp1 + textval[1] = data['logical-link'][i]['relationship-list']['relationship'][1]['relationship-data'][1]['relationship-value'];//tp2 + textval[2] = data['logical-link'][i]['resource-version'];//version + textval[3] = data['logical-link'][i]['relationship-list']['relationship'][0]['relationship-data'][0]['relationship-value'];//node1 + textval[4] = data['logical-link'][i]['relationship-list']['relationship'][1]['relationship-data'][0]['relationship-value'];//node2 + textval[5] = data['logical-link'][i]['operational-status']; + textval[6] = data['logical-link'][i]['link-name']; + this.logicalLinks.push(textval); + this.chose(textval); + } + console.log(this.logicalLinks); + if (this.dataCloudLink.length > 0) { + this.getcloudLine(this.dataCloudLink); + } + }, (err) => { + console.log(err); + }); + } + + //D3Cloud rendering + render(nodes, imgmap, dataCloud, charge, dataD3) { + let thiss = this; + let _this = this.tpoption, + width = null, + height = _this.height; + if (_this.width > 800) { + width = _this.width; + } else { + width = 800; + } + if (dataD3.length <= 4) { + charge = -300; + } else if (dataD3.length > 4 && dataD3.length <= 6) { + charge = -160; + } else if (dataD3.length > 6 && dataD3.length <= 10) { + charge = -110; + } else { + charge = -100; + } + let svg = d3.select(_this.container).append('svg') + .attr('width', width) + .attr('height', height) + .attr('id', 'content-svg') + .style('pointer-events', 'all') + .style('position', 'absolute') + .style('top', '1%') + .style('right', '2%'), + graph = svg.append('g').attr('class', 'graph').attr('id', 'graph'), + + _g_nodes = graph.selectAll('g.node') + .data(nodes) + .enter() + .append('g') + .style('display', function (d) { + let display = 'block'; + switch (d.type) { + case '1': + display = 'none'; + break; + case '2': + display = 'none'; + break; + default: + break; + } + return display; + }) + .style('cursor', 'pointer') + .attr('class', 'node'), + + _g_lines = graph.selectAll('line.line') + .data(nodes) + .enter() + .append('g') + .style('display', 'none') + .attr('class', 'line'); + + + _g_lines.append('line') + .style('stroke', '#93c62d' + ) + .style('stroke-width', 2); + + _g_nodes.append('image') + .attr('width', function (d) { + let width = 40; + switch (d.type) { + case '1': + width = 4.4 * width; + break; + case '2': + width = 0.12 * width; + break; + default: + break; + } + return width; + }) + .attr('height', function (d) { + let height = 20; + switch (d.type) { + case '1': + height = 3.5 * height; + break; + case '2': + height = 0.2 * height; + break; + default: + break; + } + return height; + }) + .attr('xlink:href', function (d) { + return imgmap[d.type]; + }); + + _g_nodes.append('text') + .text(function (d) { + return d.name; + }) + .style('transform', function (d) { + let x = null; + let y = null; + switch (d.type) { + case '1': + x = 7; + y = -7; + break; + case '2': + x = 1; + y = -2; + break; + default: + break; + } + return 'translate(' + x + '%,' + y + '%)'; + }) + .style('font-size', function (d) { + let size = 14; + switch (d.type) { + case '1': + size = 14; + break; + case '2': + size = 12; + break; + default: + break; + } + return size; + }) + .style('fill', function (d) { + let color = '#666'; + switch (d.type) { + case '1': + color = '#666'; + break; + case '2': + color = '#666'; + break; + default: + break; + } + return color; + }) + .style('font-weight', '500'); + + + //Add custom attributes online + _g_lines.each(function (d, i) { + let _this = d3.select(this); + if (d.name) { + _this.attr('data-text', d.name); + } + }); + + let force = d3.layout.force() + .size([1000, this.winHeight]) + .linkDistance(5) + // .theta(0.6) + .charge(charge) + .nodes(nodes) + .links(nodes) + .start(); + + force.on('tick', function () { + if (force.alpha() <= 0.04) { + + _g_nodes.style('display', function (d) { + let display = 'block'; + switch (d.type) { + case '1': + display = 'block'; + break; + case '2': + display = 'none'; + break; + default: + break; + } + return display; + }); + + nodes.forEach(function (d, i) { + d.x = d.x - 25 < 0 ? 25 : d.x; + d.x = d.x + 25 > width ? width - 25 : d.x; + d.y = d.y - 15 < 0 ? 15 : d.y; + d.y = d.y + 15 > height ? height - 15 : d.y; + }); + + _g_nodes.attr('transform', function (d) { + + let image = d3.select(this).select('image')[0][0], + halfWidth = parseFloat(image.attributes[0]['value']) / 2, + halfHeight = parseFloat(image.attributes[1]['value']) / 2; + let xx = d.x - halfWidth, + yy = d.y - halfHeight; + return 'translate(' + xx + ',' + yy + ')'; + }); + + _g_lines.select('line') + .attr('x1', function (d) { + return d.source.x; + }) + .attr('y1', function (d) { + return d.source.y; + }) + .attr('x2', function (d) { + return d.target.x; + }) + .attr('y2', function (d) { + return d.target.y; + }); + + _g_nodes.select('text').attr('dy', function (d) { + let image = this.previousSibling, + height = parseFloat(image.attributes[1]['value']), + fontSize = 12; + return height + 1.5 * fontSize; + }); + } + }); + + force.on('end', function () { + force.stop(); + if (dataCloud.length > 0) { + thiss.getoutCloud(dataCloud, imgmap); + } + thiss.getLinksData(); + thiss.addLinkDisabled = false; + }); + + }; + + //Topology drag and drop effect + getDragBehavior(force) { + + return d3.behavior.drag() + .origin(function (d) { + return d; + }) + .on('dragstart', dragstart) + .on('drag', dragging) + .on('dragend', dragend); + + function dragstart(d) { + d3.event.sourceEvent.stopPropagation(); + d3.select(this).classed('dragging', true); + force.start(); + } + + function dragging(d) { + d.x = d3.event.x; + d.y = d3.event.y; + } + + function dragend(d) { + d3.select(this).classed('dragging', false); + } + + } + + //Initialize node location + initPosition(datas) { + let origin = [this.tpoption.width / 2, this.tpoption.height / 2]; + let points = this.getVertices(origin, Math.min(this.tpoption.width / 2, this.tpoption.height / 2), datas.length); + datas.forEach((item, i) => { + item.x = points[i].x; + item.y = points[i].y; + }); + } + + //Get anchor points based on polygons + getVertices(origin, r, n) { + if (typeof n !== 'number') return; + let ox = origin[0]; + let oy = origin[1]; + let angle = 30 * n / n; + let i = 0; + let points = []; + let tempAngle = 0; + while (i < n) { + tempAngle = (i * angle * Math.PI) / 180; + points.push({ + x: ox - r * Math.sin(tempAngle), + y: oy - r * Math.cos(tempAngle), + }); + i++; + } + return points; + } + + //Rendering an external cloud + getoutCloud(dataCloud, imgmap) { + let _this = this, + width; + let networkId = dataCloud[0]['networkId']; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + let svg = d3.select('#content-svg'); + svg.append('g').attr('class', 'out').attr('id', 'out').style({ 'display': 'block' }).attr('transform', 'translate(' + (width - 200) + ',0)'); + let out = d3.select('#out'); + out.append('image').style('width', '200').style('height', '118').attr('xlink:href', imgmap['3']); + out.append('text').text(networkId) + .style('transform', 'translate(0,0)') + .style('font-size', '16') + .style('font-weight', '400') + .attr('dx', '40') + .attr('dy', '70') + .style('fill', '#666'); + } + + //External cloud connection + getcloudLine(dataCloudLink) { + let textval = []; + textval[0] = dataCloudLink[0]['relationship-list']['relationship'][0]['relationship-data'][1]['relationship-value'];//tp1 + textval[1] = dataCloudLink[0]['relationship-list']['relationship'][1]['relationship-data'][1]['relationship-value'];//tp2 + textval[2] = dataCloudLink[0]['resource-version'];//version + textval[3] = dataCloudLink[0]['relationship-list']['relationship'][0]['relationship-data'][0]['relationship-value'];//node1 + textval[4] = dataCloudLink[0]['relationship-list']['relationship'][1]['relationship-data'][0]['relationship-value'];//node2 + textval[5] = dataCloudLink[0]['operational-status'];//status + textval[6] = dataCloudLink[0]['relationship-list']['relationship'][2]['relationship-data'][0]['relationship-value'];//aaiId + textval[7] = this.dataCloud[0]['networkId']; + let dataD3 = this.d3Data; + let arr = [ + textval[0], + textval[1] + ]; + for (let p = 0; p < dataD3.length; p++) {//Determine which Domain network the two tp ports belong to + for (let pp = 0; pp < arr.length; pp++) {//Determine which Domain network the two tp ports belong to + if (dataD3[p]['name'] == arr[pp]) { + textval[8] = dataD3[p]['source']['name'];//network1 + } + } + } + textval[9] = dataCloudLink[0]['link-name']; + let lines_json = {}; + let _this = this, + width; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == textval[8]) { + //Get the x, y coordinates of the second level + let translates = $('.node').eq(i).css('transform'); + lines_json['x1'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y1'] = parseFloat(translates.substring(7).split(',')[5]); + lines_json['x2'] = width - 100; + lines_json['y2'] = 100; + } + } + let x1 = lines_json['x1']; + let y1 = lines_json['y1']; + let x2 = lines_json['x2']; + let y2 = lines_json['y2']; + let color = '#14bb58'; + if (textval[5] == 'up') { + color = '#14bb58'; + } else { + color = 'red'; + } + let line = '<line class=\'line cloudline line-click\' stroke=\'' + color + '\' stroke-width=\'2\' style=\'cursor:pointer\'></line>'; + let svg = d3.select('#graph'); + $('.cloudline').remove(); + $('#graph').prepend(line); + $('.cloudline').attr({ + x1: x1 + 100, + y1: y1 + 10, + x2: x2, + y2: y2, + 'data-tp1': textval[0], + 'data-tp2': textval[1], + 'data-version': textval[2], + 'data-node1': textval[3], + 'data-node2': textval[4], + 'data-network': textval[8], + 'data-cloudnetwork': textval[7], + 'data-url': '', + 'data-aaiid': textval[6], + 'data-link': textval[9], + }); + svg.html(svg.html()); + this.getCloudUrl(textval[6]); + this.getExtAAIIdVersion(textval[6]); + } + + + //Query external cloud host url address + getCloudUrl(aaiId) { + this.myhttp.queryCloudUrl(aaiId) + .subscribe((data) => { + this.delcloudUrl = data['service-url']; + $('.cloudline').attr({ + 'data-url': data['service-url'] + }); + }, (err) => { + console.log(err); + }); + } + + //Query external cloud ext-aai-id resource-version + getExtAAIIdVersion(aaiId) { + this.myhttp.queryExtAAIIdVersion(aaiId) + .subscribe((data) => { + this.delVersion = data["resource-version"]; + $('.cloudline').attr({ + 'data-version': data["resource-version"], + }); + }, (err) => { + console.log(err); + }); + } + + + //The right form drop-down box data is filled with three levels of linkage + //Left Port + network1Change(value: string): void { + this.selectedNode1 = this.nodeOption1[value][0]; + this.getPInterfaces1(); + } + + node1Change(): void { + this.getPInterfaces1(); + } + + //Get the TP data under the specified node + getPInterfaces1() { + let params = { + pnfName: this.selectedNode1, + }; + this.myhttp.getPInterfacesData1(params) + .subscribe((data) => { + this.tpOption1 = []; + for (let i = 0; i < data.length; i++) { + let tpName = data[i]['interface-name']; + this.tpOption1.push(tpName); + } + this.selecteTpName1 = this.tpOption1[0]; + }, (err) => { + console.log(err); + }); + } + + //Right Port + network2Change(value: string): void { + this.selectedNode2 = this.nodeOption1[value][0]; + this.getPInterfaces2(); + } + + node2Change(): void { + this.getPInterfaces2(); + } + + //Get the TP data under the specified node + getPInterfaces2() { + let params = { + pnfName: this.selectedNode2, + }; + this.myhttp.getPInterfacesData2(params) + .subscribe((data) => { + this.tpOption2 = []; + for (let i = 0; i < data.length; i++) { + let tpName = data[i]['interface-name']; + this.tpOption2.push(tpName); + } + this.selecteTpName2 = this.tpOption2[0]; + }, (err) => { + console.log(err); + }); + } + + //Submit form, connect + submitForm(): void { + //When the page ONAP is not selected, the local cloud TP connection + let _thiss = this; + if (this.inputshow == false) { + if (this.linkName == null || this.networkVal1 == null || this.selectedNode1 == null || this.selecteTpName1 == null || this.networkVal2 == null || this.selectedNode2 == null || this.selecteTpName2 == null) { + alert('The service port cannot be empty. Please select the port information.'); + return; + } else if (this.networkVal1 == this.networkVal2) { + alert('The TP port under the same cloud service cannot be connected!'); + return; + } + let tp_links = [], + tp1 = this.selecteTpName1, + tp2 = this.selecteTpName2; + for (let i = 0; i < $(".line-port").length; i++) { + let data_text1 = $('.line-port').eq(i).attr('data-tp1'); + let data_text2 = $('.line-port').eq(i).attr('data-tp2'); + tp_links.push(data_text1); + tp_links.push(data_text2); + } + if (tp_links.indexOf(tp1) != -1 || tp_links.indexOf(tp2) != -1) { + alert('This port number connection already exists!'); + return; + } + this.createTpLinks(); + + } else { + //When the page ONAP is selected, the external cloud is created, and the connection is made. + if (this.linkName == null || this.networkVal1 == null || this.selectedNode1 == null || this.selecteTpName1 == null || this.cloudUrl == null || this.cloudNetwork == null || this.cloudNode == null || this.cloudTp == null) { + alert('The service port cannot be empty. Please fill in the complete port information.'); + return; + } + let tp_links = [], + tp1 = this.selecteTpName1; + for (let i = 0; i < $(".line-port").length; i++) { + let data_text1 = $('.line-port').eq(i).attr('data-tp1'); + tp_links.push(data_text1); + } + if (tp_links.indexOf(tp1) != -1) { + alert('This port number connection already exists!'); + return; + } + + let time = this.cloudNetwork + new Date().getTime();//Create aaiid for the external cloud, this identifier is unique and cannot be repeated + this.createCloudUrls(time) + } + } + + //Create tp connection call interface createLink + createTpLinks() { + let params = { + 'link-name': this.linkName, + 'link-type': 'cross-link', + 'operational-status': 'up', + 'relationship-list': { + 'relationship': [ + { + 'related-to': 'p-interface', + 'related-link': '/aai/v14/network/pnfs/pnf/' + this.selectedNode1 + '/p-interfaces/p-interface/' + this.selecteTpName1, + 'relationship-data': [ + { + 'relationship-key': 'pnf.pnf-id', + 'relationship-value': this.selectedNode1 + }, + { + 'relationship-key': 'p-interface.p-interface-id', + 'relationship-value': this.selecteTpName1, + } + ] + }, + { + 'related-to': 'p-interface', + 'related-link': '/aai/v14/network/pnfs/pnf/' + this.selectedNode2 + '/p-interfaces/p-interface/' + this.selecteTpName2, + 'relationship-data': [ + { + 'relationship-key': 'pnf.pnf-id', + 'relationship-value': this.selectedNode2 + }, + { + 'relationship-key': 'p-interface.p-interface-id', + 'relationship-value': this.selecteTpName2 + } + ] + } + ] + } + }; + this.myhttp.createLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.queryAddLink(); + } + }, (err) => { + console.log(err); + console.log('Create connection interface call failed'); + }); + } + + //Query the newly added connection immediately after creating the tp cable + queryAddLink() { + let linkName = this.linkName, + selecteTpName1 = this.selecteTpName1, + selecteTpName2 = this.selecteTpName2, + selectedNode1 = this.selectedNode1, + selectedNode2 = this.selectedNode2; + let params = { + 'link-name': linkName, + }; + this.myhttp.querySpecificLinkInfo(params) + .subscribe((data) => { + let version = data['resource-version'], + operational_status = data['operational-status'], + linkname = data['link-name']; + let textval = [selecteTpName1, selecteTpName2, version, selectedNode1, selectedNode2, operational_status, linkname]; + this.hideForm(); + this.chose(textval); + }, (err) => { + console.log(err); + }); + } + + //Connection between two TP coordinates + chose(textval) { + let lines_json = {}; + lines_json['tp1'] = textval[0]; + lines_json['tp2'] = textval[1]; + lines_json['version'] = textval[2]; + lines_json['node1'] = textval[3]; + lines_json['node2'] = textval[4]; + lines_json['status'] = textval[5]; + lines_json['linkname'] = textval[6]; + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == textval[0]) { + $('.node').eq(i).show(); + //Get the x, y coordinates of the second level + let translates = $('.node').eq(i).css('transform'); + lines_json['x1'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y1'] = parseFloat(translates.substring(7).split(',')[5]); + } + if ($('.node').eq(i).find('text').html() == textval[1]) { + $('.node').eq(i).show(); + let translates = $('.node').eq(i).css('transform'); + lines_json['x2'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y2'] = parseFloat(translates.substring(7).split(',')[5]); + } + } + this.addLine(lines_json); + } + + //Connection between two TPs + addLine(lines) { + let tp1 = lines.tp1; + let tp2 = lines.tp2; + let version = lines.version; + let node1 = lines.node1; + let node2 = lines.node2; + let status = lines.status; + let linkname = lines.linkname; + let x1 = lines.x1; + let y1 = lines.y1; + let x2 = lines.x2; + let y2 = lines.y2; + let color = '#14bb58'; + if (status == 'up') { + color = '#14bb58'; + } else { + color = 'red'; + } + let line = '<line class=\'line line-port line-click\' stroke=\'' + color + '\' stroke-width=\'2\' style=\'cursor:pointer\'></line>'; + let svg = d3.select('#graph'); + $('#graph').prepend(line); + $('.line').first().attr({ + x1: x1, + y1: y1, + x2: x2, + y2: y2, + 'data-tp1': tp1, + 'data-tp2': tp2, + 'data-version': version, + 'data-node1': node1, + 'data-node2': node2, + 'data-link': linkname + }); + svg.html(svg.html()); + } + + //After creating an external cloud connection, query the connection immediately + queryOutCloudLink(time) { + let networkVal1 = this.networkVal1, + selectedNode1 = this.selectedNode1, + selecteTpName1 = this.selecteTpName1, + cloudUrl = this.cloudUrl, + cloudNetWork = this.cloudNetwork, + cloudNode = this.cloudNode, + cloudTp = this.cloudTp, + linkname = this.linkName; + let params = { + 'link-name': linkname, + }; + this.myhttp.querySpecificLinkInfo(params) + .subscribe((data) => { + let status = data['operational-status']; + let link_name = data['link-name']; + this.outCloudShow = true; + this.hideForm(); + this.outCloud(this.imgmap); + setTimeout(this.cloudLine(networkVal1, selectedNode1, selecteTpName1, cloudUrl, cloudNetWork, cloudNode, cloudTp, status, link_name, time), 0); + }, (err) => { + console.log(err); + }); + } + + //Add external cloud + outCloud(imgmap) { + let _this = this, + width; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + let svg = d3.select('#content-svg'); + svg.append('g').attr('class', 'out').attr('id', 'out').style({ 'display': 'block' }).attr('transform', 'translate(' + (width - 200) + ',0)'); + let out = d3.select('#out'); + out.append('image').style('width', '200').style('height', '118').attr('xlink:href', imgmap['3']); + out.append('text').text('Partner Network') + .style('transform', 'translate(0,0)') + .style('font-size', '16') + .style('font-weight', 'bold') + .attr('dx', '40') + .attr('dy', '70') + .style('fill', '#fff'); + } + + //Add external cloud connection + cloudLine(networkVal1, selectedNode1, selecteTpName1, cloudUrl, cloudNetWork, cloudNode, cloudTp, status, link_name, time) { + let lines_json = {}; + let _this = this, + width; + if (_this.tpoption.width > 800) { + width = _this.tpoption.width; + } else { + width = 800; + } + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == networkVal1) { + //Get the x, y coordinates of the second level + let translates = $('.node').eq(i).css('transform'); + lines_json['x1'] = parseFloat(translates.substring(7).split(',')[4]); + lines_json['y1'] = parseFloat(translates.substring(7).split(',')[5]); + lines_json['x2'] = width - 100; + lines_json['y2'] = 100; + } + } + let x1 = lines_json['x1']; + let y1 = lines_json['y1']; + let x2 = lines_json['x2']; + let y2 = lines_json['y2']; + let color = '#14bb58'; + if (status == 'up') { + color = '#14bb58'; + } else { + color = 'red'; + } + let line = '<line class=\'line cloudline line-click\' stroke=\'' + color + '\' stroke-width=\'2\' style=\'cursor:pointer\'></line>'; + let svg = d3.select('#graph'); + $('.cloudline').remove(); + $('#graph').prepend(line); + $('.cloudline').attr({ + x1: x1 + 100, + y1: y1 + 10, + x2: x2, + y2: y2, + 'data-tp1': selecteTpName1, + 'data-tp2': cloudTp, + 'data-node1': selectedNode1, + 'data-node2': cloudNode, + 'data-network': networkVal1, + 'data-cloudnetwork': cloudNetWork, + 'data-url': cloudUrl, + 'data-aaiid': time, + 'data-link': link_name + }); + svg.html(svg.html()); + this.getExtAAIIdVersion(time); + } + + //Create an external cloud, call the following 5 interfaces when connecting:createCloudNetwork,createPnfs,createCloudTp,createCloudLinks,createCloudUrls + createCloudNetwork(time) { + let _thiss = this; + let params = { + '-xmlns': 'http://org.onap.aai.inventory/v14', + 'in-maint': 'false', + "network-id": this.cloudNetwork, + "provider-id": "", + "client-id": "", + "te-topo-id": "", + "relationship-list": { + "relationship": [{ + "related-to": "ext-aai-network", + 'related-link': '/aai/v14/network/ext-aai-networks/ext-aai-network/' + time + }] + } + }; + + //Do some asynchronous operations + _thiss.myhttp.createNetwrok(params) + .subscribe((data) => { + if (data["status"] == "SUCCESS") { + _thiss.createPnfs(time) + } + }, (err) => { + console.log(err); + }); + + } + + createPnfs(time) { + let _thiss = this; + let params = { + "-xmlns": "http://org.onap.aai.inventory/v14", + "pnf-name": this.cloudNode, + "pnf-id": this.cloudNode, + "in-maint": "true", + "relationship-list": { + "relationship": [ + { + "related-to": "ext-aai-network", + "relationship-label": "org.onap.relationships.inventory.BelongsTo", + "related-link": "/aai/v14/network/ext-aai-networks/ext-aai-network/" + time, + "relationship-data": { + "relationship-key": "ext-aai-network.aai-id", + "relationship-value": time + } + }, + { + "related-to": "network-resource", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v14/network/network-resources/network-resource/" + this.cloudNetwork + } + ] + } + }; + + //Do some asynchronous operations + _thiss.myhttp.createPnf(params) + .subscribe((data) => { + if (data["status"] == "SUCCESS") { + _thiss.createCloudTp(time) + } + }, (err) => { + console.log(err); + }); + } + + createCloudTp(time) { + let _thiss = this; + let params = { + "-xmlns": "http://org.onap.aai.inventory/v14", + "interface-name": this.cloudTp, + "speed-value": "1000000", + "in-maint": "true", + "network-ref": "", + "transparent": "true", + "operational-status": "up" + }; + + let cloudNodeName = this.cloudNode; + //Do some asynchronous operations + _thiss.myhttp.createTp(params, cloudNodeName) + .subscribe((data) => { + if (data["status"] == "SUCCESS") { + _thiss.createCloudLinks(time) + } + }, (err) => { + console.log(err); + }); + } + + createCloudLinks(time) { + let _thiss = this; + let params = { + "-xmlns": "http://org.onap.aai.inventory/v14", + "link-name": this.linkName, + "in-maint": "false", + "link-type": "cross-link", + "speed-value": "", + "operational-status": "up", + "relationship-list": { + "relationship": [ + { + "related-to": "p-interface", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v14/network/pnfs/pnf/" + this.selectedNode1 + "/p-interfaces/p-interface/" + this.selecteTpName1, + "relationship-data": [ + { + "relationship-key": "pnf.pnf-name", + "relationship-value": this.selectedNode1 + }, + { + "relationship-key": "p-interface.interface-name", + "relationship-value": this.selecteTpName1 + } + ], + "related-to-property": [{ + "property-key": "p-interface.prov-status" + }] + }, + { + "related-to": "p-interface", + "relationship-label": "tosca.relationships.network.LinksTo", + "related-link": "/aai/v14/network/pnfs/pnf/" + this.cloudNode + "/p-interfaces/p-interface/" + this.cloudTp, + "relationship-data": [ + { + "relationship-key": "pnf.pnf-name", + "relationship-value": this.cloudNode + }, + { + "relationship-key": "p-interface.interface-name", + "relationship-value": this.cloudTp + } + ], + "related-to-property": [{ + "property-key": "p-interface.prov-status" + }] + }, + { + "related-to": "ext-aai-network", + "relationship-label": "org.onap.relationships.inventory.BelongsTo", + "related-link": "/aai/v14/network/ext-aai-networks/ext-aai-network/" + time, + "relationship-data": [ + { + "relationship-key": "ext-aai-network.aai-id", + "relationship-value": time + } + ] + } + ] + } + }; + + //Do some asynchronous operations + _thiss.myhttp.createCloudLink(params) + .subscribe((data) => { + // resolve(data['status']); + if (data["status"] == "SUCCESS") { + _thiss.queryOutCloudLink(time); + } + }, (err) => { + console.log(err); + }); + } + + createCloudUrls(time) { + let _thiss = this; + let params = { + '-xmlns': 'http://org.onap.aai.inventory/v14', + 'aai-id': time, + 'esr-system-info': { + 'esr-system-info-id': 'example-esr-system-info-id-val-0', + 'service-url': this.cloudUrl, + 'user-name': 'demo', + 'password': 'demo123456!', + 'system-type': 'ONAP' + } + }; + _thiss.myhttp.createCloudUrl(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + _thiss.createCloudNetwork(time); + } + }, (err) => { + console.log(err); + }); + } + + //Local cloud TP port Delete connection Call interface deleteLink + delLink(): void { + let deltp1 = this.delTp1, + deltp2 = this.delTp2, + version = this.delVersion, + dellinkname = this.delLinkname, + delLinkIndex = this.delLinkIndex; + let params = { + 'logical-link': dellinkname, + 'resource-version': version, + }; + this.myhttp.deleteLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.delLine(deltp1, deltp2); + delLinkIndex.remove(); + } + }, (err) => { + console.log(err); + console.log('Deleting a connection interface call failed'); + }); + } + + delLine(val1, val2) { + this.delBoxisVisible = false; + for (let i = 0; i < $(".node").length; i++) { + if ($('.node').eq(i).find('text').html() == val1) { + $('.node').eq(i).hide(); + } + if ($('.node').eq(i).find('text').html() == val2) { + $('.node').eq(i).hide(); + } + } + } + + + //External cloud Delete connection Call interface deleteCloudLink + delCloudLink(): void { + let deltp1 = this.delTp1, + deltp2 = this.delTp2, + version = this.delVersion, + aaiId = this.aaiId; + let params = { + "aaiId": aaiId, + "version": version, + }; + this.myhttp.deleteCloudLink(params) + .subscribe((data) => { + if (data['status'] == 'SUCCESS') { + this.delLine(deltp1, deltp2); + $('.cloudline').remove(); + $('#out').remove(); + } + }, (err) => { + console.log(err); + console.log('Deleting a connection interface call failed'); + }); + } + +} diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.html b/usecaseui-portal/src/app/views/fcaps/fcaps.component.html new file mode 100644 index 00000000..edd2111a --- /dev/null +++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.html @@ -0,0 +1,3 @@ +<iframe src="http://172.30.1.80:5601" frameborder="0" style="height:100vh;width:100%;"></iframe> +<!-- <iframe src="http://dl_es:5601/app/kibana#/dashboard/a0db79a0-624e-11e9-88e5-b7b07490dd67?_g=(refreshInterval%3A(pause%3A!f%2Cvalue%3A86400000)%2Ctime%3A(from%3Anow-1y%2Cmode%3Aquick%2Cto%3Anow))" frameborder="0" style="height:100vh;width:100%;"></iframe> --> +<!-- <iframe src="http://dl_es:5601/app/kibana#/dashboard/a0db79a0-624e-11e9-88e5-b7b07490dd67?embed=true&_g=(refreshInterval%3A(pause%3A!f%2Cvalue%3A86400000)%2Ctime%3A(from%3Anow-1y%2Cmode%3Aquick%2Cto%3Anow))" style="height:100vh;width:100%;"></iframe> --> diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.less b/usecaseui-portal/src/app/views/fcaps/fcaps.component.less new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.less diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts b/usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts new file mode 100644 index 00000000..42bdbc0f --- /dev/null +++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FcapsComponent } from './fcaps.component'; + +describe('FcapsComponent', () => { + let component: FcapsComponent; + let fixture: ComponentFixture<FcapsComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FcapsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FcapsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/fcaps/fcaps.component.ts b/usecaseui-portal/src/app/views/fcaps/fcaps.component.ts new file mode 100644 index 00000000..7f9ab7f4 --- /dev/null +++ b/usecaseui-portal/src/app/views/fcaps/fcaps.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-fcaps', + templateUrl: './fcaps.component.html', + styleUrls: ['./fcaps.component.less'] +}) +export class FcapsComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/usecaseui-portal/src/app/views/home/home.component.css b/usecaseui-portal/src/app/views/home/home.component.css new file mode 100644 index 00000000..41b3f5fe --- /dev/null +++ b/usecaseui-portal/src/app/views/home/home.component.css @@ -0,0 +1,158 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.content .services { + float: left; + background-color: #fff; + width: 30%; + height: 628px; + border-radius: 5px; + padding: 28px 22px; +} +.content .services h4 { + font: 600 16px/16px "Arial"; + color: #3d4d65; + margin-bottom: 58px; +} +.content .services h3 { + font: 400 48px/48px "Arial"; + color: #3fa8eb; + text-align: center; +} +.content .services h3 span { + font-size: 14px; +} +.content .services p { + font: 400 14px/14px "Arial"; + color: #54657e; + text-align: center; + margin-bottom: 48px; +} +.content .services .tip { + background-color: #eceff4; + color: #3d4d65; + font-size: 16px; + margin: 0 20px; + height: 35px; + line-height: 35px; + border-radius: 5px; +} +.content .rightcontent { + float: left; + padding-left: 15px; + width: 70%; +} +.content .rightcontent .rt-content { + height: 220px; + margin-bottom: 18px; +} +.content .rightcontent .rt-content .poerformance { + float: left; + margin-left: 2%; + background-color: #fff; + height: 100%; + width: 50%; + border-radius: 5px; + padding: 28px 26px; +} +.content .rightcontent .rt-content .poerformance h4 { + font: 600 16px/16px "Arial"; + color: #3d4d65; + margin-bottom: 34px; +} +.content .rightcontent .rt-content .poerformance div { + height: 57px; + position: relative; + margin-bottom: 10px; +} +.content .rightcontent .rt-content .poerformance div h3 { + font: 600 25px/25px "Arial"; + color: #3d4d65; + margin-bottom: 10px; +} +.content .rightcontent .rt-content .poerformance div p { + font: 400 12px/12px "Arial"; + color: #54657e; +} +.content .rightcontent .rt-content .poerformance div img { + position: absolute; + top: 0; + right: 0; +} +.content .rightcontent .rt-content .alarm { + float: left; + background-color: #fff; + height: 100%; + width: 48%; + margin-left: 2%; + border-radius: 5px; + position: relative; + padding: 28px 26px; +} +.content .rightcontent .rt-content .alarm h4 { + position: absolute; + font: 600 16px/16px "Arial"; + color: #3d4d65; +} +.content .rightcontent .rb-content { + height: 390px; + background-color: #fff; + border-radius: 5px; + padding: 24px 30px; + position: relative; +} +.content .rightcontent .rb-content h4 { + font: 600 16px/16px "Arial"; + color: #3d4d65; +} +.content .rightcontent .rb-content nz-dropdown { + position: absolute; + top: 24px; + right: 30px; +} +.content .rightcontent .rb-content nz-dropdown button { + width: 170px; + height: 35px; + background-color: #eceff4; + text-align: left; + border-color: #cad3df; +} +.content .rightcontent .rb-content nz-dropdown button span { + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + font-size: 14px; +} +.content .rightcontent .rb-content nz-dropdown button i { + position: absolute; + top: 12px; + right: 12px; +} +.content .rightcontent .rb-content #pfVmChartLine { + width: 100%; + height: 318px; +} diff --git a/usecaseui-portal/src/app/views/home/home.component.html b/usecaseui-portal/src/app/views/home/home.component.html new file mode 100644 index 00000000..4126f241 --- /dev/null +++ b/usecaseui-portal/src/app/views/home/home.component.html @@ -0,0 +1,102 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!--<h3 class="title"> {{"Overall trend" | translate}}</h3> +<hr> --> +<div class="content"> + <div class="left-content"> + <div class="services"> + <h4>{{"i18nTextDefine_SERVICES" | translate}}</h4> + <!-- <h3>{{serviceNumber}} <span>{{"services" | translate}}</span> </h3> + <p>{{serviceNumber}} {{"services has been created" | translate}}</p> --> + <app-pie [initData]="serviceChartInit" [chartData]="serviceChartData" *ngIf="serviceChart"></app-pie> + <div *ngIf="!serviceChart" + style="color: #ddd; font-weight: 700;font-size: 19px;height: 200px;text-align: center;line-height: 8;">No Service Instances </div> + + <div> + <h5><span>{{"i18nTextDefine_Total" | translate}}:</span> {{serviceNumber}} + <span>{{"i18nTextDefine_cutomers_and" | translate}}</span> {{serviceNumber}} + <span>{{"i18nTextDefine_service_instance" | translate}}</span></h5> + </div> + <p class="tip"> + <span style="color:#3C4F8C" (click) = "goback_services()">{{"i18nTextDefine_ViewDetails" | translate}}</span> + </p> + </div> + <div class="PACKAGE"> + <h4>{{"i18nTextDefine_PACKAGE" | translate}}</h4> + <div class="details"> + <li class="detailstoplinContent"> + <div class="detailstoplin"> + <div><span></span> NS</div> + <div> + <app-bar [initData]="serviceBarChartInit" [chartData]="servicesBarChartData"></app-bar> + </div> + <div>{{NSdata}}</div> + </div> + </li> + <li class="detailstoplinContent"> + <div class="detailstoplin"> + <div><span style="background-color:#BCECB8;"></span> VNF</div> + <div> + <app-bar [initData]="serviceBarChartInit" [chartData]="servicesBarChartData1"></app-bar> + </div> + <div>{{Vnfdata}}</div> + </div> + </li> + <li class="detailstoplinContent"> + <div class="detailstoplin"> + <div><span style="background-color:#ACCAF4;"></span> PNF</div> + <div> + <app-bar [initData]="serviceBarChartInit" [chartData]="servicesBarChartData2"></app-bar> + </div> + <div>{{PnfData}}</div> + </div> + </li> + </div> + <p class="tip"> + <span style="color:#3C4F8C" (click) = "goback_onboard()">{{"i18nTextDefine_ViewDetails" | translate}}</span> + </p> + </div> + </div> + <div class="rightcontent" style="height: 96vh"> + <div class="rt-content"> + <div class="alarm"> + <h4>{{"i18nTextDefine_ALARM" | translate}}</h4> + <app-pie [initData]="alarmChartInit" [chartData]="alarmChartData"></app-pie> + <p class="alarm-name"> {{"i18nTextDefine_VNF_Alarm" | translate}} </p> + </div> + <div class="poerformance"> + <app-pie [initData]="VMAlarmChartInit" [chartData]="VMAlarmChartData"></app-pie> + <p class="alarm-name"> {{"i18nTextDefine_VM_Alarm" | translate}} </p> + <p class="tip"> + <a href="#" style="color:#3C4F8C">{{"i18nTextDefine_ViewDetails" | translate}}</a> + </p> + </div> + </div> + <div class="rb-content"> + <h4>{{"i18nTextDefine_VM_Performance" | translate}}</h4> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomRight'"> + <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="sourceNameSelect(item)" *ngFor="let item of sourceNameList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + <app-line [initData]="alarmLineChartInit" [chartData]="alarmLineChartData"></app-line> + </div> + </div> +</div> diff --git a/usecaseui-portal/src/app/views/home/home.component.less b/usecaseui-portal/src/app/views/home/home.component.less new file mode 100644 index 00000000..9e768cf7 --- /dev/null +++ b/usecaseui-portal/src/app/views/home/home.component.less @@ -0,0 +1,265 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +// .title { +// font: 700 18px/18px "思源黑体"; +// color: #4c5e70; +// margin-bottom: 18px; +// } +// hr { +// border: none; +// height: 2px; +// background-color: #dce1e7; +// margin-bottom: 20px; +// } +.content { + padding: 20px 20px; + overflow: hidden; + .left-content{ + float: left; + width:30%; + // height:96vh; + .services,.PACKAGE{ + width: 100%; + background:rgba(255,255,255,1); + box-shadow:0px 10px 10px 2px rgba(222,222,222,0.5); + border-radius:6px; + padding: 28px 22px; + h4{ + font: 600 16px/16px "Arial Bold"; + color: #0DA9E2; + } + .tip { + float: right; + width: 110px; + line-height: 35px; + border-radius: 5px; + background-color: #eceff4; + font-size: 16px; + color: #3C4F8C; + margin-top: 20px; + margin-bottom: 0!important; + } + } + .services{ + height:466px; + h4{ + margin-bottom: 20px; + } + h5 { + font: 500 18px/18px "ArialMT"; + color:#0DA9E2; + margin: -2em 0 1em 0 ; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + span { + font-size: 14px; + font-family: "Arial"; + color:#3C4F8C; + } + span:first-child { + font-size: 18px; + padding: 0 4PX 0 4px; + } + span:last-child { + padding-left: 4px; + } + + } + } + .PACKAGE{ + height:422px; + margin-top: 20px; + h4{ + margin-bottom: 50px; + } + .details { + .detailstoplinContent{ + border-bottom:0.5px solid rgba(237,237,237,1); + border-radius:4px; + line-height: 45px; + font-size: 14px; + color: #3C4F8C; + font-family:"ArialMT"; + .detailstoplin { + width: 100%; + height: 50px; + border-top: 0.5px solid #ededed; + border-radius: 4px; + div:first-child{ + width: 20%; + float: left; + } + div:nth-child(2){ + width: 65%; + float: left; + } + div:last-child { + width: 13%; + float: right; + font-size:12px; + font-weight: 500; + color:rgba(60,79,140,0.5); + } + } + } + } + + } + } + .services,.PACKAGE{ + h3 { + font: 400 48px/48px "Arial"; + color: #3fa8eb; + text-align: center; + span { + font-size: 14px; + } + } + + p { + font: 400 14px/14px "Arial"; + color: #54657e; + text-align: center; + margin-bottom: 48px; + } + } + .rightcontent { + float: left; + padding-left: 15px; + width: 70%; + .rt-content { + height: 40%; + margin-bottom: 18px; + background:rgba(255,255,255,1); + box-shadow:0px 10px 10px 2px rgba(222,222,222,0.5); + border-radius:6px; + .poerformance { + float: left; + background-color: #fff; + height: 100%; + width: 50%; + border-radius: 5px; + padding: 28px 26px; + .pfVmPm { + h3 { + color:#BD57E5; + } + } + h4 { + font: 600 16px/16px "Arial Bold"; + color: #0DA9E2; + margin-bottom: 34px; + } + + div { + height: 57px; + position: relative; + margin-bottom: 10px; + h3 { + font: 600 25px/25px "Arial"; + color: #2F6AEF; + margin-bottom: 10px; + padding-left: 50%; + } + p { + font: 400 12px/12px "Arial"; + color:rgba(60,79,140,0.5); + padding-left: 50%; + + } + img { + position: absolute; + top: 0; + left: 0; + } + } + } + .alarm { + float: left; + background-color: #fff; + height: 100%; + width: 48%; + border-radius: 5px; + position: relative; + padding: 28px 26px; + h4 { + position: absolute; + font: 600 16px/16px "Arial Bold"; + color: #0DA9E2; + } + } + .alarm-name{ + text-align: center; + margin-top: 15px; + } + .tip{ + width: 110px; + background-color: #eceff4; + color: #3C4F8C; + font-size: 16px; + float: right; + margin-top: 20px; + margin-bottom: 0!important; + line-height: 35px; + border-radius: 5px; + text-align: center; + } + } + .rb-content { + position: relative; + height: 58%; + background-color: #fff; + padding: 24px 30px; + box-shadow:0px 10px 15px 2px rgba(222,222,222,0.5); + border-radius:6px; + h4 { + font: 600 16px/16px "Arial Bold"; + color: #0DA9E2; + } + nz-dropdown { + position: absolute; + top: 24px; + right: 30px; + button { + width: 170px; + height: 35px; + background-color: #eceff4; + text-align: left; + border-color: #cad3df; + span { + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + font-size: 14px; + } + i { + position: absolute; + top: 12px; + right: 12px; + } + } + //下拉框中的样式在style.less中,下拉框是在body中额外临时生成的 + } + #pfVmChartLine { + width: 100%; + height: 318px; + } + } + } +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/home/home.component.spec.ts b/usecaseui-portal/src/app/views/home/home.component.spec.ts new file mode 100644 index 00000000..5456a323 --- /dev/null +++ b/usecaseui-portal/src/app/views/home/home.component.spec.ts @@ -0,0 +1,42 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader} from '@ngx-translate/core'; +import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { NgxEchartsModule } from 'ngx-echarts'; +import { HttpClientModule } from '@angular/common/http'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { HomeComponent } from './home.component'; +import { PieComponent } from '../../shared/components/charts/pie/pie.component'; +import { BarComponent } from '../../shared/components/charts/bar/bar.component'; +import { LineComponent } from '../../shared/components/charts/line/line.component'; +import { HomesService } from '../../core/services/homes.service'; + +describe('HomeComponent', () => { + let component: HomeComponent; + let fixture: ComponentFixture<HomeComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HomeComponent, PieComponent, BarComponent, LineComponent ], + imports: [TranslateModule.forRoot({loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }}), + NgZorroAntdModule, + NgxEchartsModule, + HttpClientModule, + BrowserAnimationsModule, + RouterTestingModule], + providers: [HomesService, TranslateService] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/home/home.component.ts b/usecaseui-portal/src/app/views/home/home.component.ts new file mode 100644 index 00000000..11a0f1a8 --- /dev/null +++ b/usecaseui-portal/src/app/views/home/home.component.ts @@ -0,0 +1,531 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, Input, Output, EventEmitter, HostBinding } from '@angular/core'; +import { HomesService } from '../../core/services/homes.service'; +import { slideToRight } from '../../animates'; +import { TranslateService } from "@ngx-translate/core"; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.less'], + animations: [slideToRight] +}) +export class HomeComponent implements OnInit { + @HostBinding('@routerAnimate') routerAnimateState; + + constructor(private myhttp: HomesService, private router: Router) { } + + ngOnInit() { + this.getListSortMasters(); + this.getSourceNames(); + this.getHomeServiceData(); + this.getHomeAlarmData(); + this.getHomeAlarmChartData(); + this.getHomeServiceBarNsData(); + this.getHomeServiceBarVnfData(); + this.getHomeServiceBarPnfData(); + } + + + // services + serviceNumber: number = 0; + serviceChartData: Object; + serviceChartInit: Object = { + backgroundColor: '#fff', + height: 200, + option: { + legend: { + orient: 'vertical', + left: '0px', + bottom: '0px', + data: ['Active', 'Closed'] + }, + color: ["#7AC0EF", "#6A86D8", "#748CDC", "#7277D4", "#7067CE", "#B9B0F7", "#7DCFF5"], + series: [ + { + name: "服务信息", + radius: ['50%', '70%'], + center: ['50%', '45%'], + avoidLabelOverlap: false, + label: { + normal: { + show: false, + position: 'center' + }, + emphasis: { + show: true, + formatter: '{b}\n{c}', + textStyle: { + fontSize: '18', + fontWeight: 'bold' + } + } + }, + labelLine: { + normal: { + show: false + } + }, + itemStyle: { + normal: { + borderWidth: 4, + borderColor: "#fff" + }, + emphasis: { + borderWidth: 0 + } + }, + } + ] + } + }; + // gethomeServiceData + serviceChart = true; + getHomeServiceData() { + this.myhttp.getHomeServiceData() + .subscribe( + (data) => { + this.serviceNumber = data.serviceTotalNum; + if (this.serviceNumber > 0) { + this.serviceChart = true; + } else { + this.serviceChart = false; + } + this.serviceChartData = { + series: [{ data: data.customerServiceList }] + }; + }, + (err) => { + console.error(err); + } + ) + } + + // VM alarm + VMAlarmChartData: Object; + VMAlarmChartInit: Object = { + height: 180, + option: { + tooltip: { + trigger: 'item', + formatter: '{b}\n{c},{d}%' + }, + color: [ + { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [{ + offset: 0, color: '#FB93C2' // 0% color + }, { + offset: 1, color: '#FB7788' // 100% color + }], + globalCoord: false + }, { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [{ + offset: 0, color: '#A6BFE4' // 0% color + }, { + offset: 1, color: '#7A8BAE' // 100% color + }], + globalCoord: false + }], + series: [{ + name: "告警信息", + radius: ['50%', '70%'], + center: ['50%', '45%'], + label: { + normal: { + show: false, + }, + emphasis: { + show: true, + formatter: '{b}\n{c},{d}%', + color: "#3C4F8C" + } + }, + + }] + } + }; + + // alarm bar + alarmChartData: Object; + alarmChartInit: Object = { + height: 180, + option: { + tooltip: { + trigger: 'item', + formatter: '{b}\n{c},{d}%' + }, + legend: { + orient: 'vertical', + left: '0px', + bottom: '0px', + itemWidth: 10, + itemHeight: 10, + textStyle: { + color: "#3C4F8C" + }, + data: ['Active', 'Fixed'] + }, + color: [ + { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [{ + offset: 0, color: '#FB93C2' // 0% color + }, { + offset: 1, color: '#FB7788' // 100% color + }], + globalCoord: false + }, { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [{ + offset: 0, color: '#A6BFE4' // 0% + }, { + offset: 1, color: '#7A8BAE' // 100% + }], + globalCoord: false + }], + series: [{ + name: "告警信息", + radius: '55%', + center: ['50%', '45%'], + label: { + normal: { + show: false, + }, + emphasis: { + show: true, + formatter: '{b}\n{c},{d}%', + color: "#3C4F8C" + } + } + }] + } + }; + + getHomeAlarmData() { + this.myhttp.getHomeAlarmData() + .subscribe((data) => { + this.alarmChartData = { + series: [{ + data: [{ name: "Active", value: data[0] }, { name: "Fixed", value: data[1] }] + }] + }; + this.VMAlarmChartData = { + series: [{ + data: [{ name: "Active", value: data[0] }, { name: "Fixed", value: data[1] }] + }] + }; + }) + } + + // alarm line + alarmLineChartData: Object; + alarmLineChartInit: Object = { + height: 320, + option: { + legend: { + bottom: '0px', + data: ['CPU', 'Memory', 'Disk'] + }, + xAxis: { + data: [] + }, + series: [ + { + name: 'CPU', + type: 'line', + itemStyle: { + color: "#70ACEC" + }, + data: [] + }, + { + name: 'Memory', + type: 'line', + itemStyle: { + color: "#3BCD79" + }, + data: [] + }, + { + name: 'Disk', + type: 'line', + itemStyle: { + color: "#FDC288" + }, + data: [] + } + ] + } + }; + + // services + servicesBarChartData: Object; + servicesBarChartData1: Object; + servicesBarChartData2: Object; + serviceBarChartInit: Object = { + height: 40, + width: 160, + option: { + tooltip: { + + }, + grid: { + + }, + xAxis: { + type: 'value', + show: false, + min: 0, + max: 100, + axisTick: { + show: false + }, + }, + yAxis: { + type: 'category', + show: false, + axisTick: { + show: false + } + }, + series: [{ + type: 'bar', + name: 'a', + silent: true, + animation: false, + data: [], + stack: 'income', + barWidth: 12, + itemStyle: { + normal: {} + }, + }, { + type: 'bar', + name: '', + animation: false, + silent: true, + data: [100], + tooltip: { + show: false + }, + stack: 'income', + barWidth: 12, + itemStyle: { + normal: { + color: '#fff', + barBorderRadius: [10, 10, 10, 10] + } + }, + label: { + normal: { + show: false, + } + }, + } + ] + } + } + + + NSdata: number; + Vnfdata: number; + PnfData: number; + getHomeServiceBarNsData() { + this.myhttp.getHomeServiceBarNsData() + .subscribe((data) => { + this.NSdata = data.length; + this.servicesBarChartData = { + series: [ + { + data: [this.NSdata], + itemStyle: { + normal: { + color: { + type: 'bar', + colorStops: [{ + offset: 0, + color: '#FDAC63' + }, { + offset: 1, + color: '#FECE72' + }], + globalCoord: false, + }, + barBorderRadius: [10, 10, 10, 10] + } + }, + }, + { data: [100] }, + + ] + } + }, (err) => { + console.error(err); + }) + } + + getHomeServiceBarVnfData() { + this.myhttp.getHomeServiceBarVnfData() + .subscribe((data) => { + this.Vnfdata = data.length; + this.servicesBarChartData1 = { + series: [ + { + data: [this.Vnfdata], + itemStyle: { + normal: { + color: { + type: 'bar', + colorStops: [{ + offset: 0, + color: '#9AD09F' + }, { + offset: 1, + color: '#BCECB8' + }], + globalCoord: false, + + }, + barBorderRadius: [10, 10, 10, 10] + } + }, + }, + { data: [100] }, + ] + } + }, (err) => { + console.error(err); + }) + } + + getHomeServiceBarPnfData() { + this.myhttp.getHomeServiceBarPnfData() + .subscribe((data) => { + this.PnfData = data.length; + this.servicesBarChartData2 = { + series: [ + { + data: [this.PnfData], + itemStyle: { + normal: { + color: { + type: 'bar', + colorStops: [{ + offset: 0, + color: '#71ADEF' + }, { + offset: 1, + color: '#ACCAF4' + }], + globalCoord: false, + + }, + barBorderRadius: [10, 10, 10, 10] + } + }, + }, + { data: [100] }, + ] + } + }, (err) => { + console.error(err); + }) + } + // sourceName + sourceNameList = ['performanceNameOne']; + sourceNameSelected = null; + + + listSortMasters = null; + + getListSortMasters() { + if (sessionStorage.getItem("DefaultLang") == undefined) { + sessionStorage.setItem("DefaultLang", "en"); + } + this.myhttp.getListSortMasters() + .subscribe((data) => { + this.listSortMasters = JSON.stringify(data); + sessionStorage.setItem('listSortMasters', this.listSortMasters) + }) + } + + getSourceNames() { + this.myhttp.getSourceNames() + .subscribe((data) => { + this.sourceNameList = data; + }) + } + sourceNameSelect(item) { + if (this.sourceNameSelected != item) { + this.sourceNameSelected = item; + this.getHomeAlarmChartData() + } + } + getHomeAlarmChartData() { + let nowTime = this.myhttp.dateformater(Date.now()); + let startTime = this.myhttp.dateformater(Date.now() - 30 * 24 * 60 * 60 * 1000); + let obj = { + sourceName: this.sourceNameSelected, + startTime: startTime, + endTime: nowTime, + format: "day" + } + + this.myhttp.getHomeAlarmChartData(obj) + .subscribe((data) => { + this.alarmLineChartData = { + xAxis: { + data: data.dataList + }, + series: [ + { data: data.allList }, + { data: data.ActiveList }, + { data: data.closedList } + ] + } + }, (err) => { + console.error(err); + }) + } + + goback_services() { + this.router.navigateByUrl('/services/services-list'); + } + goback_onboard() { + this.router.navigateByUrl('/services/onboard-vnf-vm'); + } + +} diff --git a/usecaseui-portal/src/app/views/management/management.component.html b/usecaseui-portal/src/app/views/management/management.component.html new file mode 100644 index 00000000..c96f0253 --- /dev/null +++ b/usecaseui-portal/src/app/views/management/management.component.html @@ -0,0 +1,39 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<div class="content" style="padding: 20px 20px;height: 100vh"> + <div class="management" *ngIf="nocuster"> + <div class="title"> + <p> {{"i18nTextDefine_Create_initial_customer" | translate}} </p> + <span> {{"i18nTextDefine_Customer_not_in_ONAP" | translate}} </span> + <span> {{"i18nTextDefine_CreateCustomer" | translate}} </span> + <img src="../../../assets/images/customer01.png" alt=""> + <input nz-input placeholder=" {{'i18nTextDefine_Input_customerName' | translate}} " nzSize="large" + style="height: 50px" [(ngModel)]="firstCustomer"> + <div class="action"> + <button nz-button nzType="primary" class="cancel" (click)="clearCustomerInput()"> + {{"i18nTextDefine_Cancel" | translate}} </button> + <button nz-button nzType="primary" class="add" (click)="createNewCustomer(firstCustomer)"> + {{"i18nTextDefine_Add" | translate}} </button> + </div> + </div> + <div class="image"> + <img src="../../../assets/images/customer02.png" alt=""> + </div> + </div> + <div *ngIf="!nocuster" style="height: 100%"> + <app-customer></app-customer> + </div> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/management/management.component.less b/usecaseui-portal/src/app/views/management/management.component.less new file mode 100644 index 00000000..5a3a0f42 --- /dev/null +++ b/usecaseui-portal/src/app/views/management/management.component.less @@ -0,0 +1,79 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.content { + .management { + width: 100%; + .title { + width: 50%; + vertical-align:top; + display: inline-block; + font-family: "Arial"; + p { + font-size: 33px; + color: #3C4F8C; + margin-bottom: 0.5em; + } + span { + font-size: 18px; + color: rgba(60,79,140,0.5); + display: block; + } + img { + padding-top: 8%; + width: 55%; + margin-left: 20%; + margin-bottom: 5%; + } + input { + width: 50%; + margin: 0 auto; + margin-bottom: 5%; + display: block; + + } + .action{ + width: 50%; + height: 40px; + margin: 0 auto; + } + .action button{ + width: 40%; + height: 40px; + margin: 0 4%; + } + .cancel{ + background-color: #eee; + border-color: #eee; + color: #9DA7C5; + } + .add { + color: #fff; + background:linear-gradient(310deg,rgba(30,158,255,1) 0%,rgba(99,200,255,1) 100%); + border-color: #1890ff; + } + } + .image { + width: 49%; + vertical-align:top; + display: inline-block; + img { + width: 85%; + margin-top: 41%; + } + } + } + +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/management/management.component.spec.ts b/usecaseui-portal/src/app/views/management/management.component.spec.ts new file mode 100644 index 00000000..f6152432 --- /dev/null +++ b/usecaseui-portal/src/app/views/management/management.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ManagementComponent } from './management.component'; + +describe('ManagementComponent', () => { + let component: ManagementComponent; + let fixture: ComponentFixture<ManagementComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ManagementComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ManagementComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/management/management.component.ts b/usecaseui-portal/src/app/views/management/management.component.ts new file mode 100644 index 00000000..8b3afea7 --- /dev/null +++ b/usecaseui-portal/src/app/views/management/management.component.ts @@ -0,0 +1,68 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit , HostBinding} from '@angular/core'; +import { showHideAnimate, slideToRight } from '../../animates'; +import { ManagemencsService } from '../../core/services/managemencs.service'; + +@Component({ + selector: 'app-management', + templateUrl: './management.component.html', + styleUrls: ['./management.component.less'], + animations: [ + showHideAnimate, slideToRight + ] +}) +export class ManagementComponent implements OnInit { + @HostBinding('@routerAnimate') routerAnimateState; //Routing animation + + constructor(private managemencs: ManagemencsService) { } + + ngOnInit() { + this.getAllCustomers(); + } + + nocuster = true; + firstCustomer = null; + AllCustomersdata = []; + + // Get all customers + getAllCustomers() { + this.managemencs.getAllCustomers().subscribe((data) => { + if (data.length > 0) { + this.nocuster = false; + } else { + this.nocuster = true; + } + }) + } + + createNewCustomer(customer) { + let createParams = { + customerId: customer + }; + this.managemencs.createCustomer(customer, createParams).subscribe((data) => { + if (data["status"] == 'SUCCESS') { + this.nocuster = false; + } else { + this.nocuster = true; + console.log(data, "Interface returned error") + } + }) + } + clearCustomerInput(){ + this.firstCustomer=null; + } +} diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css new file mode 100644 index 00000000..e9631957 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.css @@ -0,0 +1,75 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.select { + margin-bottom: 20px; +} +.select span { + display: inline-block; + font: 700 14px "Arial"; + color: #4c5e70; +} +.select nz-dropdown { + vertical-align: middle; +} +.select nz-dropdown :hover { + border-color: #147dc2; +} +.select nz-dropdown button { + width: 165px; + height: 30px; + background-color: #eceff4; + text-align: left; + border-color: #9fa9ab; +} +.select nz-dropdown button span { + font-weight: 400; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; +} +.select nz-dropdown button i { + position: absolute; + top: 10px; + right: 10px; +} +.select .submit { + margin-left: 20px; + vertical-align: middle; + height: 30px; + padding: 0 10px; +} +.select .submit span { + color: #fff; + font-weight: 400; +} +.content { + background-color: #fff; + border-radius: 5px; + padding: 12px; +} diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html new file mode 100644 index 00000000..06d84353 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.html @@ -0,0 +1,79 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<!-- <h3 class="title"> + <span (click)="performanceShow()" style="cursor:pointer;">Performance VM</span> + <span (click)="graphicShow()" *ngIf="graphicshow">> Graphic list </span> + <span *ngIf="detailshow">> Details </span> +</h3> +<hr> +<div class="select" [@showHideAnimate]="state"> + <span>Source Name: </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="choseSourceName(item)" *ngFor="let item of sourceNameList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + + <span>ReportingEntityName: </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{ReportingEntityNameSelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="choseReportingEntityName(item)" *ngFor="let item of ReportingEntityNameList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + <button class="submit" nz-button [nzType]="'primary'" (click)="submit()"><i class="anticon anticon-plus-circle-o"></i><span>Submit</span></button> +</div> +<div class="content" [@showHideAnimate]="state"> + <nz-table #nzTable [nzData]="dataSet" [nzPageSize]="10" nzShowSizeChanger nzShowQuickJumper [nzPageSizeOptions]="[5,10,15,20]" nzSize="middle"> + <thead (nzSortChange)="sort($event)" nzSingleSort> + <tr> + <th nzWidth="5%">NO</th> + <th nzWidth="20%">Source Name</th> + <th nzWidth="20%">ReportingEntityName</th> + <th nzWidth="10%">Type</th> + <th nzWidth="15%">CPU</th> + <th nzWidth="10%">Memory</th> + <th nzWidth="10%">Disk</th> + <th nzWidth="10%">Action</th> + </tr> + </thead> + <tbody> --> + <!-- <ng-template ngFor let-data [ngForOf]="nzTable.data" let-i="index"> --> + <!-- <tr *ngFor="let item of nzTable.data; let i = index; "> + <td>{{i+1}}</td> + <td>{{item.name}}</td> + <td>{{item.address}}</td> + <td>{{item.age}}</td> + <td>{{item.address}}</td> + <td>{{item.age}}</td> + <td>{{item.age}}</td> + <td><a (click)="graphicShow()">Delete</a></td> + </tr> --> + <!-- </ng-template> --> + <!-- </tbody> + </nz-table> +</div> +<div [@showHideAnimate]="state2"> + <app-graphiclist (detailData)="detailShow($event)"></app-graphiclist> +</div> +<div [@showHideAnimate]="state3"> + <app-details [detailId]="detailId"></app-details> +</div> --> diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less new file mode 100644 index 00000000..31623dcf --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.less @@ -0,0 +1,76 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.select { + margin-bottom: 20px; + span { + display: inline-block; + font: 700 14px "Arial"; + color: #4c5e70; + } + nz-dropdown { + vertical-align: middle; + :hover{ + border-color: #147dc2; + } + button { + width: 165px; + height: 30px; + background-color: #eceff4; + text-align: left; + border-color: #9fa9ab; + span { + font-weight: 400; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; + } + i { + position: absolute; + top: 10px; + right: 10px; + } + } + //下拉框中的样式在style.less中,下拉框是在body中额外临时生成的 + } + .submit { + margin-left: 20px; + vertical-align: middle; + height: 30px; + padding: 0 10px; + span { + color: #fff; + font-weight: 400; + } + } +} +.content { + background-color: #fff; + border-radius: 5px; + padding: 12px; +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts new file mode 100644 index 00000000..b66b2ea0 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.spec.ts @@ -0,0 +1,68 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +import { PerformanceVmComponent } from './performance-vm.component'; + +describe('PerformanceVmComponent', () => { + let component: PerformanceVmComponent; + let fixture: ComponentFixture<PerformanceVmComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PerformanceVmComponent ], + imports: [ + BrowserAnimationsModule + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PerformanceVmComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should test performanceShow method to set proper values', () => { + component.performanceShow(); + expect(component.state).toBe('show'); + expect(component.state2).toBe('hide'); + expect(component.state3).toBe('hide'); + expect(component.graphicshow).toBe(false); + expect(component.detailshow).toBe(false); + }); + + it('should test graphicShow method to set proper values', () => { + component.graphicShow(); + expect(component.state).toBe('hide'); + expect(component.state2).toBe('show'); + expect(component.state3).toBe('hide'); + expect(component.graphicshow).toBe(true); + expect(component.detailshow).toBe(false); + }); + + it('should test detailShow method to set proper values', () => { + component.detailShow({id:1}); + expect(component.state).toBe('hide'); + expect(component.state2).toBe('hide'); + expect(component.state3).toBe('show'); + expect(component.graphicshow).toBe(true); + expect(component.detailshow).toBe(true); + expect(component.detailId).toBe(1); + }); + + it('should test choseSourceName method', () => { + component.choseSourceName('bbbb'); + expect(component.sourceNameSelected).toBe('bbbb'); + }); + + it('should test choseSourceName method', () => { + component.choseReportingEntityName('bbbb'); + expect(component.ReportingEntityNameSelected).toBe('bbbb'); + }); + +}); diff --git a/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts new file mode 100644 index 00000000..c179cdbb --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vm/performance-vm.component.ts @@ -0,0 +1,159 @@ +import { Component, OnInit, HostBinding } from '@angular/core'; +import { slideToRight, showHideAnimate } from '../../../animates'; + +@Component({ + selector: 'app-performance-vm', + templateUrl: './performance-vm.component.html', + styleUrls: ['./performance-vm.component.less'], + animations: [ slideToRight, showHideAnimate ] +}) +export class PerformanceVmComponent implements OnInit { + @HostBinding('@routerAnimate') routerAnimateState; + constructor() { } + + ngOnInit() { + } + + // Filter box (drop-down box) + sourceNameList = ['aaaa','bbbb','cccc','dddddDDDDDDDDDDDDDDD']; + sourceNameSelected = this.sourceNameList[0]; + ReportingEntityNameList = ['aaaa','bbbb','cccc','ddddd']; + ReportingEntityNameSelected = this.ReportingEntityNameList[0]; + choseSourceName(item){ + console.log(item); + this.sourceNameSelected = item; + } + choseReportingEntityName(item){ + console.log(item); + this.ReportingEntityNameSelected = item; + } + + //Tabular data + dataSet = [ + { + name : 'John Brown', + age : 32, + expand : false, + address : 'New York No. 1', + description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.' + }, + { + name : 'Aim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Bim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Cim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Jim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Xim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Jim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Jim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Jim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'Jim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'cim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'bim Green', + age : 42, + expand : false, + address : 'London No. 1', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.' + }, + { + name : 'aoe Black', + age : 32, + expand : false, + address : 'Sidney No. 1', + description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.' + } + ]; + + //Detail page title display + graphicshow = false; + detailshow = false; + // Show hidden animation + state = "show"; + state2 = "hide"; + state3 = "hide"; + performanceShow() { + this.state = 'show'; + this.state2 = 'hide'; + this.state3 = 'hide'; + this.graphicshow = false; + this.detailshow = false; + } + graphicShow() { + this.state = 'hide'; + this.state2 = 'show'; + this.state3 = 'hide'; + this.graphicshow = true; + this.detailshow = false; + } + // Selected id + detailId:number; + detailShow(prems) { + this.state = 'hide'; + this.state2 = 'hide'; + this.state3 = 'show'; + this.graphicshow = true; + this.detailshow = true; + console.log(prems); + this.detailId = prems.id; + } + +} diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css new file mode 100644 index 00000000..269af7a9 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.css @@ -0,0 +1,126 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.select { + margin-bottom: 20px; +} +.select span { + display: inline-block; + font: 700 14px "Arial"; + color: #4c5e70; +} +.select nz-dropdown { + vertical-align: middle; +} +.select nz-dropdown :hover { + border-color: #147dc2; +} +.select nz-dropdown button { + width: 165px; + height: 30px; + background-color: #eceff4; + text-align: left; + border-color: #9fa9ab; +} +.select nz-dropdown button span { + font-weight: 400; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; +} +.select nz-dropdown button i { + position: absolute; + top: 10px; + right: 10px; +} +.select .search { + margin-left: 20px; + vertical-align: middle; + height: 30px; + padding: 0 10px; +} +.select .search span { + color: #fff; + font-weight: 400; +} +.content { + background-color: #fff; + border-radius: 5px; + padding: 12px; +} +.content .vnfs { + display: flex; + flex-wrap: wrap; + justify-content: space-around; +} +.content .vnfs .vnf { + width: 18%; + height: 200px; + margin: 5px; + padding: 20px; + border-radius: 2px; + text-align: center; + cursor: pointer; + transition: all 0.3s linear; +} +.content .vnfs .vnf:hover { + background-color: #f5f5f5; + transform: scale(1.02); +} +.content .vnfs .vnf h3 { + font-size: 14px; + color: #3fa8eb; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-bottom: 0; +} +.content .vnfs .vnf .intro { + text-align: left; + font-size: 12px; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + word-wrap: break-word; + word-break: break-all; +} +.content .vnfs .empty { + width: 18%; + height: 200px; + margin: 5px; + border-radius: 2px; +} +.content .pages { + height: 25px; + margin: 20px 10px; + position: relative; +} +.content .pages nz-pagination { + float: right; +} diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html new file mode 100644 index 00000000..9e0e2ed6 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.html @@ -0,0 +1,63 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<h3 class="title"> + <span (click)="performanceShow()" style="cursor:pointer;" *ngIf="graphicshow">Performance VNF</span> + <span (click)="graphicShow()" *ngIf="graphicshow">/ Graphic list </span> + <span *ngIf="detailshow">/ Details </span> +</h3> +<div class="select" [@showHideAnimate]="state"> + <span>Source Name: </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{sourceNameSelected}}</span> <i class="anticon anticon-down"></i></button> + <ul nz-menu> + <li nz-menu-item (click)="choseSourceName(item)" *ngFor="let item of sourceNameList"> + <a>{{item}}</a> + </li> + </ul> + </nz-dropdown> + <button class="search" nz-button [nzType]="'primary'"><i + class="anticon anticon-search"></i><span>Search</span></button> + <!-- <button class="search" nz-button [nzType]="'primary'" (click)="getperformanceSsourceNames()"><i class="anticon anticon-search"></i><span>Search</span></button> --> +</div> +<div class="content" [@showHideAnimate]="state"> + <div class="vnfs"> + <div class="vnf" *ngFor="let item of totalRecords"> + <img src="../../../../assets/images/vnf01.png" title="VNF" (click)="graphicShow2(item)"> + <!-- <h3>{{item.name}}</h3> --> + <div class="intro"> + {{item.name}} + </div> + </div> + <div class="vnf" *ngFor="let item of totalpnfs"> + <img src="../../../../assets/images/pnf01.png" alt="PNF" (click)="graphicShow2(item)"> + <div class="intro"> + {{item.name}} + </div> + </div> + <div class="empty" *ngFor="let empty of emptys"></div> + </div> + <div class="pages"> + <nz-pagination [(nzPageIndex)]="currentPage" [nzTotal]="vnfsdataTotal" [nzSize]="'small'" + [(nzPageSize)]="pageSize" [nzPageSizeOptions]="[10,15,20,25,30]" nzShowSizeChanger nzShowQuickJumper> + </nz-pagination> + </div> +</div> +<div [@showHideAnimate]="state2"> + <app-graphiclist (detailData)="detailShow($event)" [vnfname]="vnfname"></app-graphiclist> +</div> +<div [@showHideAnimate]="state3"> + <app-performance-details [detailId]="detailId"></app-performance-details> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less new file mode 100644 index 00000000..cc4e1ca5 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.less @@ -0,0 +1,136 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 500 14px/18px "ArialMT"; + color: #3C4F8C; + padding: 20px 0 0 20px; +} +.select { + height: 70px; + background-color: #fff; + margin-top: -30px; + padding-left: 20px; + box-shadow: 0 2px 23px 0 rgba(0, 0, 0, 0.1), 0 2px 49px 0 rgba(0, 0, 0, 0.06); + line-height: 5; + span { + display: inline-block; + font: 400 14px "ArialMT"; + color: #3C4F8C; + } + nz-dropdown { + vertical-align: middle; + :hover{ + border-color: #147dc2; + } + button { + width: 165px; + height: 30px; + background-color: #fff; + text-align: left; + border-color: #E5E8F2; + span { + font-weight: 400; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; + } + i { + position: absolute; + top: 10px; + right: 10px; + } + } + :hover { + border-color: #48C6EF; + } + //下拉框中的样式在style.less中,下拉框是在body中额外临时生成的 + } + .search { + margin-left: 20px; + margin-top: -6px; + vertical-align: middle; + height: 30px; + padding: 0 10px; + span { + color: #fff; + font-weight: 400; + } + } +} + +.content { + // background-color: #fff; + border-radius: 5px; + padding: 12px; + .vnfs { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + .vnf { + // width: 180px; + background-color: #fff; + width: 18%; + height: 200px; + margin: 5px; + padding: 20px; + border-radius: 2px; + text-align: center; + cursor: pointer; + transition: all 0.3s linear; + &:hover { + background-color: #fff; + transform: scale(1.02); + color: #3F9CFF; + } + h3 { + font-size: 14px; + color: #3fa8eb; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-bottom: 0; + } + .intro { + text-align: left; + font-size: 12px; + overflow: hidden; + padding-top: 25px; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + word-wrap:break-word; + word-break:break-all; + } + } + .empty { + // width: 180px; + width: 18%; + height: 200px; + margin: 5px; + border-radius: 2px; + } + } + .pages { + height: 25px; + margin: 20px 10px; + position: relative; + nz-pagination { + float: right; + } + } +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts new file mode 100644 index 00000000..25bcfd50 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.spec.ts @@ -0,0 +1,45 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NO_ERRORS_SCHEMA,CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { TranslateModule, TranslateLoader, TranslateService, TranslateFakeLoader} from '@ngx-translate/core'; +import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { NgxEchartsModule } from 'ngx-echarts'; +import { NZ_I18N, en_US } from 'ng-zorro-antd'; +import { HttpClientModule } from '@angular/common/http'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +import { PerformanceDetailsComponent } from '../../../shared/components/performance-details/performance-details.component'; +import { GraphiclistComponent } from '../../../shared/components/graphiclist/graphiclist.component'; +import { PerformanceVnfComponent } from './performance-vnf.component'; +import { HomesService } from '../../../core/services/homes.service'; + +describe('PerformanceVnfComponent', () => { + let component: PerformanceVnfComponent; + let fixture: ComponentFixture<PerformanceVnfComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PerformanceVnfComponent, PerformanceDetailsComponent, GraphiclistComponent ], + imports: [ TranslateModule.forRoot({loader: { provide: TranslateLoader, useClass: TranslateFakeLoader }}), + NgZorroAntdModule.forRoot(), + NgxEchartsModule, + HttpClientModule, + BrowserAnimationsModule ], + providers: [TranslateService, HomesService ], + schemas: [ + CUSTOM_ELEMENTS_SCHEMA, + NO_ERRORS_SCHEMA + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PerformanceVnfComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +});
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts new file mode 100644 index 00000000..96b5404c --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance-vnf/performance-vnf.component.ts @@ -0,0 +1,145 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, HostBinding } from '@angular/core'; +import { slideToRight, showHideAnimate } from '../../../animates'; +import { HomesService } from '../../../core/services/homes.service'; + +@Component({ + selector: 'app-performance-vnf', + templateUrl: './performance-vnf.component.html', + styleUrls: ['./performance-vnf.component.less'], + animations: [slideToRight, showHideAnimate], +}) +export class PerformanceVnfComponent implements OnInit { + @HostBinding('@routerAnimate') routerAnimateState; + public sourceNameList: Array<any> = ['---auto---']; + public sourceName: string = ''; + public vnfsdataTotal: number; + public startTime: string = ''; + public endTime: string = ''; + public currentPage: number = 1; + public pageSize: number = 10; + list: any; + + constructor( + private myhttp: HomesService) { } + + ngOnInit() { + this.getqueryAllSourceNames(); + // this.getperformanceSsourceNames(); + let _this = this; + setTimeout(function(){ + _this.totalRecords = [ + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"} + ]; + _this.totalpnfs = [ + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"}, + {name:"Mfvs_MMEManagedElem entdElementMfvs_MMEM anagedELement��",text:"oahgieango"} + ] + _this.emptys = new Array(12-_this.totalRecords.length); + },300) + } + + + sourceNameSelected = this.sourceNameList[0]; + getqueryAllSourceNames() { + this.myhttp.getqueryAllSourceNames().subscribe((data) => { + for (let i = 0; i < data.length; i++) { + this.sourceNameList.push(data[i]); + } + this.sourceNameSelected = this.sourceNameList[0]; + }) + } + choseSourceName(item) { + this.sourceNameSelected = item; + if (item == "---auto---") { + this.sourceName = ''; + } else { + this.sourceName = item; + } + } + // vnfs data + totalRecords = []; + totalpnfs = []; + //Fill the box + emptys = []; + + // getperformanceSsourceNames() { + // this.myhttp.getperformanceSourceNames(this.currentPage, this.pageSize, this.sourceName).subscribe((data) => { + // this.totalRecords = data.totalRecords; + // this.vnfsdataTotal = data.names; + // if (Number.isInteger(this.totalRecords.length / 5)) { + // this.emptys = new Array(0); + // } else { + // this.emptys = new Array(5 - this.totalRecords.length % 5); + // } + // }) + // } + //Detail page title display + isHidden = true; + graphicshow = false; + detailshow = false; + // Show hidden animation + state = "show"; + state2 = "hide"; + state3 = "hide"; + performanceShow() { + this.state = 'show'; + this.state2 = 'hide'; + this.state3 = 'hide'; + this.graphicshow = false; + this.detailshow = false; + } + // Selected name + + graphicShow() { + this.state = 'hide'; + this.state2 = 'show'; + this.state3 = 'hide'; + this.graphicshow = true; + this.detailshow = false; + } + vnfname: string; + graphicShow2(item) { + this.state = 'hide'; + this.state2 = 'show'; + this.state3 = 'hide'; + this.graphicshow = true; + this.detailshow = false; + this.vnfname = item; + } + // Selected id + detailId: string; + detailShow(item) { + this.state = 'hide'; + this.state2 = 'hide'; + this.state3 = 'show'; + this.graphicshow = true; + this.detailshow = true; + this.detailId = item.id.id; + } +} diff --git a/usecaseui-portal/src/app/views/performance/performance.component.css b/usecaseui-portal/src/app/views/performance/performance.component.css new file mode 100644 index 00000000..f2169538 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance.component.css @@ -0,0 +1,26 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} diff --git a/usecaseui-portal/src/app/views/performance/performance.component.html b/usecaseui-portal/src/app/views/performance/performance.component.html new file mode 100644 index 00000000..cd92b659 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance.component.html @@ -0,0 +1,17 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<h3 class="title"> Performance </h3> +<hr> diff --git a/usecaseui-portal/src/app/views/performance/performance.component.less b/usecaseui-portal/src/app/views/performance/performance.component.less new file mode 100644 index 00000000..2b1949a5 --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance.component.less @@ -0,0 +1,11 @@ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} diff --git a/usecaseui-portal/src/app/views/performance/performance.component.spec.ts b/usecaseui-portal/src/app/views/performance/performance.component.spec.ts new file mode 100644 index 00000000..1bdc919d --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PerformanceComponent } from './performance.component'; + +describe('PerformanceComponent', () => { + let component: PerformanceComponent; + let fixture: ComponentFixture<PerformanceComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PerformanceComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PerformanceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/performance/performance.component.ts b/usecaseui-portal/src/app/views/performance/performance.component.ts new file mode 100644 index 00000000..12405e9e --- /dev/null +++ b/usecaseui-portal/src/app/views/performance/performance.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-performance', + templateUrl: './performance.component.html', + styleUrls: ['./performance.component.less'] +}) +export class PerformanceComponent implements OnInit { + + constructor() { } + + ngOnInit() { + + } + +} diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css new file mode 100644 index 00000000..4e80750c --- /dev/null +++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.css @@ -0,0 +1,67 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.list { + background-color: #fff; + border-radius: 5px; + padding: 10px; +} +.list nz-table tbody td span.onboarding { + font-size: 12px; + color: #147dc2; +} +.list nz-table tbody td span.onboarded { + font-size: 14px; + color: #147dc2; +} +.list nz-table tbody td span.updating { + font-size: 12px; + color: blue; +} +.list nz-table tbody td span.deleting { + font-size: 12px; + color: red; +} +.list nz-table tbody td span.invalid { + font-size: 14px; + color: purple; +} +.list nz-table tbody td i.anticon { + cursor: pointer; + font-size: 18px; + padding: 2px; +} +.list nz-table tbody td i.anticon:hover { + color: #147dc2; +} +.list nz-table tbody td .cannotclick { + pointer-events: none; + color: #aaa; + opacity: 0.6; +} +.list nz-table tbody td .fileIcon{ + display: none; +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html new file mode 100644 index 00000000..70ee81c0 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.html @@ -0,0 +1,333 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<nz-tabset [nzTabPosition]="'top'" [nzType]="'card'"> + <nz-tab *ngFor="let tab of tabs" [nzTitle]="tab" (nzClick)="handleTabChange(tab)"> + <!-- nsList --> + <div class="list" *ngIf="tab === 'NS'"> + <!-- <h3 class="title"> Onboard {{tabTitle}} </h3> --> + <div style="width:100%;height: 30%;margin-bottom: 1%"> + <div class="listupload"> + <nz-upload nzType="drag" [(nzFileList)]="fileListNS" [nzBeforeUpload]="beforeUploadNS"> + <p class="ant-upload-drag-icon"> + <i nz-icon type="inbox" class="anticon anticon-inbox"></i> + </p> + <p class="ant-upload-text"> {{"i18nTextDefine_Click_CSAR_File" | translate}} </p> + <p class="ant-upload-hint"></p> + </nz-upload> + <button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileListNS.length == 0" + style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"> + {{ nsuploading ? 'Uploading' : 'Start Upload' }} + </button> + </div> + <div class="listlin"></div> + <div class="listfile"> + <div style="color: rgba(66,84,143,1);font-family:ArialMT;padding-bottom: 15px;height: 15%"> {{"i18nTextDefine_Uploaded_files" | translate}} </div> + <div class="nouploadfile">{{"i18nTextDefine_Nofileuploading" | translate}}</div> + <div style="height:80%;overflow: auto"> + <div class="listfilebgc" *ngFor="let itemns of nsRightList"> + <div> + <i class="anticon anticon-link"></i> + </div> + <div class="color" [ngClass]="{'progress':itemns.status == true}">{{itemns.name}}</div> + <div class="color" *ngIf="itemns.status"> + <nz-progress [nzPercent]="itemns.progress" [nzShowInfo]="false"></nz-progress> + </div> + <div class="color" *ngIf="!itemns.status"> + <span *ngIf="itemns.success == 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span> + <span *ngIf="itemns.success == 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span> + </div> + <div *ngIf="!itemns.status"> + <i class="anticon anticon-check-circle" *ngIf="itemns.success == 0" style="color:#7BC7F3!important;"></i> + <i class="anticon anticon-exclamation-circle" *ngIf="itemns.success == 1" style="color:#fb5c5c!important;"></i> + </div> + </div> + </div> + </div> + </div> + <nz-spin [nzSpinning]="isSpinning" style="height: 69%"> + <div class="mask" *ngIf="isSpinning"></div> + <nz-table #nzTable [nzData]="nstableData" nzShowSizeChanger [nzFrontPagination]="true" + [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="nspageSize" + [(nzPageIndex)]='nspageIndex' [nzLoading]="loading" nzSize="middle"> + <thead (nzSortChange)="sort($event)" nzSingleSort> + <tr> + <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th> + <th nzWidth="15%" nzShowSort nzSortKey="name"> {{"i18nTextDefine_Name" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_OperationalState" | translate}} </th> + <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of nzTable.data; let i = index; "> + <td>{{i+1}}</td> + <!--<td *ngIf="item.uuid">{{item.uuid}}</td>--> + + <td *ngIf="item.nsdName">{{item.nsdName}}</td> + <td *ngIf="item.nsdName === null || item.nsdName === ''"> </td> + <td *ngIf="item.name">{{item.name}}</td> + <td *ngIf="item.name===null || item.name=== ''"> </td> + <td *ngIf="item.nsdVersion">{{item.nsdVersion}}</td> + <td *ngIf="item.nsdVersion === null || item.nsdVersion === ''"> </td> + <td *ngIf="item.version">{{item.version}}</td> + <td *ngIf="item.version === null || item.version === ''"> </td> + <td> + <span *ngIf="item.nsdOnboardingState">{{item.nsdOnboardingState}}</span> + <span *ngIf="item.nsdOnboardingState === null || item.nsdOnboardingState === ''"> </span> + <span *ngIf="item.uuid">{{status}}</span> + + <!-- <span *ngIf="item.uuid" [ngClass]="{'active':data.status=='Active','closed':data.status=='Closed','onboarding':data.status=='Onboarding', + 'updating':data.status=='Updating','deleting':data.status=='Deleting','creating':data.status=='Creating', + 'scaling':data.status=='Scaling','healing':data.status=='Healing'}">{{data.status || "Active"}}</span> + <nz-progress *ngIf="item.uuid" *ngIf="data.status == 'Creating' || data.status == 'Deleting' || data.status == 'Scaling' || data.status == 'Healing' " [nzPercent]="data.rate"></nz-progress> --> + </td> + <td>{{item.nsdOperationalState}}</td> + <td>{{item.nsdUsageState}}</td> + <td> + <i [ngClass]="{'cannotclick':onboardData.status == 'onboarding' && i == currentIndex}" + class="anticon anticon-upload upicon" #upload_icon (click)="updataNsService(item.uuid,i,notificationModel)" + *ngIf="item.uuid"></i> + <i class="anticon anticon-delete" nzType="info" (click)="showConfirm(i,item.id,tab,notificationModel)" + *ngIf="item.id"></i> + <!--<span *ngIf="item.id" [ngClass]="{'fileIcon':OnboardFile == 'disNone'}">--> + <!--<span *ngIf="item.id && item.sameid == undefined">--> + <!--<nz-upload [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload">--> + <!--<i class="anticon anticon-file" type="upload" (click)="onClickId(item.id,tab)"></i>--> + <!--</nz-upload>--> + <!--<button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileList.length == 0"--> + <!--style="margin-top: 16px" *ngIf="item.id==nsdInfoId">--> + <!--{{ nsuploading ? 'Uploading' : 'Start Upload' }}--> + <!--</button>--> + <!--</span>--> + + </td> + </tr> + </tbody> + </nz-table> + </nz-spin> + <!-- <div style="margin-top:8px;"> + Loading state: + <nz-switch [(ngModel)]="isSpinning"></nz-switch> + </div> --> + + </div> + <!-- VNFList --> + <div class="list" *ngIf="tab === 'VNF'"> + <!-- <h3 class="title"> Onboard {{tabTitle}} </h3> --> + <div style="width:100%;height: 30%;margin-bottom: 1%"> + <div class="listupload"> + <nz-upload nzType="drag" [(nzFileList)]="fileListVNF" [nzBeforeUpload]="beforeUploadVNF"> + <p class="ant-upload-drag-icon"> + <i nz-icon type="inbox" class="anticon anticon-inbox"></i> + </p> + <p class="ant-upload-text">Click or drag CSAR File here</p> + <p class="ant-upload-hint"></p> + </nz-upload> + <button nz-button [nzLoading]="vnfuploading" (click)="onClick(tab)" [disabled]="fileListVNF.length == 0" + style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"> + {{ vnfuploading ? 'Uploading' : 'Start Upload' }} + </button> + </div> + <div class="listlin"></div> + <div class="listfile"> + <div style="color: rgba(66,84,143,1);font-family:ArialMT;padding-bottom: 15px;height: 15%"> {{"i18nTextDefine_Uploaded_files" | translate}} </div> + <div class="nouploadfile">{{"i18nTextDefine_Nofileuploading" | translate}}</div> + <div style="height:80%;overflow: auto"> + <div class="listfilebgc" *ngFor="let itemns of vnfRightList"> + <div> + <i class="anticon anticon-link"></i> + </div> + <div class="color" [ngClass]="{'progress':itemns.status == true}">{{itemns.name}}</div> + <div class="color" *ngIf="itemns.status"> + <nz-progress [nzPercent]="itemns.progress" [nzShowInfo]="false"></nz-progress> + </div> + <div class="color" *ngIf="!itemns.status"> + <span *ngIf="itemns.success == 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span> + <span *ngIf="itemns.success == 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span> + </div> + <div *ngIf="!itemns.status"> + <i class="anticon anticon-check-circle" *ngIf="itemns.success == 0" style="color:#7BC7F3!important;"></i> + <i class="anticon anticon-exclamation-circle" *ngIf="itemns.success == 1" style="color:#fb5c5c!important;"></i> + </div> + </div> + </div> + </div> + </div> + <nz-spin [nzSpinning]="isSpinning" style="height: 69%"> + <div class="mask" *ngIf="isSpinning"></div> + <nz-table #nzTable [nzData]="vnftableData" nzShowSizeChanger [nzFrontPagination]="true" + [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="vnfpageSize" + [(nzPageIndex)]='vnfpageIndex' [nzLoading]="loading" nzSize="middle"> + <thead (nzSortChange)="sort($event)" nzSingleSort> + <tr> + <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th> + <th nzWidth="15%" nzShowSort nzSortKey="name"> {{"i18nTextDefine_Name" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_OperationalState" | translate}} </th> + <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of nzTable.data; let i = index; "> + <td>{{i+1}}</td> + <!--<td *ngIf="item.uuid">{{item.uuid}}</td>--> + <td *ngIf="item.vnfProductName">{{item.vnfProductName}}</td> + <td *ngIf="item.vnfProductName === null || item.vnfProductName === ''"> </td> + <td *ngIf="item.name">{{item.name}}</td> + <td *ngIf="item.vnfdVersion">{{item.vnfdVersion}}</td> + <td *ngIf="item.vnfdVersion === null || item.vnfdVersion === ''"> </td> + <td *ngIf="item.version">{{item.version}}</td> + <td>{{item.onboardingState}}</td> + <td>{{item.operationalState}}</td> + <td>{{item.usageState}}</td> + <td> + <i [ngClass]="{'cannotclick':onboardData.status == 'onboarding' && i == currentIndex}" + class="anticon anticon-upload upicon" #upload_icon (click)="updataVnfService(item.uuid,i,notificationModel)" + *ngIf="item.uuid"></i> + <i class="anticon anticon-delete" nzType="info" (click)="showConfirm(i,item.id,tab,notificationModel)" + *ngIf="item.id"></i> + <!--<span *ngIf="item.id && item.sameid == undefined">--> + <!--<nz-upload [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload">--> + <!--<!– <button nz-button> –>--> + <!--<i class="anticon anticon-file" type="upload" (click)="onClickId(item.id,tab)"></i>--> + <!--<!– <span >upload</span> –>--> + <!--<!– </button> –>--> + + <!--</nz-upload>--> + <!--<button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileList.length == 0"--> + <!--style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"--> + <!--*ngIf="item.id==vnfPkgId">--> + <!--{{ nsuploading ? 'Uploading' : 'Start Upload' }}--> + <!--</button>--> + <!--</span>--> + </td> + </tr> + </tbody> + </nz-table> + </nz-spin> + + </div> + <!-- PNFList --> + <div class="list" *ngIf="tab === 'PNF'"> + <!-- <h3 class="title"> Onboard {{tabTitle}} </h3> --> + <div style="width:100%;height: 30%;margin-bottom: 1%"> + <div class="listupload"> + <nz-upload nzType="drag" [(nzFileList)]="fileListPNF" [nzBeforeUpload]="beforeUploadPNF"> + <p class="ant-upload-drag-icon"> + <i nz-icon type="inbox" class="anticon anticon-inbox"></i> + </p> + <p class="ant-upload-text">Click or drag CSAR File here</p> + <p class="ant-upload-hint"></p> + </nz-upload> + <button nz-button [nzLoading]="pnfuploading" (click)="onClick(tab)" [disabled]="fileListPNF.length == 0" + style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"> + {{ pnfuploading ? 'Uploading' : 'Start Upload' }} + </button> + </div> + <div class="listlin"></div> + <div class="listfile"> + <div style="color: rgba(66,84,143,1);font-family:ArialMT;padding-bottom: 15px;height: 15%"> {{"i18nTextDefine_Uploaded_files" | translate}} </div> + <div class="nouploadfile">{{"i18nTextDefine_Nofileuploading" | translate}}</div> + <div style="height:80%;overflow: auto"> + <div class="listfilebgc" *ngFor="let itemns of pnfRightList"> + <div> + <i class="anticon anticon-link"></i> + </div> + <div class="color" [ngClass]="{'progress':itemns.status == true}">{{itemns.name}}</div> + <div class="color" *ngIf="itemns.status"> + <nz-progress [nzPercent]="itemns.progress" [nzShowInfo]="false"></nz-progress> + </div> + <div class="color" *ngIf="!itemns.status"> + <span *ngIf="itemns.success == 0">{{"i18nTextDefine_File_upload_completed" | translate}}</span> + <span *ngIf="itemns.success == 1">{{"i18nTextDefine_File_upload_failed" | translate}}</span> + </div> + <div *ngIf="!itemns.status"> + <i class="anticon anticon-check-circle" *ngIf="itemns.success == 0" style="color:#7BC7F3!important;"></i> + <i class="anticon anticon-exclamation-circle" *ngIf="itemns.success == 1" style="color:#fb5c5c!important;"></i> + </div> + </div> + </div> + </div> + </div> + <nz-spin [nzSpinning]="isSpinning" style="height: 69%"> + <div class="mask" *ngIf="isSpinning"></div> + <nz-table #nzTable [nzData]="pnftableData" nzShowSizeChanger [nzFrontPagination]="true" + [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="pnfpageSize" + [(nzPageIndex)]='pnfpageIndex' [nzLoading]="loading" nzSize="middle"> + <thead (nzSortChange)="sort($event)" nzSingleSort> + <tr> + <th nzWidth="15%"> {{"i18nTextDefine_NO" | translate}} </th> + <th nzWidth="15%" nzShowSort nzSortKey="name"> {{"i18nTextDefine_Name" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Version" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_OnboardingState" | translate}} </th> + <th nzWidth="10%"> {{"i18nTextDefine_UsageState" | translate}} </th> + <th nzWidth="15%"> {{"i18nTextDefine_Operationbutton" | translate}} </th> + </tr> + </thead> + <tbody> + <tr *ngFor="let item of nzTable.data; let i = index; "> + <td>{{i+1}}</td> + <td>{{item.pnfdName}}</td> + <td>{{item.pnfdVersion}}</td> + <td>{{item.pnfdOnboardingState}}</td> + <td>{{item.pnfdUsageState}}</td> + <td> + <i class="anticon anticon-delete" nzType="info" (click)="showConfirm(i,item.id,tab,notificationModel)"></i> + <!--<span *ngIf="item.id" [ngClass]="{'fileIcon':OnboardFile == 'disNone'}">--> + <!--<nz-upload [(nzFileList)]="fileList" [nzBeforeUpload]="beforeUpload">--> + <!--<i class="anticon anticon-file" type="upload" (click)="onClickId(item.id,tab)"></i>--> + <!--</nz-upload>--> + <!--<button nz-button [nzLoading]="nsuploading" (click)="onClick(tab)" [disabled]="fileList.length == 0"--> + <!--style="margin-top: 16px;margin-left: 55px;color: #FFFFFF;font-size: 13px;background-color: #3E9BFF;font-family: ArialMT;"--> + <!--*ngIf="item.id==vnfPkgId">--> + <!--{{ nsuploading ? 'Uploading' : 'Start Upload' }}--> + <!--</button>--> + <!--</span>--> + </td> + </tr> + </tbody> + </nz-table> + </nz-spin> + + </div> + </nz-tab> + <!--2019.08.14 add notification--> + <ng-template #notificationModel > + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="{{notificationAttributes.imgPath}}" alt="{{notificationAttributes.status}}"> + </span> + <div class="ant-notification-notice-message"> + {{notificationAttributes.title}} + {{"i18nTextDefine_"+notificationAttributes.action | translate}} {{"i18nTextDefine_"+notificationAttributes.status | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p>{{notificationAttributes.title}} id: </p> + <span>{{ notificationAttributes.id }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> +</nz-tabset> + diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less new file mode 100644 index 00000000..c31409c9 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.less @@ -0,0 +1,182 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.switch_btn { + position: absolute; + right: 6%; + top: 18px; + border: 1px solid #3fa8eb; + width: 8%; + border-radius: 10px; + margin-bottom: 18px; + span { + display: block; + float: left; + text-align: center; + width: 50%; + color: #3fa8eb; + font-weight: 700; + cursor: pointer; + } + span:first-child { + border-radius: 10px 0 0 10px; + } + span:last-child { + border-radius: 0 10px 10px 0; + } + span.left_b { + border-left: 1px solid #3fa8eb; + } + span.active { + color: #fff; + background: #3fa8eb; + } +} + +.list { + // background-color: #fff; + border-radius: 5px; + // padding: 10px; + .listupload { + width: 22%; + vertical-align: top; + display: inline-block; + margin-left: 13%; + } + .listlin { + vertical-align: top; + display: inline-block; + width: 1%; + margin-left: 10%; + height: 177px; + margin-bottom: 30px; + border-right: 2px solid #EEEEEE; + } + .listfile { + width: 43%; + height: 100%; + vertical-align: top; + display: inline-block; + margin-left: 10%; + .nouploadfile{ + height: 80%; + width: 100%; + text-align: center; + font-size: 22px; + margin-top: 5%; + } + .listfilebgc { + background-color: #fff; + border-bottom: 8px solid #F7F8FC; + } + .listfilebgc { + background-color: #fff; + height: 30px; + border-radius: 2px; + line-height: 2; + color: #42548F; + border-bottom: 4px solid #F7F8FC; + >div { + float: left; + } + :first-child { + width: 6%; + margin-left: 5px; + } + :nth-child(2){ + width:20%; + } + :nth-child(3){ + width: 60%; + text-align: center; + } + :nth-child(4){ + padding-left: 4%; + } + .color { + color:rgba(66,84,143,1); + span{ + color:rgba(66,84,143,0.7); + } + } + .progress{ + color:rgba(66,84,143,0.7); + } + } + } + nz-table { + tbody { + td { + span.onboarding { + font-size: 12px; + color: #147dc2; + } + span.onboarded { + font-size: 14px; + color: #147dc2; + } + span.updating { + font-size: 12px; + color: blue; + } + span.deleting { + font-size: 12px; + color: red; + } + span.invalid { + font-size: 14px; + color: purple; + } + i.anticon { + cursor: pointer; + font-size: 18px; + padding: 2px; + &:hover{ + color: #147dc2; + } + } + .cannotclick { + pointer-events: none; + color: #aaa; + opacity: 0.6; + } + .fileIcon{ + display: none; + } + } + } + } +} +.mask { + top: 0; + left: 0; + position: fixed; + width: 100%; + height: 100%; + opacity: 0.1; + background: black; + z-index: 1049; +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts new file mode 100644 index 00000000..0e49f656 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OnboardVnfVmComponent } from './onboard-vnf-vm.component'; + +describe('OnboardVnfVmComponent', () => { + let component: OnboardVnfVmComponent; + let fixture: ComponentFixture<OnboardVnfVmComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ OnboardVnfVmComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(OnboardVnfVmComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts new file mode 100644 index 00000000..4899aed8 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/onboard-vnf-vm/onboard-vnf-vm.component.ts @@ -0,0 +1,668 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { HttpClient, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Component, OnInit, HostBinding, TemplateRef } from '@angular/core'; +import { NzNotificationService } from 'ng-zorro-antd'; +// import { MyhttpService } from '../../myhttp.service'; +import { onboardService } from '../../../core/services/onboard.service'; +import { slideToRight } from '../../../animates'; +import { NzMessageService, UploadFile, NzModalRef, NzModalService } from 'ng-zorro-antd'; +import { filter } from 'rxjs/operators'; +import { Title } from '@angular/platform-browser'; + +@Component({ + selector: 'app-onboard-vnf-vm', + templateUrl: './onboard-vnf-vm.component.html', + styleUrls: ['./onboard-vnf-vm.component.less'], + animations: [slideToRight] +}) +export class OnboardVnfVmComponent implements OnInit { + @HostBinding('@routerAnimate') routerAnimateState; + + // delete Modal + confirmModal: NzModalRef; + nsdInfoId = ''; + vnfPkgId = ''; + pnfdInfoId = ''; + tabTitle = "NS"; + nsuploading = false; + vnfuploading = false; + pnfloading = false; + fileList: UploadFile[] = []; + fileListNS: UploadFile[] = []; + fileListVNF: UploadFile[] = []; + fileListPNF: UploadFile[] = []; + // onboard initial value + status = "Onboard Available"; + jobId = ''; + //url + url = { + // line up + ns: '/api/nsd/v1/ns_descriptors/*_*/nsd_content', + vnf: '/api/vnfpkgm/v1/vnf_packages/*_*/package_content', + pnf: '/api/nsd/v1/pnf_descriptors/*_*/pnfd_content' + // line local + //ns: 'https://jsonplaceholder.typicode.com/posts/', + //vnf: 'https://jsonplaceholder.typicode.com/posts/', + //pnf: 'https://jsonplaceholder.typicode.com/posts/', + }; + constructor( + private myhttp: onboardService, + private http: HttpClient, + private msg: NzMessageService, + private titleService: Title, + private modal: NzModalService, + private modalService: NzModalService, + private notification: NzNotificationService + ) { } + //default Call ns data by default + ngOnInit() { + this.getTableData(); + } + + //Tabular data + nstableData: any; + vnftableData: any; + pnftableData: any; + nssdcData: any; + nsvfcData: any; + + vnfsdcData: any; + vnfvfcData: any; + nspageIndex = 1; + nspageSize = 10; + vnfpageIndex = 1; + vnfpageSize = 10; + pnfpageIndex = 1; + pnfpageSize = 10; + total; + nsloading = false; + sortName = null; + sortValue = null; + tabs = ['NS', 'VNF', 'PNF']; + isSpinning = false; + + //2019.08.14 add + notificationAttributes = { + "title": this.tabs[0], + "imgPath": "../../../../assets/images/execute-inproess.png", + "action": "OnboardingState", + "status": "InProgress", + "id": null + }; + notificationModelShow(template: TemplateRef<{}>): void { + this.notification.template(template); + } + notificationSuccess(notificationModel) { + this.notificationAttributes.imgPath = "../../../../assets/images/execute-success.png"; + this.notificationAttributes.status = "Success"; + this.notificationModelShow(notificationModel); + } + notificationFailed(notificationModel) { + this.notificationAttributes.imgPath = "../../../../assets/images/execute-faild.png"; + this.notificationAttributes.status = "Failed"; + this.notificationModelShow(notificationModel); + } + // Handling tab switching request data + handleTabChange(tab) { + this.tabTitle = tab; + switch (tab) { + case 'NS': + this.nstableData = []; + this.getTableData(); + this.fileList = []; //Empty uploaded files when switching + break + case 'VNF': + this.vnftableData = []; + this.getTableVnfData() + this.fileList = []; + break + case 'PNF': + this.pnftableData = []; + this.getTablePnfData() + this.fileList = []; + break + } + } + + + //before put create--Drag and drop files to the page before uploading + requestBody = { + "userDefinedData": { + "additionalProp1": "", + "additionalProp2": "", + "additionalProp3": "" + } + } + + //NS/VNF List add file + beforeUpload = (file: UploadFile): boolean => { + this.fileList.push(file); + return false; + } + + // ns beforeUpload + beforeUploadNS = (file: UploadFile): boolean => { + this.fileListNS.push(file); + this.myhttp.getCreatensData("createNetworkServiceData", this.requestBody)//on-line + // this.myhttp.getCreatensData("creatensDataNS") //local + .subscribe((data) => { + this.nsdInfoId = data["id"]; + }, (err) => { + console.log(err); + }) + return false; + } + + //vnf beforeUpload + beforeUploadVNF = (file: UploadFile): boolean => { + this.fileListVNF.push(file); + this.myhttp.getCreatensData("createVnfData", this.requestBody)//on-line + // this.myhttp.getCreatensData("creatensDataVNF") //local + .subscribe((data) => { + this.vnfPkgId = data["id"]; + }, (err) => { + console.log(err); + }) + return false; + } + + // //pnf eforeUpload + beforeUploadPNF = (file: UploadFile): boolean => { + this.fileListPNF.push(file); + this.myhttp.getCreatensData("createPnfData", this.requestBody) //on-line + // this.myhttp.getCreatensData("creatensDataPNF") //local + .subscribe((data) => { + this.pnfdInfoId = data["id"]; + }, (err) => { + console.log(err); + }) + return false; + } + + //Get list list id + onClickId(id, tab) { + switch (tab) { + case 'NS': + this.nsdInfoId = id; + break + case 'VNF': + this.vnfPkgId = id; + break + case 'PNF': + this.pnfdInfoId = id; + break + } + } + + //Drag and drop and click the upload button + onClick(tab) { + switch (tab) { + case 'NS': + // this.handleUpload('/api/nsd/v1/ns_descriptors/'+this.nsdInfoId+'/nsd_content',tab); + this.handleUpload(this.url.ns.replace("*_*", this.nsdInfoId), tab); + this.getTableData(); + break + case 'VNF': + // this.handleUpload('/api/vnfpkgm/v1/vnf_packages/'+this.vnfPkgId+'/package_content',tab); + this.handleUpload(this.url.vnf.replace("*_*", this.vnfPkgId), tab); + this.getTableVnfData() + break + case 'PNF': + // this.handleUpload('/api/nsd/v1/pnf_descriptors/'+this.pnfdInfoId+'/pnfd_content',tab); + this.handleUpload(this.url.pnf.replace("*_*", this.pnfdInfoId), tab); + this.getTablePnfData(); + break + } + } + + nsRightList = []; + nsNum = 0; + vnfRightList = []; + vnfNum = 0; + pnfRightList = []; + pnfNum = 0; + //put Upload Upload + handleUpload(url, tab): void { + const formData = new FormData(); + // tslint:disable-next-line:no-any + switch (tab) { + case "NS": + this.fileListNS.forEach((file: any) => { + formData.append('file', file); + }); + this.nsuploading = true; + let lastNs = this.fileListNS[this.fileListNS.length - 1]; + let nsfile = { + name: lastNs.name, + uid: lastNs.uid, + progress: 0, + status: true, + success: 0 + }; + this.nsNum += 1; + this.nsRightList.push(nsfile); + let requeryNs = (nsfile) => { + setTimeout(() => { + nsfile.progress += 2; + if (nsfile.progress < 100) { + requeryNs(nsfile) + } else { + nsfile.progress = 100; + nsfile.status = false; + } + }, 100) + }; + requeryNs(nsfile); + break + case "VNF": + this.fileListVNF.forEach((file: any) => { + formData.append('file', file); + }); + this.vnfuploading = true; + let lastVnf = this.fileListVNF[this.fileListVNF.length - 1]; + let vnffile = { + name: lastVnf.name, + uid: lastVnf.uid, + progress: 0, + status: true, + success: 0 + }; + this.vnfNum += 1; + this.vnfRightList.push(vnffile); + let requeryVnf = (vnffile) => { + setTimeout(() => { + vnffile.progress += 2; + if (vnffile.progress < 100) { + requeryVnf(vnffile) + } else { + vnffile.progress = 100; + vnffile.status = false; + } + }, 100) + }; + requeryVnf(vnffile); + break + case "PNF": + this.fileListPNF.forEach((file: any) => { + formData.append('file', file); + }); + this.pnfloading = true; + let lastPnf = this.fileListPNF[this.fileListPNF.length - 1]; + let pnffile = { + name: lastPnf.name, + uid: lastPnf.uid, + progress: 0, + status: true, + success: 0 + }; + this.pnfNum += 1; + this.pnfRightList.push(pnffile); + let requeryPnf = (pnffile) => { + setTimeout(() => { + pnffile.progress += 2; + if (pnffile.progress < 100) { + requeryPnf(pnffile) + } else { + pnffile.progress = 100; + pnffile.status = false; + } + }, 100) + }; + requeryPnf(pnffile); + break + } + // line PUT + const req = new HttpRequest('PUT', url, formData, { + reportProgress: true, + withCredentials: true + }); + //Upload pre-empty array + this.fileList = []; + this.fileListNS = []; + this.fileListVNF = []; + this.fileListPNF = []; + this.http.request(req) + .pipe(filter(e => e instanceof HttpResponse)) + .subscribe( + (event: {}) => { + if (tab == "NS") { + this.nsRightList[this.nsNum - 1].progress = 100; + this.nsRightList[this.nsNum - 1].status = false; + this.nsRightList[this.nsNum - 1].success = 0; + } + if (tab == "VNF") { + this.vnfRightList[this.vnfNum - 1].progress = 100; + this.vnfRightList[this.vnfNum - 1].status = false; + this.vnfRightList[this.vnfNum - 1].success = 0; + } + if (tab == "PNF") { + this.pnfRightList[this.pnfNum - 1].progress = 100; + this.pnfRightList[this.pnfNum - 1].status = false; + this.pnfRightList[this.pnfNum - 1].success = 0; + } + this.changeUploadingSta(tab); + this.msg.success('upload successfully.'); + }, + err => { + if (tab == "NS") { + this.nsRightList[this.nsNum - 1].progress = 100; + this.nsRightList[this.nsNum - 1].status = false; + this.nsRightList[this.nsNum - 1].success = 1; + } + if (tab == "VNF") { + this.vnfRightList[this.vnfNum - 1].progress = 100; + this.vnfRightList[this.vnfNum - 1].status = false; + this.vnfRightList[this.vnfNum - 1].success = 1; + } + if (tab == "PNF") { + this.pnfRightList[this.pnfNum - 1].progress = 100; + this.pnfRightList[this.pnfNum - 1].status = false; + this.pnfRightList[this.pnfNum - 1].success = 1; + } + this.changeUploadingSta(tab); + this.msg.error('upload failed.'); + } + ); + } + + // Control the status of uploading + changeUploadingSta(tab) { + switch (tab) { + case "NS": + this.nsuploading = false; + break + case "VNF": + this.vnfuploading = false; + break + case "PNF": + this.pnfloading = false; + } + } + + //---------------------------------------------------------------------------------------------- + + // Get the NS list + getTableData() { + this.isSpinning = true; + //ns vfc lists + this.myhttp.getOnboardTableData() + .subscribe((data) => { + this.nsvfcData = data; + this.nstableData = this.nsvfcData; + //ns sdc list + this.myhttp.getSDC_NSTableData() + .subscribe((data) => { + this.isSpinning = false; //loading hide + this.nssdcData = data; + this.nsvfcData.map((nsvfc) => { nsvfc.sameid = this.nssdcData.find((nssdc) => { return nsvfc.id == nssdc.uuid }) && nsvfc.id; return nsvfc; }); + let sameData = this.nssdcData.filter((nssdc) => { return !this.nsvfcData.find((nsvfc) => { return nsvfc.id == nssdc.uuid }) }); + this.nstableData = this.nstableData.concat(sameData); + }, (err) => { + console.log(err); + this.isSpinning = false; + }) + }, (err) => { + console.log(err); + this.isSpinning = false; + }) + + } + + // Get the vnf list + getTableVnfData() { + this.isSpinning = true; + //vnf vfc lists + this.myhttp.getOnboardTableVnfData() + .subscribe((data) => { + this.vnfvfcData = data; + this.vnftableData = this.vnfvfcData; + //vnf sdc lists + this.myhttp.getSDC_VNFTableData() + .subscribe((data) => { + this.isSpinning = false; //loading hide + this.vnfsdcData = data; + this.vnfvfcData.map((vnfvfc) => { vnfvfc.sameid = this.vnfsdcData.find((nssdc) => { return vnfvfc.id == nssdc.uuid }) && vnfvfc.id; return vnfvfc; }); + let sameData = this.vnfsdcData.filter((vnfsdc) => { return !this.vnfvfcData.find((vnfvfc) => { return vnfvfc.id == vnfsdc.uuid }) }); + this.vnftableData = this.vnftableData.concat(sameData); + }, (err) => { + console.log(err); + }) + + }, (err) => { + console.log(err); + }) + } + + // Get pnf list + getTablePnfData() { + this.isSpinning = true; + this.myhttp.getOnboardTablePnfData() + .subscribe((data) => { + this.pnftableData = data; + this.isSpinning = false; //loading hide + }, (err) => { + console.log(err); + }) + } + + //----------------------------------------------------------------------------------- + /* onboard */ + //Successful frame + success(tab): void { + const modal = this.modalService.success({ + nzTitle: 'This is an success message', + nzContent: 'Package Onboard Completed.' + }); + switch (tab) { + case "NS": + this.getTableData(); + break + case "VNF": + this.getTableVnfData(); + break + } + } + + //Failure frame + error(): void { + this.modalService.error({ + nzTitle: 'This is an error message', + nzContent: 'Package Onboard Failed!' + }); + } + + //onboard status + onboardData = { + status: "onboard", + progress: 0, + } + currentIndex = 0; + // ns onboard Upload button + updataNsService(id, index, notificationModel) { + this.currentIndex = index; + this.onboardData.status = "onboarding"; //Disabled + this.onboardData.progress = 0; + let requestBody = { + "csarId": id + }; + this.notificationAttributes = { + "title": this.tabs[0], + "imgPath": "../../../../assets/images/execute-inproess.png", + "action": "OnboardingState", + "status": "InProgress", + "id": id + }; + this.notificationModelShow(notificationModel); + this.myhttp.getNsonboard(requestBody) + .subscribe((data) => { + if (data.status == "failed") { + this.onboardData.status = "Failed"; + this.notificationFailed(notificationModel); + this.error(); + return false + } else if (data.status == "success") { + this.success("NS"); + this.onboardData.status = "onboarded"; + this.notificationSuccess(notificationModel); + } + }, (err) => { + console.log(err); + }) + } + + // vnf onboard Upload button + updataVnfService(id, index, notificationModel) { + this.currentIndex = index; + this.onboardData.status = "onboarding"; //Disabled button + this.onboardData.progress = 0; + + + let requestBody = { + "csarId": id + }; + this.notificationAttributes = { + "title": this.tabs[1], + "imgPath": "../../../../assets/images/execute-inproess.png", + "action": "OnboardingState", + "status": "InProgress", + "id": id + }; + this.notificationModelShow(notificationModel); + this.myhttp.getVnfonboard(requestBody) + .subscribe((data) => { + this.jobId = data.jobId; + this.queryProgress(this.jobId, 0, notificationModel); //vnf Need to query progress interface + }, (err) => { + console.log(err); + }) + } + + //Progress Progress inquiry + queryProgress(jobId, responseId, notificationModel) { + let mypromise = new Promise((res) => { + this.myhttp.getProgress(jobId, responseId) + .subscribe((data) => { + if (data.responseDescriptor == null || data.responseDescriptor == "null" || data.responseDescriptor.progress == undefined || data.responseDescriptor.progress == null) { + this.onboardData.status = "onboarding"; + setTimeout(() => { + this.queryProgress(this.jobId, 0, notificationModel); + }, 10000) + return false + } + if (data.responseDescriptor.progress > 100) { + this.onboardData.status = "Failed"; + this.notificationFailed(notificationModel); + this.error(); + return false + } + if (data.responseDescriptor.progress < 100) { + this.onboardData.status = "onboarding"; + setTimeout(() => { + this.queryProgress(this.jobId, 0, notificationModel); + }, 5000) + } else if (data.responseDescriptor.progress == 100) { + res(data); + this.success("VNF"); + this.onboardData.status = "onboarded"; + this.notificationSuccess(notificationModel); + } + return false + }) + }) + return mypromise; + } + + //-------------------------------------------------------------------------------- + /* delete button */ + showConfirm(index, pkgid, tab, notificationModel): void { + this.notificationAttributes = { + "title": this.tabs[0], + "imgPath": "../../../../assets/images/execute-inproess.png", + "action": "OnboardingState", + "status": "InProgress", + "id": pkgid + }; + this.confirmModal = this.modal.confirm({ + nzTitle: 'Do you Want to delete these items?', + nzContent: 'Do you Want to delete these items?', + nzOkText: 'Yes', + nzCancelText: 'No', + nzOnOk: () => new Promise((resolve, reject) => { + switch (tab) { + case 'NS': + this.notificationAttributes.title = this.tabs[0]; + this.notificationModelShow(notificationModel); + this.deleteNsService(index, pkgid, notificationModel); + setTimeout(Math.random() > 0.5 ? resolve : reject, 2000); + break + case 'VNF': + this.notificationAttributes.title = this.tabs[1]; + this.notificationModelShow(notificationModel); + this.deleteVnfService(index, pkgid, notificationModel); + setTimeout(Math.random() > 0.5 ? resolve : reject, 2000); + break + case 'PNF': + this.notificationAttributes.title = this.tabs[2]; + this.notificationModelShow(notificationModel); + this.deletePnfService(index, pkgid, notificationModel); + setTimeout(Math.random() > 0.5 ? resolve : reject, 2000); + break + } + }).catch(() => console.log('Oops errors!')) + }); + } + + //delete nsItem + deleteNsService(index, pkgid, notificationModel) { + this.myhttp.deleteNsIdData(pkgid) + .subscribe((data) => { + this.notificationSuccess(notificationModel); + //refresh list after successful deletion + this.getTableData(); + }, (err) => { + console.log(err); + this.notificationFailed(notificationModel); + }) + } + + //delete vnfItem + deleteVnfService(index, pkgid, notificationModel) { + this.myhttp.deleteVnfIdData(pkgid) + .subscribe((data) => { + this.notificationSuccess(notificationModel); + //refresh list after successful deletion + this.getTableVnfData() + }, (err) => { + console.log(err); + this.notificationFailed(notificationModel); + }) + } + + //delete PnfItem + deletePnfService(index, pkgid, notificationModel) { + this.myhttp.deletePnfIdData(pkgid) + .subscribe((data) => { + //refresh list after successful deletion + this.notificationSuccess(notificationModel); + this.getTablePnfData() + }, (err) => { + console.log(err); + this.notificationFailed(notificationModel); + }) + } + +} diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.css b/usecaseui-portal/src/app/views/services/services-list/services-list.component.css new file mode 100644 index 00000000..0a7f92eb --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.css @@ -0,0 +1,145 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.action { + margin-bottom: 20px; +} +.action span { + display: inline-block; + font: 700 14px "Arial"; + color: #4c5e70; +} +.action nz-dropdown { + vertical-align: middle; +} +.action nz-dropdown :hover { + border-color: #147dc2; +} +.action nz-dropdown button { + width: 165px; + height: 30px; + background-color: #eceff4; + text-align: left; + border-color: #9fa9ab; +} +.action nz-dropdown button span { + font-weight: 400; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; +} +.action nz-dropdown button i { + position: absolute; + top: 10px; + right: 10px; +} +.action .create { + float: right; + height: 30px; + padding: 0 10px; +} +.action .create span { + color: #fff; + font-weight: 400; +} +.list { + background-color: #fff; + border-radius: 5px; + padding: 10px; +} +.list nz-table tbody td span.active { + font-size: 14px; + color: #147dc2; +} +.list nz-table tbody td span.closed { + font-size: 14px; + color: red; +} +.list nz-table tbody td span.onboarding { + font-size: 12px; + color: #147dc2; +} +.list nz-table tbody td span.updating { + font-size: 12px; + color: blue; +} +.list nz-table tbody td span.deleting { + font-size: 12px; + color: red; +} +.list nz-table tbody td span.creating { + font-size: 12px; + color: green; +} +.list nz-table tbody td span.scaling { + font-size: 12px; + color: purple; +} +.list nz-table tbody td span.healing { + font-size: 12px; + color: orangered; +} +.list nz-table tbody td i.anticon { + cursor: pointer; + font-size: 18px; + padding: 2px; +} +.list nz-table tbody td i.anticon:hover { + color: #147dc2; +} +.list nz-table tbody td .cannotclick { + pointer-events: none; + color: #aaa; + opacity: 0.6; +} +.list nz-table tbody tr.childtr td { + font-size: 12px; + color: #147dc2; +} +.detailComponent { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100vh; + background-color: #f3f3f3; + overflow-y: auto; + padding: 20px 32px; + z-index: 3; +} +.createComponent { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100vh; + background-color: #f3f3f3; + overflow-y: auto; + padding: 20px 32px; + z-index: 3; +} diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.html b/usecaseui-portal/src/app/views/services/services-list/services-list.component.html new file mode 100644 index 00000000..6f6d8f74 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.html @@ -0,0 +1,745 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<div class="action ant-tabs-bar"> + + <span><i style="margin-right: 10px"><img src="assets/images/customer.png" alt=""></i> + {{"i18nTextDefine_Customer" | translate}} : </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{customerSelected.name}}</span> <i class="anticon anticon-down"></i> + </button> + <ul nz-menu style="min-height:40px;max-height: 200px; overflow: auto;"> + <li nz-menu-item (click)="choseCustomer(item)" *ngFor="let item of customerList"> + <a title="{{item.name}}" + style="max-width: 165px; overflow: hidden; text-overflow: ellipsis;">{{item.name}}</a> + </li> + </ul> + </nz-dropdown> + + <span style="margin-left:40px"><i style="margin-right: 10px"><img src="assets/images/service-type.png" alt=""></i> + {{"i18nTextDefine_ServiceType" | translate}} : </span> + <nz-dropdown [nzTrigger]="'click'" [nzPlacement]="'bottomLeft'"> + <button nz-button nz-dropdown><span>{{serviceTypeSelected.name}}</span> <i class="anticon anticon-down"></i> + </button> + <ul nz-menu style="min-height:40px;max-height: 200px; overflow: auto;"> + <li nz-menu-item (click)="choseServiceType(item)" *ngFor="let item of serviceTypeList"> + <a title="{{item.name}}" + style="max-width: 165px; overflow: hidden; text-overflow: ellipsis;">{{item.name}}</a> + </li> + </ul> + </nz-dropdown> + + <button class="create" nz-button [nzType]="'primary'" (click)="createModal()"><i class="anticon anticon-plus" + style="transform: scale(1.5);line-height: 15px;margin-right: 5px;"></i><span> + {{"i18nTextDefine_Create" | translate}} </span> + </button> + <nz-modal nzWidth="428" [(nzVisible)]="isVisible" nzTitle=" {{'i18nTextDefine_ServiceCreation' | translate}} " + (nzOnCancel)="handleCancel()" (nzOnOk)="handleOk()" nzClassName="serviceCreationModel" + nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <div class="select-list"> + <span style="display:inline-block;"> {{"i18nTextDefine_Customer" | translate}} : </span> + <nz-select style="width: 176px;float: right;" [(ngModel)]="customerSelected2.name" nzAllowClear + (ngModelChange)="customerChange()"> + <nz-option *ngFor="let item of customerList2" [nzValue]="item.name" [nzLabel]="item.name"></nz-option> + </nz-select> + </div> + <div class="select-list"> + <span style="display:inline-block;"> {{"i18nTextDefine_ServiceType" | translate}} : </span> + <nz-select style="width: 176px;float: right;" [(ngModel)]="serviceTypeSelectedName" nzAllowClear + (ngModelChange)="serviceTypeChange()"> + <nz-option *ngFor="let item of serviceTypeList2" [nzValue]="item.name" [nzLabel]="item.name"> + </nz-option> + </nz-select> + </div> + <div class="select-list"> + <span style="display:inline-block;"> {{"i18nTextDefine_UseCase" | translate}} : </span> + <nz-select style="width: 176px;float: right;" [(ngModel)]="templateTypeSelected" nzAllowClear + (ngModelChange)="choseTemplateType()"> + <!-- <nz-option *ngFor="let item of templateType" [nzValue]="item" [nzLabel]="item"></nz-option> --> + <nz-option nzValue="SOTN" nzLabel="SOTN"></nz-option> + <nz-option nzValue="CCVPN" nzLabel="CCVPN"></nz-option> + <nz-option nzValue="E2E Service" nzLabel="E2E Service"></nz-option> + <nz-option nzValue="Network Service" nzLabel="Network Service"></nz-option> + </nz-select> + </div> + + <div class="select-list"> + <span style="display:inline-block;width:70px;"> {{"i18nTextDefine_Template" | translate}} : </span> + <nz-select style="width: 176px;float: right;" [(ngModel)]="template1" nzAllowClear> + <nz-option *ngFor="let item of templates" [nzValue]="item" [nzLabel]="item.name"></nz-option> + </nz-select> + </div> + <div *ngIf="templateTypeSelected == 'E2E Service'"> + <div class="select-list"> + <span style="display:inline-block;width:70px;"> {{"i18nTextDefine_Orchestrator" | translate}} : </span> + <nz-select style="width: 176px;float: right;" [(ngModel)]="orchestratorSelected" nzAllowClear> + <nz-option *ngFor="let item of orchestratorList" [nzValue]="item" [nzLabel]="item.name"></nz-option> + </nz-select> + </div> + </div> + <div *ngIf="templateTypeSelected == 'E2E Service'"> + <div class="check-box" style="margin:30px; height: 50px"> + <input class="check-box-style" style="zoom: 1.8; width: 70px" type="checkbox" + [(ngModel)]="isSol005Interface" value="true" nzAllowClear> + <label class="label" style="font-size: 20px; color: rgb(60,79,140,0.5)">Sol005</label> + </div> + </div> + <div class="select-list" style="color: red;margin-left: 66px;" *ngIf="temParametersTips"> + {{"i18nTextDefine_Templateparsingfailed" | translate}} + </div> + </nz-modal> +</div> +<nz-layout style=" padding: 20px 32px; "> + <ul class="top-num"> + <li *ngFor="let item of serviceMunber" class="top-list"> + <span class="round">{{item.serviceDomain}}</span> + <div class="top-list-text"> + <p> + <span>{{item.failed}}</span> + <span> {{"i18nTextDefine_Failed" | translate}} </span> + </p> + <p> + <span>{{item.Success}}</span> + <span> {{"i18nTextDefine_Success" | translate}} </span> + </p> + <p> + <span>{{item.InProgress}}</span> + <span> {{"i18nTextDefine_InProgress" | translate}} </span> + </p> + </div> + <p class="service-description"> {{item.detailName | translate}} </p> + </li> + </ul> + <div class="list" id="services-list" [ngClass]="{'listdisplay':listDisplay == true}"> + <nz-table *ngIf="1" #nzTable [nzData]="tableData" nzShowSizeChanger [nzFrontPagination]="false" + [nzShowQuickJumper]="true" [nzPageSizeOptions]="[5,10,15,20]" [nzTotal]='total' [(nzPageSize)]="pageSize" + [(nzPageIndex)]='pageIndex' [nzLoading]="loading" [nzSize]="'middle'" [nzScroll]="{ y: '58vh' }" + (nzPageIndexChange)="searchData()" (nzPageSizeChange)="searchData(true)"> + <thead> + <tr> + <th nzWidth="5%"> {{"i18nTextDefine_NO" | translate}}</th> + <th nzWidth="5%"></th> + <th nzWidth="20%"> {{"i18nTextDefine_Name" | translate}}</th> + <th nzWidth="20%"> {{"i18nTextDefine_InstanceID" | translate}}</th> + <th nzWidth="15%"> {{"i18nTextDefine_UseCase" | translate}}</th> + <th nzWidth="20%"> {{"i18nTextDefine_Status" | translate}}</th> + <th nzWidth="15%"> {{"i18nTextDefine_Action" | translate}}</th> + </tr> + </thead> + <tbody> + <ng-template ngFor let-data [ngForOf]="nzTable.data" let-i="index"> + <tr> + <td>{{pageSize*(pageIndex-1) + i+1}}</td> + <td [nzShowExpand]="data.childServiceInstances[0]" [(nzExpand)]="data.expand"></td> + <td>{{data["service-instance-name"] || data.nsName}}</td> + <td>{{data["service-instance-id"] || data.nsInstanceId}}</td> + <td> + <p + [ngClass]="{'e2eColor':data.serviceDomain=='E2E Service','nsColor':data.serviceDomain=='Network Service','ccvpnColor':data.serviceDomain=='CCVPN','sotnColor':data.serviceDomain=='SOTN','voLTEColor':data.serviceDomain=='voLTE type'}"> + {{data.serviceDomain}} + </p> + </td> + <td> + <span [ngClass]="{'active':data.statusClass=='2001','closed':data.statusClass=='Closed','onboarding':data.statusClass=='Onboarding', + 'updating':data.statusClass=='Updating','deleting':data.statusClass=='1002','creating':data.statusClass=='1001', + 'scaling':data.statusClass=='1003','healing':data.statusClass=='1004'}" + *ngIf="data.tips != 'Available' && data.tips != 'Unavailable'">{{data.tips}}</span> + <span *ngIf="data.tips == 'Available' " style="margin-left: 10px"> + <img src="assets/images/wancheng-icon.png" alt="Available"> + </span> + <span *ngIf="data.tips == 'Unavailable' " style="margin-left: 10px"> + <img src="assets/images/shibai-icon.png" alt="Unavailable"> + </span> + <nz-progress *ngIf="data.status == 'In Progress'" [nzPercent]="data.rate" + [nzShowInfo]="false" nzStatus="active"></nz-progress> + </td> + <td> + <i [ngClass]="{'cannotclick':data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}" + class="anticon anticon-bars" (click)="serviceDetail(data,1)"></i> + <i [ngClass]="{'cannotclick':data.status == 'In Progress'}" class="anticon anticon-delete" + (click)="deleteModel(data)"></i> + <i [ngClass]="{'cannotclick':data.status == 'In Progress'}" class="anticon anticon-ellipsis" + (click)="iconMoreShow(data,tableData)" style="transform: rotate(90deg);"></i> + + <ul *ngIf="data.iconMore==true " class="icon-more"> + <li (click)="scaleService(data)" + [ngClass]="{'cannotclick':data.serviceDomain!='E2E Service' || data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}"> + <i class="anticon anticon-scale"></i> + <span> {{"i18nTextDefine_Scale" | translate}} </span> + </li> + <li (click)="serviceDetail(data,2)" + [ngClass]="{'cannotclick':data.serviceDomain!='CCVPN' || data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}"> + <i class="anticon anticon-update"></i> + <span> {{"i18nTextDefine_Update" | translate}} </span> + </li> + </ul> + <!-- <i *ngIf="data.serviceDomain=='E2E Service'||data.serviceDomain=='Network Service' " class="anticon anticon-cloud-upload-o" (click)="updataService(data)"></i> --> + <!-- <i [ngClass]="{'cannotclick':data.status == 'processing'||data.status=='Deleting'||data.status=='Creating'||data.status=='Healing'}" + *ngIf="data.serviceDomain=='Network Service' " class="anticon anticon-reload" (click)="healService(data)"></i> --> + </td> + </tr> + <tr class="childtr" [nzExpand]="data.expand" *ngFor="let item of data.childServiceInstances"> + <td></td> + <td></td> + <td>{{item["service-instance-id"] || item.nsInstanceId || item.vnfInstanceId}}</td> + <td>{{item["service-instance-name"] || item.nsName || item.vnfInstanceName}}</td> + <td> + <p + [ngClass]="{'vnfColor':item.serviceDomain=='vnf','siteColor':item.serviceDomain=='SITE','SDWANColor':item.serviceDomain=='SDWAN'}"> + {{item.serviceDomain}} + </p> + </td> + <td> + <span [ngClass]="{'healing':data.statusClass=='1004'}">{{item.tips}}</span> + <nz-progress *ngIf=" item.status == 'In Progress' " [nzPercent]="item.rate"></nz-progress> + </td> + <td> + <i [ngClass]="{'cannotclick':data.serviceDomain!='Network Service' || data.status == 'In Progress'||(data.status=='Failed' && data.operationType=='1001')||(data.status=='Failed' && data.operationType=='1002')}" + class="anticon anticon-reload" (click)="healService(item)"></i> + </td> + </tr> + </ng-template> + </tbody> + </nz-table> + + <nz-modal nzWidth="428" [nzVisible]="scaleModelVisible" nzTitle=" {{'i18nTextDefine_Scale' | translate}} " + (nzOnCancel)="scaleCancel()" (nzOnOk)="scaleOk(templatescalestarting,templateScaleSuccessFaild)" + nzClassName="scaleModel" nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " + nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <h3><span style="color: red">* </span> {{"i18nTextDefine_SureScale" | translate}} </h3> + <div class="question"> + <h4> {{"i18nTextDefine_InstanceID" | translate}} :</h4> + <div class="scaleModelContent" style="width: 100%">{{ thisService["service-instance-id"] || + thisService["nsInstanceId"] || + thisService["vnfInstanceId"]}} + </div> + </div> + <div *ngFor="let item of e2e_nsData" style="margin-top: 20px"> + <h3>{{ item.netWorkServiceName }}</h3> + <div class="e2eScaleContent"> + <span class="e2eScaleLable"> {{"i18nTextDefine_ScaleType" | translate}} :</span> + <nz-select style="width: 165px;" [(ngModel)]="item.scaleType"> + <nz-option nzValue="SCALE_NS" nzLabel="SCALE_NS"></nz-option> + <nz-option nzValue="SCALE_VNF" nzLabel="SCALE_VNF"></nz-option> + </nz-select> + </div> + <div class="e2eScaleContent"> + <span class="e2eScaleLable"> {{"i18nTextDefine_AspectId" | translate}} :</span> + <input style="width: 165px;" nz-input [(ngModel)]="item.aspectId" placeholder="string"> + </div> + <div class="e2eScaleContent"> + <span class="e2eScaleLable"> {{"i18nTextDefine_Number_Of_Steps" | translate}} :</span> + <nz-input-number style="width: 165px;" [(ngModel)]="item.numberOfSteps" [nzMin]="1" [nzMax]="100" + nzPrecision=0 [nzStep]="1" nzPlaceHolder="number"></nz-input-number> + </div> + <div class="e2eScaleContent"> + <span class="e2eScaleLable"> {{"i18nTextDefine_ScalingDirection" | translate}} :</span> + <nz-select style="width: 165px;" nzPlaceHolder="Chose" [(ngModel)]="item.scalingDirection"> + <nz-option nzValue="SCALE_IN" nzLabel="SCALE_IN"></nz-option> + <nz-option nzValue="SCALE_OUT" nzLabel="SCALE_OUT"></nz-option> + </nz-select> + </div> + </div> + + <ng-template #templatescalestarting> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-inproess.png" alt="instance temination is starting"> + </span> + <div class="ant-notification-notice-message">E2E + {{"i18nTextDefine_InstanceTeminationStarting" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + </nz-modal> + + <nz-modal nzWidth="428" [(nzVisible)]="deleteModelVisible" nzTitle=" {{'i18nTextDefine_delete' | translate}} " + (nzOnCancel)="deleteCancel()" (nzOnOk)="deleteOk(templatedeletestarting,templateDeleteSuccessFaild)" + nzClassName="{{thisService['serviceDomain'] == 'Network Service'?'nsdeleteModel':'deleteModel'}}" + nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " + nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <h3><span style="color: red">* </span> {{"i18nTextDefine_SureDelete" | translate}} </h3> + <div class="question"> + <h4> {{"i18nTextDefine_InstanceName" | translate}} :</h4> + <div class="deleteModelContent">{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </div> + </div> + <div class="question"> + <h4> {{"i18nTextDefine_InstanceID" | translate}} :</h4> + <div class="deleteModelContent">{{ thisService["service-instance-id"] || + thisService["nsInstanceId"] }} + </div> + </div> + <div *ngIf="thisService['serviceDomain'] == 'Network Service'"> + <div class="question"> + <h4> {{"i18nTextDefine_terminationType" | translate}} :</h4> + <nz-select style="width: 306px;" [(ngModel)]="terminationType"> + <nz-option nzValue="graceful" nzLabel=" {{'i18nTextDefine_graceful' | translate}} "></nz-option> + <nz-option nzValue="forceful" nzLabel=" {{'i18nTextDefine_forceful' | translate}} "></nz-option> + </nz-select> + </div> + <div class="question"> + <h4 *ngIf="terminationType=='graceful'"> {{"i18nTextDefine_gracefulTerminationTimeout" | translate}} + :</h4> + <input *ngIf="terminationType=='graceful'" style="width: 306px;" nz-input + [(ngModel)]="gracefulTerminationTimeout"> + </div> + </div> + + <ng-template #templatedeletestarting> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-inproess.png" alt="instance temination is starting"> + </span> + <div class="ant-notification-notice-message" + *ngIf="thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN'"> + {{ thisService['serviceDomain'] }} {{"i18nTextDefine_InstanceTeminationStarting" | + translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="thisService['serviceDomain'] == 'E2E Service'">E2E + {{"i18nTextDefine_InstanceTeminationStarting" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="thisService['serviceDomain'] == 'Network Service'">NS + {{"i18nTextDefine_InstanceTeminationStarting" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + </nz-modal> + + <nz-modal nzWidth="428" [nzVisible]="healModelVisible" nzTitle=" {{'i18nTextDefine_Heal' | translate}} " + (nzOnCancel)="healCancel()" (nzOnOk)="healOk(templatehealstarting,templatehealSuccessFaild)" + nzClassName="healModel" nzCancelText=" {{'i18nTextDefine_Cancel' | translate}} " + nzOkText=" {{'i18nTextDefine_modelOk' | translate}} "> + <h3><span style="color: red">* </span> {{"i18nTextDefine_SureHeal" | translate}} </h3> + <div class="heal-question"> + <p class="heal-label"> {{"i18nTextDefine_InstanceID" | translate}} : </p> + <div class="healModelContent" title="{{ thisService['service-instance-id'] || thisService['nsInstanceId'] || + thisService['vnfInstanceId']}}"> {{ thisService["service-instance-id"] || + thisService["nsInstanceId"] || + thisService["vnfInstanceId"]}} + </div> + </div> + <!-- NS --> + <div *ngIf="thisService['serviceDomain'] == 'Network Service'"> + <div class="question"> + <p class="heal-label"> {{"i18nTextDefine_degreeHealing" | translate}} :</p> + <nz-select style="width: 200px;height:42px;margin-left: 15px;border-radius: 6px" + [(ngModel)]="nsParams.degreeHealing"> + <nz-option nzValue="HEAL_RESTORE" nzLabel="HEAL_RESTORE"></nz-option> + <nz-option nzValue="HEAL_QOS" nzLabel="HEAL_QOS"></nz-option> + <nz-option nzValue="HEAL_RESET" nzLabel="HEAL_RESET"></nz-option> + <nz-option nzValue="PARTIAL_HEALING" nzLabel="PARTIAL_HEALING"></nz-option> + </nz-select> + </div> + <div> + <span style="display:inline-block;"> {{"i18nTextDefine_actionsHealing" | translate}} :</span> + <button nz-button [nzType]="'default'" (click)="addActionsHealing()"><i + class="anticon anticon-plus-circle-o"></i></button> + <br> + <div *ngFor="let item of healActions;let i = index;" style="display:inline-block;"> + <input style="width: 165px;" nz-input [(ngModel)]="item.value"> + <button nz-button [nzType]="'dashed'" (click)="minusActionsHealing(i)"><i + class="anticon anticon-minus-circle-o"></i></button> + + </div> + </div> + <span style="display:inline-block;width:50%;"> {{"i18nTextDefine_healScript" | translate}} :</span> + <input style="width: 165px;" nz-input [(ngModel)]="nsParams.healScript"> + <div> + <span style="display:inline-block;"> {{"i18nTextDefine_additionalParamsforNs" | translate}} :</span> + <button nz-button [nzType]="'default'" (click)="addNsAdditional()"><i + class="anticon anticon-plus-circle-o"></i></button> + <br> + <div *ngFor="let item of nsAdditional;let i = index;"> + Key: <input style="width: 165px;" nz-input [(ngModel)]="item.key"> + Value: <input style="width: 165px;" nz-input [(ngModel)]="item.value"> + <button nz-button [nzType]="'dashed'" (click)="minusNsAdditional(i)"><i + class="anticon anticon-minus-circle-o"></i></button> + </div> + </div> + </div> + <!-- vnf --> + <div *ngIf="thisService['serviceDomain'] == 'vnf'" style="clear: both"> + <div class="heal-question"> + <p class="heal-label"> {{"i18nTextDefine_cause" | translate}} :</p> + <input nz-input [(ngModel)]="vnfParams.cause" class="heal-input"> + </div> + <div class="heal-question"> + <p class="heal-label"> {{"i18nTextDefine_action" | translate}} :</p> + <input nz-input [(ngModel)]="vnfParams.additionalParams.action" class="heal-input"> + </div> + <div class="heal-question"> + <p class="heal-label"> {{"i18nTextDefine_actionvminfo" | translate}}:</p> + <nz-select + style=" float: right;width: 200px;margin-left: 15px;border-radius: 6px;margin-right: 30px" + [(ngModel)]="vmSelected"> + <nz-option *ngFor="let item of vnfVms" [nzValue]="item" [nzLabel]="item.vmName"></nz-option> + </nz-select> + </div> + </div> + + <ng-template #templatehealstarting> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-inproess.png" alt="instance temination is starting"> + </span> + <div class="ant-notification-notice-message">NS + {{"i18nTextDefine_InstanceHealingStarting" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + </nz-modal> + + <!-- add notification--> + <ng-template #templateCreatestarting> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-inproess.png" alt="instance temination is starting"> + </span> + <div class="ant-notification-notice-message" + *ngIf="thisCreateService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN'"> + {{ thisService['serviceDomain'] }} {{"i18nTextDefine_InstanceCreationStarting" | + translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="thisCreateService['serviceDomain'] == 'E2E Service'">E2E + {{"i18nTextDefine_InstanceCreationStarting" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="thisCreateService['serviceDomain'] == 'Network Service'">NS + {{"i18nTextDefine_InstanceCreationStarting" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisCreateService["service-instance-name"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected2.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisCreateService['serviceDomain'] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + <ng-template #templateCreateSuccessFaild> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-success.png" alt="instance temination is starting" + *ngIf="thisCreateService.status == 'Successful'"> + <img src="assets/images/execute-faild.png" alt="instance temination is starting" + *ngIf="thisCreateService.status == 'Failed'"> + </span> + <div class="ant-notification-notice-message" + *ngIf="(thisCreateService['serviceDomain'] == 'CCVPN' || thisCreateService['serviceDomain'] == 'SOTN') && thisCreateService.status == 'Successful'"> + {{ thisCreateService['serviceDomain'] }} {{"i18nTextDefine_InstanceCreatedSuccessfully" | + translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisCreateService['serviceDomain'] == 'E2E Service') && thisCreateService.status == 'Successful'"> + E2E {{"i18nTextDefine_InstanceCreatedSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisCreateService['serviceDomain'] == 'Network Service') && thisCreateService.status == 'Successful'"> + NS {{"i18nTextDefine_InstanceCreatedSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisCreateService['serviceDomain'] == 'CCVPN' || thisCreateService['serviceDomain'] == 'SOTN') && thisCreateService.status == 'Failed'"> + {{ thisCreateService['serviceDomain'] }} {{"i18nTextDefine_InstanceCreationFailed" | + translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisCreateService['serviceDomain'] == 'E2E Service') && thisCreateService.status == 'Failed'"> + E2E {{"i18nTextDefine_InstanceCreationFailed" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisCreateService['serviceDomain'] == 'Network Service') && thisCreateService.status == 'Failed'"> + NS {{"i18nTextDefine_InstanceCreationFailed" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisCreateService["service-instance-name"] || + thisCreateService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected2.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisCreateService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + <ng-template #templateDeleteSuccessFaild> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-success.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Successful'"> + <img src="assets/images/execute-faild.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Failed'"> + </span> + <div class="ant-notification-notice-message" + *ngIf="(thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN') && thisService.status == 'Successful'"> + {{ thisService['serviceDomain'] }} {{"i18nTextDefine_InstanceTeminatedSuccessfully" | + translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisService['serviceDomain'] == 'E2E Service') && thisService.status == 'Successful'"> + E2E {{"i18nTextDefine_InstanceTeminatedSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisService['serviceDomain'] == 'Network Service') && thisService.status == 'Successful'"> + NS {{"i18nTextDefine_InstanceTeminatedSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisService['serviceDomain'] == 'CCVPN' || thisService['serviceDomain'] == 'SOTN') && thisService.status == 'Failed'"> + {{ thisService['serviceDomain'] }} {{"i18nTextDefine_InstanceTeminationFailed" | + translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisService['serviceDomain'] == 'E2E Service') && thisService.status == 'Failed'">E2E + {{"i18nTextDefine_InstanceTeminationFailed" | translate}} + </div> + <div class="ant-notification-notice-message" + *ngIf="(thisService['serviceDomain'] == 'Network Service') && thisService.status == 'Failed'"> + NS {{"i18nTextDefine_InstanceTeminationFailed" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + <ng-template #templateScaleSuccessFaild> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-success.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Successful'"> + <img src="assets/images/execute-faild.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Failed'"> + </span> + <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Successful'">E2E + {{"i18nTextDefine_InstanceScaledSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Failed'">E2E + {{"i18nTextDefine_InstanceScaleFailed" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + <ng-template #templatehealSuccessFaild> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-success.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Successful'"> + <img src="assets/images/execute-faild.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Failed'"> + </span> + <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Successful'">NS + {{"i18nTextDefine_InstanceHealedSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Failed'">NS + {{"i18nTextDefine_InstanceHealingFailed" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + <ng-template #templateUpdateSuccessFaild> + <div class="ant-notification-notice-content"> + <div class="ant-notification-notice-with-icon"> + <span class="ant-notification-notice-icon"> + <img src="assets/images/execute-success.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Successful'"> + <img src="assets/images/execute-faild.png" alt="instance temination is starting" + *ngIf="thisService.status == 'Failed'"> + </span> + <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Successful'">CCVPN + {{"i18nTextDefine_InstanceUpdatedSuccessfully" | translate}} + </div> + <div class="ant-notification-notice-message" *ngIf="thisService.status == 'Failed'">CCVPN + {{"i18nTextDefine_InstanceUpdateFailed" | translate}} + </div> + <div class="ant-notification-notice-description"> + <div class="notificationlist"> + <p> {{"i18nTextDefine_InstanceName" | translate}} :</p> + <span>{{ thisService["service-instance-name"] || + thisService["nsInstanceName"] }} + </span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_Customer" | translate}} :</p> + <span>{{ customerSelected.name }}</span> + </div> + <div class="notificationlist"> + <p> {{"i18nTextDefine_UseCase" | translate}} :</p> + <span>{{ thisService["serviceDomain"] }}</span> + </div> + </div> + <div class="close-icons">{{"i18nTextDefine_Close" | translate}}</div> + </div> + </div> + </ng-template> + </div> + <div class="detailComponent" *ngIf="detailshow"> + <app-ccvpn-detail [detailParams]="detailData" [upDateShow]="upDateShow" + (closeUpdate)="closeCCVPNUpdate($event,templateUpdateSuccessFaild)" + (closeDetail)="detailshow = false;listDisplay = false;"></app-ccvpn-detail> + </div> + <div class="detailComponent" *ngIf="detailshow2"> + <app-e2e-detail [detailParams]="detailData" (closeDetail)="detailshow2 = false;listDisplay = false;"> + </app-e2e-detail> + </div> + <div class="createComponent" *ngIf="createshow"> + <app-ccvpn-creation [createParams]="createData" [ccvpn_temParametersContent]="ccvpn_temParametersContent" + (closeCreate)="closeCreate($event,templateCreatestarting,templateCreateSuccessFaild)"> + </app-ccvpn-creation> + </div> + <div class="createComponent" *ngIf="createshow2"> + <app-e2e-creation [createParams]="createData" [e2e_ns_temParametersContent]="e2e_ns_temParametersContent" + (nsCloseCreate)="nsCloseCreate($event,templateCreatestarting,templateCreateSuccessFaild)" + (e2eCloseCreate)="e2eCloseCreate($event,templateCreatestarting,templateCreateSuccessFaild)"> + </app-e2e-creation> + </div> + <!--</div>--> +</nz-layout> +<div class="loading" *ngIf="loadingAnimateShow"> + <img src="assets/images/loading-animate2.gif" alt="loading"> + <p>Please wating……</p> +</div>
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.less b/usecaseui-portal/src/app/views/services/services-list/services-list.component.less new file mode 100644 index 00000000..392d1b3a --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.less @@ -0,0 +1,380 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +.title { + font: 700 18px/18px "思源黑体"; + color: #4c5e70; + margin-bottom: 18px; +} +hr { + border: none; + height: 2px; + background-color: #dce1e7; + margin-bottom: 20px; +} +.ant-tabs-bar{ + margin-bottom: 0!important; +} +.mask{ + width: 100%; + height: 100%; + position: absolute; + z-index: 999; + background: rgba(0, 0, 0, 0.65); + top:0; +} +.loading{ + width: 100%; + height: 100%; + position: fixed; + top: 0; + margin-top: -50px; + margin-left: -50px; + z-index: 1001; + text-align: center; + background: transparent; + p{ + color: #0DA9E2; + text-align: center; + position: absolute; + width: 300px; + height: 30px; + line-height: 30px; + top: 71%; + left: 36%; + margin-top: -150px; + margin-left: -150px; + } + img{ + width: 300px; + height: 300px; + position: absolute; + top: 50%; + left: 36%; + margin-top: -150px; + margin-left: -150px; + } +} +.action { + margin-bottom: 15px; + padding: 28px; + background: #ffffff; + position: relative; + span { + display: inline-block; + font: 700 14px "Arial"; + color: #3C4F8C; + margin-right: 5px; + } + nz-dropdown { + vertical-align: middle; + background-color:#ffffff; + :hover{ + border-color: #48C6EF; + } + button { + width: 165px; + height: 42px; + background-color:#ffffff; + text-align: left; + border-color: #EEEEEE; + span { + font-weight: 400; + color: #3C4F8C; + display: inline-block; + width: 120px; + overflow: hidden; + text-overflow: ellipsis; + padding-top: 2px; + } + i { + position: absolute; + top: 10px; + right: 10px; + } + } + } + //The style in the drop-down box is in style.less, and the drop-down box is extra temporary generated in the body. + .create { + position: absolute; + right: 3%; + top:50%; + width:116px; + height:42px; + background:#0DA9E2; + border-radius:6px; + margin-top: -15px; + span { + color: #fff; + font-weight: 400; + font-size: 18px; + } + .anticon-plus-circle-o{ + font-size: 18px; + } + } + .create.ant-btn.ant-btn-primary{ + border: none; + } + .create:hover{ + background:#09C6E2; + } + +} +.top-num{ + overflow: auto; + width: 100%; +} +.top-list{ + position: relative; + width:29%; + height:170px; + margin: 10px 1%; + float: left; + background:url("../../../../assets/images/servicelist-e2e.png") no-repeat; + background-size: 100% 100%; + border-radius:2px; +} +.top-num .top-list:nth-child(2){ + background:url("../../../../assets/images/servicelist-e2e.png") no-repeat; + background-size: 100% 100%; +} +.top-num .top-list:nth-child(3){ + background:url("../../../../assets/images/servicelist-e2e.png") no-repeat; + background-size: 100% 100%; +} +.top-num .top-list:nth-child(4){ + background:url("../../../../assets/images/servicelist-sotn.png") no-repeat; + background-size: 100% 100%; +} +.top-list .round{ + position: absolute; + width: 60px; + height: 60px; + line-height: 60px; + text-align: center; + top:45%; + left: 50px; + margin-top: -30px; + background:#E0EDFF; + border:2px solid rgba(224,237,255,1); + border-radius: 50%; + font-size:16px; + font-family:ArialMT; + color:#3C4F8C; +} +.top-list { + .top-list-text { + position: absolute; + text-align: right; + height: 40px; + line-height: 20px; + right: 50px; + color: #fff; + p { + font-size: 14px; + width: 250px; + margin: 15px 0 0 0; + height: 13px; + clear: both; + span { + display: inline-block; + font-weight: 500; + text-align: right; + float: right; + } + span:nth-child(1) { + font-size: 18px; + width: 40px; + min-width: 40px; + } + span:nth-child(2) { + width: 85px; + font-size: 16px; + } + } + p:nth-child(1) { + margin-top: 25px; + } + } + .service-description{ + font-size: 14px; + width: 250px; + height: 13px; + position: absolute; + bottom: 30px; + left: 50px; + color: #3C4F8C; + } +} +.list { + background-color: #fff; + border-radius: 5px; + padding: 10px; + nz-table { + tbody { + td { + position: relative; + span.active { + font-size: 14px; + color: #147dc2; + } + span.closed { + font-size: 14px; + color: red; + } + span.onboarding{ + font-size: 12px; + color: #147dc2; + } + span.updating{ + font-size: 12px; + color: blue; + } + span.deleting { + font-size: 12px; + color: red; + } + span.creating { + font-size: 12px; + color: green; + } + span.scaling { + font-size: 12px; + color: purple; + } + span.healing { + font-size: 12px; + color: orangered; + } + i.anticon { + cursor: pointer; + font-size: 18px; + padding: 2px; + &:hover{ + color: #147dc2; + } + } + .cannotclick { + pointer-events: none; + color: #aaa; + opacity: 0.6; + } + .icon-more{ + position: absolute; + width: 115px; + height: 90px; + top:50px; + padding:15px 0 0 15px; + background: #ffffff; + z-index: 2; + border-radius: 5px; + box-shadow: 0px 10px 15px 2px rgba(247, 247, 247, 0.5); + li{ + margin-bottom:10px; + line-height: 20px; + text-align: left; + cursor: pointer; + .anticon{ + width: 18px; + height: 18px; + background: url("../../../../assets/images/scale.png") no-repeat; + } + .anticon.anticon-update{ + background: url("../../../../assets/images/update.png") no-repeat; + } + span{ + margin-left: 5px; + } + } + li:hover{ + color: #0DA9E2; + .anticon{ + background: url("../../../../assets/images/scale-active.png") no-repeat; + } + .anticon.anticon-update{ + background: url("../../../../assets/images/update-active.png") no-repeat; + } + } + } + } + tr.childtr { + td { + font-size: 12px; + color: #147dc2; + } + } + } + } +} + + +.detailComponent { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100vh; + background-color: #f3f3f3; + overflow-y: auto; + z-index: 3; +} +.createComponent { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100vh; + background-color: #F7F8FC; + overflow-y: auto; + z-index: 3; +} + +.e2eColor,.nsColor,.ccvpnColor,.sotnColor,.voLTEColor{ + width:120px; + height: 34px; + line-height: 34px; + margin-bottom: 0!important; + text-align: center; + background:rgba(158, 158, 158, 0.38); + border-radius:4px +} + +.vnfColor,.siteColor,.SDWANColor{ + color:rgba(60,79,140,0.5); + width:120px; + height: 34px; + line-height: 34px; + margin-bottom: 0!important; + text-align: center; + background:rgba(238,238,238,1); + border-radius:4px; +} + +.select-list{ + width: 320px; + height: 32px; + line-height: 32px; + margin: 35px auto; +} +.select-list>span{ + text-align: right; + width: 110px!important; + line-height: 32px; +} + +.listdisplay{ + display: none; +}
\ No newline at end of file diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts b/usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts new file mode 100644 index 00000000..61440dc3 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ServicesListComponent } from './services-list.component'; + +describe('ServicesListComponent', () => { + let component: ServicesListComponent; + let fixture: ComponentFixture<ServicesListComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ServicesListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ServicesListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts b/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts new file mode 100644 index 00000000..c15e9f11 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services-list/services-list.component.ts @@ -0,0 +1,1410 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import { Component, OnInit, HostBinding, TemplateRef } from '@angular/core'; +import { MyhttpService } from '../../../core/services/myhttp.service'; +import { slideToRight } from '../../../animates'; +import { NzModalService } from 'ng-zorro-antd'; +import { NzNotificationService } from 'ng-zorro-antd'; + +@Component({ + selector: 'app-services-list', + templateUrl: './services-list.component.html', + styleUrls: ['./services-list.component.less'], + animations: [slideToRight] +}) +export class ServicesListComponent implements OnInit { + @HostBinding('@routerAnimate') routerAnimateState; + + constructor(private myhttp: MyhttpService, private modalService: NzModalService, private notification: NzNotificationService) { + } + + ngOnInit() { + this.getallCustomers(); + } + + // customer servicetype + isSol005Interface = false; + orchestratorList = []; + customerList = []; + customerList2 = []; + customerSelected = { name: null, id: null }; + customerSelected2 = { name: null, id: null }; + serviceTypeList = []; + serviceTypeList2 = []; + serviceTypeSelected = { name: '' }; + serviceTypeSelected2 = { name: '' }; + serviceTypeSelectedName = ""; + templateTypeSelected = "CCVPN"; + orchestratorSelected = { name: null, id: null }; + listSortMasters = JSON.parse(sessionStorage.getItem('listSortMasters')); + language = sessionStorage.getItem("DefaultLang"); + iconMore = false; + loadingAnimateShow = false; + serviceMunber = [ // top: E2E/NS/CCVPN data + { + "serviceDomain": "E2E", + "Success": 0, + "failed": 0, + "InProgress": 0, + "detailName": "i18nTextDefine_End_To_End_Service" + }, + { + "serviceDomain": "NS", + "Success": 0, + "failed": 0, + "InProgress": 0, + "detailName": "i18nTextDefine_Network_Service" + }, + { + "serviceDomain": "CCVPN", + "Success": 0, + "failed": 0, + "InProgress": 0, + "detailName": "i18nTextDefine_Cross_Domain_and_Cross_Layer_VPN" + } + ]; + + //The icon behind each row of data in the table expands + iconMoreShow(data, tableData) { + tableData.map((its) => { + if (its["service-instance-id"] == data["service-instance-id"]) { + if (its["iconMore"] == false) { + data.iconMore = true; + } else if (its["iconMore"] == true) { + data.iconMore = false; + } + } else { + its["iconMore"] = false; + } + }) + } + + //Get all the customers + getallCustomers() { + console.log(this.language, "this.language"); + this.myhttp.getAllCustomers() + .subscribe((data) => { + this.customerList = data.map((item) => { + return { name: item["subscriber-name"], id: item["global-customer-id"] } + }); + if (this.customerList.length == 0) { + console.log("customerList.length == 0", this.customerList); + return false; + } + this.customerList2 = data.map((item) => { + return { name: item["subscriber-name"], id: item["global-customer-id"] } + }); + if (this.customerList2.length == 0) { + return false; + } + this.customerSelected = this.customerList[0]; + this.choseCustomer(this.customerSelected); + }) + } + + getallOrchestrators() { + this.myhttp.getAllOrchestrators() + .subscribe((data) => { + this.orchestratorList = data.map((item) => { + return { name: item["name"], id: item["name"] } + }); + if (this.orchestratorList.length == 0) { + console.log("orchestratorList.length == 0", this.orchestratorList); + return false; + } + this.orchestratorSelected = this.orchestratorList[0]; + }) + } + + choseCustomer(item) { + this.customerSelected = item; + this.myhttp.getServiceTypes(this.customerSelected) + .subscribe((data) => { + this.serviceTypeList = data.map((item) => { + return { name: item["service-type"] } + }); + + if (this.serviceTypeList.length == 0) { + console.log("serviceTypeList.length == 0", this.serviceTypeList); + return false; + } + + this.serviceTypeSelected = this.serviceTypeList[0]; + + this.choseServiceType(this.serviceTypeSelected); + }) + } + + choseServiceType(item) { + this.serviceTypeSelected = item; + this.getTableData(); + } + + + // Create modal box 2 (dialog box) create ------------------------------- + isVisible = false; + + customerChange(): void { + this.getServiceType(this.customerSelected2); + } + + getServiceType(customerSelected2) { + this.myhttp.getServiceTypes(customerSelected2) + .subscribe((data) => { + this.serviceTypeList2 = data.map((item) => { + return { name: item["service-type"] } + }); + if (this.serviceTypeList2.length == 0) { + console.log("serviceTypeList.length == 0", this.serviceTypeList2); + return false; + } + this.getAlltemplates(); + }) + } + + serviceTypeChange(): void { + this.serviceTypeSelected2.name = this.serviceTypeSelectedName + } + + createModal(): void { + this.isVisible = true; + this.getallOrchestrators(); + this.customerSelected2 = this.customerSelected; + this.serviceTypeSelectedName = this.serviceTypeSelected.name; + this.serviceTypeSelected2 = Object.assign({}, this.serviceTypeSelected); + this.getServiceType(this.customerSelected2); + } + + choseTemplateType() { + this.getallOrchestrators(); + this.getAlltemplates(); + } + + templates = []; + template1 = { name: null }; + + getAlltemplates() { + this.myhttp.getAllServiceTemplates(this.templateTypeSelected) + .subscribe((data) => { + this.templates = data; + if (this.templateTypeSelected == "Network Service") { + this.templates = data.filter((d) => { + return typeof d.packageInfo.csarName == "string"; + }).map((item) => { + let cName = item.packageInfo.csarName.split("/").reverse()[0]; + return { name: cName, id: item.csarId, packageInfo: item.packageInfo } + }); + } + this.template1 = this.templates[0]; + }, (err) => { + console.log(err); + }) + } + + createshow = false; + createshow2 = false; + listDisplay = false; + createData: Object = {}; + + handleOk(): void { + if (this.templateTypeSelected == "SOTN" || this.templateTypeSelected == "CCVPN") { + this.createData = { + commonParams: { + customer: this.customerSelected, + serviceType: this.serviceTypeSelected2, + templateType: this.templateTypeSelected + }, template: this.template1 + }; + } else if (this.templateTypeSelected == "E2E Service" || this.templateTypeSelected == "Network Service") { + this.createData = { + commonParams: { + customer: this.customerSelected, + serviceType: this.serviceTypeSelected2, + templateType: this.templateTypeSelected + }, + template: this.template1, + orchestrator: this.orchestratorSelected, + isSol005Interface: this.isSol005Interface + }; + } + this.getTemParameters(); + } + + handleCancel(): void { + this.isVisible = false; + this.loadingAnimateShow = false; + } + + temParametersTips = false; + ccvpn_temParametersContent: any; + e2e_ns_temParametersContent: any; + + getTemParameters() { + let chosedtemplates = this.createData["template"]; + let types = this.createData["commonParams"].templateType; + if (types == "E2E Service") { + types = "e2e"; + } else if (types == "Network Service") { + types = "ns"; + } + this.loadingAnimateShow = true; + this.myhttp.getTemplateParameters(types, chosedtemplates) + .subscribe((data) => { + this.loadingAnimateShow = false; + if (data.status == "FAILED") { + this.temParametersTips = true; + this.isVisible = true; + console.log("Template parsing Failed"); + } else { + this.isVisible = false; + this.temParametersTips = false; + if (this.templateTypeSelected == "SOTN" || this.templateTypeSelected == "CCVPN") { + this.ccvpn_temParametersContent = data; + this.createshow = true; + this.listDisplay = true; + } else if (this.templateTypeSelected == "E2E Service" || this.templateTypeSelected == "Network Service") { + this.e2e_ns_temParametersContent = data; + this.createshow2 = true; + this.listDisplay = true; + } + } + }) + } + + //tableData + tableData = []; + pageIndex = 1; + pageSize = 10; + total = 100; + loading = false; + + getTableData() { + this.loading = true; + // Query parameter: customer serviceType Current page number, number of pages per page + let paramsObj = { + customerId: this.customerSelected.id, + serviceType: this.serviceTypeSelected.name, + currentPage: this.pageIndex, + pageSize: this.pageSize + } + this.myhttp.getServicesTableData(paramsObj) + .subscribe((data) => { + this.total = data.body.total; + this.tableData = data.body.tableList.map((item) => { + if (typeof item == "string") { + item = JSON.parse(item); + } + + item["iconMore"] = this.iconMore; + if (item["serviceDomain"] == "Network Service") { + if (item["vnfInfo"]) { + item["childServiceInstances"] = item["vnfInfo"].map((vnf) => { + vnf["serviceDomain"] = "vnf"; + return vnf; + }); + } else if (item["relationship-list"] && item["relationship-list"]["relationship"]) { + item["childServiceInstances"] = item["relationship-list"]["relationship"].filter((relate) => { + return relate["related-to"] == "generic-vnf"; + }).map((vnf) => { + let vnfInfo = { + vnfNsInstanceId: "", + vnfInstanceId: "", + vnfInstanceName: "", + serviceDomain: "vnf" + }; + vnfInfo.vnfNsInstanceId = item["nsInstanceId"] || item["service-instance-id"]; + vnfInfo.vnfInstanceId = vnf["relationship-data"].find((vnfid) => { + return vnfid["relationship-key"] == "generic-vnf.vnf-id" + })["relationship-value"]; + vnfInfo.vnfInstanceName = vnf["related-to-property"].find((vnfname) => { + return vnfname["property-key"] == "generic-vnf.vnf-name" + })["property-value"]; + return vnfInfo; + }) + } + } else { + item["childServiceInstances"] = []; + } + + // + if (item["operationResult"] == "2001") { //operationResult==2001 + item["status"] = "Available"; + item["tips"] = "Available"; + item["statusClass"] = item["operationResult"]; + } + // 2018.12.13 + else if (item["operationResult"] == "2002") { //operationResult==2002 + if (item["operationType"] == "1001" || item["operationType"] == "1002") { + // item["status"] = this.accordingState["operationResult"][item["operationResult"]]; + item["status"] = this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == item["operationResult"] && its["language"] == this.language + })["sortValue"]; + item["tips"] = "Unavailable"; + item["statusClass"] = item["operationType"]; + } else if (item["operationType"] != "1001" && item["operationType"] != "1002") { + // item["status"] = this.accordingState["operationResult"][item["operationResult"]]; + item["status"] = this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == item["operationResult"] && its["language"] == this.language + })["sortValue"]; + item["tips"] = "Available"; + item["statusClass"] = item["operationType"]; + } + + } + else if (item["operationResult"] == "2003") { //operationResult==2003 + // item["status"] = this.accordingState["operationResult"][item["operationResult"]]; + item["status"] = this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == item["operationResult"] && its["language"] == this.language + })["sortValue"]; + item["statusClass"] = item["operationType"]; + if (item["serviceDomain"] == "Network Service") { + let updata = (prodata) => { + item["rate"] = prodata.progress; + item["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == item["operationType"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + prodata.progress + "%"; + if (item["rate"] > 100) { + item["status"] = prodata.status; + item["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == item["operationType"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + item["status"]; + } + } + let id = item["nsInstanceId"] || item["service-instance-id"]; + let jobid = item["jobId"] || item["operationId"]; + let operationType = item["operationType"]; + this.queryNsProgress(jobid, id, updata, operationType).then(() => { + item["rate"] = 100; + item["status"] = this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + item["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == item["operationType"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + item["status"]; + }) + } else { + let updata = (prodata) => { + item["rate"] = prodata.progress || item["rate"]; + item["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == item["operationType"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + prodata.progress + "%"; + if (item["rate"] > 100) { + item["status"] = prodata.status; + item["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == item["operationType"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + item["status"]; + } + } + let obj = { + serviceId: item["service-instance-id"], + operationId: item["operationId"], + operationType: item["operationType"] + } + this.queryProgress(obj, updata).then(() => { + item["rate"] = 100; + item["status"] = this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + item["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == item["operationType"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + item["status"]; + }) + } + } + return item; + }) + this.tableData.map((item, index) => { + if (item.serviceDomain == 'E2E Service') { + if (item.operationResult == 2001) { + this.serviceMunber[0]["Success"] += 1; + } else if (item.operationResult == 2002) { + this.serviceMunber[0]["failed"] += 1; + } else if (item.operationResult == 2003) { + this.serviceMunber[0]["InProgress"] += 1; + } + } + else if (item.serviceDomain == 'Network Service') { + if (item.operationResult == 2001) { + this.serviceMunber[1]["Success"] += 1; + } else if (item.operationResult == 2002) { + this.serviceMunber[1]["failed"] += 1; + } else if (item.operationResult == 2003) { + this.serviceMunber[1]["InProgress"] += 1; + } + } + else if (item.serviceDomain == 'CCVPN') { + if (item.operationResult == 2001) { + this.serviceMunber[2]["Success"] += 1; + } else if (item.operationResult == 2002) { + this.serviceMunber[2]["failed"] += 1; + } else if (item.operationResult == 2003) { + this.serviceMunber[2]["InProgress"] += 1; + } + } + }) + this.loading = false; + }, (err) => { + console.log(err); + this.loading = false; + }) + } + + searchData(reset: boolean = false) { + this.getTableData(); + } + + thisService = {}; //The current service of the operation + e2e_nsData: Object[]; + scaleModelVisible = false; + + scaleService(service) { + this.thisService = service; + this.scaleModelVisible = true; + let paramsObj = { + customerId: this.customerSelected.id, + serviceType: this.serviceTypeSelected.name, + serviceId: service["service-instance-id"] + } + this.myhttp.getE2e_nsData(paramsObj) + .subscribe((data) => { + this.e2e_nsData = data; + }) + } + + scaleOk(templatescalestarting, templateScaleSuccessFaild) { + this.scaleModelVisible = false; + let requestBody = { + "service": { + "serviceInstanceName": this.thisService["service-instance-name"], + "serviceType": this.serviceTypeSelected.name, + "globalSubscriberId": this.customerSelected.id, + "resources": this.e2e_nsData.map((item) => { + return { + "resourceInstanceId": item["netWorkServiceId"], + "scaleType": item["scaleType"], + "scaleNsData": { + "scaleNsByStepsData": { + "aspectId": item["aspectId"], + "numberOfSteps": item["numberOfSteps"], + "scalingDirection": item["scalingDirection"] + } + } + } + }) + } + } + this.scaleE2eService(this.thisService, requestBody, templateScaleSuccessFaild); + this.scaleNotification(templatescalestarting); + } + + scaleCancel() { + this.scaleModelVisible = false; + } + + scaleNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + scaleSuccessNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + //heal + healModelVisible = false; + healActions = []; + nsAdditional = []; + nsParams = { + degreeHealing: "HEAL_RESTORE", + actionsHealing: [], + healScript: "", + additionalParamsforNs: "" + } + vnfVms = []; + vmSelected = {}; + vnfParams = { + vnfInstanceId: "", + cause: "", + additionalParams: { + action: "", + actionvminfo: { + vmid: "", + vduid: "", + vmname: "" + } + } + } + + addActionsHealing() { + this.healActions.push({ value: "" }) + } + + minusActionsHealing(index) { + this.healActions.splice(index, 1); + } + + addNsAdditional() { + this.nsAdditional.push({ key: "", value: "" }) + } + + minusNsAdditional(index) { + this.nsAdditional.splice(index, 1); + } + + healService(service) { + this.thisService = service; + this.healModelVisible = true; + if (service.serviceDomain == "vnf") { + this.vnfParams.vnfInstanceId = service.vnfInstanceId; + this.myhttp.getVnfInfo(service.vnfInstanceId) + .subscribe((data) => { + this.vnfVms = data.vnfVms; + this.vmSelected = this.vnfVms[0]; + }) + } + } + + healOk(templatehealstarting, templatehealSuccessFaild) { + this.healModelVisible = false; + // nsParams + this.nsParams.actionsHealing = this.healActions.map((item) => { + return item.value + }); + let additional = {}; + this.nsAdditional.forEach((item) => { + additional[item.key] = item.value; + }); + this.nsParams.additionalParamsforNs = JSON.stringify(additional); + // vnfParams + this.vnfParams.additionalParams.actionvminfo.vmid = this.vmSelected["vmId"]; + this.vnfParams.additionalParams.actionvminfo.vmname = this.vmSelected["vmName"]; + + let requestBody = this.thisService["serviceDomain"] == "Network Service" ? { healNsData: this.nsParams } : { healVnfData: this.vnfParams }; + this.healNsVnfService(this.thisService, requestBody, templatehealSuccessFaild); + this.healNotification(templatehealstarting); + } + + healCancel() { + this.healModelVisible = false; + } + + healNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + healSuccessNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + // show detail + detailshow = false; + detailshow2 = false; + upDateShow = false; + detailData: Object; + + serviceDetail(service, typeNum) { + service["siteSer"] = []; + service["sdwanSer"] = []; + service["customer"] = this.customerSelected; + service["serviceType"] = this.serviceTypeSelected; + + service.childServiceInstances.forEach((item) => { + if (item.serviceDomain == "SITE") { + service.siteSer.push(item); + } else if (item.serviceDomain == "SDWAN") { + service.sdwanSer.push(item); + } + }) + if (service["serviceDomain"] == 'CCVPN' || service["serviceDomain"] == 'SOTN') { + this.detailshow = true; + if (typeNum == 1) { + this.upDateShow = false; + } else { + this.upDateShow = true; + } + } else if (service["serviceDomain"] == 'E2E Service' || service["serviceDomain"] == 'Network Service') { + this.detailshow2 = true; + } + this.listDisplay = true; + this.detailData = service; + console.log(service); + } + + deleteModelVisible = false; + terminationType = "graceful"; + gracefulTerminationTimeout = 120; + + // delete Model show + deleteModel(service) { + this.thisService = service; + this.deleteModelVisible = true; + } + + deleteOk(templatedeletestarting, templateDeleteSuccessFaild) { + this.deleteModelVisible = false; + this.loadingAnimateShow = true; + if (this.thisService["serviceDomain"] == "Network Service") { + this.deleteNsService(this.thisService, templateDeleteSuccessFaild); + } else { + this.deleteService(this.thisService, templateDeleteSuccessFaild); + } + this.deleteNotification(templatedeletestarting); + } + + deleteCancel() { + this.deleteModelVisible = false; + } + + deleteNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + deleteSuccessNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + createNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + createSuccessNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + //ccvpn sotn createservice + parentServiceInstanceId = ""; + thisCreateService = {}; + + closeCreate(obj, templateCreatestarting, templateCreateSuccessFaild) { + if (!obj) { + this.createshow = false; //close + this.listDisplay = false; //close + return false; + } + this.createshow = false; + this.listDisplay = false; + this.loadingAnimateShow = true; + console.log(obj); + let newData; //Newly created service data for the main table + + let createParams = "?customerId=" + this.customerSelected2.id + + "&serviceType=" + this.serviceTypeSelected2.name + + "&serviceDomain=" + this.templateTypeSelected; + this.createService(obj, createParams, templateCreatestarting, templateCreateSuccessFaild).then((data) => { + console.log(data); + this.loadingAnimateShow = false; + newData = { //Newly created service data in the main form + 'service-instance-id': data["serviceId"], + 'service-instance-name': obj.service.name, + serviceDomain: this.templateTypeSelected, + childServiceInstances: [], + status: "In Progress", + rate: 0, + statusClass: 1001, + tips: "" + }; + this.thisCreateService = newData; + this.tableData = [newData, ...this.tableData]; + this.createNotification(templateCreatestarting); + let updata = (prodata) => { + newData.rate = prodata.progress; + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + newData.rate + "%"; + if (newData["rate"] > 100) { + newData["status"] = prodata.status; + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + newData["status"]; + } + }; + let queryParams = { serviceId: data["serviceId"], operationId: data["operationId"], operationType: "1001" }; + return this.queryProgress(queryParams, updata); + }).then((data) => { + console.log(data); + newData.rate = 100; + newData.status = "Successful"; + this.createSuccessNotification(templateCreateSuccessFaild); + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + let hasUndone = this.tableData.some((item) => { + return item.rate < 100; + }); + if (!hasUndone) { + setTimeout(() => { + this.getTableData(); + }, 1000) + } + }) + } + + e2eCloseCreate(obj, templateCreatestarting, templateCreateSuccessFaild) { + if (!obj) { + this.createshow2 = false; // + this.listDisplay = false; // + return false; + } + this.createshow2 = false; // + this.listDisplay = false; // + this.loadingAnimateShow = true; + console.log(obj); + let newData; // + let createParams = "?customerId=" + this.customerSelected.id + + "&serviceType=" + this.serviceTypeSelected2.name + + "&serviceDomain=" + this.templateTypeSelected + + "&parentServiceInstanceId=" + + "&uuid=" + obj.service.serviceUuid + + "&invariantUuuid=" + obj.service.serviceInvariantUuid; + this.createService(obj, createParams, templateCreatestarting, templateCreateSuccessFaild).then((data) => { + console.log(data); + this.loadingAnimateShow = false; + newData = { // + 'service-instance-id': data["serviceId"], + 'service-instance-name': obj.service.name, + serviceDomain: this.templateTypeSelected, + childServiceInstances: [], + status: "In Progress", + statusClass: 1001, + rate: 0, + tips: "" + } + this.thisCreateService = newData; + this.tableData = [newData, ...this.tableData]; + this.createNotification(templateCreatestarting); + let updata = (prodata) => { + newData.rate = prodata.progress; + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + newData.rate + "%"; + if (newData["rate"] > 100) { + newData["status"] = prodata.status; + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + newData["status"]; + } + } + let queryParams = { serviceId: data["serviceId"], operationId: data["operationId"], operationType: "1001" }; + return this.queryProgress(queryParams, updata); + }).then((data) => { + console.log(data); + newData.rate = 100; + newData.status = "Successful"; + this.createSuccessNotification(templateCreateSuccessFaild); + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + let hasUndone = this.tableData.some((item) => { + return item.rate < 100; + }) + if (!hasUndone) { + setTimeout(() => { + this.getTableData(); + }, 1000) + } + }) + + } + + nsCloseCreate(obj, templateCreatestarting, templateCreateSuccessFaild) { + if (!obj) { + this.createshow2 = false; // + this.listDisplay = false; // + return false; + } + this.createshow2 = false; // + this.listDisplay = false; // + this.loadingAnimateShow = true; + console.log(obj); + let newData; // + // step1 + this.myhttp.nsCreateInstance(obj.step1) + .subscribe((data) => { + // console.log(data); + this.loadingAnimateShow = false; + newData = { // + 'service-instance-id': data.nsInstanceId, + 'service-instance-name': obj.step1.nsName, + serviceDomain: this.templateTypeSelected, + childServiceInstances: [], + status: "In Progress", + statusClass: 1001, + rate: 0, + tips: "" + } + this.thisCreateService = newData; + this.tableData = [newData, ...this.tableData]; + this.createNotification(templateCreatestarting); + if (data.status == "FAILED") { + console.log("create ns service Failed :" + JSON.stringify(data)); + newData.status = "Failed"; + this.createSuccessNotification(templateCreateSuccessFaild); + return false; + } + let createParams = "?ns_instance_id=" + data.nsInstanceId + + "&customerId=" + this.customerSelected2.id + + "&serviceType=" + this.serviceTypeSelected2.name + + "&serviceDomain=" + this.templateTypeSelected + + "&parentServiceInstanceId="; + // step2 + this.createNsService(createParams, obj.step2).then((jobid) => { + if (jobid == "Failed") { + newData.status = "Failed"; + console.log(jobid, "ns two jobid") + this.thisCreateService = newData; + console.log(this.thisCreateService) + this.createSuccessNotification(templateCreateSuccessFaild); + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + return false; + } + let operationType = "1001"; + let updata = (prodata) => { + newData.rate = prodata.progress; + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + newData.rate + "%"; + if (newData["rate"] > 100) { + newData["status"] = prodata.status; + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + newData["status"]; + } + } + + return this.queryNsProgress(jobid, newData["service-instance-id"], updata, operationType); + }).then((data) => { + console.log(data); + newData.rate = 100; + newData.status = "Successful"; + this.thisCreateService = newData; + console.log(this.thisCreateService) + this.createSuccessNotification(templateCreateSuccessFaild); + newData.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == newData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + let hasUndone = this.tableData.some((item) => { + return item.rate < 100; + }) + if (!hasUndone) { + setTimeout(() => { + this.getTableData(); + }, 1000) + } + }) + }) + } + + createService(requestBody, createParams, templateCreatestarting, templateCreateSuccessFaild) { + let mypromise = new Promise((res, rej) => { + this.myhttp.createInstance(requestBody, createParams) + .subscribe((data) => { + if (data.status == "FAILED") { + this.loadingAnimateShow = false; + res("Failed"); + console.log("create e2e service Failed :" + JSON.stringify(data)); + return false; + } + res(data.service); + }) + }) + return mypromise; + } + + createNsService(id, obj) { + let mypromise = new Promise((res, rej) => { + this.myhttp.nsCreateInstance2(id, obj) + .subscribe((data) => { + if (data.status == "FAILED") { + this.loadingAnimateShow = false; + console.log("instantiate ns service Failed :" + JSON.stringify(data)); + res("Failed"); + return false; + } + res(data.jobId); + }) + }) + return mypromise; + } + + scaleE2eService(service, requestBody, templateScaleSuccessFaild) { + let id = service["service-instance-id"]; + service.rate = 0; + service.status = "In Progress"; + service.statusClass = "1003"; + service.tips = ""; + this.myhttp.scaleE2eService(id, requestBody) + .subscribe((data) => { + if (data.status == "FAILED") { + console.log("scale E2e service Failed :" + JSON.stringify(data)); + service.status = "Failed"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + this.scaleSuccessNotification(templateScaleSuccessFaild); + return false; + } + let obj = { + serviceId: id, + operationId: data.operationId, + operationType: "1003" + } + let updata = (prodata) => { + service.rate = prodata.progress; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service["rate"] + "%"; + if (service["rate"] > 100) { + service["status"] = prodata.status; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service["status"]; + } + } + this.queryProgress(obj, updata).then(() => { + service.rate = 100; + service.status = "Successful"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + this.scaleSuccessNotification(templateScaleSuccessFaild); + }) + }) + } + + healNsVnfService(service, requestBody, templatehealSuccessFaild) { + console.log(service); + service.rate = 0; + service.status = "In Progress"; + service.tips = ""; + service.statusClass = "1004"; + let id = service.nsInstanceId || service["service-instance-id"] || service["vnfNsInstanceId"]; + this.myhttp.healNsService(id, requestBody) + .subscribe((data) => { + if (data.status == "FAILED") { + console.log("heal nsvnf service Failed :" + JSON.stringify(data)); + service.status = "Failed"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + this.healSuccessNotification(templatehealSuccessFaild); + return false; + } + let jobid = data.jobId; + let operationType = "1004"; + let updata = (prodata) => { + service.rate = prodata.progress; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service.rate + "%"; + console.log(service.rate) + if (service["rate"] > 100) { + service["status"] = prodata.status; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service["status"]; + } + } + this.queryNsProgress(jobid, null, updata, operationType).then((data1) => { + console.log(data1); + service.rate = 100; + service.status = "Successful"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + this.healSuccessNotification(templatehealSuccessFaild); + }); + }) + } + + updateCcvpnNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + updateCcvpnSuccessNotification(template: TemplateRef<{}>): void { + this.notification.template(template); + } + + closeCCVPNUpdate(obj, templateUpdateSuccessFaild) { + console.log(obj); + this.detailshow = false; + this.listDisplay = false; + this.upDateShow = false; + this.detailData["rate"] = 0; + this.detailData["status"] = "In Progress"; + this.detailData['tips'] = ""; + this.detailData["statusClass"] = "1005"; + let id = this.detailData["service-instance-id"]; + this.myhttp.updateccvpn(id, obj) + .subscribe((data) => { + if (data.status == "FAILED") { + console.log("scale E2e service Failed :" + JSON.stringify(data)); + this.detailData["status"] = "Failed"; + this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + this.updateCcvpnSuccessNotification(templateUpdateSuccessFaild); + return false; + } + let obj = { + serviceId: id, + operationId: data.operationId + } + let updata = (prodata) => { + this.detailData["rate"] = prodata.progress; + this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.detailData["rate"] + "%"; + if (this.detailData["rate"] > 100) { + this.detailData["status"] = prodata.status; + this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.detailData["status"]; + } + }; + this.queryProgress(obj, updata).then(() => { + this.detailData["rate"] = 100; + this.detailData["status"] = "Successful"; + this.detailData["tips"] = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == this.detailData["statusClass"] && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + this.updateCcvpnSuccessNotification(templateUpdateSuccessFaild); + }) + }) + } + + deleteService(service, templateDeleteSuccessFaild) { + let allprogress = {}; // + let querypros = []; // + service.rate = 0; + service.status = "In Progress"; + service.tips = ""; + service.statusClass = "1002"; + service["childServiceInstances"].push({ "service-instance-id": service["service-instance-id"] }); + let deletePros = service["childServiceInstances"].map((item) => { + let params = { + globalSubscriberId: this.customerSelected.id, + serviceType: this.serviceTypeSelected, + serviceInstanceId: item["service-instance-id"] + } + return new Promise((res, rej) => { + this.myhttp.deleteInstance(params) + .subscribe((data) => { + this.loadingAnimateShow = false; + if (data.status == "FAILED") { + console.log("delete service Failed :" + JSON.stringify(data)); + service.status = "Failed"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + return false; + } + let obj = { + serviceId: params.serviceInstanceId, + operationId: data.operationId, + operationType: "1002" + } + let updata = (prodata) => { + allprogress[prodata.operationId] = prodata.progress; + let average = ((arr) => { + return eval(arr.join("+")) / arr.length + })(Object.values(allprogress)); + service["rate"] = average; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service["rate"] + "%"; + if (service["rate"] > 100) { + service["status"] = prodata.status; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service["status"]; + } + }; + querypros.push(this.queryProgress(obj, updata)); + res(); + }) + }) + }); + Promise.all(deletePros).then(() => { + Promise.all(querypros).then((data) => { + console.log(data); + service.rate = 100; + service.status = "Successful"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + this.deleteSuccessNotification(templateDeleteSuccessFaild); + let hasUndone = this.tableData.some((item) => { + return item.rate < 100; + }) + if (!hasUndone) { + setTimeout(() => { + this.getTableData(); + }, 1000) + } + }) + }) + } + + deleteNsService(service, templateDeleteSuccessFaild) { + service.rate = 0; + service.status = "In Progress"; + service.tips = ""; + service.statusClass = "1002"; + let id = service.nsInstanceId || service["service-instance-id"]; + let operationType = "1002"; + let requestBody = { + terminationType: this.terminationType, + gracefulTerminationTimeout: this.gracefulTerminationTimeout + } + this.stopNsService(id, requestBody).then((jobid) => { + if (jobid == "Failed") { + service.status = "Failed"; + this.deleteSuccessNotification(templateDeleteSuccessFaild); + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + return false; + } + let updata = (prodata) => { + service.rate = prodata.progress; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + '\xa0\xa0\xa0' + service.rate + "%"; + if (service["rate"] > 100) { + service["status"] = prodata.status; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + service["status"]; + } + } + return this.queryNsProgress(jobid, null, updata, operationType); + }).then(() => { + this.myhttp.nsDeleteInstance(id) + .subscribe((data) => { + console.log(data); + service.rate = 100; + service.status = "Successful"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2001 && its["language"] == this.language + })["sortValue"]; + this.deleteSuccessNotification(templateDeleteSuccessFaild); + if (data.status == "FAILED") { + console.log("delete ns service Failed :" + JSON.stringify(data)); + service.status = "Failed"; + service.tips = this.listSortMasters["operationTypes"].find((its) => { + return its["sortCode"] == service.statusClass && its["language"] == this.language + })["sortValue"] + this.listSortMasters["operationResults"].find((its) => { + return its["sortCode"] == 2002 && its["language"] == this.language + })["sortValue"]; + this.deleteSuccessNotification(templateDeleteSuccessFaild); + return false; + } + console.log(service, "deleteservice"); + console.log(this.thisService, "thisService"); + let hasUndone = this.tableData.some((item) => { + return item.rate < 100; + }) + if (!hasUndone) { + setTimeout(() => { + this.getTableData(); + }, 1000) + } + }) + }) + } + + stopNsService(id, obj) { + let mypromise = new Promise((res, rej) => { + this.myhttp.stopNsService(id, obj) + .subscribe((data) => { + this.loadingAnimateShow = false; + if (data.status == "FAILED") { + console.log("stop ns service Failed :" + JSON.stringify(data)); + res("Failed"); + return false; + } + res(data.jobId); + }) + }) + return mypromise; + } + + queryProgress(obj, callback) { + let mypromise = new Promise((res, rej) => { + // let data = { + // operationStatus:{ + // "operationId": "XXXXXX", + // "operation": "create|delete|update|scale", + // "result": "finished|error|processing", + // "reason": "", + // "userId": "", + // "operationContent": "Be creating pop.", + // "progress": 0, + // "operateAt": "", + // "finishedAt": "" + // } + // } + let errorNums = 180; + let requery = () => { + this.myhttp.getProgress(obj) + .subscribe((data) => { + if (data.status == "FAILED") { + callback({ progress: 255, status: "Failed" }); + return false; + } + if (data.operationStatus == null || data.operationStatus.progress == undefined) { + // console.log(data); + errorNums--; + if (errorNums == 0) { + callback({ progress: 255, status: "time over" }); + return false; + } + setTimeout(() => { + requery(); + }, 10000) + return false; + } + if (data.operationStatus.progress > 100) { + callback({ progress: 255, status: "time over" }); + return false; + } + if (data.operationStatus.progress < 100) { + callback(data.operationStatus); + setTimeout(() => { + requery(); + }, 5000) + } else { + res(data.operationStatus); + } + }) + // setTimeout(()=>{ + // console.log(data.operationStatus.progress) + // data.operationStatus.progress++; + // if(data.operationStatus.progress<100){ + // callback(data.operationStatus); + // requery() + // }else{ + // callback(data.operationStatus); + // res(data.operationStatus) + // } + // },100) + } + requery(); + }) + return mypromise; + } + + queryNsProgress(jobid, id, callback, operationType) { + let mypromise = new Promise((res, rej) => { + // let data = { + // "jobId": "string", + // "responseDescriptor": { + // "status": "string", + // "progress": 0, + // "statusDescription": "string", + // "errorCode": "string", + // "responseId": "string", + // "responseHistoryList": [ + // { + // "status": "string", + // "progress": "string", + // "statusDescription": "string", + // "errorCode": "string", + // "responseId": "string" + // } + // ] + // } + // } + let errorNums = 180; + let requery = () => { + this.myhttp.getNsProgress(jobid, id, operationType) + .subscribe((data) => { + if (data.status == "FAILED") { + callback({ progress: 255, status: "Failed" }); + return false; + } + if (data.responseDescriptor == null || data.responseDescriptor.progress == undefined) { + // console.log(data); + errorNums--; + if (errorNums == 0) { + callback({ progress: 255, status: "time over" }); + return false; + } + setTimeout(() => { + requery(); + }, 10000) + return false; + } + if (data.responseDescriptor.progress > 100 && data.responseDescriptor.status == "error") { + callback({ progress: 255, status: data.responseDescriptor.statusDescription }); + return false; + } + if (data.responseDescriptor.progress < 100) { + callback(data.responseDescriptor); + setTimeout(() => { + requery(); + }, 5000) + } else { + res(data); + } + }) + // setTimeout(()=>{ + // console.log(data.responseDescriptor.progress) + // data.responseDescriptor.progress++; + // if(data.responseDescriptor.progress<100){ + // callback(data.responseDescriptor); + // requery() + // }else{ + // callback(data); + // res(data) + // } + // },100) + }; + requery(); + }); + return mypromise; + } + +} diff --git a/usecaseui-portal/src/app/views/services/services.component.html b/usecaseui-portal/src/app/views/services/services.component.html new file mode 100644 index 00000000..10142833 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services.component.html @@ -0,0 +1,18 @@ +<!-- + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<p> + services works! +</p> diff --git a/usecaseui-portal/src/app/views/services/services.component.less b/usecaseui-portal/src/app/views/services/services.component.less new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services.component.less diff --git a/usecaseui-portal/src/app/views/services/services.component.spec.ts b/usecaseui-portal/src/app/views/services/services.component.spec.ts new file mode 100644 index 00000000..2e76b9f9 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ServicesComponent } from './services.component'; + +describe('ServicesComponent', () => { + let component: ServicesComponent; + let fixture: ComponentFixture<ServicesComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ServicesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ServicesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/usecaseui-portal/src/app/views/services/services.component.ts b/usecaseui-portal/src/app/views/services/services.component.ts new file mode 100644 index 00000000..eec235b4 --- /dev/null +++ b/usecaseui-portal/src/app/views/services/services.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-services', + templateUrl: './services.component.html', + styleUrls: ['./services.component.less'] +}) +export class ServicesComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} |