Ver código fonte

1、应用列表新增分类
2、密码修改新增强度说明
3、忘记密码页新增强度说明
4、登录失败无提示的功能修复

shibanglin 2 anos atrás
pai
commit
bf413e4014

+ 34 - 18
maxkey-web-frontend/maxkey-web-app/src/app/routes/config/password/password.component.html

@@ -1,14 +1,15 @@
 <nz-card>
-  <form nz-form [formGroup]="formGroup" (ngSubmit)="onSubmit()" se-container="1">
+  <form nz-form [formGroup]="validateForm" (ngSubmit)="onSubmit()">
     <div nz-row style="width: 100%">
-      <div nz-col nzMd="6"></div>
-      <div nz-col nzMd="12">
+      <div nz-col nzMd="16">
         <nz-form-item style="display: none">
           <nz-form-label [nzMd]="6" nzFor="id">id</nz-form-label>
           <nz-form-control [nzMd]="18" nzErrorTip="The input is not valid id!">
             <input [(ngModel)]="form.model.id" [ngModelOptions]="{ standalone: true }" nz-input name="id" id="id" value="id" />
           </nz-form-control>
         </nz-form-item>
+
+
         <nz-form-item>
           <nz-form-label [nzSm]="6" [nzXs]="24" nzFor="displayName">{{ 'mxk.password.displayName' | i18n }}</nz-form-label>
           <nz-form-control [nzSm]="14" [nzXs]="36" [nzXl]="48" nzErrorTip="The input is not displayName!">
@@ -38,14 +39,14 @@
         </nz-form-item>
         <nz-form-item>
           <nz-form-label nzRequired [nzSm]="6" [nzXs]="24" nzFor="oldPassword">{{ 'mxk.password.oldPassword' | i18n }}</nz-form-label>
-          <nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid oldPassword!">
+          <nz-form-control [nzSm]="14" [nzXs]="24" [nzErrorTip]="'validation.oldPassword.input' | i18n">
             <nz-input-group [nzSuffix]="suffixOldPasswordTemplate" style="width: 100%">
               <input
                 [type]="oldPasswordVisible ? 'text' : 'password'"
                 nz-input
-                placeholder="old password"
+                formControlName="oldPassword"
+                placeholder="{{ 'validation.oldPassword.input' | i18n }}"
                 [(ngModel)]="form.model.oldPassword"
-                [ngModelOptions]="{ standalone: true }"
                 name="oldPassword"
                 id="oldPassword"
               />
@@ -57,36 +58,43 @@
         </nz-form-item>
         <nz-form-item>
           <nz-form-label nzRequired [nzSm]="6" [nzXs]="24" nzFor="password">{{ 'mxk.password.password' | i18n }}</nz-form-label>
-          <nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid password!">
+          <nz-form-control [nzSm]="14" [nzXs]="24" [nzErrorTip]="'validation.password.input' | i18n">
             <nz-input-group [nzSuffix]="suffixPasswordTemplate" style="width: 100%">
               <input
                 [type]="passwordVisible ? 'text' : 'password'"
                 nz-input
-                placeholder="new password"
+                formControlName="password"
+                placeholder="{{ 'validation.password.input' | i18n }}"
+                (input)="dynamicallyCheckPassword(form.model.password)"
                 [(ngModel)]="form.model.password"
-                [ngModelOptions]="{ standalone: true }"
-                name="password"
-                id="password"
+
               />
             </nz-input-group>
             <ng-template #suffixPasswordTemplate>
               <i nz-icon [nzType]="passwordVisible ? 'eye-invisible' : 'eye'" (click)="passwordVisible = !passwordVisible"></i>
             </ng-template>
+            <nz-alert
+              *ngIf="dynamicallyCheckPasswordErrorMsg !=''"
+              nzType="warning"
+              nzMessage="{{dynamicallyCheckPasswordErrorMsg}}"
+              nzShowIcon
+            ></nz-alert>
           </nz-form-control>
         </nz-form-item>
         <nz-form-item>
           <nz-form-label nzRequired [nzSm]="6" [nzXs]="24" nzFor="confirmPassword">{{
             'mxk.password.confirmPassword' | i18n
-          }}</nz-form-label>
-          <nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="The input is not valid confirmPassword!">
+            }}</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24" [nzErrorTip]="'validation.confirmPassword.input' | i18n">
             <input
               nz-input
