UNPKG

bixi

Version:

企业级中后台前端解决方案

145 lines (128 loc) 4.15 kB
import { DOCUMENT } from '@angular/common'; import { Inject, Injectable, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { Observable, Observer } from 'rxjs'; import { BIXI_SERVICE_TOKEN, ITokenModel, ITokenService } from '../token/interface'; const OPENTYPE = '_bixiAuthSocialType'; const HREFCALLBACK = '_bixiAuthSocialCallbackByHref'; export type SocialOpenType = 'href' | 'window'; @Injectable() export class SocialService implements OnDestroy { private _win: Window | null; // tslint:disable-next-line:no-any private _winTime: any; private observer: Observer<ITokenModel | null>; constructor( @Inject(BIXI_SERVICE_TOKEN) private tokenService: ITokenService, // tslint:disable-next-line:no-any @Inject(DOCUMENT) private doc: any, private router: Router ) { } /** * 使用窗体打开授权页,返回值是 `Observable<ITokenModel>` 用于订阅授权后返回的结果 * @param url 获取授权地址 * @param callback 回调路由地址 * @param options options.windowFeatures 等同 `window.open` 的 `features` 参数值 */ login( url: string, callback?: string, options?: { type?: 'window'; windowFeatures?: string; } ): Observable<ITokenModel>; /** * 跳转至授权页 * @param url 获取授权地址 * @param callback 回调路由地址 * @param options type */ login( url: string, callback?: string, options?: { type?: 'href'; } ): void; /** * 跳转至登录页,若为 `type=window` 时,返回值是 `Observable<ITokenModel>` * @param url 获取授权地址 * @param callback 当 `type=href` 成功时的回调路由地址 * @param options options.type 打开方式,默认 `window` options.windowFeatures 等同 `window.open` 的 `features` 参数值 */ login( url: string, callback: string = '/', options: { type?: SocialOpenType; windowFeatures?: string; } = {} ): Observable<ITokenModel | null> | void { options = { type: 'window', windowFeatures: 'location=yes,height=570,width=520,scrollbars=yes,status=yes', ...options }; // tslint:disable-next-line:no-non-null-assertion localStorage.setItem(OPENTYPE, options.type!); localStorage.setItem(HREFCALLBACK, callback); if (options.type === 'href') { this.doc.location.href = url; return; } this._win = window.open(url, '_blank', options.windowFeatures); this._winTime = setInterval(() => { if (this._win && this._win.closed) { this.ngOnDestroy(); let model = this.tokenService.get(); if (model && !model.token) model = null; // 触发变更通知 if (model) { this.tokenService.set(model); } this.observer.next(model); this.observer.complete(); } }, 100); return new Observable((observer: Observer<ITokenModel | null>) => { this.observer = observer; }); } /** * 授权成功后的回调处理 * * @param rawData 指定回调认证信息,为空时从根据当前URL解析 */ callback(rawData?: ITokenModel | string | null): ITokenModel { // from uri if (!rawData && this.router.url.indexOf('?') === -1) { throw new Error(`url muse contain a ?`); } // parse let data: ITokenModel = { token: `` }; if (typeof rawData === 'string') { const rightUrl = rawData.split('?')[1].split('#')[0]; data = this.router.parseUrl('./?' + rightUrl).queryParams as ITokenModel; } else { data = rawData as ITokenModel; } if (!data || !data.token) throw new Error(`invalide token data`); this.tokenService.set(data); const url = localStorage.getItem(HREFCALLBACK) || '/'; localStorage.removeItem(HREFCALLBACK); const type = localStorage.getItem(OPENTYPE); localStorage.removeItem(OPENTYPE); if (type === 'window') { window.close(); } else { this.router.navigateByUrl(url); } return data; } ngOnDestroy(): void { clearInterval(this._winTime); this._winTime = null; } }