需求是当用户修改某个敏感字段的时候,此时弹出弹框需要高等级用户输入账号密码来进行确认,于是将此弹框写成可复用的组件。首先请看:dual-approval.component.html
<div class=" modal-rs" style="margin-top: -24px;margin-left: -24px;margin-right: -24px;">
<div class="modal-content"style="background-color: #E3001A" >
<h4 mat-dialog-title style="color: #FFFFFF;font-weight:bolder;margin-top: 35px;text-align: center">DUAL APPROVAL REQUIRED</h4>
</div>
</div>
<p style="margin-top: 5px;color: #7f7f7f;text-align: center">In order to confirm this change,a second admin's approval is required</p>
<div style="margin-top: 130px">
<form class="login-form-column d-flex flex-column" [formGroup]="confirmForm" target="myframe" autocomplete="off">
<div class="login-credentials d-flex flex-column justify-content-center align-items-center" style="height: 50%;">
<!--username alert-->
<div class="login-alert-wrapper">
<div>
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('username') && this.confirmForm.get('username').hasError('required')">Second Approval's Username is required <a class="login-error-icon"></a></span>
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('username') && !this.confirmForm.get('username').hasError('required') && this.confirmForm.get('username').errors.minlength">Second Approval's Username must be at least 5 characters<a class="login-error-icon"></a></span>
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('username') && !this.confirmForm.get('username').errors.minlength && !this.confirmForm.get('username').hasError('required') && this.confirmForm.get('username').hasError('pattern')">Second Approval's Username cannot have invalid characters<a class="login-error-icon"></a></span>
</div>
</div>
<!-- username field -->
<div class="input-group login-form">
<span class="input-group-addon" >
<a class="login-icon-user" ></a></span>
<input type="text" class="form-control" placeholder="Second Approval's Username" required formControlName = "username" autocomplete="off" minlength="5" maxlength="64">
</div>
<!-- password alert -->
<div class="login-alert-wrapper">
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('password') && this.confirmForm.get('password').hasError('required')">Second Approval's Password is required <a class="login-error-icon"></a></span>
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('password') && !this.confirmForm.get('password').hasError('required') && this.confirmForm.get('password').errors.minlength">Second Approval's Password must be at least 5 characters <a class="login-error-icon"></a></span>
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('password') && !this.confirmForm.get('password').errors.minlength && !this.confirmForm.get('password').hasError('required') && this.confirmForm.get('password').hasError('pattern')">Second Approval's Password cannot have invalid characters<a class="login-error-icon"></a></span>
</div>
<!-- password field -->
<div class="input-group login-form">
<span class="input-group-addon">
<a class="login-icon-password"></a></span>
<input type="text" class="form-control text-security" placeholder="Second Approval's Password" id="password" required formControlName="password" minlength="5" maxlength="64">
</div>
<!-- reason alert -->
<div class="login-alert-wrapper">
<span class="login-error-alert" *ngIf="this.isFormInputInvalid('reason') && this.confirmForm.get('reason').hasError('required')">Reason is required <a class="login-error-icon"></a></span>
</div>
<div class="input-group login-form" style="margin-top: 20px">
<textarea id="reason" name="reason" rows="8" class="form-control" formControlName="reason" minlength="1" maxlength="399" placeholder="Please describe your reason for this change..." required></textarea>
</div>
</div>
</form>
<div mat-dialog-actions >
<input class="btn btn-red-rs6" type="submit" (click)="onConfirm()" [disabled]="!confirmForm.valid" value="Confirm" style="margin-left: 80px;margin-bottom: 30px">
<input class="btn btn-red-rs6" type="button" (click)="onClose()" value="Cancel" style="margin-left: 205px;margin-bottom: 30px;width: 77px">
</div>
<iframe name="myframe" hidden ></iframe>
</div>
接下来是dual-approval.component.ts文件
import {Component, Inject} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {DialogService} from '../../service/dialog.service';
import {Utility} from '../../utility/utility';
import {DualApprovalService} from '../../service/dual-approval.service';
import {DualApproval} from '../../model/dual-approval.model';
import {Audit} from '../../model/audit.model';
import {ObjectType} from '../../model/object-type.model';
import {OperationType} from '../../model/operation-type.model';
@Component({
selector: 'app-dual-approval',
templateUrl: './dual-approval.component.html'
})
export class DualApprovalComponent {
confirmForm: FormGroup;
model: DualApproval = {username: '', password: '', reason: ''};
targetUser = '';
constructor(private fb: FormBuilder,
public dialog: MatDialog, public dialogRef: MatDialogRef<DualApprovalComponent>,
public dualApprovalService: DualApprovalService, @Inject(MAT_DIALOG_DATA) public data: any) {
this.createForm();
}
private createForm() {
this.confirmForm = this.fb.group({
username: ['', [Validators.required,
Validators.pattern(/^((?![<>/\\~"{}\[\]*'|`:;,\s]).){5,64}$/g.source)]],
password: ['', [Validators.required,
Validators.pattern(/^((?![<>/\\~"{}\[\]*'|`:;,\s]).){5,64}$/g.source)]],
reason: []
});
}
updateModel() {
this.model.username = this.confirmForm.get('username').value;
this.model.password = this.confirmForm.get('password').value;
this.model.reason = this.confirmForm.get('reason').value;
}
/**
* Submit the form after you click on onConfirm button in html.
*/
onConfirm() {
this.updateModel();
this.targetUser = this.data['targetUserName'];
this.dualApprovalService.verifyHierarchy(this.targetUser, this.model.username,
this.model.password).toPromise().then((res) => {
this.dialogRef.close(res);
const result = Utility.isDualApprovalResponseSuccess(res);
if (result) {
this.sendAuditLog().toPromise().then();
}
});
}
/**
* Close the dual approval pop-up.
*/
onClose() {
this.dialogRef.close();
}
/**
* Verify the validity of input box contents.
* @param input The contents of input box.
* @returns Return value here is true if the input is valid and false otherwise.
*/
isFormInputInvalid(input: string): boolean {
return Utility.isFormInputInvalid(input, this.confirmForm);
}
/**
* Collect the audit info to send a post request to backend.
* @returns creating a audit logs of the operations.
*/
sendAuditLog() {
const audit = new Audit();
audit.objectId = this.data['objectId'];
if (this.data['objectType'].match('Organization')) {
audit.objectType = ObjectType.Organization;
audit.operation = OperationType.UpdateOrganization;
} else if (this.data['objectType'].match('User')) {
audit.objectType = ObjectType.User;
audit.operation = OperationType.UpdateUser;
} else {
audit.objectType = ObjectType.Unknown;
}
audit.field = this.data['fieldName'];
audit.oldValue = this.data['oldValue'];
audit.newValue = this.data['newValue'];
audit.details = this.model.reason;
return this.dualApprovalService.auditLog(audit); // 请求后端保存日志
}
}
Utility.ts:
import {Injectable} from '@angular/core';
import {FormGroup} from '@angular/forms';
@Injectable()
export class Utility {
constructor() {
}
static isFormInputInvalid(input: string, form: FormGroup): boolean {
return form.get(input).touched && form.get(input).status === 'INVALID';
}
/**
* Determine if the dual approval's verify hierarchy is successful.
* @param response response object of dual approval's verify hierarchy.
* @returns dual approval's verify hierarchy successfully return true,
* dual approval's verify hierarchy failed return false.
*/
static isDualApprovalResponseSuccess(response: any): boolean {
if (response['body']['rsErrorCode'] === undefined) {
return true;
} else {
return false;
}
}
}
dual-approval.component.spec.ts
import {async, TestBed} from '@angular/core/testing';
import {Observable} from 'rxjs/Observable';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {DualApprovalComponent} from './dual-approval.component';
import {DialogService} from '../../service/dialog.service';
import {DualApprovalService} from '../../service/dual-approval.service';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {HttpResponse} from '@angular/common/http';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
describe('DualApprovalComponent', () => {
beforeEach(async(() => {
class DialogServiceStub {
openDialog(title, msg) {
return Observable.of('OK');
}
}
class DualApprovalServiceStub {
verifyHierarchy(targetUser: string, userName: string, password: string) {
const response = new HttpResponse({body: {message: 'Response Message'}});
return Observable.of(
response
);
}
}
class MatDialogStub {
}
class MatDialogRefStub {
}
TestBed.configureTestingModule({
imports: [FormsModule, ReactiveFormsModule],
declarations: [DualApprovalComponent],
providers: [
{provide: DialogService, useClass: DialogServiceStub},
{provide: DualApprovalService, useClass: DualApprovalServiceStub},
{provide: MatDialog, useClass: MatDialogStub},
{provide: MAT_DIALOG_DATA, useValue: {}},
{provide: MatDialogRef, useClass: MatDialogRefStub}
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
it('should create DualApprovalComponent', () => {
const fixture = TestBed.createComponent(DualApprovalComponent);
const comp = fixture.debugElement.componentInstance;
expect(comp).toBeTruthy();
});
it('should return the correct response from verifyHierarchy', () => {
const fixture = TestBed.createComponent(DualApprovalComponent);
const result = fixture.componentInstance.dualApprovalService.verifyHierarchy('', '', '');
result.subscribe((response: HttpResponse<{ message: string }>) => {
expect(response.body.message).toEqual('Response Message');
});
});
it('should verify username', () => {
const fixture = TestBed.createComponent(DualApprovalComponent);
const comp = fixture.debugElement.componentInstance;
fixture.detectChanges();
comp.confirmForm.get('username').setValue('');
expect(comp.confirmForm.get('username').invalid).toBe(true, 'Second Approval\'s Username is required');
comp.confirmForm.get('username').setValue('<>/');
expect(comp.confirmForm.get('username').invalid).toBe(true, 'Second Approval\'s Username cannot have invalid characters');
comp.confirmForm.get('username').setValue('user');
expect(comp.confirmForm.get('username').invalid).toBe(true, 'Second Approval\'s Username must be at least 5 characters');
});
it('should verify password', () => {
const fixture = TestBed.createComponent(DualApprovalComponent);
const comp = fixture.debugElement.componentInstance;
fixture.detectChanges();
comp.confirmForm.get('password').setValue('');
expect(comp.confirmForm.get('password').invalid).toBe(true, 'Second Approval\'s Username is required');
comp.confirmForm.get('password').setValue('<>/');
expect(comp.confirmForm.get('password').invalid).toBe(true, 'Second Approval\'s Username cannot have invalid characters');
comp.confirmForm.get('password').setValue('1111');
expect(comp.confirmForm.get('password').invalid).toBe(true, 'Second Approval\'s Username must be at least 5 characters');
});
it('should verify reason', () => {
const fixture = TestBed.createComponent(DualApprovalComponent);
const comp = fixture.debugElement.componentInstance;
fixture.detectChanges();
comp.confirmForm.get('reason').setValue('');
expect(comp.confirmForm.get('password').invalid).toBe(true, 'Reason is required');
});
});
希望对其他人也有所帮助!博主能力有限,若有不足之处还请批评指出,谢谢!