登录接口实现
This commit is contained in:
		| @ -14,4 +14,14 @@ module.exports = { | ||||
|   //   secure: false, // Ignore invalid SSL certificates | ||||
|   //   changeOrigin: true | ||||
|   // } | ||||
|   '//cuc': { | ||||
|     target: { | ||||
|       host: '172.30.9.44', | ||||
|       protocol: 'http:', | ||||
|       port: 8003 | ||||
|     }, | ||||
|     secure: false, | ||||
|     changeOrigin: true, | ||||
|     logLevel: 'debug' | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| @ -19,10 +19,11 @@ const GLOBAL_THIRD_MODULES: Array<Type<any>> = [BidiModule]; | ||||
| // #region Http Interceptors | ||||
| import { HTTP_INTERCEPTORS } from '@angular/common/http'; | ||||
|  | ||||
| import { DefaultInterceptor } from '@core'; | ||||
| import { BusinessInterceptor, DefaultInterceptor } from '@core'; | ||||
|  | ||||
| const INTERCEPTOR_PROVIDES = [ | ||||
|   { provide: HTTP_INTERCEPTORS, useClass: SimpleInterceptor, multi: true }, | ||||
|   { provide: HTTP_INTERCEPTORS, useClass: BusinessInterceptor, multi: true }, | ||||
|   { provide: HTTP_INTERCEPTORS, useClass: DefaultInterceptor, multi: true } | ||||
| ]; | ||||
| // #endregion | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| export * from './module-import-guard'; | ||||
| export * from './net/default.interceptor'; | ||||
| export * from './net/business.interceptor'; | ||||
|  | ||||
| // Services | ||||
| export * from './core.service'; | ||||
|  | ||||
							
								
								
									
										100
									
								
								src/app/core/net/business.interceptor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/app/core/net/business.interceptor.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | ||||
| import { | ||||
|   HttpErrorResponse, | ||||
|   HttpEvent, | ||||
|   HttpHandler, | ||||
|   HttpInterceptor, | ||||
|   HttpRequest, | ||||
|   HttpResponse, | ||||
|   HttpResponseBase, | ||||
| } from '@angular/common/http'; | ||||
| import { Inject, Injectable, Optional } from '@angular/core'; | ||||
| import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth'; | ||||
| import { environment } from '@env/environment'; | ||||
| import { EAEnvironmentService, EAUserService } from '@shared'; | ||||
| import { Observable, of } from 'rxjs'; | ||||
| import { catchError, mergeMap } from 'rxjs/operators'; | ||||
|  | ||||
| @Injectable() | ||||
| export class BusinessInterceptor implements HttpInterceptor { | ||||
|   constructor( | ||||
|     private envSrv: EAEnvironmentService, | ||||
|     private eaUserSrv: EAUserService, | ||||
|     @Optional() | ||||
|     @Inject(DA_SERVICE_TOKEN) | ||||
|     private tokenSrv: ITokenService, | ||||
|   ) {} | ||||
|   intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { | ||||
|     // 构造新的请求URL | ||||
|     req = this.constructNewRequestUrl(req); | ||||
|     // 附加额外的请求头 | ||||
|     req = this.attachAdditionalHeaders(req); | ||||
|     // 后续操作 | ||||
|     return next.handle(req).pipe( | ||||
|       mergeMap((ev) => this.handlingBussinessResponseData(ev)), | ||||
|       catchError((err: HttpErrorResponse) => this.handlingBusinessErrors(err)), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 构造新的请求URL | ||||
|    */ | ||||
|   private constructNewRequestUrl(req: HttpRequest<any>): HttpRequest<any> { | ||||
|     let url = req.url; | ||||
|     if (!url.startsWith('https://') && !url.startsWith('http://')) { | ||||
|       if (!url.startsWith('assets')) { | ||||
|         url = environment.api.baseUrl + url; | ||||
|       } | ||||
|     } | ||||
|     return req.clone({ url }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 附加额外的请求头 | ||||
|    */ | ||||
|   private attachAdditionalHeaders(req: HttpRequest<any>): HttpRequest<any> { | ||||
|     // 附加环境变量 | ||||
|     const header: any = { | ||||
|       appId: this.envSrv.env.appId, | ||||
|       tenantId: this.envSrv.env.tenantId, | ||||
|     }; | ||||
|  | ||||
|     // 附加授权声明 | ||||
|     const token = this.tokenSrv.get()?.token; | ||||
|     if (token) { | ||||
|       header.Authorization = `Bearer ${token}`; | ||||
|     } | ||||
|     return req.clone({ setHeaders: header }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 处理业务数据 | ||||
|    */ | ||||
|   private handlingBussinessResponseData(ev: HttpEvent<any>): Observable<any> { | ||||
|     if (ev instanceof HttpResponseBase) { | ||||
|       const body = (ev as HttpResponse<any>).body; | ||||
|       if (body) { | ||||
|         switch (body.status) { | ||||
|           case 505001: | ||||
|           case 505002: | ||||
|             this.eaUserSrv.logout(); | ||||
|             break; | ||||
|           default: | ||||
|             break; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (ev instanceof HttpErrorResponse) { | ||||
|       return this.handlingBusinessErrors(ev); | ||||
|     } | ||||
|     return of(ev); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 处理响应错误 | ||||
|    */ | ||||
|   private handlingBusinessErrors(err: HttpErrorResponse): Observable<any> { | ||||
|     /** Http响应异常已在默认拦截器处理完成 ,该处不再处理 */ | ||||
|  | ||||
|     return of(err); | ||||
|   } | ||||
| } | ||||
| @ -1,20 +1,8 @@ | ||||
| import { | ||||
|   HttpErrorResponse, | ||||
|   HttpEvent, | ||||
|   HttpHandler, | ||||
|   HttpHeaders, | ||||
|   HttpInterceptor, | ||||
|   HttpRequest, | ||||
|   HttpResponseBase | ||||
| } from '@angular/common/http'; | ||||
| import { Injectable, Injector } from '@angular/core'; | ||||
| import { Router } from '@angular/router'; | ||||
| import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth'; | ||||
| import { _HttpClient } from '@delon/theme'; | ||||
| import { environment } from '@env/environment'; | ||||
| import { NzNotificationService } from 'ng-zorro-antd/notification'; | ||||
| import { BehaviorSubject, Observable, of, throwError } from 'rxjs'; | ||||
| import { catchError, filter, mergeMap, switchMap, take } from 'rxjs/operators'; | ||||
| import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponseBase } from '@angular/common/http'; | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { Observable, of } from 'rxjs'; | ||||
| import { catchError, mergeMap } from 'rxjs/operators'; | ||||
| import { CoreService } from './../core.service'; | ||||
|  | ||||
| const CODEMESSAGE: { [key: number]: string } = { | ||||
|   200: '服务器成功返回请求的数据。', | ||||
| @ -34,228 +22,38 @@ const CODEMESSAGE: { [key: number]: string } = { | ||||
|   504: '网关超时。' | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * 默认HTTP拦截器,其注册细节见 `app.module.ts` | ||||
|  */ | ||||
| @Injectable() | ||||
| export class DefaultInterceptor implements HttpInterceptor { | ||||
|   private refreshTokenEnabled = environment.api.refreshTokenEnabled; | ||||
|   private refreshTokenType: 're-request' | 'auth-refresh' = environment.api.refreshTokenType; | ||||
|   private refreshToking = false; | ||||
|   private refreshToken$: BehaviorSubject<any> = new BehaviorSubject<any>(null); | ||||
|  | ||||
|   constructor(private injector: Injector) { | ||||
|     if (this.refreshTokenType === 'auth-refresh') { | ||||
|       this.buildAuthRefresh(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private get notification(): NzNotificationService { | ||||
|     return this.injector.get(NzNotificationService); | ||||
|   } | ||||
|  | ||||
|   private get tokenSrv(): ITokenService { | ||||
|     return this.injector.get(DA_SERVICE_TOKEN); | ||||
|   } | ||||
|  | ||||
|   private get http(): _HttpClient { | ||||
|     return this.injector.get(_HttpClient); | ||||
|   } | ||||
|  | ||||
|   private goTo(url: string): void { | ||||
|     setTimeout(() => this.injector.get(Router).navigateByUrl(url)); | ||||
|   } | ||||
|  | ||||
|   private checkStatus(ev: HttpResponseBase): void { | ||||
|     if ((ev.status >= 200 && ev.status < 300) || ev.status === 401) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const errortext = CODEMESSAGE[ev.status] || ev.statusText; | ||||
|     this.notification.error(`请求错误 ${ev.status}: ${ev.url}`, errortext); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 刷新 Token 请求 | ||||
|    */ | ||||
|   private refreshTokenRequest(): Observable<any> { | ||||
|     const model = this.tokenSrv.get(); | ||||
|     return this.http.post(`/api/auth/refresh`, null, null, { headers: { refresh_token: model?.refresh_token || '' } }); | ||||
|   } | ||||
|  | ||||
|   // #region 刷新Token方式一:使用 401 重新刷新 Token | ||||
|  | ||||
|   private tryRefreshToken(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> { | ||||
|     // 1、若请求为刷新Token请求,表示来自刷新Token可以直接跳转登录页 | ||||
|     if ([`/api/auth/refresh`].some(url => req.url.includes(url))) { | ||||
|       this.toLogin(); | ||||
|       return throwError(ev); | ||||
|     } | ||||
|     // 2、如果 `refreshToking` 为 `true` 表示已经在请求刷新 Token 中,后续所有请求转入等待状态,直至结果返回后再重新发起请求 | ||||
|     if (this.refreshToking) { | ||||
|       return this.refreshToken$.pipe( | ||||
|         filter(v => !!v), | ||||
|         take(1), | ||||
|         switchMap(() => next.handle(this.reAttachToken(req))) | ||||
|       ); | ||||
|     } | ||||
|     // 3、尝试调用刷新 Token | ||||
|     this.refreshToking = true; | ||||
|     this.refreshToken$.next(null); | ||||
|  | ||||
|     return this.refreshTokenRequest().pipe( | ||||
|       switchMap(res => { | ||||
|         // 通知后续请求继续执行 | ||||
|         this.refreshToking = false; | ||||
|         this.refreshToken$.next(res); | ||||
|         // 重新保存新 token | ||||
|         this.tokenSrv.set(res); | ||||
|         // 重新发起请求 | ||||
|         return next.handle(this.reAttachToken(req)); | ||||
|       }), | ||||
|       catchError(err => { | ||||
|         this.refreshToking = false; | ||||
|         this.toLogin(); | ||||
|         return throwError(err); | ||||
|       }) | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 重新附加新 Token 信息 | ||||
|    * | ||||
|    * > 由于已经发起的请求,不会再走一遍 `@delon/auth` 因此需要结合业务情况重新附加新的 Token | ||||
|    */ | ||||
|   private reAttachToken(req: HttpRequest<any>): HttpRequest<any> { | ||||
|     // 以下示例是以 NG-ALAIN 默认使用 `SimpleInterceptor` | ||||
|     const token = this.tokenSrv.get()?.token; | ||||
|     return req.clone({ | ||||
|       setHeaders: { | ||||
|         token: `Bearer ${token}` | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   // #endregion | ||||
|  | ||||
|   // #region 刷新Token方式二:使用 `@delon/auth` 的 `refresh` 接口 | ||||
|  | ||||
|   private buildAuthRefresh(): void { | ||||
|     if (!this.refreshTokenEnabled) { | ||||
|       return; | ||||
|     } | ||||
|     this.tokenSrv.refresh | ||||
|       .pipe( | ||||
|         filter(() => !this.refreshToking), | ||||
|         switchMap(res => { | ||||
|           console.log(res); | ||||
|           this.refreshToking = true; | ||||
|           return this.refreshTokenRequest(); | ||||
|         }) | ||||
|       ) | ||||
|       .subscribe( | ||||
|         res => { | ||||
|           // TODO: Mock expired value | ||||
|           res.expired = +new Date() + 1000 * 60 * 5; | ||||
|           this.refreshToking = false; | ||||
|           this.tokenSrv.set(res); | ||||
|         }, | ||||
|         () => this.toLogin() | ||||
|       ); | ||||
|   } | ||||
|  | ||||
|   // #endregion | ||||
|  | ||||
|   private toLogin(): void { | ||||
|     this.notification.error(`未登录或登录已过期,请重新登录。`, ``); | ||||
|     this.goTo(this.tokenSrv.login_url!); | ||||
|   } | ||||
|  | ||||
|   private handleData(ev: HttpResponseBase, req: HttpRequest<any>, next: HttpHandler): Observable<any> { | ||||
|     this.checkStatus(ev); | ||||
|     // 业务处理:一些通用操作 | ||||
|     switch (ev.status) { | ||||
|       case 200: | ||||
|         // 业务层级错误处理,以下是假定restful有一套统一输出格式(指不管成功与否都有相应的数据格式)情况下进行处理 | ||||
|         // 例如响应内容: | ||||
|         //  错误内容:{ status: 1, msg: '非法参数' } | ||||
|         //  正确内容:{ status: 0, response: {  } } | ||||
|         // 则以下代码片断可直接适用 | ||||
|         // if (ev instanceof HttpResponse) { | ||||
|         //   const body = ev.body; | ||||
|         //   if (body && body.status !== 0) { | ||||
|         //     this.injector.get(NzMessageService).error(body.msg); | ||||
|         //     // 注意:这里如果继续抛出错误会被行254的 catchError 二次拦截,导致外部实现的 Pipe、subscribe 操作被中断,例如:this.http.get('/').subscribe() 不会触发 | ||||
|         //     // 如果你希望外部实现,需要手动移除行254 | ||||
|         //     return throwError({}); | ||||
|         //   } else { | ||||
|         //     // 忽略 Blob 文件体 | ||||
|         //     if (ev.body instanceof Blob) { | ||||
|         //        return of(ev); | ||||
|         //     } | ||||
|         //     // 重新修改 `body` 内容为 `response` 内容,对于绝大多数场景已经无须再关心业务状态码 | ||||
|         //     return of(new HttpResponse(Object.assign(ev, { body: body.response }))); | ||||
|         //     // 或者依然保持完整的格式 | ||||
|         //     return of(ev); | ||||
|         //   } | ||||
|         // } | ||||
|         break; | ||||
|       case 401: | ||||
|         if (this.refreshTokenEnabled && this.refreshTokenType === 're-request') { | ||||
|           return this.tryRefreshToken(ev, req, next); | ||||
|         } | ||||
|         this.toLogin(); | ||||
|         break; | ||||
|       case 403: | ||||
|       case 404: | ||||
|       case 500: | ||||
|         this.goTo(`/exception/${ev.status}`); | ||||
|         break; | ||||
|       default: | ||||
|         if (ev instanceof HttpErrorResponse) { | ||||
|           console.warn( | ||||
|             '未可知错误,大部分是由于后端不支持跨域CORS或无效配置引起,请参考 https://ng-alain.com/docs/server 解决跨域问题', | ||||
|             ev | ||||
|           ); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     if (ev instanceof HttpErrorResponse) { | ||||
|       return throwError(ev); | ||||
|     } else { | ||||
|       return of(ev); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private getAdditionalHeaders(headers?: HttpHeaders): { [name: string]: string } { | ||||
|     const res: { [name: string]: string } = {}; | ||||
|     // const lang = this.injector.get(ALAIN_I18N_TOKEN).currentLang; | ||||
|     // if (!headers?.has('Accept-Language') && lang) { | ||||
|     //   res['Accept-Language'] = lang; | ||||
|     // } | ||||
|  | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   constructor(private coreSrv: CoreService) {} | ||||
|   intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { | ||||
|     // 统一加上服务端前缀 | ||||
|     let url = req.url; | ||||
|     if (!url.startsWith('https://') && !url.startsWith('http://')) { | ||||
|       const { baseUrl } = environment.api; | ||||
|       url = baseUrl + (baseUrl.endsWith('/') && url.startsWith('/') ? url.substring(1) : url); | ||||
|     } | ||||
|  | ||||
|     const newReq = req.clone({ url, setHeaders: this.getAdditionalHeaders(req.headers) }); | ||||
|     return next.handle(newReq).pipe( | ||||
|       mergeMap(ev => { | ||||
|         // 允许统一对请求错误处理 | ||||
|         if (ev instanceof HttpResponseBase) { | ||||
|           return this.handleData(ev, newReq, next); | ||||
|         } | ||||
|         // 若一切都正常,则后续操作 | ||||
|         return of(ev); | ||||
|       }), | ||||
|       catchError((err: HttpErrorResponse) => this.handleData(err, newReq, next)) | ||||
|     return next.handle(req).pipe( | ||||
|       mergeMap(ev => this.handlingHttpResponseData(ev)), | ||||
|       catchError((err: HttpErrorResponse) => this.handlingHttpErrorResponse(err)) | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 处理Http响应数据 | ||||
|    */ | ||||
|   private handlingHttpResponseData(ev: HttpEvent<any>): Observable<any> { | ||||
|     if (ev instanceof HttpResponseBase) { | ||||
|       // 正常情况直接返回到下个业务拦截器处理 | ||||
|       if (ev.status >= 200 && ev.status < 300) { | ||||
|         return of(ev); | ||||
|       } | ||||
|  | ||||
|       // 所有状态不是2xx和3xx都当作异常处理 | ||||
|       if (ev instanceof HttpErrorResponse) { | ||||
|         return this.handlingHttpErrorResponse(ev); | ||||
|       } | ||||
|     } | ||||
|     return of(ev); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 处理默认Http响应错误 | ||||
|    */ | ||||
|   private handlingHttpErrorResponse(err: HttpErrorResponse): Observable<any> { | ||||
|     return of(err); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -191,12 +191,14 @@ export class UserLoginComponent implements OnInit, OnDestroy { | ||||
|       // this.userSrv.loginByCaptcha(this.captchaSF.value.phone, this.captchaSF.value.smsCode, this.captchaSF.value.sc); | ||||
|     } else { | ||||
|       this.accountSF.validator({ emitError: true }); | ||||
|       console.log(this.accountSF.value); | ||||
|        | ||||
|       if (!this.accountSF.valid) { | ||||
|         return; | ||||
|         // this.userSrv.loginByAccount(this.accountSF.value.username, this.accountSF.value.password, this.accountSF.value.sc); | ||||
|       } | ||||
|       this.userSrv.loginByAccount(this.accountSF.value.username, this.accountSF.value.password); | ||||
|     } | ||||
|     this.router.navigateByUrl('/'); | ||||
|     // this.router.navigateByUrl('/'); | ||||
|     /*  if (!this.accountSF.valid && !this.captchaSF.valid) { | ||||
|        return; | ||||
|      } | ||||
|  | ||||
| @ -1 +1,39 @@ | ||||
| <amap-path-simplifier></amap-path-simplifier> | ||||
| <page-header-wrapper [title]="'黑名单'" [content]="content"> | ||||
|     <ng-template #content> | ||||
|         <nz-tabset class="tabs-wrap"> | ||||
|             <nz-tab *ngFor="let tab of tabs" [nzTitle]="tab.name" (nzSelect)="changeTab(tab)"> </nz-tab> | ||||
|         </nz-tabset> | ||||
|     </ng-template> | ||||
| </page-header-wrapper> | ||||
|  | ||||
| <nz-card class="search-box"> | ||||
|     <div nz-row nzGutter="8"> | ||||
|         <div nz-col [nzXl]="18" [nzLg]="24" [nzSm]="24" [nzXs]="24"> | ||||
|             <sf #sf [schema]="searchSchema" | ||||
|                 [ui]="{ '*': { spanLabelFixed: 90,grid: { lg: 8, md: 12, sm: 12, xs: 24 } }}" [compact]="true" | ||||
|                 [button]="'none'"></sf> | ||||
|         </div> | ||||
|         <div nz-col [nzXl]="6" [nzLg]="24" [nzMd]="24" [nzSm]="24" [nzXs]="24" class="text-right"> | ||||
|             <button nz-button nzType="primary" [nzLoading]="service.http.loading" (click)="st?.load(1)">查询</button> | ||||
|             <button nz-button (click)="resetSF()">重置</button> | ||||
|             <button nz-button> 导出</button> | ||||
|         </div> | ||||
|     </div> | ||||
| </nz-card> | ||||
|  | ||||
| <nz-card> | ||||
|     <div class="d-flex align-items-center mb-md"> | ||||
|         <button nz-button>添加</button> | ||||
|         <button nz-button>删除</button> | ||||
|         <div class="ml-md"> | ||||
|             已选择 | ||||
|             <strong class="text-primary">{{ selectedRows.length }}</strong> 条删除 | ||||
|             <a *ngIf="selectedRows.length > 0" (click)="st.clearCheck()" class="ml-lg">清空</a> | ||||
|         </div> | ||||
|     </div> | ||||
|     <st #st [data]="url" [columns]="columns" | ||||
|         [req]="{ method: 'POST', allInBody: true, reName: { pi: 'pageIndex', ps: 'pageSize' }, params: reqParams }" | ||||
|         [res]="{ reName: { list: 'data.records', total: 'data.total' } }" | ||||
|         [page]="{ show: true, showSize: true, pageSizes: [10, 20, 30, 50, 100, 200, 300, 500, 1000] }" | ||||
|         [loading]="service.http.loading" [scroll]="{ y: '370px' }" (change)="stChange($event)"></st> | ||||
| </nz-card> | ||||
| @ -0,0 +1,21 @@ | ||||
| :host::ng-deep { | ||||
|     .search-box { | ||||
|         .ant-card-body { | ||||
|             padding-bottom: 18px; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .content-box { | ||||
|         .ant-card-body { | ||||
|             padding-top: 14px; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .tabs-wrap>.ant-tabs-nav { | ||||
|         margin-bottom: 0; | ||||
|     } | ||||
|  | ||||
|     h1 { | ||||
|         margin: 0; | ||||
|     } | ||||
| } | ||||
| @ -1,4 +1,8 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { Component, OnInit, ViewChild } from '@angular/core'; | ||||
| import { STComponent, STColumn, STChange } from '@delon/abc/st'; | ||||
| import { SFComponent, SFSchema } from '@delon/form'; | ||||
| import { NzModalService } from 'ng-zorro-antd/modal'; | ||||
| import { SystemService } from 'src/app/routes/sys-setting/services/system.service'; | ||||
|  | ||||
| @Component({ | ||||
|   selector: 'app-etc-blacklist', | ||||
| @ -6,10 +10,178 @@ import { Component, OnInit } from '@angular/core'; | ||||
|   styleUrls: ['./etc-blacklist.component.less'] | ||||
| }) | ||||
| export class ETCBlacklistComponent implements OnInit { | ||||
|   @ViewChild('st', { static: true }) | ||||
|   st!: STComponent; | ||||
|   @ViewChild('sf', { static: false }) | ||||
|   sf!: SFComponent; | ||||
|   tabs = [ | ||||
|     { | ||||
|       name: '货主', | ||||
|       type: 1, | ||||
|       isActived: false | ||||
|     }, | ||||
|     { | ||||
|       name: '车辆', | ||||
|       type: 2, | ||||
|       isActived: false | ||||
|     } | ||||
|   ]; | ||||
|   tabType = 1; | ||||
|   url = `/rule?_allow_anonymous=true`; | ||||
|  | ||||
|   constructor() { } | ||||
|   searchSchema: SFSchema = { | ||||
|     properties: { | ||||
|       tabType: { | ||||
|         type: 'number', | ||||
|         ui: { | ||||
|           hidden: true | ||||
|         } | ||||
|       }, | ||||
|       params1: { | ||||
|         title: '企业名称', | ||||
|         type: 'string', | ||||
|         ui: { | ||||
|           placeholder: '请输入', | ||||
|           visibleIf: { | ||||
|             tabType: (value: number) => this.tabType === 1 | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       params2: { | ||||
|         title: '联系人姓名', | ||||
|         type: 'string', | ||||
|         ui: { | ||||
|           placeholder: '姓名/手机/车牌号', | ||||
|           visibleIf: { | ||||
|             tabType: (value: number) => this.tabType === 1 | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       params3: { | ||||
|         title: '手机号', | ||||
|         type: 'string', | ||||
|         ui: { | ||||
|           placeholder: '请输入', | ||||
|           visibleIf: { | ||||
|             tabType: (value: number) => this.tabType === 1 | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       params4: { | ||||
|         title: '车牌号', | ||||
|         type: 'string', | ||||
|         ui: { | ||||
|           placeholder: '请输入', | ||||
|           visibleIf: { | ||||
|             tabType: (value: number) => this.tabType === 2 | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       params5: { | ||||
|         title: '司机姓名', | ||||
|         type: 'string', | ||||
|         ui: { | ||||
|           placeholder: '请输入', | ||||
|           visibleIf: { | ||||
|             tabType: (value: number) => this.tabType === 2 | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       params6: { | ||||
|         title: '手机号', | ||||
|         type: 'string', | ||||
|         ui: { | ||||
|           placeholder: '请输入', | ||||
|           visibleIf: { | ||||
|             tabType: (value: number) => this.tabType === 2 | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|   columns: STColumn[] = [ | ||||
|     { title: '', index: 'key', type: 'checkbox' }, | ||||
|     { title: '企业名称', index: 'no', iif: () => this.tabType === 1 }, | ||||
|     { title: '联系人姓名', index: 'no', iif: () => this.tabType === 1 }, | ||||
|     { title: '车牌号', index: 'no', iif: () => this.tabType === 2 }, | ||||
|     { title: '司机姓名', index: 'no', iif: () => this.tabType === 2 }, | ||||
|     { title: '手机号', index: 'no' }, | ||||
|     { | ||||
|       title: '认证状态', | ||||
|       className: 'text-center', | ||||
|       index: 'status', | ||||
|       type: 'badge', | ||||
|       badge: { | ||||
|         0: { text: '启用', color: 'success' }, | ||||
|         2: { text: '禁用', color: 'error' }, | ||||
|         3: { text: '禁用', color: 'error' }, | ||||
|         1: { text: '禁用', color: 'error' } | ||||
|       } | ||||
|     }, | ||||
|     { title: '创建者', index: 'no' }, | ||||
|     { | ||||
|       title: '创建时间', | ||||
|       index: 'updatedAt', | ||||
|       type: 'date' | ||||
|     }, | ||||
|     { | ||||
|       title: '操作', | ||||
|       buttons: [ | ||||
|         { | ||||
|           text: '删除', | ||||
|           click: item => this.deleteAction(item) | ||||
|         } | ||||
|       ] | ||||
|     } | ||||
|   ]; | ||||
|  | ||||
|   selectedRows: any[] = []; | ||||
|  | ||||
|   reqParams = { pageIndex: 1, pageSize: 10 }; | ||||
|  | ||||
|   constructor(public service: SystemService, private nzModalService: NzModalService) {} | ||||
|  | ||||
|   ngOnInit(): void {} | ||||
|  | ||||
|   // 切换Tab | ||||
|   changeTab(item: any) { | ||||
|     this.tabType = item.type; | ||||
|     this.sf?.setValue('/tabType', item.type); | ||||
|     this.sf?.reset(); | ||||
|     setTimeout(() => { | ||||
|       this.tabs.forEach(i => (i.isActived = false)); | ||||
|       item.isActived = !item.isActived; | ||||
|       this.st.load(1); | ||||
|       this.st.resetColumns(); | ||||
|     }, 500); | ||||
|   } | ||||
|  | ||||
|   stChange(e: STChange): void { | ||||
|     switch (e.type) { | ||||
|       case 'checkbox': | ||||
|         this.selectedRows = e.checkbox!; | ||||
|         break; | ||||
|       case 'filter': | ||||
|         this.st.load(); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   configAction(item?: any) {} | ||||
|  | ||||
|   deleteAction(item?: any) { | ||||
|     this.nzModalService.error({ | ||||
|       nzTitle: '确认删除?', | ||||
|       nzClosable: false, | ||||
|       nzCancelText: '取消', | ||||
|       nzOnOk: () => {} | ||||
|     }); | ||||
|   } | ||||
|   /** | ||||
|    * 重置表单 | ||||
|    */ | ||||
|   resetSF() { | ||||
|     this.sf.reset(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -20,6 +20,7 @@ export * from './components/amap/index'; | ||||
|  | ||||
| // Utils | ||||
| export * from './utils'; | ||||
| export * from './services'; | ||||
|  | ||||
| // Module | ||||
| export * from './shared.module'; | ||||
|  | ||||
							
								
								
									
										27
									
								
								src/app/shared/services/business/environment.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/app/shared/services/business/environment.service.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| import { Injectable, Injector } from '@angular/core'; | ||||
| import { cacheConf } from '@conf/cache.conf'; | ||||
| import { sysConf } from '@conf/sys.conf'; | ||||
| import { BaseService } from '../core/base.service'; | ||||
| import { EACacheService } from './../core/cache.service'; | ||||
|  | ||||
| @Injectable({ | ||||
|   providedIn: 'root', | ||||
| }) | ||||
| export class EAEnvironmentService extends BaseService { | ||||
|   constructor(public injector: Injector, private eaCacheSrv: EACacheService) { | ||||
|     super(injector); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 环境信息 | ||||
|    */ | ||||
|   public get env(): { appId: string; tenantId: string } { | ||||
|     const cacheEnv: any = this.eaCacheSrv.get(cacheConf.env); | ||||
|     // 附加环境变量 | ||||
|     const env: { appId: string; tenantId: string } = { | ||||
|       appId: cacheEnv?.appId || sysConf.appId, | ||||
|       tenantId: cacheEnv?.tenantId || sysConf.tenantId, | ||||
|     }; | ||||
|     return env; | ||||
|   } | ||||
| } | ||||
| @ -25,7 +25,7 @@ export class EAUserService extends BaseService { | ||||
|   /** | ||||
|    * 账号密码登录 | ||||
|    */ | ||||
|   $api_login_by_account = `/scce/cuc/cuc/user/login?_allow_anonymous=true`; | ||||
|   $api_login_by_account = `/cuc/user/login?_allow_anonymous=true`; | ||||
|   /** | ||||
|    * 手机号登录 | ||||
|    */ | ||||
| @ -112,7 +112,7 @@ export class EAUserService extends BaseService { | ||||
|    * @param account 账号 | ||||
|    * @param password 密码 | ||||
|    */ | ||||
|   loginByAccount(account: string, password: string, sc: string) { | ||||
|   loginByAccount(account: string, password: string, sc?: string) { | ||||
|     this.request(this.$api_login_by_account, { username: account, password, sc }, 'POST', true, 'FORM').subscribe((res: any) => { | ||||
|       if (res?.token) { | ||||
|         this.tokenSrv.set({ token: res.token }); | ||||
|  | ||||
| @ -10,3 +10,5 @@ export * from './business/enterprise.service'; | ||||
| export * from './business/captcha.service'; | ||||
| export * from './business/user.service'; | ||||
| export * from './business/sl-platform.service'; | ||||
| export * from './business/user.service'; | ||||
| export * from './business/environment.service'; | ||||
|  | ||||
| @ -7,7 +7,11 @@ export const sysConf = { | ||||
|   /** | ||||
|    * 应用ID | ||||
|    */ | ||||
|   appId: ``, | ||||
|   appId: `5800BF51DC9A494489700F09E3B81520`, | ||||
|   /** | ||||
|    * 租户ID | ||||
|    */ | ||||
|   tenantId: `1`, | ||||
|   /** | ||||
|    * 登录路径 | ||||
|    */ | ||||
| @ -29,6 +33,6 @@ export const sysConf = { | ||||
|     '/tabs/industry/index', | ||||
|     '/tabs/partner/index', | ||||
|     '/tabs/community/index', | ||||
|     '/tabs/my/index', | ||||
|   ], | ||||
|     '/tabs/my/index' | ||||
|   ] | ||||
| }; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user