1.手機端 圖片預覽組件css
組件:sideshowhtml
效果圖:(預覽圖全屏 且能夠左右移動)node
code:git
<div class="row ui-app-screenshot"> <img src="{{proUrl(pic.Url)}}" *ngFor="let pic of currApp.Pictures;let i = index;" (click)="onViewPicture(i)"> </div>
<slideshow [imageUrls]="slideUrls" [showArrows]="false" #slideRef (click)="onCloseViewPicture()"></slideshow>
import { ViewChild, Component, ElementRef, Renderer2 } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { AppStoreService } from '../../service/appService'; import { ConfigureOptions } from '../../configure/configure.options'; import { BrowserService } from '../../service/browser.service'; import { Adal4Service } from '../../adal/adal4.service'; @Component({ selector: 'mobile-app-info', templateUrl: './mobileAppInfo.html', styleUrls: ['./mobileAppInfo.css'] }) export class MobileAppInfo { @ViewChild('slideRef') slideRef: ElementRef; constructor( private router: Router, private actRouter: ActivatedRoute, private appService: AppStoreService, private browserService: BrowserService, private appOptions: ConfigureOptions, private renderer: Renderer2, private adalService: Adal4Service) { } id: string; platSource: any; showRateBox: boolean = false; rateVal: number = 0; screenHeight: any; currApp: any = []; currPackage: any = []; userRateStars: any = [{}, {}, {}, {}, {}]; slideUrls: any = [{}]; eleSlidershow: any; username: string; ngOnInit(): void { this.initWinHeight(); this.eleSlidershow = this.slideRef && this.slideRef['container'].nativeElement; if (this.eleSlidershow) { this.renderer.setStyle(this.eleSlidershow, 'position', 'fixed'); this.renderer.setStyle(this.eleSlidershow, 'top', '0'); this.renderer.setStyle(this.eleSlidershow, 'z-index', '1041'); this.renderer.setStyle(this.eleSlidershow, 'display', 'none'); } this.actRouter.params.subscribe((params: Params) => { this.id = params["id"]; this.platSource = this.browserService.getBrowserInfo(); if (!this.platSource.isMobile && !this.platSource.isWechat) { this.router.navigate(["/appInfo/" + this.id], {}); } this.appService.GetAppInfo(this.id, (rtv) => { this.initAppData(rtv); }); }); this.username = this.adalService.userInfo.username || "未登陸"; } initAppData(rtv: any) { this.currApp.IconUrl = this.proUrl(rtv.IconUrl); this.currApp.Name = rtv.Name || ''; this.currApp.DownloadCount = rtv.DownloadCount || 0; this.currApp.AvgScore = rtv.AvgScore || 0; this.currApp.ScoreCount = rtv.ScoreCount || 0; this.currApp.Pictures = rtv.Pictures || []; this.currApp.CreatedOn = rtv.CreatedOn || ''; this.currApp.Category = rtv.Category || ''; this.currApp.Version = rtv.Version || ''; this.currApp.IsScored = rtv.IsScored || false; this.currApp.Description = this.proTxt(rtv.Description); this.currApp.scoreTxt = rtv.IsScored ? '已評分' : '評 分'; this.slideUrls = rtv.Pictures.map(p => this.proUrl(p.Url)); if (this.slideUrls.length == 0) { this.slideUrls.push({}); } this.slideRef['slideIndex'] = this.slideUrls.length - 1; let _pkgArray = this.platSource.platform.Android ? rtv.AndoridPackages[0] : rtv.iOSPackages[0]; this.currPackage.Version = _pkgArray && _pkgArray.Version || ''; this.currPackage.ReleaseNotes = this.proTxt(_pkgArray && _pkgArray.ReleaseNotes); this.currPackage.FileSize = this.proSize(_pkgArray && _pkgArray.FileSize || 0); } initWinHeight() { this.screenHeight = (window.screen.height || window.innerHeight) - 52; let self = this; window.addEventListener("resize", function () { self.screenHeight = (window.screen.height || window.innerHeight) - 52; }); } proUrl(url) { return this.appOptions.BlobUrl + url; } proDevice() { let devStr = ''; if (this.platSource.platform.Android) { this.currPackage ? devStr = 'Android' : devStr = '不支持Android'; } else if (this.platSource.platform.iPad || this.platSource.platform.iPhone) { this.currPackage ? devStr = 'IOS' : devStr = '不支持IOS'; } return devStr; } proTxt(txt: string) { return txt ? txt.replace(/\r?\n/g, "<br />").replace('undefined', '<font color="#a1a1a1">暫無信息</font>') : '<font color="#a1a1a1">暫無信息</font>'; } proSize(limit: any) { var size = ""; if (!limit) return size; if (limit < 0.1 * 1024) { //若是小於0.1KB轉化成B size = limit.toFixed(2) + "B"; } else if (limit < 0.1 * 1024 * 1024) {//若是小於0.1MB轉化成KB size = (limit / 1024).toFixed(2) + "KB"; } else if (limit < 0.1 * 1024 * 1024 * 1024) { //若是小於0.1GB轉化成MB size = (limit / (1024 * 1024)).toFixed(2) + "MB"; } else { //其餘轉化成GB size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB"; } var sizestr = size + ""; var len = sizestr.indexOf("\."); var dec = sizestr.substr(len + 1, 2); if (dec == "00") {//當小數點後爲00時 去掉小數部分 return sizestr.substring(0, len) + sizestr.substr(len + 3, 2); } return sizestr; } getStarClass(val: number): number { return Math.floor(val * 2) || 0; } onOpenRate() { if (this.checkAuth()) { this.showRateBox = true; this.rateVal = 0; } } onCloseRate() { this.showRateBox = false; } onSetScore() { this.appService.SetScore(this.id, this.rateVal, (rtv) => { this.currApp.IsScored = true; this.onCloseRate() }); } onRate(value): void { this.rateVal = value; } getDownloadUrl(): void { if (!this.checkAuth()) { return; } this.appService.GetDownloadUrl(this.id, this.platSource.platform.Android ? "Android" : "iOS", (ret) => { if (!!ret) { window.location.href = ret; } else { alert("獲取下載地址失敗,請稍後再試"); } }); } private checkAuth(): boolean { var user = this.adalService.userInfo; if (user.authenticated) { return true; } localStorage.setItem("app-store-redirect-uri", window.location.pathname); this.router.navigate(["/login"], {}); return false; } onViewPicture(index: any): void { this.renderer.setStyle(this.eleSlidershow, 'display', 'block'); this.slideRef && this.slideRef['onButtonClick'].call(this.slideRef, index || 0); } onCloseViewPicture(): void { this.renderer.setStyle(this.eleSlidershow, 'display', 'none'); } }
2.樹形組件或者樹形下拉框組件github
ng2tree ngx-treeviewexpress
地址:https://github.com/leovo2708/ngx-treeviewnpm
angular2-treeapi
2.1 難點:ng2tree 異步加載angular2
預覽:app
code:
<tree [tree] ="orgTree" [settings]="{rootIsVisible: false}" (nodeSelected)="logEvent($event)" (nodeMoved)="onNodeMoved($event)"></tree>
import { Component } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { TreeModel, NodeEvent, TreeModelSettings } from 'ng2-tree'; import { UserService } from '../common/userService'; import { CommonService } from '../../providers/commonService'; @Component({ selector: 'orgTree', templateUrl: './orgTree.html', styleUrls: ['./orgTree.css'] }) export class orgTree { menuItems: any = [ { title: "添加", icon: "#FxSymbol0-0bd", event: this.onAdd.bind(this) }, { title: "編輯", icon: "#FxSymbol0-0bf", event: this.onEdit.bind(this) } ] public orgTree: TreeModel; public nodeTree: Array<TreeModel> = []; constructor( private router: Router, private actRouter: ActivatedRoute, private comService: CommonService, private userService: UserService) { this.onRefresh(comService); } loadNodes(id: string,callback:any):void { let rtv: Array<TreeModel> = []; this.userService.LoadSyncTree(id, (result) => { let length: number = result.children.length; if (length > 0) { for (let i = 0; i < length; i++) { let node: TreeModel = { id: result.children[i].id, value: result.children[i].value, loadChildren: (cb) => {this.loadNodes(result.children[i].id,cb) } } rtv.push(node); } }
callback(rtv);
}); } currGroup: string = ''; groupId: string = ''; ngOnInit(): void { this.actRouter.params.subscribe((params: Params) => { this.groupId = params["id"]; if (!this.groupId) { this.groupId = "org"; } this.currGroup = params["id"]; this.onLoadTree(this.groupId); }); } public logEvent(e: NodeEvent): void { if (e.node.id.toString() == '') { alert('根機構不可編輯!') } else { this.currGroup = e.node.id.toString(); if (this.currGroup != "") { this.router.navigate(['/ou/org/' + this.currGroup + '/member'], {}); } } } onLoadTree(id: string) { this.userService.LoadSyncTree(null, (result) => { const treeSettings: TreeModelSettings = { static: false, rightMenu: false, leftMenu: false, isCollapsedOnInit: false } let length: number = result.children.length; for (let i = 0; i < length; i++) { result.children[i].loadChildren = (callback) => {this.loadNodes(result.children[i].id,callback) } }; this.orgTree = result; this.orgTree.settings = treeSettings; }); } onEdit() { if (this.currGroup == '' || this.currGroup == null) { alert('請先選擇一個機構再進行編輯操做。'); } else this.router.navigate(['/ou/' + this.groupId + '/' + this.currGroup + '/edit'], {}); } onAdd() { if (this.currGroup == '' || this.currGroup == null) { alert('請先選擇一個機構再進行添加操做。'); } else this.router.navigate(['/ou/' + this.groupId + '/' + this.currGroup + '/create'], {}); } onOUFresh() { this.userService.RefreshTree(this.groupId, (result) => { const treeSettings: TreeModelSettings = { static: false, rightMenu: false, leftMenu: false, isCollapsedOnInit: false } this.orgTree = result; this.orgTree.settings = treeSettings; }); } onClose() { this.router.navigate(['/ou']); } onRefresh(comService: CommonService) { this.comService.notifyObservable$.subscribe(data => { if (data == 'refreshOrgTree') { this.currGroup = ''; this.onLoadTree(this.groupId); } }, error => { console.log(`subscribe error:${error}`) }) } onNodeMoved(e: NodeEvent): void { console.log("curr:" + e.node.parent.value); console.log(e.node.value); } }
2.2 改造:下拉框 tree
預覽:
3. 上傳組件
組件:ng2-file-upload
code:
<input type="file" ng2FileSelect [uploader]="uploader" [(ngModel)]="fileInfo"/>
import { Component } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { FileUploader, FileItem, ParsedResponseHeaders } from 'ng2-file-upload'; import { Adal4Service } from '../../adal/adal4.service'; import { ConfigureService } from '../../configure/configure.service'; import { UserService } from '../common/userService'; @Component({ selector: 'usersimport', templateUrl: './importUsers.html', styleUrls: ['./importUsers.css'] }) export class importUsers { errorMsg: string; lstHistory: any; template: string; token: string; uploader: FileUploader = null; parentUrl: string; fileInfo: string; groupId: string; orgPath: string; menuItems: any = [ { title: "刷新", icon: "#FxSymbol0-0bf", event: this.onRefresh.bind(this) } ] constructor( private router: Router, private actRouter: ActivatedRoute, public configService: ConfigureService, private adal4Service: Adal4Service, private userService: UserService ) { this.template = "/api/import/template?type=user"; this.token = this.adal4Service.userInfo.token; this.uploader = new FileUploader({ url: "/api/Import/User", method: "POST", itemAlias: "dataFile", autoUpload: false, headers: [{ name: 'Authorization', value: `Bearer ${this.token}` }] }); this.menuItems = [ { title: "上傳", icon: "#FxSymbol0-001", event: this.uploadExcel.bind(this) }, { title: "刷新", icon: "#FxSymbol0-0bf", event: this.onRefresh.bind(this) } ]; this.onRefresh(); } onRefresh(): void { this.userService.RefreshHistory("ImportUser", (rtv) => { this.lstHistory = rtv; }); } ngOnInit(): void { this.parentUrl = this.router.url; this.actRouter.params.subscribe((params: Params) => { this.groupId = params["groupId"] || this.groupId; this.groupId && this.initOrgPath(); }); } onClose() { this.router.navigate(['/ou/org/' + this.groupId + '/member/'], {}); } uploadExcel() { if (this.uploader != null && this.uploader.queue[0] != null) { this.uploader.queue[0].onSuccess = (response, status, headers) => { if (status == 200) { this.errorMsg = ""; let rtv = JSON.parse(response); if (rtv.RetCode == 0) { this.errorMsg = "文件上傳成功,結果查看結果列表。"; } else { this.errorMsg = "文件上傳失敗." + rtv.RetMessage; } } else { this.errorMsg = response; } this.fileInfo = ""; }; this.uploader.onBeforeUploadItem = (item) => { item.withCredentials = false; } this.uploader.onSuccessItem = this.onSuccessItem.bind(this); this.uploader.onErrorItem = this.onErrorItem.bind(this); this.uploader.uploadAll(); } else { alert('請選擇上傳文件!'); } } onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any { if (status != 200) { alert('導入人員失敗!'); } else { alert(response); } this.fileInfo = ""; this.onClose(); } onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any { if (status == 200) { this.errorMsg = ""; let rtv = JSON.parse(response); if (rtv.status == 1) { alert('文件上傳成功!'); } else { alert('文件上傳失敗,錯誤信息:' + rtv.message); } this.fileInfo = ""; this.uploader.removeFromQueue(item); this.uploader.clearQueue(); this.uploader.destroy(); this.onRefresh(); } else { alert(response); } this.onClose(); } initOrgPath() { let _array = decodeURIComponent(this.groupId).split(','); if (_array && _array.length > 0) { this.orgPath = _array.map(o => o.replace('OU=', '')).reverse().join('#'); if(this.orgPath) this.orgPath = decodeURIComponent(this.orgPath); } } }
2.頭像上傳 編輯圖片組件
angular2-img-cropper
3.日期選擇
https://github.com/CuppaLabs/angular2-datetimepicker
4.列表分頁組件
npm install ngx-pagination
5.html 編輯器
npm install angular-froala-wysiwyg --save
https://summernote.org/
https://github.com/lula/ngx-summernote/
推薦組件庫:
FreeNG
https://freengs.github.io/#/main/introduction
http://www.wheelsfactory.cn
https://www.jqwidgets.com/angular/#demos/angular2/angular-fileupload-defaultfunctionality.htm
https://www.telerik.com/kendo-angular-ui/components/
https://www.infragistics.com/angularsite/components/grids_and_lists.html
https://docs.nativescript.org/angular/ui/ng-ui-widgets/date-picker
https://material.angular.io/components/datepicker/examples
https://js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/RecordPaging/jQuery/Light/
https://akveo.github.io/ngx-admin/?utm_source=github&utm_medium=ngx_admin_readme&utm_campaign=themes
未完待續,本文章待補充....