-              placeholder="confirm password"
+              type="password"
+              formControlName="confirmPassword"
+              placeholder="{{ 'validation.confirmPassword.input' | i18n }}"
               [(ngModel)]="form.model.confirmPassword"
-              [ngModelOptions]="{ standalone: true }"
-              name="confirmPassword"
-              id="confirmPassword"
+              (input)="dynamicallyCheckConfirm(form.model.confirmPassword)"
             />
+
           </nz-form-control>
         </nz-form-item>
         <nz-form-item style="width: 100%">
@@ -95,7 +103,15 @@
           </nz-form-control>
         </nz-form-item>
       </div>
+
+      <div nz-col nzMd="8">
+        <h2><span nz-icon nzType="lock" nzTheme="outline"></span>{{'validation.password.conformance-strength'| i18n}}</h2>
+        <ul style="padding: 0 20px;">
+          <li *ngFor="let item of policyMessage">{{item}}</li>
+        </ul>
+      </div>
     </div>
-    <div nz-col nzMd="6"></div>
+
   </form>
 </nz-card>
+

+ 152 - 26
maxkey-web-frontend/maxkey-web-app/src/app/routes/config/password/password.component.ts

@@ -19,10 +19,11 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { I18NService } from '@core';
 import { SettingsService, User, ALAIN_I18N_TOKEN } from '@delon/theme';
 import { NzMessageService } from 'ng-zorro-antd/message';
-
+import { Router, ActivatedRoute } from '@angular/router';
 import { ChangePassword } from '../../../entity/ChangePassword';
 import { PasswordService } from '../../../service/password.service';
 
