summaryrefslogtreecommitdiffstats
path: root/usecaseui-portal/src/app/ccvpn-creation
diff options
context:
space:
mode:
Diffstat (limited to 'usecaseui-portal/src/app/ccvpn-creation')
-rw-r--r--usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.css195
-rw-r--r--usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.html313
-rw-r--r--usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.spec.ts25
-rw-r--r--usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.ts548
4 files changed, 1081 insertions, 0 deletions
diff --git a/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.css b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.css
new file mode 100644
index 00000000..35fdbef5
--- /dev/null
+++ b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.css
@@ -0,0 +1,195 @@
+/*
+ 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: 10px;
+}
+.model {
+ background-color: #fff;
+ height: 90%;
+ overflow-y: auto;
+}
+.model .back {
+ position: absolute;
+ top: 10px;
+ right: 20px;
+}
+.model .creation {
+ position: relative;
+ width: 60%;
+ height: 100%;
+ overflow-y: auto;
+ border-radius: 5px;
+ padding: 15px;
+}
+.model .creation h3.title {
+ height: 20px;
+ font: 700 20px/20px "Arial";
+ color: #666;
+}
+.model .creation h3 {
+ height: 20px;
+ font: 700 16px/20px "Arial";
+ margin: 5px 0px;
+ color: #000;
+}
+.model .creation .submit {
+ position: absolute;
+ top: 10px;
+ right: 20px;
+}
+/* SOTN VPN */
+.model .creation .sotnvpn ul li {
+ display: inline-block;
+ height: 35px;
+ width: 49.5%;
+}
+.model .creation .sotnvpn ul li span {
+ display: inline-block;
+ width: 110px;
+ font: 700 14px "Arial";
+ color: #3fa8eb;
+ vertical-align: middle;
+}
+.model .creation .sotnvpn ul li input {
+ width: 165px;
+}
+/* Site List */
+/* addsite model */
+.model .sitemodel {
+ position: absolute;
+ z-index: 10;
+ left: 10px;
+ top: 60px;
+ background-color: #fff;
+ box-shadow: 0px 0px 20px #000;
+ width: 60%;
+ max-height: 90%;
+ border-radius: 5px;
+ overflow-y: auto;
+}
+.model .sitemodel h3 {
+ height: 30px;
+ font: 700 16px/30px "Arial";
+ border-bottom: 1px solid #aaa;
+ padding-left: 10px;
+}
+.model .sitemodel h4 {
+ height: 30px;
+ font: 700 16px/30px "Arial";
+ padding-left: 10px;
+ background-color: #ddd;
+}
+.model .sitemodel .inputs {
+ padding: 10px 20px 0;
+}
+.model .sitemodel .inputs ul li {
+ display: inline-block;
+ height: 35px;
+ width: 49.5%;
+}
+.model .sitemodel .inputs ul li span {
+ display: inline-block;
+ width: 110px;
+ font: 700 14px "Arial";
+ color: #3fa8eb;
+ vertical-align: middle;
+}
+.model .sitemodel .inputs input {
+ width: 165px;
+}
+.model .sitemodel .action {
+ float: left;
+ padding: 10px;
+}
+
+.model nz-table tbody td i.anticon:hover {
+ color: #3fa8eb;
+ cursor: pointer;
+}
+
+/* site table */
+.model .site nz-table tbody td i.anticon:hover {
+ color: #3fa8eb;
+ cursor: pointer;
+}
+/* WAN Port */
+
+/* Site Group List */
+.model .sitegroup .sitegroupmodal {
+ position: absolute;
+ z-index: 10;
+ left: 200px;
+ top: 300px;
+ background-color: #fff;
+ box-shadow: 0px 0px 20px #000;
+ width: 330px;
+ border-radius: 5px;
+}
+.model .sitegroup .sitegroupmodal h3 {
+ height: 30px;
+ font: 700 16px/30px "Arial";
+ border-bottom: 1px solid #aaa;
+ padding-left: 10px;
+}
+.model .sitegroup .sitegroupmodal .inputs {
+ padding: 10px 20px 0;
+}
+.model .sitegroup .sitegroupmodal span {
+ display: inline-block;
+ width: 100px;
+ margin-bottom: 10px;
+}
+.model .sitegroup .sitegroupmodal .inputs input {
+ width: 165px;
+}
+.model .sitegroup .sitegroupmodal .action {
+ float: right;
+ padding: 10px;
+}
+
+
+/* 图 */
+.model .chart {
+ width: 40%;
+ padding: 10px;
+ height: 100%;
+ border-left: 10px solid #f3f3f3;
+}
+.model .chart #createChart {
+ width: 100%;
+ height: 80%;
+ 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;
+}
diff --git a/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.html b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.html
new file mode 100644
index 00000000..15486238
--- /dev/null
+++ b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.html
@@ -0,0 +1,313 @@
+<!--
+ 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.
+-->
+<h3 class="title"> Services List </h3>
+<hr>
+<div class="model">
+ <!-- 创建数据 -->
+ <button class="back" nz-button (click)="goback()"><span><i class="anticon anticon-rollback"></i></span></button>
+ <div class="creation fl">
+ <h3 class="title">{{createParams.commonParams.templateType}} Instance Creation</h3>
+ <div class="sotnvpn clearfix">
+ <h3>SOTN VPN Info</h3>
+ <ul>
+ <li><span>Name:</span> <input nz-input [(ngModel)]="sotnInfo.name"></li>
+ <li><span>Description:</span> <input nz-input [(ngModel)]="sotnInfo.description"></li>
+ <li><span>Start Time:</span>
+ <nz-date-picker [(ngModel)]="sotnInfo.startTime"
+ (ngModelChange)="startTimeChange($event)"
+ nzPlaceHolder="start time"
+ nzShowTime>
+ </nz-date-picker>
+ </li>
+ <li><span>End Time:</span>
+ <nz-date-picker [(ngModel)]="sotnInfo.endTime"
+ (ngModelChange)="endTimeChange($event)"
+ nzPlaceHolder="end time"
+ nzShowTime>
+ </nz-date-picker>
+ </li>
+ <li><span>COS:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="sotnInfo.COS" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="premium" nzLabel="premium"></nz-option>
+ <nz-option nzValue="standard" nzLabel="standard"></nz-option>
+ </nz-select>
+ </li>
+ <li><span>Reroute Enabled:</span> <nz-switch [(ngModel)]="sotnInfo.reroute"></nz-switch> </li>
+ <li><span>Service Level Specification:</span> <input nz-input [(ngModel)]="sotnInfo.SLS"></li>
+ <li><span>Dual Link:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="sotnInfo.dualLink" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="no_protection" nzLabel="no_protection"></nz-option>
+ <nz-option nzValue="static_1+1" nzLabel="static_1+1"></nz-option>
+ <nz-option nzValue="permanent_1+1" nzLabel="permanent_1+1"></nz-option>
+ </nz-select>
+ </li>
+ <li><span>CIR:</span> <input nz-input [(ngModel)]="sotnInfo.CIR"></li>
+ <li><span>EIR:</span> <input nz-input [(ngModel)]="sotnInfo.EIR"></li>
+ <li><span>CBS:</span> <input nz-input [(ngModel)]="sotnInfo.CBS"></li>
+ <li><span>EBS:</span> <input nz-input [(ngModel)]="sotnInfo.EBS"></li>
+ <li><span>Color Aware:</span> <nz-switch [(ngModel)]="sotnInfo.colorAware"></nz-switch> </li>
+ <li><span>Coupling Flag:</span> <nz-switch [(ngModel)]="sotnInfo.couplingFlag"></nz-switch> </li>
+ </ul>
+ </div>
+
+ <div class="site">
+ <h3>Site List</h3>
+ <button nz-button (click)="addSite()">Add Site</button>
+ <nz-table #siteTable [nzData]="siteTableData"
+ [nzShowPagination]="false"
+ nzSize="small">
+ <thead>
+ <tr>
+ <th nzWidth="10%"> NO. </th>
+ <th nzWidth="15%"> Name </th>
+ <th nzWidth="15%"> Description </th>
+ <th nzWidth="15%"> Post Code </th>
+ <th nzWidth="15%"> Address </th>
+ <th nzWidth="15%"> VLAN </th>
+ <th nzWidth="15%"> Action </th>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- <ng-template ngFor let-data [ngForOf]="siteTable.data" let-i="index"> -->
+ <tr *ngFor="let item of siteTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.baseData.name}}</td>
+ <td>{{item.baseData.description}}</td>
+ <td>{{item.baseData.postcode}}</td>
+ <td>{{item.baseData.address}}</td>
+ <td>{{item.baseData.vlan}}</td>
+ <td>
+ <span class="action" (click)="editSite(i+1)"><i class="anticon anticon-edit"></i></span> &nbsp;
+ <span class="action" (click)="deleteSite(i+1)"><i class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ <!-- </ng-template> -->
+ </tbody>
+ </nz-table>
+ </div>
+
+ <div class="sitegroup" *ngIf="createParams.commonParams.templateType == 'CCVPN'">
+ <h3>Site_Group List</h3>
+ <button nz-button (click)="addSiteGroup()">Add Group</button>
+ <div class="sitegroupmodal" *ngIf="siteGroupModelShow">
+ <h3>Site_Group</h3>
+ <div class="inputs">
+ <span>Group Name:</span> <input nz-input [(ngModel)]="siteGroupModelData.name"> <br>
+ <span>Topology:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="siteGroupModelData.topology" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="full-mesh" nzLabel="full-mesh"></nz-option>
+ <nz-option nzValue="hub-spoke" nzLabel="hub-spoke"></nz-option>
+ </nz-select>
+ <nz-table #groupModalTable [nzData]="siteGroupModalTableData" [nzLoading]="loading" [nzShowPagination]="false" nzSize="small">
+ <thead>
+ <tr>
+ <th nzShowCheckbox [(nzChecked)]="allChecked" [nzIndeterminate]="indeterminate" (nzCheckedChange)="groupModal_checkAll($event)"></th>
+ <th> Site Name</th>
+ <th> Role</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let item of groupModalTable.data; let i = index;">
+ <td nzShowCheckbox [nzDisabled]="item.disabled" [(nzChecked)]="item.checked" (nzCheckedChange)="refreshStatus($event)"></td>
+ <td>{{ item.siteName }}</td>
+ <td>
+ <nz-select style="width: 80px;" [(ngModel)]="item.role"
+ nzAllowClear nzPlaceHolder="Choose"
+ [nzDisabled]="siteGroupModelData.topology != 'hub-spoke'">
+ <nz-option nzValue="hub" nzLabel="hub"></nz-option>
+ <nz-option nzValue="spoke" nzLabel="spoke"></nz-option>
+ </nz-select>
+ </td>
+ </tr>
+ </tbody>
+ </nz-table>
+ </div>
+ <div class="action">
+ <button nz-button nzType="primary" (click)="addsitegroup_OK()">OK</button>
+ <button nz-button nzType="primary" (click)="addsitegroup_cancel()">Cancel</button>
+ </div>
+ </div>
+ <nz-table #siteGroupTable [nzData]="siteGroupTableData"
+ [nzLoading]="loading"
+ [nzShowPagination]="false"
+ nzSize="small">
+ <thead>
+ <tr>
+ <th nzWidth="10%"> NO. </th>
+ <th nzWidth="20%"> Group Name </th>
+ <th nzWidth="20%"> Topology </th>
+ <th nzWidth="20%"> Sites </th>
+ <th nzWidth="15%"> Role </th>
+ <th nzWidth="15%"> Action </th>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- <ng-template ngFor let-data [ngForOf]="siteGroupTable.data" let-i="index"> -->
+ <tr *ngFor="let item of siteGroupTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.name}}</td>
+ <td>{{item.topology}}</td>
+ <td>{{item.sites}}</td>
+ <td>{{item.role}}</td>
+ <td>
+ <span class="action" (click)="editGroupSite(i+1)"><i class="anticon anticon-edit"></i></span> &nbsp;
+ <span class="action" (click)="deleteGroupSite(i+1)"><i class="anticon anticon-delete"></i></span>
+ </td>
+ </tr>
+ <!-- </ng-template> -->
+ </tbody>
+ </nz-table>
+ </div>
+
+ <button class="submit" nz-button [nzType]="'primary'" (click)="submit()"><span>Create</span></button>
+ </div>
+ <!-- site模态框 -->
+ <div class="sitemodel" *ngIf="siteModelShow">
+ <h3>Site_Enterprise Service</h3>
+ <div class="inputs">
+ <ul>
+ <li><span>Name:</span> <input nz-input [(ngModel)]="siteBaseData.name"></li>
+ <li><span>Description:</span> <input nz-input [(ngModel)]="siteBaseData.description"></li>
+ <li *ngIf="createParams.commonParams.templateType == 'CCVPN'"><span>Type:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="siteBaseData.type" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="single-gateway" nzLabel="single-gateway"></nz-option>
+ <nz-option nzValue="dual-gateway" nzLabel="dual-gateway"></nz-option>
+ </nz-select>
+ </li>
+ <li *ngIf="createParams.commonParams.templateType == 'CCVPN'"><span>Role:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="siteBaseData.role" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="dsvpn-hub" nzLabel="dsvpn-hub"></nz-option>
+ <nz-option nzValue="sd-wan-edge" nzLabel="sd-wan-edge"></nz-option>
+ </nz-select>
+ </li>
+ <li><span>PostCode:</span> <input nz-input [(ngModel)]="siteBaseData.postcode"></li>
+ <li><span>VLAN:</span> <input nz-input [(ngModel)]="siteBaseData.vlan"></li>
+ <li><span>Address:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="siteBaseData.address" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option *ngFor="let item of siteModeAddress" nzValue="{{item}}" nzLabel="{{item}}"></nz-option>
+ </nz-select>
+ </li>
+ </ul>
+ </div>
+ <div *ngIf="createParams.commonParams.templateType == 'CCVPN'">
+ <h4>CPE</h4>
+ <div class="inputs">
+ <ul>
+ <li><span>Name:</span> <input nz-input [(ngModel)]="siteCpeData.device_name"></li>
+ <li><span>Version:</span> <input nz-input [(ngModel)]="siteCpeData.device_version"></li>
+ <li><span>ESN:</span> <input nz-input [(ngModel)]="siteCpeData.device_esn"></li>
+ <li><span>Class:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="siteCpeData.device_class" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="VNF" nzLabel="VNF"></nz-option>
+ <nz-option nzValue="PNF" nzLabel="PNF"></nz-option>
+ </nz-select>
+ </li>
+ <li><span>System IP:</span> <input nz-input [(ngModel)]="siteCpeData.device_systemIp"></li>
+ <li><span>Vendor:</span> <input nz-input [(ngModel)]="siteCpeData.device_vendor"></li>
+ <li><span>Type:</span> <input nz-input [(ngModel)]="siteCpeData.device_type"></li>
+ </ul>
+ </div>
+ <h4>WAN Port</h4>
+ <div>
+ <nz-table #siteModalTable [nzData]="siteWanData"
+ [nzLoading]="loading"
+ [nzShowPagination]="false"
+ nzSize="small">
+ <thead>
+ <tr>
+ <th nzWidth="10%"> NO. </th>
+ <th nzWidth="15%"> Name </th>
+ <th nzWidth="15%"> Description </th>
+ <th nzWidth="15%"> PortType </th>
+ <th nzWidth="18%"> PortNumber </th>
+ <th nzWidth="17%"> IPAddress </th>
+ <th nzWidth="10%"> Action </th>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- <ng-template ngFor let-data [ngForOf]="siteModalTable.data" let-i="index"> -->
+ <tr *ngFor="let item of siteModalTable.data; let i = index; ">
+ <td>{{i+1}}</td>
+ <td>{{item.sitewanport_name}}</td>
+ <td>{{item.sitewanport_description}}</td>
+ <td>{{item.sitewanport_portType}}</td>
+ <td>{{item.sitewanport_portNumber}}</td>
+ <td>{{item.sitewanport_ipAddress}}</td>
+ <td>
+ <span class="action" (click)="editWanPort(i+1)"><i class="anticon anticon-edit"></i></span>
+ </td>
+ </tr>
+ <!-- </ng-template> -->
+ </tbody>
+ </nz-table>
+ </div>
+ <nz-modal [(nzVisible)]="wanPortModal" nzWidth="400" nzTitle="WAN Port Edit" (nzOnCancel)="wanPortModal_Cancel()" (nzOnOk)="wanPortModal_Ok()">
+ <ul class="wanPortModalList">
+ <li><span>Name:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_name"></li>
+ <!-- <li><span>Device Name:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_deviceName"></li> -->
+ <li><span>Description:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_description"></li>
+ <li><span>Port Type:</span>
+ <nz-select style="width: 165px;" [(ngModel)]="siteWanParams.sitewanport_portType" nzAllowClear nzPlaceHolder="Choose">
+ <nz-option nzValue="GE" nzLabel="GE"></nz-option>
+ <nz-option nzValue="FE" nzLabel="FE"></nz-option>
+ <nz-option nzValue="XGE" nzLabel="XGE"></nz-option>
+ <nz-option nzValue="LTE" nzLabel="LTE"></nz-option>
+ <nz-option nzValue="xDSL(ATM)" nzLabel="xDSL(ATM)"></nz-option>
+ <nz-option nzValue="xSDL(PTM)" nzLabel="xSDL(PTM)"></nz-option>
+ </nz-select>
+ </li>
+ <li><span>Port Number:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_portNumber"></li>
+ <li><span>Ip Address:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_ipAddress"></li>
+ <li><span>Provider IP Address:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_providerIpAddress"></li>
+ <li><span>Transport Nerwork:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_transportNetworkName"></li>
+ <li><span>Input Bandwidth:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_inputBandwidth"></li>
+ <li><span>Output Bandwidth:</span> <input nz-input [(ngModel)]="siteWanParams.sitewanport_outputBandwidth"></li>
+ </ul>
+ </nz-modal>
+ </div>
+
+ <div class="action">
+ <button nz-button nzType="primary" (click)="addsite_OK()">OK</button>
+ <button nz-button nzType="primary" (click)="addsite_cancel()">Cancel</button>
+ </div>
+ </div>
+ <!-- 图 -->
+ <div class="chart fr">
+ Create Service
+ {{createParams.commonParams.templateType}}
+ <div id="createChart">
+ <svg width="100%" height="100%">
+ <line *ngFor="let item of lines" x1=50% y1="45%" [attr.x2]="item.x2" y2="72%" style="stroke:#3fa8eb;stroke-width:2"/>
+ <image xlink:href="./assets/images/cloud-site.png"
+ x="25%" y="30%" width="50%"/>
+ <!-- <text dx="42%" dy="45%" style="font:700 18px 'Arial';fill:#666">{{createParams.commonParams.templateType}}</text> -->
+ <text dx="42%" dy="45%" style="font:700 18px 'Arial';fill:#666"></text>
+ <g *ngFor="let item of siteImage"
+ (mouseover)="showSite($event,item)"
+ (mousemove)="moveSite($event,item)"
+ (mouseout)="hideSite($event)">
+ <image
+ xlink:href="./assets/images/site.png"
+ [attr.x]="item.x" y="65%" width="80px"/>
+ <text [attr.dx]="item.x + 25" dy="72%" style="font:700 16px 'Arial';fill:#666">{{ item.name }}</text>
+ </g>
+
+ </svg>
+ <!-- <p class="siteNameP" [ngStyle]="siteNameStyle">{{ siteName }}</p> -->
+ </div>
+ </div>
+
+</div>
diff --git a/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.spec.ts b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.spec.ts
new file mode 100644
index 00000000..922bd9ea
--- /dev/null
+++ b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.spec.ts
@@ -0,0 +1,25 @@
+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/ccvpn-creation/ccvpn-creation.component.ts b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.ts
new file mode 100644
index 00000000..ffc354c7
--- /dev/null
+++ b/usecaseui-portal/src/app/ccvpn-creation/ccvpn-creation.component.ts
@@ -0,0 +1,548 @@
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { MyhttpService } from '../myhttp.service';
+
+@Component({
+ selector: 'app-ccvpn-creation',
+ templateUrl: './ccvpn-creation.component.html',
+ styleUrls: ['./ccvpn-creation.component.css']
+})
+export class CcvpnCreationComponent implements OnInit {
+
+ constructor(private myhttp:MyhttpService) { }
+
+ ngOnInit() {
+ this.getSiteAddressList();
+ this.getTemParameters();
+ }
+
+ @Input() createParams;
+ @Input() namesTranslate; //输入项参数名字转换
+ @Output() closeCreate = new EventEmitter();
+
+ templateParameters = {};
+ getTemParameters(){ //获取模板参数
+ let chosedtemplates = Object.values(this.createParams.templates);
+ // console.log(this.createParams);
+ console.log(chosedtemplates); //模板id数组
+ let types = ["sotnvpn","site","sdwanvpn"];
+ chosedtemplates.forEach((item,index)=>{
+ this.myhttp.getTemplateParameters(types[index],item)
+ .subscribe((data)=>{
+ if(index === 0){
+ this.templateParameters["sotnvpn"] = data;
+ this.sotnNames = data.inputs.map((item)=>{return item.name}); //云的真实名字
+ }else if(index === 1){
+ this.templateParameters["site"] = data;
+ let wanportnames = {};
+ this.siteNames = data.inputs.map((item)=>{return item.name}); //site中所有真实名字,没有分组,放在一起了
+ this.siteNames.forEach((item)=>{
+ if(item.includes("_device_")){
+ this.siteCpeNames.push(item);
+ }else if(item.includes("_sitewanport_")){
+ let firstName = item.split("_")[0];
+ wanportnames[firstName]?wanportnames[firstName].push(item):wanportnames[firstName]=[item];
+ }else {
+ this.siteBaseNames.push(item);
+ }
+ })
+ this.siteWanNames = Object.values(wanportnames);
+ this.siteWanNames.forEach((item)=>{
+ this.siteWanData.push(this.siteWanParams); //根据wanport组添加表格中
+ })
+ // console.log(this.sotnNames)
+ // console.log(this.siteNames)
+ // console.log(this.siteBaseNames)
+ // console.log(this.siteCpeNames)
+ // console.log(this.siteWanNames)
+ // console.log(this.siteWanData)
+ }else if(index === 2){
+ this.templateParameters["sdwan"] = data;
+ this.siteGroupNames = data.inputs.map((item)=>{return item.name}); //sdwanvpn真实名字
+ // console.log(this.siteGroupNames);
+ }
+
+ },(err)=>{
+
+ })
+ })
+
+ }
+ // SOTN VPN Info 输入参数
+ sotnInfo = {
+ name:null,description:null,
+ startTime:null,endTime:null,
+ COS:"premium",reroute:false,
+ SLS:null,dualLink:false,
+ CIR:null,EIR:null,
+ CBS:null,EBS:null,
+ colorAware:false,couplingFlag:false
+ }
+ sotnNames = [] //真实名字
+
+ startTimeChange(event){
+ console.log(event)
+ }
+ endTimeChange(event){
+ console.log(event)
+ }
+
+
+ // Site List
+ siteTableData = [
+
+ ]
+ siteModeAddress = [];//site地址,筛选框数据,本地配置文件
+ siteNames = [];//site中所有真实名字,未分组,模拟真实请求情况;
+
+ siteBaseData = { //模态框数据,输入参数,绑定数据
+ name:null,
+ description:null,
+ type:null,
+ role:null,
+ postcode:null,
+ address:null,
+ vlan:null,
+ sotnVpnName:null, //SOTN VPN Info中name
+ controlPoint:null, //site group里面site的Role设置为spoke时,传递site group里面Role设置为hub的site name;否则传递空白
+ groupRole:null, //site group的role
+ groupName:null, //site group的name
+ emails:null,// 不显示传空
+ latitude:null,//
+ longitude:null,//
+ clientSignal:null//
+ };
+ siteBaseNames = [] //真实名字
+ // cpe 编辑
+ siteCpeData = {
+ device_name:null,
+ device_version:null,
+ device_esn:null,
+ device_class:null,
+ device_systemIp:null,
+ device_vendor:null,
+ device_type:null
+ };
+ siteCpeNames = [] //真实名字
+ // Wan Port 编辑
+ siteWanData = []; //wan port 表格绑定数据
+ siteWanParams = { //每一行数据详细参数,模态框
+ sitewanport_name:null,
+ sitewanport_deviceName:null,
+ sitewanport_description:null,
+ sitewanport_portType:null,
+ sitewanport_portNumber:null,
+ sitewanport_ipAddress:null,
+ sitewanport_providerIpAddress:null,
+ sitewanport_transportNetworkName:null,
+ sitewanport_inputBandwidth:null,
+ sitewanport_outputBandwidth:null
+ };
+ siteWanNames = [] //真实名字
+ wanPortModal = false; //模态框显示隐藏
+ wanPortEditNum = 0;//编辑哪行
+ editWanPort(num){
+ this.wanPortModal = true;
+ this.wanPortEditNum = num;
+ this.siteWanParams = Object.assign({},this.siteWanData[num-1]);
+ }
+ wanPortModal_Ok(){
+ let inputsData = Object.assign({},this.siteWanParams); //新建对象,断开原引用,因为后面要清空模态框
+ inputsData.sitewanport_deviceName = this.siteCpeData.device_name;
+ this.siteWanData[this.wanPortEditNum-1] = inputsData;
+ this.siteWanData = [...this.siteWanData]; //表格刷新
+ Object.keys(this.siteWanParams).forEach((item)=>{ //清空模态框
+ this.siteWanParams[item] = null;
+ })
+ this.wanPortModal = false;
+ console.log(this.siteWanData)
+ }
+ wanPortModal_Cancel(){
+ this.wanPortModal = false;
+ }
+
+
+ // 获取site地址,手动文件
+ getSiteAddressList(){
+ this.myhttp.getSiteAddress()
+ .subscribe((data)=>{
+ console.log(data);
+ this.siteModeAddress = data.map((item)=>{ return item.location});
+ },(err)=>{
+ console.log(err);
+ })
+ }
+ siteModelShow = false;
+ addSite(){
+ this.siteModelShow = true;
+ this.isEdit = 0;
+ }
+ // addsite模态框按钮
+ isEdit = 0; //编辑序号,No值,0表示增加
+ addsite_OK(){
+ this.siteBaseData.sotnVpnName = this.sotnInfo.name;
+ // let inputsData = Object.assign({},this.siteBaseData,this.siteCpeData,this.siteWanData); //新建对象,断开原引用,因为后面要清空模态框
+ let inputs = {};
+ inputs["baseData"] = Object.assign({},this.siteBaseData);
+ inputs["cpeData"] = Object.assign({},this.siteCpeData);
+ inputs["wanportData"] = this.siteWanData.map((item)=>{
+ return Object.assign({},item);
+ })
+ console.log(inputs);
+ if(this.isEdit){
+ // 编辑状态不增加
+ this.siteTableData[this.isEdit-1] = inputs;
+ this.siteTableData = [...this.siteTableData]; //表格刷新
+ this.siteGroupTableData.forEach((item)=>{ //site修改名字后,更新组中sites值
+ if(item.sites.split(";").filter((d)=>{return d!=""}).includes(this.lastSiteName)){
+ item.sites = item.sites.replace(this.lastSiteName,this.siteBaseData.name);
+ }
+ })
+ }else{
+ // this.siteTableData.push(inputs);//使用 push 或者 splice 修改 nzData 失效 当加上[nzFrontPagination]="false" 时,生效
+ this.siteTableData = [...this.siteTableData,inputs];
+ }
+
+ Object.keys(this.siteBaseData).forEach((item)=>{ //清空模态框
+ this.siteBaseData[item] = null;
+ })
+ Object.keys(this.siteCpeData).forEach((item)=>{ //清空模态框
+ this.siteCpeData[item] = null;
+ })
+ this.siteWanData.forEach((item)=>{
+ Object.keys(item).forEach((item2)=>{
+ item[item2] = null;
+ })
+ })
+ // console.log(this.siteTableData);
+ this.lastSiteName = null;
+ this.drawImage(this.siteTableData);
+ this.siteModelShow = false;
+ }
+ addsite_cancel(){
+ Object.keys(this.siteBaseData).forEach((item)=>{ //清空模态框
+ this.siteBaseData[item] = null;
+ })
+ Object.keys(this.siteCpeData).forEach((item)=>{ //清空模态框
+ this.siteCpeData[item] = null;
+ })
+ this.siteWanData.forEach((item)=>{
+ Object.keys(item).forEach((item2)=>{
+ item[item2] = null;
+ })
+ })
+ this.lastSiteName = null;
+ this.siteModelShow = false;
+ }
+ lastSiteName = null; //当site修改之后,若修改了名字,则需要更新group中sites的名字
+ editSite(num){ //编辑修改选中site信息
+ this.siteModelShow = true;
+ this.isEdit=num;
+ this.siteBaseData = Object.assign({},this.siteTableData[num-1].baseData);
+ this.siteCpeData = Object.assign({},this.siteTableData[num-1].cpeData);
+ this.siteWanData = this.siteTableData[num-1].wanportData.map((item)=>{return Object.assign({},item)});
+ this.lastSiteName = this.siteBaseData.name;
+ }
+ deleteSite(num){
+ let deleteSiteName = this.siteTableData[num-1].baseData.name; //删除的site中name
+ let groupSites = [];
+ this.siteGroupTableData.forEach((item)=>{ groupSites.push(...item.sites.split(";").filter((d)=>{return d!=""})) });
+ if(groupSites.includes(deleteSiteName)){
+ alert("this site has in grouplist;can't delete!")
+ return false;
+ }
+ this.siteTableData = this.siteTableData.filter((d,i) => i !== num-1);
+ // this.siteTableData.splice(num-1,1); //模板中加上[nzFrontPagination]="false" 时,生效
+ this.drawImage(this.siteTableData);
+
+ // let groupIndex = this.siteGroupTableData.findIndex((item)=>{return item.sites.split(";").includes(deleteSiteName)});
+ // console.log(groupIndex)
+ // this.deleteGroupSite(groupIndex + 1); //删除时首行编号为1
+ }
+
+ // site节点图形描绘
+ lines=[];
+ siteImage=[];
+ drawImage(sitelist){
+ let cx = 200;
+ let cy = 200;
+ let r = 180;
+ let startAngle = -210 * (Math.PI/180);
+ let step = sitelist.length > 1 ? 120/(sitelist.length-1) * (Math.PI/180) : 1;
+
+ this.lines = sitelist.map((item,index)=>{
+ let x = cx + Math.cos(startAngle - step*index)*r;
+ let y = cy + Math.sin(startAngle - step*index)*r;
+ return {img:"line",site:item.baseData.name,x1:cx,y1:cy,x2:x,y2:y}
+ })
+ this.siteImage = this.lines.map((item)=>{
+ return {img:"site",name:item.site,x:item.x2 - 40,y:item.y2 - 40}
+ })
+ }
+
+ siteName=null;
+ siteNameStyle = {
+ 'display':'none',
+ 'left':'0',
+ 'top':'0'
+ }
+ showSite($event,item){
+ this.siteName = item.name;
+ this.siteNameStyle.display = 'block';
+ }
+ moveSite($event,item){
+ this.siteNameStyle.left = $event.clientX + "px";
+ this.siteNameStyle.top = $event.clientY - 35 + "px";
+ }
+ hideSite($event){
+ this.siteNameStyle.display = 'none';
+ }
+ // siteGroup List
+ siteGroupTableData = [
+
+ ]
+ siteGroupModelData = {
+ name:null,
+ topology:null,
+ sites:null,
+ role:null
+ }
+ siteGroupModelShow = false;
+ siteGroupModalTableData = [];// ==> siteTableData?
+ siteGroupNames=[]; //sdwanvpn真实名字
+
+ // 勾选框
+ allChecked = false;
+ indeterminate = false;
+ groupModal_checkAll(value){
+ this.siteGroupModalTableData.forEach(data => {
+ if (!data.disabled) {
+ data.checked = value;
+ }
+ });
+ this.refreshStatus();
+ }
+ refreshStatus(){
+ const allChecked = this.siteGroupModalTableData.filter(item => !item.disabled).every(item => item.checked === true);
+ const allUnChecked = this.siteGroupModalTableData.filter(item => !item.disabled).every(item => !item.checked);
+ this.allChecked = allChecked;
+ this.indeterminate = (!allChecked) && (!allUnChecked);
+ }
+
+ addSiteGroup(){
+ this.isGroupEdit = 0;
+ this.siteGroupModelShow = true;
+ let checkedSite = this.siteGroupTableData.map((item)=>{return item.sites}).join(";").split(";").filter((d)=>{return d!=""});//循环组中是否已经选用了某个site,若存在 则新组不可选
+ // console.log(checkedSite);
+ this.siteTableData.forEach((item,index)=>{
+ if(checkedSite.includes(item.baseData.name)){
+ this.siteGroupModalTableData.push({siteName:item.baseData.name,role:null,checked:false,disabled:true})
+ }else {
+ this.siteGroupModalTableData.push({siteName:item.baseData.name,role:null,checked:false,disabled:false})
+ }
+ })
+ }
+ // addsiteGroup模态框按钮
+ addsitegroup_OK(){ //将模态框中的值赋给表中对应项--->将选中的site中的groupRole、groupName、controlPoint更新--->
+ //拷贝数据判断是增加或编辑,更新表中数据---> 清除模态框中数据,便于下次添加,关闭模态框
+ console.log(this.siteGroupModalTableData);
+ this.siteGroupModelData.sites=""; //置空组成员名字,写成""方便+= ,若为null +=时会转成 "null"
+ this.siteGroupModelData.role=""; //
+ let site_controlPoint = this.siteGroupModalTableData.map((item)=>{ if(item.checked&&item.role=="hub"){ return item.siteName}}).filter((item)=>{return item!=undefined});
+ // console.log(site_controlPoint);
+ this.siteGroupModalTableData.forEach((item,index)=>{ //模态框中site顺序和 表中site顺序一致
+ if(item.checked){
+ this.siteGroupModelData.sites += item.siteName+";";
+ this.siteGroupModelData.role += item.role+";";
+ this.siteTableData[index].baseData.groupRole = item.role; //site group的role
+ this.siteTableData[index].baseData.groupName = this.siteGroupModelData.name; //site group的name
+ if(item.role == "spoke"){
+ this.siteTableData[index].baseData.controlPoint = site_controlPoint.join(); //site group里面site的Role设置为spoke时,传递site group里面Role设置为hub的site name;否则传递空白
+ }
+ }
+ })
+
+ let inputsData = {};
+ Object.assign(inputsData,this.siteGroupModelData);
+ if(this.isGroupEdit){
+ // 编辑状态不增加
+ this.siteGroupTableData[this.isGroupEdit-1] = inputsData;
+ this.siteGroupTableData = [...this.siteGroupTableData]; //表格刷新
+ }else{
+ // this.siteTableData.push(inputsData);//使用 push 或者 splice 修改 nzData 失效
+ this.siteGroupTableData = [...this.siteGroupTableData,inputsData];
+ }
+
+ Object.keys(this.siteGroupModelData).forEach((item)=>{
+ this.siteGroupModelData[item] = null;
+ })
+ this.siteGroupModalTableData = [];
+ this.siteGroupModelShow = false;
+ }
+ addsitegroup_cancel(){
+ this.siteGroupModalTableData = [];
+ this.siteGroupModelShow = false;
+ }
+ isGroupEdit = 0; //编辑序号,No值,0表示增加
+ editGroupSite(num){ //将当前编辑的行数据填入模态框--->获取当前编辑项sites名--->判断更新模态框中site项状态
+ this.siteGroupModelShow = true;
+ this.isGroupEdit=num;
+ this.siteGroupModelData = Object.assign({},this.siteGroupTableData[num-1]);
+ console.log(this.siteGroupModelData)
+ let editSites = this.siteGroupTableData[num-1].sites.split(";").filter((item)=>{return item!=""}); //获取组中的site名
+ // console.log(editSites);
+ let checkedSite = this.siteGroupTableData.map((item)=>{return item.sites}).join(";").split(";").filter((d)=>{return d!=""});//循环组中是否已经选用了某个site,若存在 则新组不可选
+ // console.log(checkedSite);
+ this.siteTableData.forEach((item,index)=>{
+ if(editSites.includes(item.baseData.name)){//先将编辑组中的site 中这三个值还原,否则减少某个site时 不会更新不选中的
+ item.baseData.groupRole = null; //site group的role
+ item.baseData.groupName = null; //site group的name
+ item.baseData.controlPoint = null;
+ this.siteGroupModalTableData.push({siteName:item.baseData.name,role:item.baseData.groupRole,checked:true,disabled:false})
+ }else
+ if(checkedSite.includes(item.baseData.name)){
+ this.siteGroupModalTableData.push({siteName:item.baseData.name,role:null,checked:false,disabled:true})
+ }else {
+ this.siteGroupModalTableData.push({siteName:item.baseData.name,role:null,checked:false,disabled:false})
+ }
+ })
+
+ }
+ deleteGroupSite(num){
+ let deleteSiteGroupsites = this.siteGroupTableData[num-1].sites.split(";").filter((item)=>{return item!=""}); //删除的site中name
+ this.siteGroupTableData = this.siteGroupTableData.filter((d,i) => i !== num-1);
+ this.siteTableData.forEach((item,index)=>{
+ if(deleteSiteGroupsites.includes(item.baseData.name)){
+ item.baseData.groupRole = null; //site group的role
+ item.baseData.groupName = null; //site group的name
+ item.baseData.controlPoint = null;
+ }
+ })
+ }
+
+
+
+ // 提交创建数据
+ submit(){
+ let globalCustomerId = this.createParams.commonParams.customer.id;
+ let globalServiceType = this.createParams.commonParams.serviceType;
+ let sotnInputs = {};
+ // 由于请求模板不一样,所以外层需要循环请求回来的真实名字,内层循环本地参数,将当前值赋给真实名字
+ this.sotnNames.forEach((name)=>{
+ for(let key in this.sotnInfo){
+ let nameParts = this.namesTranslate.sotnNameTranslate[key].split("_");
+ if(name.startsWith(nameParts[0])&&name.endsWith(nameParts[1])){
+ sotnInputs[name] = this.sotnInfo[key];
+ break;
+ }
+ }
+ })
+ console.log(sotnInputs);
+ let vpnbody = {
+ service:{
+ name:this.sotnInfo.name,
+ description:this.sotnInfo.description,
+ serviceInvariantUuid:this.templateParameters["sotnvpn"].invariantUUID, //template.invariantUUID, //serviceDefId
+ serviceUuid:this.templateParameters["sotnvpn"].uuid, //template.uuid, // uuid ?? templateId
+ globalSubscriberId:globalCustomerId, //customer.id
+ serviceType:globalServiceType, //serviceType.value
+ parameters:{
+ locationConstraints:[],
+ resources:[],
+ requestInputs:sotnInputs
+ }
+ }
+ }
+
+ let sitebody = this.siteTableData.map((site)=>{
+ let siteInputs = {};
+ this.siteBaseNames.forEach((basename)=>{
+ for(let key in site.baseData){
+ let namePart = this.namesTranslate.siteNameTranslate.baseNames[key];
+ if(basename.endsWith(namePart)){
+ siteInputs[basename] = site.baseData[key];
+ break;
+ }
+ }
+ })
+ this.siteCpeNames.forEach((cpename)=>{
+ for(let key in site.cpeData){
+ let namePart = this.namesTranslate.siteNameTranslate.cpeNames[key];
+ if(cpename.endsWith(namePart)){
+ siteInputs[cpename] = site.cpeData[key];
+ break;
+ }
+ }
+ })
+ this.siteWanNames.forEach((item,index)=>{
+ item.forEach((wanportname)=>{
+ for(let key in site.wanportData[index]){
+ let namePart = this.namesTranslate.siteNameTranslate.wanportNames[key];
+ if(wanportname.endsWith(namePart)){
+ siteInputs[wanportname] = site.wanportData[index][key];
+ break;
+ }
+ }
+ })
+ })
+
+ return {
+ service:{
+ name:site.baseData.name,
+ description:site.baseData.description,
+ serviceInvariantUuid:this.templateParameters["site"].invariantUUID,
+ serviceUuid:this.templateParameters["site"].uuid,
+ globalSubscriberId:globalCustomerId,
+ serviceType:globalServiceType,
+ parameters:{
+ locationConstraints:[],
+ resources:[],
+ requestInputs:siteInputs
+ }
+ }
+ }
+ });
+ console.log(sitebody);
+
+ let groupbody = this.siteGroupTableData.map((item)=>{
+ let siteGroupInputs = {};
+ this.siteGroupNames.forEach((name)=>{
+ for(let key in item){
+ let nameParts = this.namesTranslate.siteGroupNameTranslate[key].split("_");
+ if(name.startsWith(nameParts[0])&&name.endsWith(nameParts[1])){
+ siteGroupInputs[name] = item[key];
+ break;
+ }
+ }
+ })
+ return {
+ service:{
+ name:item.name,
+ description:item.topology,
+ serviceInvariantUuid:this.templateParameters["sdwan"].invariantUUID,
+ serviceUuid:this.templateParameters["sdwan"].uuid,
+ globalSubscriberId:globalCustomerId,
+ serviceType:globalServiceType,
+ parameters:{
+ locationConstraints:[],
+ resources:[],
+ requestInputs:siteGroupInputs
+ }
+ }
+ }
+ })
+ console.log(groupbody);
+
+ let createObj = {
+ vpnbody:vpnbody,
+ sitebody:sitebody,
+ groupbody:groupbody
+ }
+
+ this.closeCreate.emit(createObj);
+
+ }
+
+ goback(){
+ this.closeCreate.emit();
+ }
+}