显示枚举字符串初始值设定项而不是枚举值

Display enum string initializer instead of the enum value

标题很容易理解。 get role(): string 没有 return 字符串初始值设定项。对于前。它 return 是“管理员”,而不是“主管管理员”。 Role["Administrator"] 会做这件事,但 IUser.role 实际上是 Role | undefined,这是问题所在,我不能简单地做

get role(): string {
  return Role[this.authService.userInfo?.role];
}

正因为如此。

header.component.ts

import { Component } from '@angular/core';

import { AuthService } from '@core/services';
import { LayoutComponent } from '../layout.component';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html'
})
export class HeaderComponent {
  get username(): string {
    return this.authService.userInfo?.username || '';
  }

  get role(): string {
    return this.authService.userInfo?.role || '';
  }

  constructor(private authService: AuthService, public app: LayoutComponent) {}

  signOut(event: any) {
    this.authService.signOut();

    event.preventDefault();
  }
}

user.model.ts

export interface IUser extends IEntity {
  email: string;
  username: string;
  role: Role;
}

export enum Role {
  Administrator = 'Head Administrator',
  DepartmentAdministrator = 'Department Administrator',
  User = 'Super User'
}

auth.service.ts

import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';

import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
import { delay, map, tap } from 'rxjs/operators';

import { environment } from '@env';
import { IAuthResponse, IUser } from '@core/models';
import { INITIAL_AUTH_STATE } from '@core/constants';

import { JwtService } from '../util';

@Injectable({
  providedIn: 'root'
})
export class AuthService implements OnDestroy {
  private readonly TOKEN_URL = `${environment.apiUrl}/Accounts/token`;

  private currentUserSubject = new BehaviorSubject<IAuthResponse>(INITIAL_AUTH_STATE);
  private timer!: Subscription;

  currentUser$: Observable<IAuthResponse> = this.currentUserSubject.asObservable();

  get userInfo(): IUser | null {
    const accessToken = this.currentUserValue?.accessToken;

    return accessToken ? this.jwtService.decodeToken<IUser>(accessToken) : null;
  }

  private get currentUserValue(): IAuthResponse | null {
    return this.currentUserSubject.value;
  }

  private get localStorageCurrentUser(): IAuthResponse {
    const localStorageUser = localStorage.getItem('currentUser');
    return localStorageUser ? JSON.parse(localStorageUser) : INITIAL_AUTH_STATE;
  }

  constructor(
    private httpClient: HttpClient,
    private router: Router,
    private jwtService: JwtService
  ) {
    this.currentUserSubject.next(this.localStorageCurrentUser);
    window.addEventListener('storage', this.storageEventListener.bind(this));
  }

  ngOnDestroy(): void {
    window.removeEventListener('storage', this.storageEventListener.bind(this));
  }

  signIn(username: string, password: string): Observable<IAuthResponse> {
    const TOKEN_URL: string = this.TOKEN_URL + '/create';

    return this.httpClient
      .post<IAuthResponse>(TOKEN_URL, {
        username,
        password
      })
      .pipe(
        map((res) => {
          if (res && res.accessToken) {
            this.setCurrentUser(res);
          }

          return res;
        })
      );
  }

  signOut(): void {
    this.clearCurrentUser();
    this.router.navigate(['auth']);
  }

  refreshToken(): Observable<IAuthResponse | null> {
    const refreshToken = this.currentUserValue?.refreshToken;
    if (!refreshToken) {
      this.clearCurrentUser();
      return of(null);
    }

    return this.httpClient.post<IAuthResponse>(`${this.TOKEN_URL}/refresh`, { refreshToken }).pipe(
      map((res) => {
        this.setCurrentUser(res);
        return res;
      })
    );
  }

  private setCurrentUser(user: IAuthResponse): void {
    this.currentUserSubject.next(user);
    this.setLocalStorage(user);
    this.startTokenTimer();
  }

  private clearCurrentUser(): void {
    this.currentUserSubject.next(INITIAL_AUTH_STATE);
    this.clearLocalStorage();
    this.stopTokenTimer();
  }

  private setLocalStorage(userState: IAuthResponse): void {
    localStorage.setItem('currentUser', JSON.stringify(userState));
    localStorage.setItem('login-event', 'login' + Math.random());
  }

  private clearLocalStorage(): void {
    localStorage.removeItem('currentUser');
    localStorage.setItem('logout-event', 'logout' + Math.random());
  }

  private getTokenRemainingTime(): number {
    const expiresAtUtc = this.currentUserValue?.expiresAtUtc;
    if (!expiresAtUtc) {
      return 0;
    }
    const expires = new Date(expiresAtUtc);
    return expires.getTime() - Date.now();
  }

  private startTokenTimer(): void {
    const timeout = this.getTokenRemainingTime();
    this.timer = of(true)
      .pipe(
        delay(timeout),
        tap(() => this.refreshToken().subscribe())
      )
      .subscribe();
  }

  private stopTokenTimer(): void {
    this.timer?.unsubscribe();
  }

  private storageEventListener(event: StorageEvent): void {
    if (event.storageArea === localStorage) {
      if (event.key === 'logout-event') {
        this.currentUserSubject.next(INITIAL_AUTH_STATE);
      }

      if (event.key === 'login-event') {
        location.reload();
      }
    }
  }
}

你写的代码是正确的。

我在一个孤立的操场上进行了实验并创建了 2 个函数:第一个是 return 字符串初始值设定项,第二个是 return 枚举值名称。

enum Role {
  Administrator = 'Head Administrator',
  DepartmentAdministrator = 'Department Administrator',
  User = 'Super User'
}

function getRoleName1(role: Role): string {
    return role
}

function getRoleName2(role: Role) {
    const roleEnum = Role as Record<string, string>
    for (const key of Object.keys(roleEnum)) {
        if (roleEnum[key] === role) {
            return key
        }
    }

    return undefined
}

console.log('1:', getRoleName1(Role.Administrator)) // Head Administrator
console.log('2:', getRoleName2(Role.Administrator)) // Administrator

第一个函数正在执行您需要的操作,我看到您在代码中以类似的方式编写了它。

我怀疑它没有按预期工作,因为枚举与您的后端实际 return 不匹配,即它可能 returning 'Administrator'而不是 'Head Administrator'.