+
 @Component({
   selector: 'app-password',
   templateUrl: './password.component.html',
@@ -36,27 +37,28 @@ export class PasswordComponent implements OnInit {
     submitting: false,
     model: new ChangePassword()
   };
-
-  formGroup: FormGroup = new FormGroup({});
-
+  validateForm!: FormGroup;
   oldPasswordVisible = false;
-
+  policy:any = {};
   passwordVisible = false;
-
+  policyMessage:any[] =[];
+  dynamicallyCheckPasswordErrorMsg = "";
   constructor(
+    private router: Router,
     private fb: FormBuilder,
     private settingsService: SettingsService,
     private passwordService: PasswordService,
     private msg: NzMessageService,
     @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
     private cdr: ChangeDetectorRef
-  ) {}
+  ) { }
 
   ngOnInit(): void {
-    this.formGroup = this.fb.group({
+    this.loadPolicy();
+    this.validateForm = this.fb.group({
       oldPassword: [null, [Validators.required]],
       confirmPassword: [null, [Validators.required]],
-      password: [1, [Validators.min(6), Validators.max(20)]]
+      password: [null, [Validators.required]],
     });
 
     let user: any = this.settingsService.user;
@@ -64,27 +66,151 @@ export class PasswordComponent implements OnInit {
     this.form.model.displayName = user.displayName;
     this.form.model.username = user.username;
     this.form.model.id = user.userId;
-
     this.cdr.detectChanges();
   }
 
-  onSubmit(): void {
-    this.form.submitting = true;
-    this.form.model.trans();
-    //if (this.formGroup.valid) {
-    this.passwordService.changePassword(this.form.model).subscribe(res => {
-      if (res.code == 0) {
-        this.form.model.init(res.data);
-        this.msg.success(this.i18n.fanyi('mxk.alert.operate.success'));
-      } else {
-        this.msg.error(this.i18n.fanyi('mxk.alert.operate.error'));
+
+  loadPolicy():void {
+    this.policyMessage=[];
+    this.passwordService.passwordpolicy().subscribe(res => {
+      if(res.code == 0) {
+        let data = res.data;
+        this.policy = data;
+        this.policyMessage=res.data.policMessageList;
       }
     });
-    // } else {
-    //  this.formGroup.updateValueAndValidity({ onlySelf: true });
-    // this.msg.success(`提交失败`);
-    //}
-    this.form.submitting = false;
-    this.cdr.detectChanges();
   }
+
+  dynamicallyCheckConfirm(value:any):void {
+    if (value != this.form.model.password) {
+      this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.twice')
+    } else {
+      this.dynamicallyCheckPasswordErrorMsg = '';
+    }
+  }
+
+  dynamicallyCheckPassword(value:any):void {
+    if (value == '') {
+      this.dynamicallyCheckPasswordErrorMsg = '';
+      return;
+    }
+    let data = this.policy;
+    if (data.minLength != 0 && data.maxLength != 0) {
+      let inputLength = value.length;
+      if (inputLength < data.minLength || inputLength > data.maxLength) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码长度为"+data.minLength+"-"+data.maxLength+"位"
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+
+    if (data.lowerCase > 0) {
+      let strArr = Array.from(value)
+      let abc:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        let code = value.charCodeAt()
+        if (code >= 'a'.charCodeAt(0) && code <= 'z'.charCodeAt(0)) {
+          abc.push(value)
+        }
+      })
+      if(abc.length < data.lowerCase) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.lowerCase+"位【a-z】小写字母"
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+
+
+    if(data.upperCase > 0) {
+      let strArr = Array.from(value)
+      let ABC:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        let code = value.charCodeAt()
+        if (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0)) {
+          ABC.push(value)
+        }
+      })
+      if(ABC.length < data.upperCase) {
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.lowerCase+"位【A-Z】大写字母"
+        return;
+      }
+    }
+
+    if (data.digits > 0) {
+      let strArr = Array.from(value)
+      let number:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        var regPos = /^[0-9]+.?[0-9]*/; //判断是否是数字。
+        if(regPos.test(value) ){
+          number.push(value)
+        }
+      })
+      if(number.length < data.digits) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.digits+"位【0-9】阿拉伯数字";
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+
+
+    if(data.specialChar > 0) {
+      var AllNumIsSame = new Array("’","”","!","@","#","$","%","^","&","*",".");
+      let strArr = Array.from(value)
+      let number:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        if(AllNumIsSame.indexOf(value) != -1){//$.type 是jquery的函数,用来判断对象类型
+          number.push(value)
+        }
+      })
+      if(number.length < data.specialChar) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.specialChar+"位特殊字符";
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+    this.dynamicallyCheckPasswordErrorMsg = '';
+
+  }
+
+  onSubmit(): void {
+    if (this.validateForm.valid) {
+      if (this.dynamicallyCheckPasswordErrorMsg == '') {
+        this.form.submitting = true;
+        this.form.model.trans();
+        this.passwordService.changePassword(this.form.model).subscribe(res => {
+          if (res.code == 0) {
+            this.form.model.init(res.data);
+            this.msg.success(this.i18n.fanyi('mxk.alert.operate.success'));
+            this.form.model.password = '';
+            this.form.model.oldPassword = '';
+            this.form.model.confirmPassword = '';
+            //设置密码正常,路由不进行拦截
+            let user = this.settingsService.user;
+            user['passwordSetType'] = 0;
+            this.settingsService.setUser(user)
+            this.router.navigateByUrl('/');
+          } else {
+            if (res.message) {
+              this.msg.error(res.message);
+              return
+            }
+            this.msg.error(this.i18n.fanyi('mxk.alert.operate.error'));
+          }
+        });
+        this.form.submitting = false;
+        this.cdr.detectChanges();
+      }
+    } else {
+      Object.values(this.validateForm.controls).forEach(control => {
+        if (control.invalid) {
+          control.markAsDirty();
+          control.updateValueAndValidity({ onlySelf: true });
+        }
+      });
+    }
+  }
+
+
+
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 5 - 47
maxkey-web-frontend/maxkey-web-app/src/app/routes/dashboard/home/home.component.html


+ 11 - 0
maxkey-web-frontend/maxkey-web-app/src/app/routes/dashboard/home/home.component.less

@@ -0,0 +1,11 @@
+.el_content {
+  display: flex;
+}
+.el-img img{
+  width: 22px;
+}
+
+.el-title{
+  font-size: 18px;
+  margin-left: 5px;
+}

+ 135 - 1
maxkey-web-frontend/maxkey-web-app/src/app/routes/dashboard/home/home.component.ts

@@ -31,6 +31,8 @@ import { AuthnService } from '../../../service/authn.service';
 import { AccoutsComponent } from '../../config/accouts/accouts.component';
 
 import { Console } from 'console';
+import {ALAIN_I18N_TOKEN} from "@delon/theme";
+import {I18NService} from "@core";
 
 @Component({
   selector: 'app-home',
@@ -51,7 +53,9 @@ export class HomeComponent implements OnInit {
   loading: boolean = false;
   appList: any[] = [];
   baseUrl: String = '';
-
+  staticAppList: any[] = [];
+  appCategoryList: any[] = [];
+  appsCategory: String = '';
   constructor(
     private modal: NzModalService,
     private viewContainerRef: ViewContainerRef,
@@ -59,6 +63,7 @@ export class HomeComponent implements OnInit {
     private cdr: ChangeDetectorRef,
     private obSrv: OnboardingService,
     private platform: Platform,
+    @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
     @Inject(DOCUMENT) private doc: NzSafeAny
   ) {
     // TODO: Wait for the page to load
@@ -106,7 +111,136 @@ export class HomeComponent implements OnInit {
     this.appListService.appList().subscribe(res => {
       //console.log(res.data);
       this.appList = res.data;
+      this.staticAppList = this.appList;
       this.cdr.detectChanges();
     });
+    this.appCategoryList = [{
+        id:'none',
+        name:this.i18n.fanyi('mxk.apps.category.none')
+      },{
+        id:'1011',
+        name:this.i18n.fanyi('mxk.apps.category.1011')
+      },
+      {
+        id:'1012',
+        name:this.i18n.fanyi('mxk.apps.category.1012')
+      },
+      {
+        id:'1013',
+        name:this.i18n.fanyi('mxk.apps.category.1013')
+      },
+      {
+        id:'1014',
+        name:this.i18n.fanyi('mxk.apps.category.1014')
+      },
+      {
+        id:'1015',
+        name:this.i18n.fanyi('mxk.apps.category.1015')
+      },
+      {
+        id:'1016',
+        name:this.i18n.fanyi('mxk.apps.category.1016')
+      },
+      {
+        id:'1017',
+        name:this.i18n.fanyi('mxk.apps.category.1017')
+      },
+      {
+        id:'1111',
+        name:this.i18n.fanyi('mxk.apps.category.1111')
+      },
+      {
+        id:'1112',
+        name:this.i18n.fanyi('mxk.apps.category.1112')
+      },
+      {
+        id:'1113',
+        name:this.i18n.fanyi('mxk.apps.category.1113')
+      },
+      {
+        id:'1114',
+        name:this.i18n.fanyi('mxk.apps.category.1114')
+      },
+      {
+        id:'1211',
+        name:this.i18n.fanyi('mxk.apps.category.1211')
+      },
+      {
+        id:'1212',
+        name:this.i18n.fanyi('mxk.apps.category.1212')
+      },
+      {
+        id:'1213',
+        name:this.i18n.fanyi('mxk.apps.category.1213')
+      },
+      {
+        id:'1214',
+        name:this.i18n.fanyi('mxk.apps.category.1214')
+      },
+      {
+        id:'1215',
+        name:this.i18n.fanyi('mxk.apps.category.1215')
+      },
+      {
+        id:'1215',
+        name:this.i18n.fanyi('mxk.apps.category.1215')
+      },
+      {
+        id:'1311',
+        name:this.i18n.fanyi('mxk.apps.category.1311')
+      },
+      {
+        id:'1411',
+        name:this.i18n.fanyi('mxk.apps.category.1411')
+      },
+      {
+        id:'1511',
+        name:this.i18n.fanyi('mxk.apps.category.1511')
+      },
+      {
+        id:'1512',
+        name:this.i18n.fanyi('mxk.apps.category.1512')
+      },
+      {
+        id:'1611',
+        name:this.i18n.fanyi('mxk.apps.category.1611')
+      },
+      {
+        id:'1711',
+        name:this.i18n.fanyi('mxk.apps.category.1711')
+      },
+      {
+        id:'1712',
+        name:this.i18n.fanyi('mxk.apps.category.1712')
+      },
+      {
+        id:'1811',
+        name:this.i18n.fanyi('mxk.apps.category.1811')
+      },
+      {
+        id:'1812',
+        name:this.i18n.fanyi('mxk.apps.category.1812')
+      },{
+        id:'1911',
+        name:this.i18n.fanyi('mxk.apps.category.1911')
+      },
+      {
+        id:'1912',
+        name:this.i18n.fanyi('mxk.apps.category.1912')
+      }
+    ]
+  }
+  changeCategory (): void {
+    this.appList = [];
+    if (this.appsCategory === null || this.appsCategory === '') {
+      this.appList = this.staticAppList;
+    } else {
+      for(let i = 0;i<this.staticAppList.length;i++){
+        if(this.staticAppList[i].category === this.appsCategory) {
+          this.appList.push(this.staticAppList[i]);
+        }
+      }
+    }
+    this.cdr.detectChanges();
   }
 }

+ 21 - 4
maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/forgot/forgot.component.html

@@ -71,18 +71,27 @@
       <a class="login" routerLink="/passport/login">{{ 'mxk.forgot.login' | i18n }}</a>
     </nz-form-item>
   </nz-form-item>
+  <nz-form-item style="width: 400px;
+    position: absolute;
+    right: 50px;" *ngIf="step === 1">
+    <h2 style="width: 100%;"><span nz-icon nzType="lock" nzTheme="outline"></span>{{'validation.password.conformance-strength'| i18n}}</h2>
+    <ul style="padding: 0 20px;">
+      <li *ngFor="let item of policyMessage">{{item}}</li>
+    </ul>
+  </nz-form-item>
   <nz-form-item style="width: 100%" *ngIf="step === 1">
     <nz-form-item style="width: 100%">
       <nz-form-label nzRequired nzFor="password">{{ 'mxk.password.password' | i18n }}</nz-form-label>
     </nz-form-item>
     <nz-form-item style="width: 100%">
-      <nz-form-control nzErrorTip="The input is not valid password!">
+      <nz-form-control [nzErrorTip]="'validation.password.input' | i18n">
         <nz-input-group nzSize="large" [nzSuffix]="suffixPasswordTemplate" style="width: 100%">
           <input
             [type]="passwordVisible ? 'text' : 'password'"
             nz-input
-            placeholder="new password"
+            placeholder="{{ 'validation.password.input' | i18n }}"
             [(ngModel)]="form.model.password"
+            (input)="dynamicallyCheckPassword(form.model.password)"
             formControlName="password"
             id="password"
           />
@@ -90,6 +99,12 @@
         <ng-template #suffixPasswordTemplate>
           <i nz-icon [nzType]="passwordVisible ? 'eye-invisible' : 'eye'" (click)="passwordVisible = !passwordVisible"></i>
         </ng-template>
+        <nz-alert
+          *ngIf="dynamicallyCheckPasswordErrorMsg !=''"
+          nzType="warning"
+          nzMessage="{{dynamicallyCheckPasswordErrorMsg}}"
+          nzShowIcon
+        ></nz-alert>
       </nz-form-control>
     </nz-form-item>
 
@@ -97,13 +112,14 @@
       <nz-form-label nzRequired nzFor="confirmPassword">{{ 'mxk.password.confirmPassword' | i18n }}</nz-form-label>
     </nz-form-item>
     <nz-form-item style="width: 100%">
-      <nz-form-control nzErrorTip="The input is not valid confirmPassword!">
+      <nz-form-control [nzErrorTip]="'validation.confirmPassword.input' | i18n">
         <input
           nz-input
           type="password"
           nzSize="large"
-          placeholder="confirm password"
+          placeholder="{{ 'validation.confirmPassword.input' | i18n }}"
           [(ngModel)]="form.model.confirmPassword"
+          (input)="dynamicallyCheckConfirm(form.model.confirmPassword)"
           formControlName="confirmPassword"
           name="confirmPassword"
           id="confirmPassword"
@@ -117,4 +133,5 @@
       <a class="login" routerLink="/passport/login">{{ 'mxk.forgot.login' | i18n }}</a>
     </nz-form-item>
   </nz-form-item>
+
 </form>

+ 209 - 32
maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/forgot/forgot.component.ts

@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
+import { Component, OnInit, ChangeDetectorRef, Inject } from '@angular/core';
 import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { Router, ActivatedRoute } from '@angular/router';
+import { I18NService } from '@core';
+import { ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme';
 import { NzMessageService } from 'ng-zorro-antd/message';
 import { NzStepsModule } from 'ng-zorro-antd/steps';
 
 import { ChangePassword } from '../../../entity/ChangePassword';
 import { ForgotPasswordService } from '../../../service/forgot-password.service';
 import { ImageCaptchaService } from '../../../service/image-captcha.service';
+import {PasswordService} from "../../../service/password.service";
 
 @Component({
   selector: 'app-forgot',
@@ -49,12 +52,16 @@ export class ForgotComponent implements OnInit {
   interval$: any;
   userId = '';
   username = '';
-
+  policyMessage:any[] =[];
+  policy:any = {};
+  dynamicallyCheckPasswordErrorMsg:string = '';
   constructor(
     fb: FormBuilder,
+    private router: Router,
     private forgotPasswordService: ForgotPasswordService,
     private imageCaptchaService: ImageCaptchaService,
     private msg: NzMessageService,
+    @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
     private cdr: ChangeDetectorRef
   ) {
     this.formGroup = fb.group({
@@ -89,6 +96,14 @@ export class ForgotComponent implements OnInit {
 
   ngOnInit(): void {
     this.getImageCaptcha();
+    this.policyMessage=[];
+    this.forgotPasswordService.passwordpolicy().subscribe(res => {
+      if(res.code == 0) {
+        let data = res.data;
+        this.policy = data;
+        this.policyMessage=res.data.policMessageList;
+      }
+    });
   }
 
   getImageCaptcha(): void {
@@ -116,70 +131,138 @@ export class ForgotComponent implements OnInit {
       this.forgotPasswordService
         .produceOtp({ mobile: this.mobile.value, state: this.state, captcha: this.captcha.value })
         .subscribe(res => {
-          if (res.code !== 0) {
-            this.msg.success(`发送失败`);
+          if (res.code == 103) {
+            this.msg.error(this.i18n.fanyi('validation.forgot.captcha.error'));
             this.getImageCaptcha();
             this.cdr.detectChanges();
+            return;
+          }
+          if (res.code != 0) {
+            this.msg.error(this.i18n.fanyi('mxk.alert.operate.error'));
+            this.getImageCaptcha();
+            this.cdr.detectChanges();
+            return;
           }
           this.userId = res.data.userId;
           this.username = res.data.username;
-          //console.log(res.data);
+          this.count = 59;
+          this.interval$ = setInterval(() => {
+            this.count -= 1;
+            if (this.count <= 0) {
+              clearInterval(this.interval$);
+            }
+            this.cdr.detectChanges();
+          }, 1000);
         });
     } else if (this.forgotType == 'email') {
       this.forgotPasswordService
         .produceEmailOtp({ email: this.email.value, state: this.state, captcha: this.captcha.value })
         .subscribe(res => {
-          if (res.code !== 0) {
-            this.msg.success(`发送失败`);
+          if (res.code == 103) {
+            this.msg.error(this.i18n.fanyi('validation.forgot.captcha.error'));
+            this.getImageCaptcha();
+            this.cdr.detectChanges();
+            return;
+          }
+          if (res.code != 0) {
+            this.msg.error(this.i18n.fanyi('mxk.alert.operate.error'));
             this.getImageCaptcha();
             this.cdr.detectChanges();
+            return;
           }
           this.userId = res.data.userId;
           this.username = res.data.username;
+          this.count = 59;
+          this.interval$ = setInterval(() => {
+            this.count -= 1;
+            if (this.count <= 0) {
+              clearInterval(this.interval$);
+            }
+            this.cdr.detectChanges();
+          }, 1000);
           //console.log(res.data);
         });
     }
-    this.count = 59;
-    this.interval$ = setInterval(() => {
-      this.count -= 1;
-      if (this.count <= 0) {
-        clearInterval(this.interval$);
-      }
-      this.cdr.detectChanges();
-    }, 1000);
+
   }
 
   onNextReset(e: MouseEvent) {
+    if (this.forgotType == 'mobile' && this.mobile.invalid) {
+      this.mobile.markAsDirty({ onlySelf: true });
+      this.mobile.updateValueAndValidity({ onlySelf: true });
+      return;
+    }
+
+    if (this.forgotType == 'email' && this.email.invalid) {
+      this.email.markAsDirty({ onlySelf: true });
+      this.email.updateValueAndValidity({ onlySelf: true });
+      return;
+    }
+
+    if (this.captcha.invalid) {
+      this.captcha.markAsDirty({ onlySelf: true });
+      this.captcha.updateValueAndValidity({ onlySelf: true });
+      return;
+    }
+
     if (this.otpCaptcha.invalid) {
       this.otpCaptcha.markAsDirty({ onlySelf: true });
       this.otpCaptcha.updateValueAndValidity({ onlySelf: true });
       return;
     }
-    this.step = 1;
-  }
 
-  onSubmit(e: MouseEvent) {
-    this.forgotPasswordService
-      .setPassWord({
-        forgotType: this.forgotType,
-        userId: this.userId,
-        username: this.username,
-        password: this.password.value,
-        confirmPassword: this.confirmPassword.value,
-        otpCaptcha: this.otpCaptcha.value,
-        state: this.state
-      })
+    //this.step = 1;
+    //判断验证码
+    this.forgotPasswordService.validateCaptcha({ userId:this.userId, state: this.state, captcha: this.captcha.value, otpCaptcha: this.otpCaptcha.value })
       .subscribe(res => {
         if (res.code !== 0) {
-          this.msg.success(`密码修改失败`);
-          this.getImageCaptcha();
-          this.step = 0;
+          this.msg.error(this.i18n.fanyi('app.login.message-invalid-verification-code'));
           this.cdr.detectChanges();
+          return;
         }
-        this.msg.success(`密码修改成功`);
+        this.step = 1;
       });
   }
 
+  onSubmit(e: MouseEvent) {
+    if (this.password.invalid) {
+      this.password.markAsDirty({ onlySelf: true });
+      this.password.updateValueAndValidity({ onlySelf: true });
+      return;
+    }
+
+    if (this.confirmPassword.invalid) {
+      this.confirmPassword.markAsDirty({ onlySelf: true });
+      this.confirmPassword.updateValueAndValidity({ onlySelf: true });
+      return;
+    }
+    if (this.dynamicallyCheckPasswordErrorMsg == '') {
+      this.forgotPasswordService
+        .setPassWord({
+          forgotType: this.forgotType,
+          userId: this.userId,
+          username: this.username,
+          password: this.password.value,
+          confirmPassword: this.confirmPassword.value,
+          otpCaptcha: this.otpCaptcha.value,
+          state: this.state
+        })
+        .subscribe(res => {
+          if (res.code !== 0) {
+            this.msg.error(this.i18n.fanyi('mxk.alert.operate.error'));
+            this.getImageCaptcha();
+            this.step = 1;
+            this.cdr.detectChanges();
+            return;
+          }
+          this.msg.success(this.i18n.fanyi('mxk.alert.operate.success'));
+          setTimeout(() => {
+            this.router.navigateByUrl('/');
+          }, 3000);
+        });
+    }
+  }
+
   ngModelChange() {
     if (this.forgotType == 'email') {
       this.mobile.reset();
@@ -188,4 +271,98 @@ export class ForgotComponent implements OnInit {
       this.email.reset();
     }
   }
+
+  dynamicallyCheckConfirm(value:any):void {
+    if (value != this.form.model.password) {
+      this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.twice')
+    } else {
+      this.dynamicallyCheckPasswordErrorMsg = '';
+    }
+  }
+
+
+  dynamicallyCheckPassword(value:any):void {
+    if (value == '') {
+      this.dynamicallyCheckPasswordErrorMsg = '';
+      return;
+    }
+    let data = this.policy;
+    if (data.minLength != 0 && data.maxLength != 0) {
+      let inputLength = value.length;
+      if (inputLength < data.minLength || inputLength > data.maxLength) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码长度为"+data.minLength+"-"+data.maxLength+"位"
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+
+    if (data.lowerCase > 0) {
+      let strArr = Array.from(value)
+      let abc:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        let code = value.charCodeAt()
+        if (code >= 'a'.charCodeAt(0) && code <= 'z'.charCodeAt(0)) {
+          abc.push(value)
+        }
+      })
+      if(abc.length < data.lowerCase) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.lowerCase+"位【a-z】小写字母"
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+
+
+    if(data.upperCase > 0) {
+      let strArr = Array.from(value)
+      let ABC:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        let code = value.charCodeAt()
+        if (code >= 'A'.charCodeAt(0) && code <= 'Z'.charCodeAt(0)) {
+          ABC.push(value)
+        }
+      })
+      if(ABC.length < data.upperCase) {
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.lowerCase+"位【A-Z】大写字母"
+        return;
+      }
+    }
+
+    if (data.digits > 0) {
+      let strArr = Array.from(value)
+      let number:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        var regPos = /^[0-9]+.?[0-9]*/; //判断是否是数字。
+        if(regPos.test(value) ){
+          number.push(value)
+        }
+      })
+      if(number.length < data.digits) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.digits+"位【0-9】阿拉伯数字";
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+
+
+    if(data.specialChar > 0) {
+      var AllNumIsSame = new Array("’","”","!","@","#","$","%","^","&","*",".");
+      let strArr = Array.from(value)
+      let number:any = [];
+      strArr.forEach(function (value:any, index, array) {
+        if(AllNumIsSame.indexOf(value) != -1){//$.type 是jquery的函数,用来判断对象类型
+          number.push(value)
+        }
+      })
+      if(number.length < data.specialChar) {
+        //this.dynamicallyCheckPasswordErrorMsg = "限定新密码至少需要包含"+data.specialChar+"位特殊字符";
+        this.dynamicallyCheckPasswordErrorMsg = this.i18n.fanyi('validation.password.non-conformance-strength')
+        return;
+      }
+    }
+    this.dynamicallyCheckPasswordErrorMsg = '';
+
+  }
+
 }

+ 2 - 2
maxkey-web-frontend/maxkey-web-app/src/app/routes/passport/login/login.component.ts

@@ -263,8 +263,8 @@ export class UserLoginComponent implements OnInit, OnDestroy {
       .subscribe(res => {
         this.loading = true;
         if (res.code !== 0) {
-          this.error = res.msg;
-          //this.msg.success(`登录失败,请重新登录!`);
+          this.error = res.message;
+          //this.msg.error(this.error);
           if (this.loginType === 'normal') {
             this.getImageCaptcha();
           }

+ 8 - 0
maxkey-web-frontend/maxkey-web-app/src/app/service/forgot-password.service.ts

@@ -33,4 +33,12 @@ export class ForgotPasswordService {
   setPassWord(param: any) {
     return this.http.get('/forgotpassword/setpassword?_allow_anonymous=true', param);
   }
+
+  validateCaptcha(param: any) {
+    return this.http.get(`/forgotpassword/validateCaptcha?_allow_anonymous=true`, param);
+  }
+
+  passwordpolicy() {
+    return this.http.get('/forgotpassword/passwordpolicy?_allow_anonymous=true',null);
+  }
 }

+ 3 - 0
maxkey-web-frontend/maxkey-web-app/src/app/service/password.service.ts

@@ -34,4 +34,7 @@ export class PasswordService extends BaseService<ChangePassword> {
   public changePassword(body: NzSafeAny): Observable<Message<ChangePassword>> {
     return this.http.put<Message<ChangePassword>>('/config/changePassword', body);
   }
+  public passwordpolicy(): Observable<Message<ChangePassword>> {
+    return this.http.put<Message<ChangePassword>>('/config/passwordpolicy',null);
+  }
 }

+ 9 - 3
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/en-US.json

@@ -663,7 +663,7 @@
 				"success":"Operate Success!",
 				"error":"Operate Error!"
 			}
-			
+
 		},
 		"text": {
 			"action": "Action",
@@ -870,5 +870,11 @@
 	"validation.title.required": "Please enter a title",
 	"validation.date.required": "Please select the start and end date",
 	"validation.goal.required": "Please enter a description of the goal",
-	"validation.standard.required": "Please enter a metric"
-}
+	"validation.standard.required": "Please enter a metric",
+  "validation.password.conformance-strength": "Password Strength",
+  "validation.password.non-conformance-strength": "The password does not meet the strength!",
+  "validation.oldPassword.input": "Please enter old password!",
+  "validation.password.input": "Please enter new password!",
+  "validation.confirmPassword.input": "Please enter confirm password!",
+  "validation.forgot.captcha.error": "Picture Captcha Fail"
+}

+ 8 - 2
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/zh-CN.json

@@ -867,5 +867,11 @@
 	"validation.title.required": "请输入标题",
 	"validation.date.required": "请选择起止日期",
 	"validation.goal.required": "请输入目标描述",
-	"validation.standard.required": "请输入衡量标准"
-}
+	"validation.standard.required": "请输入衡量标准",
+  "validation.password.conformance-strength": "密码强度",
+  "validation.password.non-conformance-strength": "密码不符合强度!",
+  "validation.oldPassword.input": "请输入当前密码!",
+  "validation.password.input": "请输入新密码!",
+  "validation.confirmPassword.input": "请输入确认密码!",
+  "validation.forgot.captcha.error": "图形验证码错误"
+}

+ 8 - 2
maxkey-web-frontend/maxkey-web-app/src/assets/i18n/zh-TW.json

@@ -867,5 +867,11 @@
 	"validation.title.required": "請輸入標題",
 	"validation.date.required": "請選擇起止日期",
 	"validation.goal.required": "請輸入目標描述",
-	"validation.standard.required": "請輸入衡量標準"
-}
+	"validation.standard.required": "請輸入衡量標準",
+  "validation.password.conformance-strength": "密碼强度",
+  "validation.password.non-conformance-strength": "密碼不符合强度!",
+  "validation.oldPassword.input": "請輸入當前密碼!",
+  "validation.password.input": "請輸入新密碼!",
+  "validation.confirmPassword.input": "請輸入確認密碼!",
+  "validation.forgot.captcha.error": "圖形驗證碼錯誤"
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff