文章目录
Angular 项目的搭建步骤
创建项目
npm i --global angular@13.3.0
ng new icrm-release-track-tool-ui --style=scss --skip-install --routing true
安装所需的包
npm i bootstrap //都是最新版本
npm i echarts
npm i font-awesome
npm i jquery
npm i primeng@13.4.1 --save //要对应好angular版本,不然会报错
npm i primeicons@4.1.0 --save
//11/12 version需要这个
npm i primeng-lts@12.2.5 --save
//primeng 包的依赖
npm i @angular/cdk@13.3.2 --save-dev
项目文件结构
创建组件以及服务
创建核心模块
ng g module core
ng g module shared
ng g module shared/primeng
ng g module --routing
app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// import { ReleaseManagementModule } from './modules/release-management/release-management.module';
// import { DashboardsModule } from './modules/dashboards/dashboards.module';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
CoreModule,
SharedModule,
// ReleaseManagementModule,
// DashboardsModule
],
providers: [],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule { }
primeng.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PanelModule } from 'primeng/panel';
import { CardModule } from 'primeng/card';
import { PanelMenuModule } from 'primeng/panelmenu';
import { AccordionModule } from 'primeng/accordion';
import { TabViewModule } from 'primeng/tabview';
import { TableModule } from 'primeng/table';
import { ButtonModule } from 'primeng/button';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { ToastModule } from 'primeng/toast';
import { DropdownModule } from 'primeng/dropdown';
import { TooltipModule } from 'primeng/tooltip';
import { MultiSelectModule } from 'primeng/multiselect';
import { DialogModule } from 'primeng/dialog';
import { AutoCompleteModule } from 'primeng/autocomplete';
import { OverlayPanelModule } from 'primeng/overlaypanel';
@NgModule({
declarations: [],
imports: [
CommonModule,
PanelModule,
CardModule,
PanelMenuModule,
AccordionModule,
TabViewModule,
TableModule,
ButtonModule,
ConfirmDialogModule,
ToastModule,
DropdownModule,
TooltipModule,
MultiSelectModule,
DialogModule,
AutoCompleteModule,
OverlayPanelModule
],
exports:[
PanelModule,
CardModule,
PanelMenuModule,
AccordionModule,
TabViewModule,
TableModule,
ButtonModule,
ConfirmDialogModule,
ToastModule,
DropdownModule,
TooltipModule,
MultiSelectModule,
DialogModule,
AutoCompleteModule,
OverlayPanelModule
]
})
export class PrimengModule { }
core.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MessageService } from 'primeng/api';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { LoaderComponent } from './components/loader/loader/loader.component';
import { LoaderService } from './services/loader/loader.service';
import { TokenInterceptor } from './services/http-interceptors/token-interceptor.service';
import { GrowlService } from './services/growl/growl.service';
@NgModule({
imports: [
CommonModule,
RouterModule,
HttpClientModule,
ConfirmDialogModule
],
providers: [
MessageService,
LoaderService,
GrowlService,
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
],
declarations: [
LoaderComponent,
],
exports:[
LoaderComponent
]
})
export class CoreModule { }
shared.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { PrimengModule } from './primeng/primeng.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RttHeaderComponent } from './components/rtt-header/rtt-header.component';
import { RttNavBarComponent } from './components/rtt-nav-bar/rtt-nav-bar.component';
import { RttActionButtonComponent } from './components/rtt-action-button/rtt-action-button.component';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
@NgModule({
declarations: [
RttHeaderComponent,
RttNavBarComponent,
RttActionButtonComponent
],
imports: [
CommonModule,
FormsModule,
RouterModule,
PrimengModule,
ReactiveFormsModule,
ConfirmDialogModule
],
exports: [
FormsModule,
PrimengModule,
RttHeaderComponent,
RttNavBarComponent,
RttActionButtonComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class SharedModule { }
全局样式
angular.json中引入第三方全局样式
"node_modules/primeicons/primeicons.css",
"node_modules/primeng-lts/resources/themes/saga-blue/theme.css",
"node_modules/primeng-lts/resources/primeng.min.css",
"node_modules/primeng/resources/primeng.min.css",
//根据不同版本有不同的引用
"node_modules/primeicons/primeicons.css",
"node_modules/primeng/resources/themes/lara-light-blue/theme.css",
"node_modules/primeng/resources/primeng.min.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/font-awesome/css/font-awesome.css"
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
创建项目中的开发模块
ng g module modules/login --routing
ng g module modules/dashboards --routing
ng g module modules/release-management --routing
ng g component modules/login
ng g component modules/dashboards
ng g component modules/release-management
创建子模块
ng g component modules/release-management/components/release-management-list
ng g component modules/release-management/components/release-management-detail
ng g component modules/release-management/components/release-management-pr-list
ng g component modules/release-management/components/release-project-info-list
ng g service modules/release-management/services/release-management
创建路由模块
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{
path: 'login',
loadChildren: () => import('./modules/login/login.module').then(m => m.LoginModule),
},
{
path: 'dashboards',
loadChildren: () => import('./modules/dashboards/dashboards.module').then(m => m.DashboardsModule),
},
{
path: 'release-management',
loadChildren: () => import('./modules/release-management/release-management.module').then(m => m.ReleaseManagementModule),
},
// {
// path: '**',
// pathMatch: 'full',
// redirectTo: 'release-management/release-management-list',
// },
{
path: "", redirectTo: "login", pathMatch: "full"
},
];
@NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true})],
exports: [RouterModule]
})
export class AppRoutingModule { }
路由守卫
创建布局组件
ng g component shared/components/rtt-header
ng g component shared/components/rtt-nav-bar
ng g component shared/components/rtt-action-button
全局的服务
ng g service core/services/helper/helper
ng g service core/services/growl/growl
ng g service core/services/guards/guards
ng g service core/services/http-interceptors/http-interceptors
ng g service core/services/loader/loader
ng g component core/components/loader
全局helper
import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment';
import { HttpErrorResponse } from '@angular/common/http';
import { Observable, of } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class HelperService {
constructor() { }
public getResourceURL(resourceUrl: string, isAsset = false): string {
return `${isAsset ? environment.ASSET_URL : environment.BASE_URL}${resourceUrl}`;
}
public handleError<T>(operation = 'operation', result?: T) {
return (err: HttpErrorResponse): Observable<T> => {
if (err.error instanceof Error) {
console.log('Client-side error occured.');
} else {
console.log('Server-side error occured.');
}
// TODO: send the error to remote logging infrastructure
console.error(err); // log to console instead
// TODO: better job of transforming error for user consumption
console.log(`${operation} failed: ${err.message}`);
//Let the app keep running by returning an empty result.
return of(result);
};
}
}
export const environment = {
production: false,
// BASE_URL: 'http://10.243.166.199:8080/', //tyg
// BASE_URL: 'http://10.108.88.251:8014/', // han,lei
// BASE_URL: 'http://10.243.203.65:8014/', //Ya, xin
BASE_URL:'http://10.243.160.124:8014/', //yang, yu
ASSET_URL: '/assets/'
};
全局loading效果
loader.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
@Injectable()
export class LoaderService {
private showCount = 0;
public loader$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor() {
//will write code
}
setLoader(isLoader: boolean): void {
if (isLoader) {
this.showCount++;
} else if (this.showCount > 0) {
this.showCount--;
}
if (isLoader || this.showCount === 0) {
this.loader$.next(isLoader);
}
}
resetActiveCount(): void {
this.showCount = 0;
}
}
loader.component.html
<div class="spinner-bg" [class.hidden]="!isLoading">
<div class="spinner-container">
<div class="spinner-image"></div>
</div>
</div>
loader.component.scss
/* spinner CSS */
.spinner-bg {
z-index: 10000;
height: 100vh;
width: 100vw;
background: rgba(158, 131, 131, 0.25);
position: fixed;
top: 0;
left: 0;
display: flex;
align-content: center;
justify-content: center;
}
.spinner-bg .spinner-container {
align-self: center;
}
.spinner-bg .spinner-container .spinner {
border: 14px solid #f3f3f3;
/* Light grey */
border-top: 14px solid #3498db;
/* Blue */
border-radius: 50%;
width: 90px;
height: 90px;
animation: spin 2s linear infinite;
}
.spinner-bg .spinner-container .spinner-image {
background: url('../../../../../assets/images/controls-spinner.png') no-repeat 0 0;
height: 50px;
width: 50px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.hidden {
display: none;
}
loader.component.ts
import { Component, OnInit } from '@angular/core';
import { LoaderService } from 'src/app/core/services/loader/loader.service';
@Component({
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss']
})
export class LoaderComponent implements OnInit {
isLoading = true;
constructor(
private loaderService: LoaderService
) { }
ngOnInit() {
this.loaderService.loader$.subscribe(d => {
this.isLoading = d;
});
}
}
全局message
growls.service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import {MessageService} from 'primeng-lts/api';
@Injectable()
export class GrowlService {
public severity: string = 'success';
public summary: string = 'Success!';
isShowMsg_$:Subject<boolean> = new Subject<boolean>();
constructor(
private messageService: MessageService
) { }
setIsShowMsg(isShow: boolean) {
this.isShowMsg_$.next(isShow);
}
addMessage({ severity = 'info', summary = '', detail = ''}) {
this.clear();
this.messageService.add({
severity,
summary,
detail
});
}
clear() {
this.messageService.clear();
}
showMessage(msg: string, isError) {
if (isError) {
this.severity = 'error';
this.summary = 'Error : ';
}
this.addMessage({
severity: this.severity,
summary: this.summary,
detail: msg
});
}
}
全局dialog
拦截器
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse, HttpParams } from '@angular/common/http';
import { throwError } from 'rxjs';
import { Observable } from 'rxjs/internal/Observable';
import { tap, catchError } from 'rxjs/operators';
import { Router } from '@angular/router';
import { LoaderService } from '../loader/loader.service';
import { GrowlService } from '../growl/growl.service';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(
private loaderService: LoaderService,
private growlService: GrowlService,
private router: Router
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Excluding service check for ssoe enabled service..
if (this.showLoader(request)) {
// console.log(request);
this.loaderService.setLoader(true);
}
//we will set token and request header cookie information.
// const authToken = 'lvxinToken';
// if (authToken) {
// // add token
// const authReq = request.clone({
// headers: request.headers.set('Authorization', 'bearer' + authToken),
// url: request.url
// });
// // service response.
// }
return next.handle(request).pipe(
tap(data => {
if (data.type !== 0 && this.showLoader(request)) {
this.loaderService.setLoader(false);
}
return data;
}),
catchError(error => {
if (this.showLoader(request)) {
this.loaderService.setLoader(false);
}
this.loaderService.setLoader(false);
if (error instanceof HttpErrorResponse) {
if (error.status === 500 || error.status === 600 ||error.status === 700 ||error.status === 800 ||error.status === 900) {
if (error.error.errorKey) {
console.log(`${error.error.errorKey}:${error.error.stackTrace}-${JSON.stringify(request.body)}`);
this.growlService.showMessage(`${error.error.errorKey}:${error.error.errorMessage}`, true);
} else {
this.growlService.showMessage(`There is a system error, please contact administrator.`, true);
console.log(`${JSON.stringify(request.body)}`);
}
this.growlService.setIsShowMsg(true);
}
}
return throwError(error);
})
);
}
showLoader(request: HttpRequest<any>) {
if (request.responseType === 'json' && request.body && request.body.isShowLoader === true) {
return false;
}
if (request.params instanceof CustomHttpParams && !request.params.isShowLoader) {
return false;
}
return true;
}
getCookie(cname) {
const name = cname + '=';
const ca = window.parent.document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
}
export class CustomHttpParams extends HttpParams {
constructor(public isShowLoader: boolean) {
super();
}
}
代码地址
JS Stacktrace
node --max-old-space-size=8192 ./node_modules/@angular/cli/bin/ng serve --host 10.61.177.108 --port 4900