iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 11
0
Modern Web

用Angular打造完整後台系列 第 11

day11 AppComponent(二) 登入初始流程

  • 分享至 

  • xImage
  •  

簡述

AppComponent 是系統內的 根組件
這篇會講述登入初始流程。

功能

開發過程中大概遇到幾種設定如下。

  • 多語系初始設定
  • icon 讀取圖片
  • 登入初始流程

登入初始流程

首先上個流程圖

flow

那大概會需要以下幾樣服務:

  • DialogModule
  • SpinnerModule
  • AppService
  • LoginService
  • UserService
  • StorageService

實作

(一) DialogModule

SharedMoudle裡常用的共用模塊之一,
用途就是會跳個小框框提示目前狀況。

樣式請參照day03 SharedModule(一)


(二) SpinnerModule

在進入主要畫面之前,先做一層讀取畫面。

spinner

檔案結構

-src
  |-app
    |-app.component.css
    |-app.component.html
    |-app.component.ts
    |-app.module.ts
    |-spinner
          |-spinner.component.css
          |-spinner.component.html
          |-spinner.component.ts
          |-spinner.service.ts

--

spinner.service.ts

import { Injectable } from "@angular/core";
import { Subject } from "rxjs/internal/Subject";

export interface SpinnerState {
  show: boolean;
}

@Injectable()
export class SpinnerService {
  private spinnerSubject = new Subject<SpinnerState>();
  spinnerState = this.spinnerSubject.asObservable();

  constructor() {}

  load() {
    this.spinnerSubject.next(<SpinnerState>{ show: true });
  }

  hide() {
    this.spinnerSubject.next(<SpinnerState>{ show: false });
  }
}

--

spinner.component.ts

@Component({
  selector: "app-spinner",
  templateUrl: "./spinner.component.html",
  styleUrls: ["./spinner.component.css"]
})
export class SpinnerComponent implements OnInit {
  visible = false;
  subscription: Subscription;

  constructor(
    private spinnerService: SpinnerService, 
    public dialog: MatDialog
  ) {
    this.subscription = this.spinnerService.spinnerState
    .subscribe((state: SpinnerState) => {
      this.visible = state.show;
    });
  }

  ngOnInit() {}

  ngOnDestroy() {
    if (!!this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}
  • SpinnerService定義了一條管道 Subject
    跟它同名的SpinnerComponent負責接收資料,
    並且根據接受的值來判斷要顯示的 Spinner 畫面。

  • 其他組件若要推送資料,則如下:

this.spinnerService.load();
this.spinnerService.hide();

Spinner 用法皆是參照 Angular 官網,

--

spinner.component.html

<div class="spinner flex" *ngIf="visible">
  <div class="load"><div class="loader"></div></div>
</div>

樣式請參照下方#範例網。

--

app.service.ts

其實就是寫個登出 funcion,來做需要關掉的多項相關服務。

@Injectable()
export class AppService {
  constructor(
    private loginService: LoginService, 
    private userService: UserService
  ) {}

  backLogin() {
    this.userService.delUser();
    this.loginService.logout();
    //  window.location.href = LoginUrl;
  }
}

(三) 其他 Service

  • LoginService:
    上一章節有提及,通常接收者為路由守衛,
    如果有登入才能看到 Menu 跟首頁。

  • UserService:
    上一章節有提及,紀錄登入者身份。


(四) StorageService

主要用途是會紀錄此登入者的一些喜好,例如使用的語言。

或是紀錄目前正在看的頁面,
通常 SPA 框架是重新整理後資料就會不見,
都要重新來過。

所以可以把正在看的頁面路徑做紀錄,後面會有詳細的介紹。

storage.service.ts

import { Injectable } from "@angular/core";
import { Md5 } from "ts-md5/dist/md5";
import { LangKey, UserKey } from "../config/config";

@Injectable({
  providedIn: "root"
})
export class StorageService {
  defaultLangVal = "tw";
  key = "";

  constructor() {}

  setKey(account: string) {
    this.key = JSON.stringify(Md5.hashStr(account + UserKey));
    this.getStorage();
  }

  setLangStorage(lang: string) {
    sessionStorage.setItem(LangKey, lang);
  }

  getLangStorage() {
    if (!sessionStorage.getItem(LangKey)) {
      this.setLangStorage(this.defaultLangVal);
    }
    return sessionStorage.getItem(LangKey);
  }

  delStorage() {
    sessionStorage.clear();
  }
}

通常儲存 storage,會多一層加密當索引避免資安問題,
Demo 加密方式請參照
https://github.com/cotag/ts-md5

預設語系基本上會寫在這裡,當判斷 storage 已有存語系,
將會代替成目前使用語系,沒有的話將採用預設值。


總結登入流程

最後AppComponent將會照流程圖上,把各式流程串起來:

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  constructor(
    private router: Router,
    private service: AppService,
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer,
    private spinnerService: SpinnerService,
    private dataService: DataService,
    private translate: TranslateService,
    private storageService: StorageService,
    private loginService: LoginService,
    private dialog: MatDialog,
    private userService: UserService
  ) {
    ICONS.forEach(val => {
      this.matIconRegistry.addSvgIcon(
        val.tab,
        this.domSanitizer.bypassSecurityTrustResourceUrl(val.path)
      );
    });
    let arr = LANG.map(item => {
      return item.short;
    });
    translate.addLangs(arr);
    let lang = this.storageService.getLangStorage();
    translate.setDefaultLang(lang);
    translate.use(lang);
  }

  ngOnInit() {
    if (!this.userService.getUser().token) {
      this.router.events
        .pipe(
          filter(event => event instanceof RoutesRecognized),
          take(1)
        )
        .subscribe((e: any) => {
          if (!!e.state.root.queryParams["token"]) {
            this.setToken(e.state.root.queryParams["token"]);
          } else {
            this.dialogOpen(1); //reconnect
          }
        });
    }
  }

  setToken(token: string) {
    if (!!token) {
      this.userService.setToken(token);
      this.spinnerService.load();
      this.dataService.connect(token).subscribe((data: IData) => {
        this.spinnerService.hide();
        if (!!data.errorcode) {
          this.dialogOpen(data.errorcode);
        } else {
          let user = data.res[0];
          this.setLogin(user.account);
          this.userService.setOne(user);
        }
      });
    }
  }

  dialogOpen(errorcode) {
    let dialogRef = this.dialog.open(DialogAlertComponent, {
      width: "550px",
      data: {
        errorcode: errorcode
      }
    });
    dialogRef.afterClosed().subscribe(() => {
      this.service.backLogin();
    });
  }

  setLogin(account: string) {
    this.storageService.setKey(account);
    this.loginService.login();
  }
}
  • Demo 目前沒有做登入頁,所以直接假設拿到一組正確的 token。

  • ngOnInit() 判斷網址如果沒有 token 帶入,則會判斷連線失敗。

  • setToken() 則是拿 token 請求拿 user 身份訊息,
    如果 user 帳號是停用的情況則會出現錯誤訊息。

nostatuslogin


範例碼

https://stackblitz.com/edit/ngcms-appcomp


上一篇
day10 AppComponent(一)
下一篇
day12 CoreComponent
系列文
用Angular打造完整後台30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言