├── .gitignore ├── README.md ├── conf ├── styleLoaderConf.js ├── webpack.config.js ├── webpack.dev.conf.js ├── webpack.dll.conf.js └── webpack.prod.conf.js ├── demos ├── app.component.ts ├── app.module.ts ├── app.routes.ts ├── app.ts ├── crisis-list │ ├── component.ts │ ├── crisis-list.component.html │ └── module.ts ├── heroes-list │ ├── component.ts │ ├── heroes-list.component.html │ └── module.ts ├── index.html ├── miniapp │ ├── about.component.ts │ ├── app-routing.module.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── home.component.ts │ ├── index.html │ ├── index.ts │ └── main.ts ├── not-found.component.ts ├── tsconfig.json └── webpack.config.js ├── package.json ├── pnpm-lock.yaml ├── src ├── antd │ ├── demos.ts │ ├── directive.ts │ ├── module.ts │ └── ngModule.ts ├── app.ts ├── app │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routing.ts │ ├── article │ │ ├── addarticle │ │ │ ├── addarticle.html │ │ │ ├── addarticle.service.ts │ │ │ └── addarticle.ts │ │ ├── article.component.ts │ │ ├── article.module.ts │ │ ├── article.routing.ts │ │ ├── articlelist │ │ │ ├── articlelist.html │ │ │ ├── articlelist.service.ts │ │ │ └── articlelist.ts │ │ ├── editarticle │ │ │ ├── editarticle.html │ │ │ ├── editarticle.service.ts │ │ │ └── editarticle.ts │ │ └── model │ │ │ └── article.model.ts │ ├── articletype │ │ ├── addarticletype │ │ │ ├── addarticletype.html │ │ │ ├── addarticletype.service.ts │ │ │ └── addarticletype.ts │ │ ├── articletype.component.ts │ │ ├── articletype.module.ts │ │ ├── articletype.routing.ts │ │ ├── articletypelist │ │ │ ├── articletypelist.html │ │ │ ├── articletypelist.service.ts │ │ │ └── articletypelist.ts │ │ ├── editarticletype │ │ │ ├── editarticletype.html │ │ │ ├── editarticletype.service.ts │ │ │ └── editarticletype.ts │ │ └── model │ │ │ └── articletype.model.ts │ ├── charts │ │ ├── chart.component.ts │ │ ├── chart.html │ │ ├── chart.module.ts │ │ ├── chart.routing.ts │ │ ├── chart.service.ts │ │ ├── model │ │ │ └── chart.model.ts │ │ └── out-let.component.ts │ ├── comment │ │ ├── comment.component.ts │ │ ├── comment.module.ts │ │ ├── comment.routing.ts │ │ ├── commentdetail │ │ │ ├── commentdetail.html │ │ │ ├── commentdetail.service.ts │ │ │ └── commentdetail.ts │ │ ├── commentlist │ │ │ ├── commentlist.html │ │ │ ├── commentlist.service.ts │ │ │ └── commentlist.ts │ │ └── model │ │ │ └── comment.model.ts │ ├── dashboard │ │ ├── dashboard.component.ts │ │ ├── dashboard.html │ │ ├── dashboard.module.ts │ │ ├── dashboard.routing.ts │ │ ├── dashboard.service.ts │ │ └── index.ts │ ├── demos │ │ ├── demos.component.ts │ │ ├── demos.html │ │ ├── demos.module.ts │ │ ├── demos.routing.ts │ │ ├── demos.service.ts │ │ ├── models │ │ │ └── demo.model.ts │ │ └── out-let.component.ts │ ├── doubleball │ │ ├── doubleball.component.ts │ │ ├── doubleball.module.ts │ │ ├── doubleball.routing.ts │ │ ├── doubleballlist │ │ │ ├── doubleball.directive.ts │ │ │ ├── doubleballlist.html │ │ │ ├── doubleballlist.service.ts │ │ │ └── doubleballlist.ts │ │ └── model │ │ │ └── doubleball.model.ts │ ├── home │ │ ├── home.component.html │ │ ├── home.component.ts │ │ └── index.ts │ ├── login │ │ ├── bubble.ts │ │ ├── login.component.ts │ │ ├── login.html │ │ └── style.less │ ├── systemlogs │ │ ├── model │ │ │ └── systemlog.model.ts │ │ ├── systemlog.component.ts │ │ ├── systemlog.module.ts │ │ ├── systemlog.routing.ts │ │ ├── systemlogdetail │ │ │ ├── systemlogdetail.html │ │ │ ├── systemlogdetail.service.ts │ │ │ └── systemlogdetail.ts │ │ └── systemloglist │ │ │ ├── systemloglist.html │ │ │ ├── systemloglist.service.ts │ │ │ └── systemloglist.ts │ ├── tag │ │ ├── addtag │ │ │ ├── addtag.html │ │ │ ├── addtag.service.ts │ │ │ └── addtag.ts │ │ ├── edittag │ │ │ ├── edittag.html │ │ │ ├── edittag.service.ts │ │ │ └── edittag.ts │ │ ├── index.ts │ │ ├── model │ │ │ └── tag.model.ts │ │ ├── tag.component.ts │ │ ├── tag.module.ts │ │ ├── tag.routing.ts │ │ └── taglist │ │ │ ├── taglist.html │ │ │ ├── taglist.service.ts │ │ │ └── taglist.ts │ └── user │ │ ├── adduser │ │ ├── adduser.html │ │ ├── adduser.service.ts │ │ └── adduser.ts │ │ ├── edituser │ │ ├── edituser.html │ │ ├── edituser.service.ts │ │ └── edituser.ts │ │ ├── index.ts │ │ ├── model │ │ └── user.model.ts │ │ ├── user.component.ts │ │ ├── user.module.ts │ │ ├── user.routing.ts │ │ └── userlist │ │ ├── userlist.html │ │ ├── userlist.service.ts │ │ └── userlist.ts ├── assets │ ├── i18n │ │ ├── en.json │ │ └── zh.json │ ├── images │ │ ├── logo.png │ │ └── logo.svg │ └── less │ │ └── index.less ├── components │ ├── datetime-picker │ │ ├── datetime-picker.component.ts │ │ ├── datetime-picker.module.ts │ │ └── datetime-range.html │ ├── editor │ │ ├── editor.component.ts │ │ ├── editor.html │ │ └── editor.module.ts │ ├── shared │ │ ├── breadcrumb │ │ │ ├── breadcrumb.component.html │ │ │ ├── breadcrumb.component.less │ │ │ └── breadcrumb.component.ts │ │ ├── header │ │ │ ├── header.component.html │ │ │ ├── header.component.less │ │ │ └── header.component.ts │ │ ├── index.ts │ │ └── sidebar │ │ │ ├── sidebar.component.html │ │ │ ├── sidebar.component.less │ │ │ └── sidebar.component.ts │ └── upload-file │ │ ├── upload-file.component.ts │ │ ├── upload-file.directvie.ts │ │ ├── upload-file.html │ │ └── upload-file.module.ts ├── index.ts ├── polyfills.ts ├── registerServiceWorker.ts ├── styles │ ├── global.less │ ├── index.less │ ├── tailwind.css │ └── theme.less ├── template │ └── index_base.html ├── types │ ├── custome.d.ts │ ├── demo.ts │ ├── global.d.ts │ └── login.ts ├── utils │ ├── auth │ │ ├── auth-guard.service.ts │ │ └── auth.service.ts │ ├── echarts │ │ └── index.ts │ ├── funs.ts │ ├── httpInterceptor │ │ ├── helper.service.ts │ │ ├── httpInterceptor.service.ts │ │ └── index.ts │ ├── params.service.ts │ └── tools.ts └── vendor.ts ├── static ├── favicon.ico ├── logo.svg └── manifest.json ├── tailwind.config.js ├── tsconfig.json └── tslint.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | 4 | .vscode 5 | .idea 6 | 7 | node_modules 8 | .npm 9 | 10 | .tmp 11 | dist 12 | tests 13 | deploy.js 14 | 15 | logs 16 | *.log 17 | npm-debug.log* 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular18 for CMS 2 | 3 | ### Project Technical Structure 4 | *** 5 | * angular18 6 | * ng-zorro-antd 7 | * angular/router 8 | * angular/http 9 | * rxjs 10 | * webpack5 11 | * less 12 | 13 | ### Install 14 | 15 | *** 16 | project address: (`git clone`) 17 | 18 | ``` 19 | git clone git@github.com:xpioneer/angular-typescript.git 20 | ``` 21 | install node_modules with `yarn` 22 | 23 | ``` 24 | yarn #in your command terminal 25 | ``` 26 | *** 27 | ### Run 28 | 29 | start server: (http://localhost:9100) 30 | 31 | ``` 32 | yarn run start 33 | ``` 34 | 35 | publish production 36 | 37 | ``` 38 | yarn run build 39 | ``` 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /conf/styleLoaderConf.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const MiniCssExtractPlugin = require("mini-css-extract-plugin") 3 | 4 | const _PROD_ = process.env.NODE_ENV === 'production' 5 | 6 | const postcssLoader = { 7 | loader: 'postcss-loader', 8 | options: { 9 | sourceMap: _PROD_ ? false : true, 10 | postcssOptions: { 11 | plugins: [ 12 | require('tailwindcss'), 13 | ['postcss-preset-env', { 14 | browsers: '> 0.5%, not dead, iOS >= 12, Android >= 4.5' 15 | }] 16 | ] 17 | }, 18 | // plugins: [ 19 | // require('autoprefixer')({ 20 | // browsers: ["Android 4.1", "iOS 7.1", "Chrome > 31", "ff > 31", "ie >= 8"] 21 | // }) 22 | // ] 23 | } 24 | } 25 | 26 | const styleRules = [ 27 | // { 28 | // test: /\.less$/, 29 | // use: [ 30 | // 'raw-loader', 31 | // 'less-loader' 32 | // ] 33 | // }, 34 | { 35 | test: /\.less$/, 36 | use: [ 37 | 'style-loader', 38 | 'css-loader', 39 | postcssLoader, 40 | { 41 | loader: 'less-loader', 42 | options: { 43 | lessOptions: { 44 | modifyVars: { 45 | '@primary-color': '#8514f5', 46 | '@link-color': '#8514f5', 47 | }, 48 | javascriptEnabled: true 49 | } 50 | } 51 | } 52 | ] 53 | }, 54 | { 55 | test: /\.css$/, 56 | use: [ 57 | 'style-loader', 58 | 'css-loader', 59 | postcssLoader 60 | ] 61 | }, 62 | ] 63 | 64 | if(_PROD_) { 65 | styleRules.forEach(rule => { 66 | rule.use.splice(0, 1, MiniCssExtractPlugin.loader) 67 | }) 68 | } 69 | 70 | module.exports = styleRules 71 | -------------------------------------------------------------------------------- /conf/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | webpack = require('webpack'), 3 | UglifyJSPlugin = require("uglifyjs-webpack-plugin"), 4 | HtmlWebpackPlugin = require("html-webpack-plugin"), 5 | config = require('./webpack.config.js'); 6 | 7 | const _PROD_ = process.env.NODE_ENV === 'production' 8 | 9 | config.mode = _PROD_ ? 'development' : 'none' 10 | config.watchOptions = { 11 | aggregateTimeout: 300, 12 | poll: 1000, 13 | } 14 | config.devServer = { 15 | port: '9100', 16 | host: 'localhost', 17 | 18 | proxy: [{ 19 | context: ['/api', '/uploads'], 20 | target: 'http://127.0.0.1:9901' 21 | }], 22 | historyApiFallback: true, 23 | static: { 24 | directory: path.join(__dirname, 'public'), 25 | }, 26 | // contentBase: path.join(__dirname, '../dist'), 27 | // publicPath: '/', 28 | // inline: true, 29 | // stats: { 30 | // colors: true 31 | // }, 32 | client: { 33 | // progress: true, 34 | overlay: { 35 | warnings: false, 36 | errors: true, 37 | }, 38 | }, 39 | // hot: true, 40 | // hotOnly: true, 41 | } 42 | 43 | config.plugins = (config.plugins || []).concat([ 44 | new webpack.HotModuleReplacementPlugin(), 45 | // new webpack.NamedModulesPlugin(), 46 | new HtmlWebpackPlugin({ 47 | title: 'CMS-FE DEV', 48 | filename: 'index.html', 49 | template: '../src/template/index_base.html', 50 | inject: 'body', 51 | templateParameters: false, 52 | }) 53 | ]); 54 | 55 | module.exports = config; -------------------------------------------------------------------------------- /conf/webpack.dll.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | webpack = require('webpack'), 3 | UglifyJSPlugin = require("uglifyjs-webpack-plugin"), 4 | HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | 6 | const _DEV_ = process.env.NODE_ENV === 'development'; 7 | 8 | const config = { 9 | entry: { 10 | polyfills: [path.resolve(__dirname, '../src/polyfills.ts')], 11 | vendor: [path.resolve(__dirname, '../src/vendor.ts')], 12 | vendor1: ['ng-zorro-antd'], 13 | }, 14 | 15 | output: { 16 | path: path.resolve(__dirname, "../dist/vendor"), 17 | filename: "[name].[chunkhash].dll.js", 18 | library: "[name]_[chunkhash]_lib" 19 | }, 20 | 21 | // plugins 22 | plugins: [ 23 | new UglifyJSPlugin({ 24 | output: { 25 | comments: false, 26 | beautify: !_DEV_ ? false : true, 27 | }, 28 | compress: !_DEV_ ? { 29 | drop_console: true, 30 | } : false, 31 | warnings: false 32 | }), 33 | new webpack.optimize.CommonsChunkPlugin({ 34 | name: ['vendor1', 'vendor', 'polyfills'], 35 | }), 36 | new webpack.DllPlugin({ 37 | context: path.resolve(__dirname, '../dist'), 38 | name: "[name]_[chunkhash]_lib", 39 | path: path.join(__dirname, "../dist/vendor", "[name].manifest.json") 40 | }), 41 | new HtmlWebpackPlugin({ 42 | title: 'CMS-管理后台', 43 | filename: '../index.html', 44 | template: 'src/template/index_base.html', 45 | }), 46 | // new webpack.ContextReplacementPlugin( 47 | // /angular(\\|\/)core(\\|\/)@angular/, 48 | // path.resolve(__dirname, '../src') 49 | // ) 50 | ] 51 | }; 52 | 53 | module.exports = config; -------------------------------------------------------------------------------- /conf/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'), 2 | webpack = require('webpack'), 3 | config = require('./webpack.config.js'), 4 | UglifyJsPlugin = require("uglifyjs-webpack-plugin"), 5 | HtmlWebpackPlugin = require("html-webpack-plugin"), 6 | // CleanWebpackPlugin = require('clean-webpack-plugin'), 7 | OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"), 8 | SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); 9 | 10 | const _PROD_ = process.env.NODE_ENV === 'production' 11 | 12 | config.mode = _PROD_ ? 'production' : 'none' 13 | config.plugins = (config.plugins || []).concat([ 14 | // new CleanWebpackPlugin(['dist/*'], 15 | // { 16 | // root: path.join(__dirname, '../'), 17 | // verbose: true, 18 | // dry: false 19 | // }), 20 | new OptimizeCSSAssetsPlugin({ 21 | // cssProcessor: require('cssnano')({ autoprefixer: false }) 22 | }), 23 | new UglifyJsPlugin({ 24 | uglifyOptions: { 25 | compress: { 26 | warnings: false, 27 | drop_console: !_PROD_ ? false : true, 28 | }, 29 | output: { 30 | comments: false 31 | } 32 | }, 33 | parallel: true 34 | }), 35 | // new webpack.HashedModuleIdsPlugin(), 36 | // new webpack.NamedModulesPlugin(), 37 | new HtmlWebpackPlugin({ 38 | title: 'CMS-管理后台', 39 | filename: 'index.html', 40 | template: '../src/template/index_base.html', 41 | minify: { 42 | minifyJS: true, 43 | removeComments: true, 44 | collapseWhitespace: true, 45 | removeAttributeQuotes: true 46 | } 47 | }), 48 | new SWPrecacheWebpackPlugin({ 49 | cacheId: 'ngadmin-sw', 50 | dontCacheBustUrlsMatching: /\.\w{8}\./, 51 | filename: 'serviceWorker.js', 52 | logger(message) { 53 | console.log(message); 54 | if (message.indexOf('Total precache size is') === 0) { 55 | return; 56 | } 57 | if (message.indexOf('Skipping static resource') === 0) { 58 | return; 59 | } 60 | }, 61 | minify: true, 62 | navigateFallback: '/index.html', 63 | navigateFallbackWhitelist: [/^(?!\/__).*/], 64 | staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/], 65 | }) 66 | ]); 67 | 68 | module.exports = config; -------------------------------------------------------------------------------- /demos/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewEncapsulation } from '@angular/core'; 2 | import { RouterOutlet } from '@angular/router' 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | encapsulation: ViewEncapsulation.Emulated, 7 | imports: [ 8 | RouterOutlet 9 | ], 10 | template: ` 11 |

Angular Router Sample

12 | 16 |

Hello, Angular

17 | 18 | `, 19 | }) 20 | export class AppComponent implements OnInit { 21 | 22 | constructor () { 23 | } 24 | 25 | public ngOnInit () { 26 | console.log('demo app entry') 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /demos/app.module.ts: -------------------------------------------------------------------------------- 1 | import { registerLocaleData } from '@angular/common'; 2 | import zh from '@angular/common/locales/zh'; 3 | import { LOCALE_ID, NgModule, OnInit } from '@angular/core'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { provideRouter, RouterModule } from '@angular/router' 6 | import { AppComponent } from './app.component'; 7 | import { AppRoutingModule, routes } from './app.routes'; 8 | import { CrisisModule } from './crisis-list/module' 9 | import { HeroesModule } from './heroes-list/module' 10 | 11 | 12 | registerLocaleData(zh); 13 | 14 | @NgModule({ 15 | // schemas: [], 16 | declarations: [ 17 | AppComponent, 18 | ], 19 | imports: [ 20 | BrowserModule, 21 | // RouterModule, 22 | AppRoutingModule, 23 | CrisisModule, 24 | HeroesModule, 25 | ], 26 | exports: [ 27 | ], 28 | providers: [ 29 | // provideRouter(routes), // use with RouterModule 30 | ], 31 | bootstrap: [AppComponent], 32 | }) 33 | export class AppModule { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /demos/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { CrisisListComponent } from './crisis-list/component'; 4 | import { HeroesListComponent } from './heroes-list/component'; 5 | import { NotFoundComponent } from './not-found.component'; 6 | 7 | export const routes: Routes = [ 8 | { path: 'crisis-list', component: CrisisListComponent }, 9 | { path: 'heroes-list', component: HeroesListComponent }, 10 | { path: '', redirectTo: '/crisis-list', pathMatch: 'full' }, 11 | { path: '**', component: NotFoundComponent }, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forRoot(routes)], 16 | exports: [RouterModule], 17 | }) 18 | export class AppRoutingModule { } 19 | -------------------------------------------------------------------------------- /demos/app.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import { AppModule } from './app.module'; 4 | 5 | platformBrowserDynamic().bootstrapModule(AppModule).catch((e) => console.error(e)); -------------------------------------------------------------------------------- /demos/crisis-list/component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewEncapsulation, OnChanges, OnDestroy, AfterContentChecked, ChangeDetectionStrategy } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-crisis-list', 5 | encapsulation: ViewEncapsulation.Emulated, 6 | changeDetection: ChangeDetectionStrategy.OnPush, 7 | templateUrl: `./crisis-list.component.html`, 8 | }) 9 | export class CrisisListComponent implements OnInit, OnChanges, OnDestroy, AfterContentChecked { 10 | 11 | constructor () { 12 | } 13 | 14 | crisisName = '' 15 | 16 | public ngOnInit () { 17 | console.log('CrisisListComponent') 18 | } 19 | 20 | ngOnChanges() { 21 | console.log('ngOnChanges') 22 | } 23 | 24 | // 自定义变更检查 25 | ngDoCheck() { 26 | console.log('ngDoCheck', this.crisisName) 27 | } 28 | 29 | // 内容投影初始化完成后的逻辑 30 | ngAfterContentInit() { 31 | console.log('ngAfterContentInit') 32 | } 33 | 34 | // 每次内容变更检测后的逻辑 35 | ngAfterContentChecked() { 36 | console.log('ngAfterContentChecked', this.crisisName) 37 | } 38 | 39 | // 视图初始化完成后的逻辑 40 | ngAfterViewInit() { 41 | console.log('ngAfterViewInit') 42 | } 43 | 44 | // 每次视图变更检测后的逻辑 45 | ngAfterViewChecked() { 46 | console.log('ngAfterViewChecked', this.crisisName) 47 | } 48 | 49 | // 清理工作 50 | ngOnDestroy() { 51 | console.log('ngOnDestroy') 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /demos/crisis-list/crisis-list.component.html: -------------------------------------------------------------------------------- 1 |

CRISIS CENTER

2 |

Get your crisis here

3 |
4 | 5 | Your crisis name is: {{ crisisName }} 6 |
-------------------------------------------------------------------------------- /demos/crisis-list/module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | // import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { CrisisListComponent } from './component' 5 | 6 | @NgModule({ 7 | declarations: [CrisisListComponent], 8 | exports: [CrisisListComponent], // 导出组件 9 | imports: [ 10 | FormsModule, 11 | ], 12 | }) 13 | export class CrisisModule { } -------------------------------------------------------------------------------- /demos/heroes-list/component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewEncapsulation } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-heroes-list', 5 | encapsulation: ViewEncapsulation.Emulated, 6 | templateUrl: `./heroes-list.component.html`, 7 | }) 8 | export class HeroesListComponent implements OnInit { 9 | 10 | constructor () { 11 | } 12 | 13 | public ngOnInit () { 14 | console.log('HeroesListComponent') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /demos/heroes-list/heroes-list.component.html: -------------------------------------------------------------------------------- 1 |

HEROES

2 |

Get your heroes here

-------------------------------------------------------------------------------- /demos/heroes-list/module.ts: -------------------------------------------------------------------------------- 1 | import { Component, NgModule, OnInit, ViewEncapsulation } from '@angular/core'; 2 | import { HeroesListComponent } from './component' 3 | // import { CommonModule } from '@angular/common'; 4 | 5 | @NgModule({ 6 | declarations: [HeroesListComponent], 7 | exports: [HeroesListComponent], // 导出组件 8 | // imports: [CommonModule] 9 | }) 10 | export class HeroesModule { } -------------------------------------------------------------------------------- /demos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CMS-管理后台 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /demos/miniapp/about.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-about', 5 | template: `

About Page

` 6 | }) 7 | export class AboutComponent {} 8 | -------------------------------------------------------------------------------- /demos/miniapp/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { HomeComponent } from './home.component'; 4 | import { AboutComponent } from './about.component'; 5 | 6 | const routes: Routes = [ 7 | { path: '', component: HomeComponent }, // 根路径显示 HomeComponent 8 | { path: 'about', component: AboutComponent } // /about 显示 AboutComponent 9 | ]; 10 | 11 | @NgModule({ 12 | imports: [RouterModule.forRoot(routes)], 13 | exports: [RouterModule] 14 | }) 15 | export class AppRoutingModule {} 16 | -------------------------------------------------------------------------------- /demos/miniapp/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | template: ` 6 |

Angular Routing Example

7 | 11 | 12 | ` 13 | }) 14 | export class AppComponent {} 15 | -------------------------------------------------------------------------------- /demos/miniapp/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { AppComponent } from './app.component'; 4 | import { HomeComponent } from './home.component'; 5 | import { AboutComponent } from './about.component'; 6 | import { AppRoutingModule } from './app-routing.module'; // 导入路由模块 7 | 8 | @NgModule({ 9 | declarations: [AppComponent, HomeComponent, AboutComponent], 10 | imports: [BrowserModule, AppRoutingModule], // 引入 BrowserModule 和 AppRoutingModule 11 | bootstrap: [AppComponent] 12 | }) 13 | export class AppModule {} 14 | -------------------------------------------------------------------------------- /demos/miniapp/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | template: `

Home Page

` 6 | }) 7 | export class HomeComponent {} 8 | -------------------------------------------------------------------------------- /demos/miniapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular Routing Example 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /demos/miniapp/index.ts: -------------------------------------------------------------------------------- 1 | import "@angular/compiler" 2 | import("./main") -------------------------------------------------------------------------------- /demos/miniapp/main.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import { AppModule } from './app.module'; 4 | 5 | platformBrowserDynamic().bootstrapModule(AppModule) 6 | .catch(err => console.error(err)); 7 | -------------------------------------------------------------------------------- /demos/not-found.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-not-found', 5 | template: `

404 - Page Not Found

`, 6 | }) 7 | export class NotFoundComponent {} 8 | -------------------------------------------------------------------------------- /demos/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "ESNext", 12 | "typeRoots": ["node_modules/@types"], 13 | "lib": ["es2017", "dom"], 14 | "baseUrl": "./demos", 15 | }, 16 | "include": ["./**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /demos/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { AngularWebpackPlugin } = require('@ngtools/webpack'); 2 | const path = require('path'); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin") 4 | 5 | const _PROD_ = process.env.NODE_ENV === 'production' 6 | 7 | console.log(` 8 | This is mini app with Angular Router. 9 | `) 10 | 11 | module.exports = { 12 | devServer: { 13 | port: '9100', 14 | historyApiFallback: true, 15 | client: { 16 | overlay: { 17 | warnings: false, 18 | errors: true, 19 | }, 20 | }, 21 | }, 22 | mode: _PROD_ ? 'production' : 'development', 23 | entry: './demos/app.ts', // 入口文件 24 | output: { 25 | path: path.resolve(__dirname, 'dist'), 26 | filename: 'bundle.js', 27 | publicPath: '/', 28 | assetModuleFilename: 'static/assets/[hash][ext][query]', 29 | }, 30 | resolve: { 31 | extensions: ['.ts', '.js'], // 解析 .ts 和 .js 文件 32 | }, 33 | module: { 34 | rules: [ 35 | { 36 | test: /\.ts$/, 37 | use: [ 38 | { 39 | loader: '@ngtools/webpack', 40 | }, 41 | ], 42 | }, 43 | { 44 | test: /\.html$/, 45 | use: 'html-loader', 46 | }, 47 | ], 48 | }, 49 | plugins: [ 50 | new AngularWebpackPlugin({ 51 | tsconfig: './demos/tsconfig.json', 52 | jitMode: true, 53 | }), 54 | new HtmlWebpackPlugin({ 55 | title: 'CMS-FE DEV', 56 | filename: 'index.html', 57 | template: './demos/index.html', 58 | inject: 'body', 59 | templateParameters: false, 60 | }) 61 | ], 62 | }; 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-typescript", 3 | "version": "1.2.0", 4 | "description": "Angular18 for CMS", 5 | "main": "index.js", 6 | "author": "xpioneer", 7 | "keywords": [ 8 | "Angular18", 9 | "Typescript", 10 | "HttpInterceptor", 11 | "lazyload", 12 | "ng-zorro-antd", 13 | "loadChildren" 14 | ], 15 | "license": "MIT", 16 | "scripts": { 17 | "start": "NODE_ENV=development webpack-dev-server --config conf/webpack.dev.conf.js", 18 | "dev": "yarn start", 19 | "clean": "rm -rf dist", 20 | "demo": "webpack-dev-server --config ./demos/webpack.config.js", 21 | "build": "NODE_ENV=production webpack --config conf/webpack.prod.conf.js", 22 | "test": "NODE_ENV=development yarn run dll && webpack --config conf/webpack.dev.conf.js", 23 | "lint": "NODE_ENV=development node_modules/.bin/tslint -c tslint.json -p tsconfig.json", 24 | "lintfix": "NODE_ENV=development node_modules/.bin/tslint -c tslint.json -p tsconfig.json --fix --force" 25 | }, 26 | "dependencies": { 27 | "@angular/animations": "^18.2.5", 28 | "@angular/common": "^18.2.5", 29 | "@angular/core": "^18.2.5", 30 | "@angular/forms": "^18.2.5", 31 | "@angular/platform-browser": "^18.2.5", 32 | "@angular/router": "^18.2.5", 33 | "@ant-design/icons-angular": "^18.0.0", 34 | "core-js": "^3.38.1", 35 | "cron-parser": "^4.9.0", 36 | "d3-selection": "^3.0.0", 37 | "d3-zoom": "^3.0.0", 38 | "dagre-compound": "^0.0.13", 39 | "date-fns": "^4.1.0", 40 | "dayjs": "^1.11.13", 41 | "echarts": "^5.5.1", 42 | "monaco-editor": "^0.52.0", 43 | "ng-zorro-antd": "^18.1.1", 44 | "quill": "^1.3.2", 45 | "rxjs": "^7.8.1", 46 | "zone.js": "^0.15.0" 47 | }, 48 | "devDependencies": { 49 | "@angular/compiler": "^18.2.5", 50 | "@angular/compiler-cli": "^18.2.5", 51 | "@angular/platform-browser-dynamic": "^18.2.5", 52 | "@ngtools/webpack": "^18.2.5", 53 | "@types/d3-zoom": "^3.0.8", 54 | "@types/node": "^22.6.1", 55 | "copy-webpack-plugin": "^12.0.2", 56 | "css-loader": "^7.1.2", 57 | "html-loader": "^5.1.0", 58 | "html-webpack-plugin": "^5.6.0", 59 | "less": "^4.2.0", 60 | "less-loader": "^12.2.0", 61 | "mini-css-extract-plugin": "^2.9.1", 62 | "optimize-css-assets-webpack-plugin": "^6.0.1", 63 | "postcss-loader": "^8.1.1", 64 | "postcss-preset-env": "^10.0.5", 65 | "raw-loader": "^4.0.2", 66 | "style-loader": "^4.0.0", 67 | "sw-precache-webpack-plugin": "^0.11.5", 68 | "tailwindcss": "^3.4.14", 69 | "typescript": "5.5.4", 70 | "uglifyjs-webpack-plugin": "^2.2.0", 71 | "webpack": "^5.94.0", 72 | "webpack-cli": "^5.1.4", 73 | "webpack-dev-server": "^5.1.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/antd/demos.ts: -------------------------------------------------------------------------------- 1 | import { Component, NgModule } from '@angular/core' 2 | import { NzFlexDirective } from 'ng-zorro-antd/flex'; 3 | 4 | // demo for NzFlexDirective use specially 5 | 6 | /** 7 | * your component 8 | */ 9 | @Component({ 10 | selector: 'app-your-component', 11 | templateUrl: './your-component.component.html', 12 | styleUrls: ['./your-component.component.css'] 13 | }) 14 | export class YourComponent { 15 | // ... 16 | } 17 | 18 | @NgModule({ 19 | declarations: [ 20 | YourComponent, 21 | NzFlexDirective // add NzFlexDirective to declarations 22 | ], 23 | // ... other configs 24 | }) 25 | export class YourModule { } -------------------------------------------------------------------------------- /src/antd/directive.ts: -------------------------------------------------------------------------------- 1 | 2 | export { NzDateCellDirective, NzMonthCellDirective, NzDateFullCellDirective, NzMonthFullCellDirective } from 'ng-zorro-antd/calendar'; 3 | export { NzCardGridDirective } from 'ng-zorro-antd/card'; 4 | export { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; 5 | export { NzCollapseModule } from 'ng-zorro-antd/collapse'; 6 | export { NzCommentAvatarDirective, NzCommentContentDirective, NzCommentActionHostDirective } from 'ng-zorro-antd/comment'; 7 | export { NzWaveDirective } from 'ng-zorro-antd/core/wave'; 8 | export { NzDropDownADirective, NzDropDownDirective, NzDropdownButtonDirective, NzDropDownModule, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown'; 9 | export { NzFlexDirective } from 'ng-zorro-antd/flex'; 10 | export { NzFormDirective } from 'ng-zorro-antd/form'; 11 | export { NzRowDirective, NzColDirective } from 'ng-zorro-antd/grid'; 12 | export { NzIconDirective } from 'ng-zorro-antd/icon'; 13 | export { NzImageDirective } from 'ng-zorro-antd/image'; 14 | export { NzInputDirective, NzAutosizeDirective, NzInputGroupWhitSuffixOrPrefixDirective } from 'ng-zorro-antd/input'; 15 | export { NzInputNumberGroupWhitSuffixOrPrefixDirective } from 'ng-zorro-antd/input-number'; 16 | export { NzListGridDirective, NzListLoadMoreDirective, NzListItemMetaDescriptionComponent } from 'ng-zorro-antd/list'; 17 | export { NzMentionTriggerDirective, NzMentionSuggestionDirective } from 'ng-zorro-antd/mention'; 18 | export { NzMenuDirective, NzMenuDividerDirective } from 'ng-zorro-antd/menu'; 19 | export { NzModalTitleDirective, NzModalContentDirective, NzModalFooterDirective } from 'ng-zorro-antd/modal'; 20 | export { 21 | NzPageHeaderTagDirective, NzPageHeaderTitleDirective, NzPageHeaderAvatarDirective, 22 | NzPageHeaderBreadcrumbDirective, NzPageHeaderFooterDirective, NzPageHeaderExtraDirective, 23 | NzPageHeaderContentDirective, NzPageHeaderSubtitleDirective 24 | } from 'ng-zorro-antd/page-header'; 25 | export { NzPopconfirmDirective } from 'ng-zorro-antd/popconfirm'; 26 | export { NzPopoverDirective } from 'ng-zorro-antd/popover'; 27 | export { 28 | NzResultIconDirective, NzResultExtraDirective, NzResultTitleDirective, 29 | NzResultContentDirective, NzResultSubtitleDirective 30 | } from 'ng-zorro-antd/result'; 31 | export { NzSkeletonElementDirective } from 'ng-zorro-antd/skeleton'; 32 | export { NzSpaceDirection, NzSpaceItemDirective } from 'ng-zorro-antd/space'; 33 | export { 34 | NzCellAlignDirective, NzTrDirective, NzTableDataService, NzTrExpandDirective, 35 | NzCellFixedDirective, NzRowIndentDirective, NzTableCellDirective, NzThMeasureDirective, 36 | NzCellEllipsisDirective, NzCustomColumnDirective, NzCellBreakWordDirective, 37 | NzTableInnerDefaultComponent, NzRowExpandButtonDirective, NzTableVirtualScrollDirective, 38 | } from 'ng-zorro-antd/table'; 39 | export { 40 | NzTabDirective, NzTabLinkDirective, NzTabsCanDeactivateFn, NzTabLinkTemplateDirective 41 | } from 'ng-zorro-antd/tabs'; 42 | export { NzTooltipDirective, NzTooltipBaseDirective } from 'ng-zorro-antd/tooltip'; 43 | export { 44 | NzTreeNodeDefDirective, NzTreeNodeOutletDirective, NzTreeNodeToggleDirective, 45 | NzTreeNodePaddingDirective, NzTreeNodeIndentLineDirective, NzTreeNodeNoopToggleDirective, 46 | NzTreeNodeToggleActiveIconDirective, NzTreeNodeToggleRotateIconDirective, 47 | NzTreeVirtualScrollNodeOutletDirective 48 | } from 'ng-zorro-antd/tree-view'; 49 | export { NzResizeDirection, NzResizableDirective } from 'ng-zorro-antd/resizable'; 50 | export { 51 | NzGraphEdgeDirective, NzGraphNodeDirective, NzGraphZoomDirective, NzGraphGroupNodeDirective 52 | } from 'ng-zorro-antd/graph'; 53 | -------------------------------------------------------------------------------- /src/antd/module.ts: -------------------------------------------------------------------------------- 1 | 2 | export { NzAffixModule } from 'ng-zorro-antd/affix'; 3 | export { NzAlertModule } from 'ng-zorro-antd/alert'; 4 | export { NzAnchorModule } from 'ng-zorro-antd/anchor'; 5 | export { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; 6 | export { NzAvatarModule } from 'ng-zorro-antd/avatar'; 7 | export { NzBackTopModule } from 'ng-zorro-antd/back-top'; 8 | export { NzBadgeModule } from 'ng-zorro-antd/badge'; 9 | export { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb'; 10 | export { NzButtonModule } from 'ng-zorro-antd/button'; 11 | export { NzCalendarModule } from 'ng-zorro-antd/calendar'; 12 | export { NzCardModule } from 'ng-zorro-antd/card'; 13 | export { NzCarouselModule } from 'ng-zorro-antd/carousel'; 14 | export { NzCascaderModule } from 'ng-zorro-antd/cascader'; 15 | export { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; 16 | export { NzCollapseModule } from 'ng-zorro-antd/collapse'; 17 | export { NzCommentModule } from 'ng-zorro-antd/comment'; 18 | export { NzNoAnimationModule } from 'ng-zorro-antd/core/no-animation'; 19 | export { NzTransButtonModule } from 'ng-zorro-antd/core/trans-button'; 20 | export { NzWaveModule } from 'ng-zorro-antd/core/wave'; 21 | export { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; 22 | export { NzDescriptionsModule } from 'ng-zorro-antd/descriptions'; 23 | export { NzDividerModule } from 'ng-zorro-antd/divider'; 24 | export { NzDrawerModule } from 'ng-zorro-antd/drawer'; 25 | export { NzDropDownModule } from 'ng-zorro-antd/dropdown'; 26 | export { NzEmptyModule } from 'ng-zorro-antd/empty'; 27 | export { NzFlexModule } from 'ng-zorro-antd/flex'; 28 | export { NzFormModule } from 'ng-zorro-antd/form'; 29 | export { NzGridModule } from 'ng-zorro-antd/grid'; 30 | export { NzI18nModule } from 'ng-zorro-antd/i18n'; 31 | export { NzIconModule } from 'ng-zorro-antd/icon'; 32 | export { NzImageModule } from 'ng-zorro-antd/image'; 33 | export { NzInputModule } from 'ng-zorro-antd/input'; 34 | export { NzInputNumberModule } from 'ng-zorro-antd/input-number'; 35 | export { NzLayoutModule } from 'ng-zorro-antd/layout'; 36 | export { NzListModule } from 'ng-zorro-antd/list'; 37 | export { NzMentionModule } from 'ng-zorro-antd/mention'; 38 | export { NzMenuModule } from 'ng-zorro-antd/menu'; 39 | export { NzMessageModule } from 'ng-zorro-antd/message'; 40 | export { NzModalModule } from 'ng-zorro-antd/modal'; 41 | export { NzNotificationModule } from 'ng-zorro-antd/notification'; 42 | export { NzPageHeaderModule } from 'ng-zorro-antd/page-header'; 43 | export { NzPaginationModule } from 'ng-zorro-antd/pagination'; 44 | export { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; 45 | export { NzPopoverModule } from 'ng-zorro-antd/popover'; 46 | export { NzProgressModule } from 'ng-zorro-antd/progress'; 47 | export { NzRadioModule } from 'ng-zorro-antd/radio'; 48 | export { NzRateModule } from 'ng-zorro-antd/rate'; 49 | export { NzResultModule } from 'ng-zorro-antd/result'; 50 | export { NzSegmentedModule } from 'ng-zorro-antd/segmented'; 51 | export { NzSelectModule } from 'ng-zorro-antd/select'; 52 | export { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; 53 | export { NzSliderModule } from 'ng-zorro-antd/slider'; 54 | export { NzSpaceModule } from 'ng-zorro-antd/space'; 55 | export { NzSpinModule } from 'ng-zorro-antd/spin'; 56 | export { NzStatisticModule } from 'ng-zorro-antd/statistic'; 57 | export { NzStepsModule } from 'ng-zorro-antd/steps'; 58 | export { NzSwitchModule } from 'ng-zorro-antd/switch'; 59 | export { NzTableModule } from 'ng-zorro-antd/table'; 60 | export { NzTabsModule } from 'ng-zorro-antd/tabs'; 61 | export { NzTagModule } from 'ng-zorro-antd/tag'; 62 | export { NzTimePickerModule } from 'ng-zorro-antd/time-picker'; 63 | export { NzTimelineModule } from 'ng-zorro-antd/timeline'; 64 | export { NzToolTipModule } from 'ng-zorro-antd/tooltip'; 65 | export { NzTransferModule } from 'ng-zorro-antd/transfer'; 66 | export { NzTreeModule } from 'ng-zorro-antd/tree'; 67 | export { NzTreeViewModule } from 'ng-zorro-antd/tree-view'; 68 | export { NzTreeSelectModule } from 'ng-zorro-antd/tree-select'; 69 | export { NzTypographyModule } from 'ng-zorro-antd/typography'; 70 | export { NzUploadModule } from 'ng-zorro-antd/upload'; 71 | export { NzResizableModule } from 'ng-zorro-antd/resizable'; 72 | export { NzPipesModule } from 'ng-zorro-antd/pipes'; 73 | export { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'; 74 | export { NzGraphModule } from 'ng-zorro-antd/graph'; 75 | export { NzCronExpressionModule } from 'ng-zorro-antd/cron-expression'; 76 | export { NzQRCodeModule } from 'ng-zorro-antd/qr-code'; 77 | export { NzWaterMarkModule } from 'ng-zorro-antd/water-mark'; 78 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import { AppModule } from './app/app.module'; 4 | // import './assets/less/index.less'; 5 | import './styles/index.less'; 6 | import '@/styles/tailwind.css' 7 | // require('../node_modules/ng-zorro-antd/ng-zorro-antd.min.css'); 8 | // import 'quill/dist/quill.bubble.css'; 9 | // import 'quill/dist/quill.core.css'; 10 | import 'quill/dist/quill.snow.css'; 11 | import registerServiceWorker from './registerServiceWorker' 12 | 13 | // declare var module: any; 14 | // if (module.hot) { 15 | // module.hot.accept(); 16 | // } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | enableProdMode(); 20 | } 21 | platformBrowserDynamic().bootstrapModule(AppModule).catch((e) => console.error(e)); 22 | registerServiceWorker() -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewEncapsulation } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | encapsulation: ViewEncapsulation.Emulated, 6 | template: '', 7 | }) 8 | export class AppComponent implements OnInit { 9 | 10 | constructor () { 11 | } 12 | 13 | public ngOnInit () { 14 | console.log('app entry') 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { registerLocaleData } from '@angular/common'; 2 | import zh from '@angular/common/locales/zh'; 3 | import { HttpClientModule, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; 4 | import { LOCALE_ID, NgModule } from '@angular/core'; 5 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 6 | import { BrowserModule } from '@angular/platform-browser'; 7 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 8 | import { provideRouter, RouterModule } from '@angular/router'; 9 | import { NZ_ICONS } from 'ng-zorro-antd/icon'; 10 | import { NZ_I18N, zh_CN } from 'ng-zorro-antd/i18n'; 11 | import { IconDefinition } from '@ant-design/icons-angular' 12 | import { UserOutline, LockOutline, SettingOutline, AppstoreOutline, CalculatorOutline, LineChartOutline, SmileOutline, BulbOutline, PlusOutline, GlobalOutline } from '@ant-design/icons-angular/icons' 13 | 14 | import { BreadCrumbComponent, HeaderComponent, SidebarComponent } from '../components/shared'; 15 | import { AppComponent } from './app.component'; 16 | import { AppRouting, appRoutes } from './app.routing'; 17 | import { HomeComponent } from './home'; 18 | import { LoginComponent } from './login/login.component'; 19 | 20 | import { HttpClientInterceptor } from '@utils/httpInterceptor'; 21 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 22 | import { AuthService } from '../utils/auth/auth.service'; 23 | import { HelperService } from '../utils/httpInterceptor/helper.service'; 24 | import { Params } from '../utils/params.service'; 25 | import { ZorroAntdModule } from '@/antd/ngModule' 26 | 27 | registerLocaleData(zh); 28 | const icons: IconDefinition[] = [ 29 | UserOutline, LockOutline, SettingOutline, AppstoreOutline, 30 | CalculatorOutline, LineChartOutline, SmileOutline, BulbOutline, 31 | PlusOutline, GlobalOutline, 32 | ] 33 | 34 | @NgModule({ 35 | // schemas: [], 36 | declarations: [ 37 | AppComponent, 38 | HomeComponent, 39 | LoginComponent, 40 | HeaderComponent, 41 | SidebarComponent, 42 | BreadCrumbComponent, 43 | // NzPageHeaderBreadcrumbDirective, 44 | // NzMenuDirective, 45 | ], 46 | imports: [ 47 | BrowserModule, 48 | BrowserAnimationsModule, 49 | FormsModule, 50 | ReactiveFormsModule, 51 | // HttpClientModule, 52 | RouterModule, 53 | // AppRouting, 54 | ZorroAntdModule, 55 | ], 56 | exports: [ 57 | 58 | // NzMenuModule, 59 | ], 60 | providers: [ 61 | provideRouter(appRoutes), 62 | provideHttpClient(withInterceptorsFromDi()), 63 | { provide: NZ_I18N, useValue: zh_CN }, 64 | { provide: NZ_ICONS, useValue: icons }, 65 | { 66 | provide: HTTP_INTERCEPTORS, 67 | useClass: HttpClientInterceptor, 68 | multi: true, 69 | }, 70 | Params, 71 | HelperService, 72 | AuthGuard, 73 | AuthService, 74 | ], 75 | bootstrap: [AppComponent], 76 | }) 77 | export class AppModule { 78 | constructor () {} 79 | } 80 | -------------------------------------------------------------------------------- /src/app/app.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '../utils/auth/auth-guard.service'; 4 | import { HomeComponent } from './home'; 5 | import { LoginComponent } from './login/login.component'; 6 | 7 | export const appRoutes: Routes = [ 8 | { 9 | path: 'login', 10 | component: LoginComponent, 11 | }, 12 | { 13 | path: '', 14 | component: HomeComponent, 15 | children: [ 16 | { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, 17 | { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module') }, 18 | { path: 'article', loadChildren: () => import('./article/article.module') }, 19 | { path: 'articletype', loadChildren: () => import('./articletype/articletype.module') }, 20 | { path: 'tag', loadChildren: () => import('./tag/tag.module') }, 21 | { path: 'user', loadChildren: () => import('./user/user.module') }, 22 | { path: 'comment', loadChildren: () => import('./comment/comment.module') }, 23 | { path: 'charts', loadChildren: () => import('./charts/chart.module') }, 24 | { path: 'systemlog', loadChildren: () => import('./systemlogs/systemlog.module') }, 25 | { path: 'doubleball', loadChildren: () => import('./doubleball/doubleball.module') }, 26 | { path: 'demos', loadChildren: () => import('./demos/demos.module') }, 27 | { path: '**', redirectTo: 'dashboard', pathMatch: 'full' }, 28 | ], 29 | }, 30 | ]; 31 | 32 | @NgModule({ 33 | imports: [RouterModule.forRoot(appRoutes, { useHash: false })], 34 | exports: [RouterModule], 35 | }) 36 | export class AppRouting { } 37 | -------------------------------------------------------------------------------- /src/app/article/addarticle/addarticle.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class AddArticleService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public insertArticle (data: any) { 13 | return this.http.post('/article', data); 14 | } 15 | 16 | public getTags () { 17 | return this.http.get('/tag?' + this.params.format({ 18 | current_page: 1, 19 | per_page: 999, 20 | })); 21 | } 22 | 23 | public getTypes () { 24 | return this.http.get('/articletype?' + this.params.format({ 25 | current_page: 1, 26 | per_page: 999, 27 | })); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/app/article/addarticle/addarticle.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { ArticleModel, ITag } from '../model/article.model'; 6 | import { AddArticleService } from './addarticle.service'; 7 | 8 | @Component({ 9 | selector: 'app-add-article', 10 | templateUrl: './addarticle.html', 11 | // styles: [``], 12 | }) 13 | export class AddArticleComponent implements OnInit { 14 | public isConfirmLoading = false; 15 | public addArticle: ArticleModel = new ArticleModel(); 16 | @ViewChild('form') private form: NgForm; 17 | 18 | public tagList: ITag[] = []; 19 | public checkedTag: AnyObject = {}; 20 | public typeAjaxList: any[] = []; 21 | 22 | constructor ( 23 | private router: Router, 24 | private addArticleService: AddArticleService, 25 | private notification: NzNotificationService, 26 | ) { } 27 | 28 | public ngOnInit () { 29 | this.getTypeList(); 30 | this.getTagList(); 31 | } 32 | 33 | public save () { 34 | for (const i in this.form.controls) { 35 | this.form.controls[ i ].markAsDirty(); 36 | } 37 | this.addArticle.tag = this.getCheckedTag(); 38 | if (this.form.valid) { 39 | this.isConfirmLoading = true; 40 | this.addArticleService.insertArticle(this.addArticle).subscribe((res: any) => { 41 | this.isConfirmLoading = false; 42 | this.router.navigate(['/article']); 43 | }, (err: any) => { 44 | this.isConfirmLoading = false; 45 | }); 46 | } 47 | } 48 | 49 | public getTypeList () { 50 | this.addArticleService.getTypes().subscribe((res: any) => { 51 | this.typeAjaxList = res.data; 52 | }, (err: any) => { 53 | // 54 | }); 55 | } 56 | 57 | public getTagList () { 58 | this.addArticleService.getTags().subscribe((res: any) => { 59 | this.tagList = res.data; 60 | }, (err: any) => { 61 | // 62 | }); 63 | } 64 | 65 | public getCheckedTag () { 66 | const arr = []; 67 | for (const item of this.tagList) { 68 | if (this.checkedTag[item.id]) { 69 | arr.push(item.name); 70 | } 71 | } 72 | return arr.join(','); 73 | } 74 | 75 | public back () { 76 | this.router.navigate(['article']); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/app/article/article.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-article', 5 | template: '', 6 | }) 7 | export class ArticleComponent { 8 | } 9 | -------------------------------------------------------------------------------- /src/app/article/article.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { EditorModule } from '@components/editor/editor.module'; 6 | import { UploadFileModule } from '@components/upload-file/upload-file.module'; 7 | import { AddArticleComponent } from './addarticle/addarticle'; 8 | import { AddArticleService } from './addarticle/addarticle.service'; 9 | import { ArticleComponent } from './article.component'; 10 | import { ArticleRouting } from './article.routing'; 11 | import { ArticleListComponent } from './articlelist/articlelist'; 12 | import { ArticleListService } from './articlelist/articlelist.service'; 13 | import { EditArticleComponent } from './editarticle/editarticle'; 14 | import { EditArticleService } from './editarticle/editarticle.service'; 15 | import { ZorroAntdModule } from '@/antd/ngModule' 16 | 17 | @NgModule({ 18 | imports: [ 19 | FormsModule, 20 | // ReactiveFormsModule, 21 | CommonModule, 22 | ArticleRouting, 23 | // NgZorroAntdModule.forRoot(), 24 | UploadFileModule, 25 | EditorModule, 26 | ZorroAntdModule, 27 | ], 28 | declarations: [ 29 | ArticleComponent, 30 | ArticleListComponent, 31 | AddArticleComponent, 32 | EditArticleComponent, 33 | ], 34 | providers: [ 35 | ArticleListService, 36 | AddArticleService, 37 | EditArticleService, 38 | ], 39 | }) 40 | export default class ArticleModule {} 41 | -------------------------------------------------------------------------------- /src/app/article/article.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { AddArticleComponent } from './addarticle/addarticle'; 5 | import { ArticleComponent } from './article.component'; 6 | import { ArticleListComponent } from './articlelist/articlelist'; 7 | import { EditArticleComponent } from './editarticle/editarticle'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: '', 12 | canActivateChild: [AuthGuard], 13 | component: ArticleComponent, 14 | children: [ 15 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 16 | { path: 'list', component: ArticleListComponent }, 17 | { path: 'add', component: AddArticleComponent }, 18 | { path: 'edit/:id', component: EditArticleComponent }, 19 | ], 20 | }, 21 | ]; 22 | 23 | @NgModule({ 24 | imports: [RouterModule.forChild(routes)], 25 | exports: [RouterModule], 26 | }) 27 | export class ArticleRouting {} 28 | -------------------------------------------------------------------------------- /src/app/article/articlelist/articlelist.html: -------------------------------------------------------------------------------- 1 | 2 |

文章列表

3 |
4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 |
21 | 22 | 23 | 24 | 34 | 35 | 36 | 文章名称 37 | 图片 38 | 摘要 39 | 浏览数 40 | 原创 41 | 创建时间 42 | 操作 43 | 44 | 45 | 46 | 47 |
{{data.title}}
48 | 49 | 50 |
{{data.abstract}}
51 | 52 | {{data.view_count}} 53 | {{data.is_original?'是':'否'}} 54 | {{data.created_at}} 55 | 56 | 编辑 57 | 删除 58 | 59 | 60 | 61 |
62 | -------------------------------------------------------------------------------- /src/app/article/articlelist/articlelist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { Params } from '../../../utils/params.service'; 5 | 6 | @Injectable() 7 | export class ArticleListService { 8 | constructor ( 9 | private http: HttpClient, 10 | private params: Params, 11 | ) {} 12 | 13 | public getArticleList (data: any) { 14 | return this.http.get('/article?' + this.params.fmtpages(data)); 15 | } 16 | 17 | public deleteArticle (id: string) { 18 | return this.http.delete('/article/' + id); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/article/articlelist/articlelist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { NzModalService } from 'ng-zorro-antd/modal'; 4 | import { ArticleModel } from '../model/article.model'; 5 | import { ArticleListService } from './articlelist.service'; 6 | import { finalize } from 'rxjs'; 7 | 8 | @Component({ 9 | selector: 'app-article-list', 10 | templateUrl: './articlelist.html', 11 | }) 12 | export class ArticleListComponent implements OnInit { 13 | 14 | public current_page = 1; 15 | public per_page = 10; 16 | public total = 1; 17 | public dataSet: ArticleModel[] = []; 18 | public _loading = true; 19 | 20 | public value: any = {}; 21 | public isVisible = false; 22 | public isConfirmLoading = false; 23 | public deleteId: string; 24 | 25 | public options: object[]; 26 | 27 | constructor ( 28 | private router: Router, 29 | private modalService: NzModalService, 30 | private articleListService: ArticleListService, 31 | ) { 32 | } 33 | 34 | public ngOnInit () { 35 | this.clear(); 36 | this.query(); 37 | } 38 | 39 | public query () { 40 | this._loading = true; 41 | this.value.current_page = this.current_page; 42 | this.value.per_page = this.per_page; 43 | this.articleListService.getArticleList(this.value) 44 | .pipe(finalize(() => { this._loading = false; })) 45 | .subscribe((res: any) => { 46 | this.dataSet = res.data; 47 | this.current_page = res.meta.current_page; 48 | this.total = res.meta.total; 49 | }, (e) => { }); 50 | } 51 | 52 | public clear () { 53 | this.value = { 54 | title: { 55 | val: '', 56 | exp: 'like', 57 | }, 58 | abstract: { 59 | val: '', 60 | exp: 'like', 61 | }, 62 | }; 63 | } 64 | 65 | public delArticle (id: string) { 66 | const that = this; 67 | this.modalService.confirm({ 68 | nzTitle : '确认是否删除', 69 | nzContent: '删除后将无法找回这篇文章', 70 | nzOkLoading: true, 71 | nzOnOk () { 72 | return new Promise((resolve) => { 73 | that.articleListService.deleteArticle(id) 74 | .pipe(finalize(() => { resolve(); })) 75 | .subscribe((res: any) => { that.query(); }, (err) => { }); 76 | }); 77 | }, 78 | nzOnCancel () { }, 79 | }); 80 | } 81 | 82 | public getPics (url: string) { 83 | return !!url ? url + '?Authorization-User=' + localStorage.getItem('ACCESS_TOKEN') : ''; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/app/article/editarticle/editarticle.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class EditArticleService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getArticle (id: string) { 13 | return this.http.get('/article/' + id); 14 | } 15 | 16 | public updateArticle (data: any) { 17 | return this.http.put('/article/' + data.id, data); 18 | } 19 | 20 | public getTags () { 21 | return this.http.get('/tag?' + this.params.format({ 22 | current_page: 1, 23 | per_page: 999, 24 | })); 25 | } 26 | 27 | public getTypes () { 28 | return this.http.get('/articletype?' + this.params.format({ 29 | current_page: 1, 30 | per_page: 999, 31 | })); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/app/article/editarticle/editarticle.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { ArticleModel, ITag } from '../model/article.model'; 6 | import { EditArticleService } from './editarticle.service'; 7 | import { finalize } from 'rxjs'; 8 | 9 | @Component({ 10 | selector: 'app-edit-aritcle', 11 | templateUrl: './editarticle.html', 12 | // styles: [``], 13 | }) 14 | export class EditArticleComponent implements OnInit { 15 | public isConfirmLoading = false; 16 | public mainModel: ArticleModel = new ArticleModel(); 17 | @ViewChild('form') private form: NgForm; 18 | 19 | public tagList: ITag[] = []; 20 | public _tagList: object[] = []; 21 | public checkedTag: AnyObject = {}; 22 | public typeAjaxList: any[] = []; 23 | 24 | constructor ( 25 | private router: Router, 26 | private route: ActivatedRoute, 27 | private editArticleService: EditArticleService, 28 | private notification: NzNotificationService, 29 | ) { } 30 | 31 | public ngOnInit () { 32 | this.route.params.subscribe((param) => { 33 | if (param.id) { 34 | this.getData(param.id); 35 | } 36 | this.getTypeList(); 37 | this.getTagList(); 38 | }, (err) => { 39 | this.notification.warning('错误', '参数错误'); 40 | }); 41 | } 42 | 43 | public getData (id: string) { 44 | this.editArticleService.getArticle(id).subscribe((res: any) => { 45 | this.mainModel = res.data; 46 | res.data.tag.split(',').forEach((v: string) => { 47 | this.checkedTag[v] = true; 48 | }); 49 | }, (err: any) => { 50 | // 51 | }); 52 | } 53 | 54 | public getPics (url: string) { 55 | return !!url ? url + '?Authorization-User=' + localStorage.getItem('ACCESS_TOKEN') : ''; 56 | } 57 | 58 | public save () { 59 | for (const i in this.form.controls) { 60 | this.form.controls[ i ].markAsDirty(); 61 | } 62 | this.mainModel.tag = this.getCheckedTag(); 63 | if (this.form.valid) { 64 | this.isConfirmLoading = true; 65 | this.editArticleService.updateArticle(this.mainModel) 66 | .pipe(finalize(() => this.isConfirmLoading = false)) 67 | .subscribe((res: any) => { 68 | this.router.navigate(['/article']); 69 | }, (err: any) => { 70 | }); 71 | } 72 | } 73 | 74 | public getTypeList () { 75 | this.editArticleService.getTypes().subscribe((res: any) => { 76 | this.typeAjaxList = res.data; 77 | }, (err: any) => { 78 | // 79 | }); 80 | } 81 | 82 | public getTagList () { 83 | this.editArticleService.getTags().subscribe((res: any) => { 84 | this.tagList = res.data; 85 | }, (err: any) => { 86 | // 87 | }); 88 | } 89 | 90 | public getCheckedTag () { 91 | return this.tagList.filter((t) => { 92 | return this.checkedTag[t.name]; 93 | }).map((t) => { 94 | return t.name; 95 | }).join(','); 96 | } 97 | 98 | public back () { 99 | this.router.navigate(['article']); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/app/article/model/article.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class ArticleModel { 3 | public id: string; 4 | public title: string; 5 | public is_top: number = 0; 6 | public type_id: string; 7 | public abstract: string; 8 | public pics: string; 9 | public content: string; 10 | public praise: number; 11 | public view_count: number; 12 | public is_original: boolean = true; 13 | public tag: string; 14 | public created_at: string; 15 | } 16 | 17 | export interface ITag { 18 | id: string; 19 | name: string; 20 | } 21 | -------------------------------------------------------------------------------- /src/app/articletype/addarticletype/addarticletype.html: -------------------------------------------------------------------------------- 1 |

添加文章类型

2 |
3 |
4 |

基本信息

5 |
6 | 7 | 8 | 类型名称 9 | 10 | 11 |
必须填写!
12 |
13 | 14 |
15 | 16 | 17 | 备注 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
-------------------------------------------------------------------------------- /src/app/articletype/addarticletype/addarticletype.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class AddArticleTypeService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public addArticleType (data: any) { 13 | return this.http.post('/articletype', data); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/articletype/addarticletype/addarticletype.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { ArticleTypeModel } from '../model/articletype.model'; 6 | import { AddArticleTypeService } from './addarticletype.service'; 7 | 8 | @Component({ 9 | selector: 'app-add-articletype', 10 | templateUrl: './addarticletype.html', 11 | // styles: [], 12 | }) 13 | export class AddArticleTypeComponent implements OnInit { 14 | public isConfirmLoading = false; 15 | public addArticleType: ArticleTypeModel = new ArticleTypeModel(); 16 | @ViewChild('form') private form: NgForm; 17 | 18 | constructor ( 19 | private router: Router, 20 | private addArticleTypeService: AddArticleTypeService, 21 | private notification: NzNotificationService, 22 | ) { } 23 | 24 | public ngOnInit () { 25 | // 26 | } 27 | 28 | public save () { 29 | for (const i in this.form.controls) { 30 | this.form.controls[ i ].markAsDirty(); 31 | } 32 | if (this.form.valid) { 33 | this.isConfirmLoading = true; 34 | this.addArticleTypeService.addArticleType(this.addArticleType).subscribe((res: any) => { 35 | this.isConfirmLoading = false; 36 | this.notification.success('成功', res.msg); 37 | this.router.navigate(['/articletype']); 38 | }, (err: any) => { 39 | this.isConfirmLoading = false; 40 | }); 41 | } 42 | } 43 | 44 | public back () { 45 | this.router.navigate(['./articletype']); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/app/articletype/articletype.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'app-articletype', 6 | template: '', 7 | }) 8 | export class ArticleTypeComponent { 9 | 10 | constructor () { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/articletype/articletype.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { AddArticleTypeComponent } from './addarticletype/addarticletype'; 6 | import { AddArticleTypeService } from './addarticletype/addarticletype.service'; 7 | import { ArticleTypeComponent } from './articletype.component'; 8 | import { ArticleTypeRouting } from './articletype.routing'; 9 | import { ArticleTypeListComponent } from './articletypelist/articletypelist'; 10 | import { ArticleTypeListService } from './articletypelist/articletypelist.service'; 11 | import { EditArticleTypeComponent } from './editarticletype/editarticletype'; 12 | import { EditArticleTypeService } from './editarticletype/editarticletype.service'; 13 | import { ZorroAntdModule } from '@/antd/ngModule' 14 | 15 | @NgModule({ 16 | imports: [ 17 | FormsModule, 18 | // ReactiveFormsModule, 19 | CommonModule, 20 | ArticleTypeRouting, 21 | // NgZorroAntdModule.forRoot(), 22 | ZorroAntdModule, 23 | ], 24 | declarations: [ 25 | ArticleTypeComponent, 26 | ArticleTypeListComponent, 27 | AddArticleTypeComponent, 28 | EditArticleTypeComponent, 29 | ], 30 | providers: [ 31 | ArticleTypeListService, 32 | AddArticleTypeService, 33 | EditArticleTypeService, 34 | ], 35 | }) 36 | export default class ArticleTypeModule {} 37 | -------------------------------------------------------------------------------- /src/app/articletype/articletype.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { AddArticleTypeComponent } from './addarticletype/addarticletype'; 5 | import { ArticleTypeComponent } from './articletype.component'; 6 | import { ArticleTypeListComponent } from './articletypelist/articletypelist'; 7 | import { EditArticleTypeComponent } from './editarticletype/editarticletype'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: '', 12 | canActivateChild: [AuthGuard], 13 | component: ArticleTypeComponent, 14 | children: [ 15 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 16 | { path: 'list', component: ArticleTypeListComponent }, 17 | { path: 'add', component: AddArticleTypeComponent }, 18 | { path: 'edit/:id', component: EditArticleTypeComponent }, 19 | ], 20 | }, 21 | ]; 22 | 23 | @NgModule({ 24 | imports: [RouterModule.forChild(routes)], 25 | exports: [RouterModule], 26 | }) 27 | export class ArticleTypeRouting {} 28 | -------------------------------------------------------------------------------- /src/app/articletype/articletypelist/articletypelist.html: -------------------------------------------------------------------------------- 1 | 2 |

文章类型列表

3 |
4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 |
21 | 22 | 32 | 33 | 34 | ID 35 | 类型名称 36 | 备注 37 | 创建时间 38 | 操作 39 | 40 | 41 | 42 | 43 | {{data.id}} 44 | {{data.type_name}} 45 |
{{data.remark}}
46 | 47 | {{data.created_at}} 48 | 编辑 49 | 50 | 51 |
-------------------------------------------------------------------------------- /src/app/articletype/articletypelist/articletypelist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class ArticleTypeListService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getArticleTypeList (data: any) { 13 | return this.http.get('/articletype?' + this.params.fmtpages(data)); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/articletype/articletypelist/articletypelist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { ArticleTypeModel } from '../model/articletype.model'; 4 | import { ArticleTypeListService } from './articletypelist.service'; 5 | import { finalize } from 'rxjs'; 6 | 7 | @Component({ 8 | selector: 'app-article-list', 9 | templateUrl: './articletypelist.html', 10 | }) 11 | export class ArticleTypeListComponent implements OnInit { 12 | 13 | public current_page = 1; 14 | public per_page = 10; 15 | public total = 1; 16 | public dataSet: ArticleTypeModel[] = []; 17 | public _loading = true; 18 | 19 | public value: any = {}; 20 | public _startDate = ''; 21 | public __endDate = ''; 22 | 23 | public options: object[]; 24 | 25 | constructor ( 26 | private router: Router, 27 | private articleListService: ArticleTypeListService, 28 | ) { 29 | } 30 | 31 | public ngOnInit () { 32 | this.clear(); 33 | this.query(); 34 | } 35 | 36 | public query () { 37 | this._loading = true; 38 | this.value.current_page = this.current_page; 39 | this.value.per_page = this.per_page; 40 | this.articleListService.getArticleTypeList(this.value) 41 | .pipe(finalize(() => { this._loading = false; })) 42 | .subscribe((res: any) => { 43 | this.dataSet = res.data; 44 | this.current_page = res.meta.current_page; 45 | this.total = res.meta.total; 46 | }, (e) => { }); 47 | } 48 | 49 | public clear () { 50 | this.value = { 51 | type_name: { 52 | val: '', 53 | exp: 'like', 54 | }, 55 | remark: { 56 | val: '', 57 | exp: 'like', 58 | }, 59 | created_at: { 60 | val: '', 61 | exp: 'between', 62 | }, 63 | }; 64 | } 65 | 66 | public _startValueChange () { 67 | console.log(this._startDate, this.__endDate); 68 | this.__endDate = this._startDate; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/app/articletype/editarticletype/editarticletype.html: -------------------------------------------------------------------------------- 1 |

编辑文章类型

2 |
3 |
4 |

基本信息

5 |
6 | 7 | 8 | 类型名称 9 | 10 | 11 |
必须填写!
12 |
13 | 14 |
15 | 16 | 17 | 备注 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
-------------------------------------------------------------------------------- /src/app/articletype/editarticletype/editarticletype.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class EditArticleTypeService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getArticleType (id: string) { 13 | return this.http.get('/articletype/' + id); 14 | } 15 | 16 | public updateArticleType (data: any) { 17 | return this.http.put('/articletype/' + data.id, data); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/articletype/editarticletype/editarticletype.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { ArticleTypeModel } from '../model/articletype.model'; 6 | import { EditArticleTypeService } from './editarticletype.service'; 7 | 8 | @Component({ 9 | selector: 'app-edit-articletype', 10 | templateUrl: './editarticletype.html', 11 | // styles: [], 12 | }) 13 | export class EditArticleTypeComponent implements OnInit { 14 | public isConfirmLoading = false; 15 | public editArticleType: ArticleTypeModel = new ArticleTypeModel(); 16 | @ViewChild('form') private form: NgForm; 17 | 18 | constructor ( 19 | private router: Router, 20 | private route: ActivatedRoute, 21 | private editArticleTypeService: EditArticleTypeService, 22 | private notification: NzNotificationService, 23 | ) { } 24 | 25 | public ngOnInit () { 26 | this.route.params.subscribe((param) => { 27 | if (param.id) { 28 | this.getData(param.id); 29 | } 30 | }, (err) => { 31 | this.notification.warning('错误', '参数错误'); 32 | }); 33 | } 34 | 35 | public getData (id: string) { 36 | this.editArticleTypeService.getArticleType(id).subscribe((res: any) => { 37 | this.editArticleType = res.data; 38 | }, (err) => { 39 | // 40 | }); 41 | } 42 | 43 | public save () { 44 | for (const i in this.form.controls) { 45 | this.form.controls[ i ].markAsDirty(); 46 | } 47 | if (this.form.valid) { 48 | this.isConfirmLoading = true; 49 | this.editArticleTypeService.updateArticleType(this.editArticleType).subscribe((res: any) => { 50 | this.isConfirmLoading = false; 51 | this.notification.success('成功', res.msg); 52 | this.router.navigate(['/articletype']); 53 | }, (err: any) => { 54 | this.isConfirmLoading = false; 55 | }); 56 | } 57 | } 58 | 59 | public back () { 60 | this.router.navigate(['./articletype']); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/app/articletype/model/articletype.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class ArticleTypeModel { 3 | public id: string; 4 | public type_name: string; 5 | public remark: string; 6 | public created_at: string; 7 | } 8 | 9 | export class ArticleTypeEditModel { 10 | public type_name: string; 11 | public remark: string; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/charts/chart.html: -------------------------------------------------------------------------------- 1 | 2 |

图表

3 |
4 | 5 |
6 |
7 |
8 |
9 |
10 |
11 | 系统日志每日统计数据 12 |
13 |
14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 | 系统日志分时统计 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 |
31 |
32 |
33 |
34 |
35 | 文章分类统计 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 标签分类统计 44 |
45 |
46 |
47 | 48 |
-------------------------------------------------------------------------------- /src/app/charts/chart.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { ChartComponent } from './chart.component'; 6 | import { ChartService } from './chart.service'; 7 | import { ChartRouting } from './chart.routing'; 8 | import { OutletComponent } from './out-let.component'; 9 | import { ZorroAntdModule } from '@/antd/ngModule' 10 | 11 | @NgModule({ 12 | imports: [ 13 | FormsModule, 14 | // ReactiveFormsModule, 15 | CommonModule, 16 | ChartRouting, 17 | // NgZorroAntdModule.forRoot(), 18 | ZorroAntdModule, 19 | ], 20 | declarations: [ 21 | OutletComponent, 22 | ChartComponent, 23 | ], 24 | providers: [ 25 | ChartService, 26 | ], 27 | }) 28 | export default class ChartModule {} 29 | -------------------------------------------------------------------------------- /src/app/charts/chart.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { ChartComponent } from './chart.component'; 5 | import { OutletComponent } from './out-let.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | canActivateChild: [AuthGuard], 11 | component: OutletComponent, 12 | children: [ 13 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 14 | { path: 'list', component: ChartComponent }, 15 | ], 16 | }, 17 | ]; 18 | 19 | @NgModule({ 20 | imports: [RouterModule.forChild(routes)], 21 | exports: [RouterModule], 22 | }) 23 | export class ChartRouting {} 24 | -------------------------------------------------------------------------------- /src/app/charts/chart.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { Params } from '@utils/params.service'; 5 | 6 | @Injectable() 7 | export class ChartService { 8 | constructor ( 9 | private http: HttpClient, 10 | private params: Params, 11 | ) {} 12 | 13 | public getSystemLog () { 14 | return this.http.get('/chart/systemlog?' + this.params.fmtpages(null)); 15 | } 16 | 17 | public getSystemLogDate (date: string) { 18 | return this.http.get('/chart/systemlogdate?' + this.params.fmtpages({date})); 19 | } 20 | 21 | public getArticleType () { 22 | return this.http.get('/chart/articletype?' + this.params.fmtpages(null)); 23 | } 24 | 25 | public getArticleTag () { 26 | return this.http.get('/chart/articletag?' + this.params.fmtpages(null)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/app/charts/model/chart.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class SystemLogModel { 3 | public date: string; 4 | public total: number; 5 | } 6 | 7 | export interface ISystemLog { 8 | date: string; 9 | total: number; 10 | } 11 | 12 | export interface IArticleType { 13 | type_name: string; 14 | total: number; 15 | } 16 | 17 | export interface IArticleTag { 18 | name: string; 19 | total: number; 20 | } 21 | -------------------------------------------------------------------------------- /src/app/charts/out-let.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-charts-outlet', 5 | template: '', 6 | }) 7 | export class OutletComponent { } 8 | -------------------------------------------------------------------------------- /src/app/comment/comment.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-comment', 5 | template: '', 6 | }) 7 | export class CommentComponent { 8 | } 9 | -------------------------------------------------------------------------------- /src/app/comment/comment.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { CommentComponent } from './comment.component'; 6 | import { CommentListComponent } from './commentlist/commentlist'; 7 | import { CommentListService } from './commentlist/commentlist.service'; 8 | import { CommentDetailComponent } from './commentdetail/commentdetail'; 9 | import { CommentDetailService } from './commentdetail/commentdetail.service'; 10 | import { CommentRouting } from './comment.routing'; 11 | import { ZorroAntdModule } from '@/antd/ngModule' 12 | 13 | @NgModule({ 14 | imports: [ 15 | FormsModule, 16 | // ReactiveFormsModule, 17 | CommonModule, 18 | CommentRouting, 19 | // NgZorroAntdModule.forRoot(), 20 | ZorroAntdModule, 21 | ], 22 | declarations: [ 23 | CommentComponent, 24 | CommentListComponent, 25 | CommentDetailComponent, 26 | ], 27 | providers: [ 28 | CommentListService, 29 | CommentDetailService, 30 | ], 31 | }) 32 | export default class CommentModule {} 33 | -------------------------------------------------------------------------------- /src/app/comment/comment.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { CommentComponent } from './comment.component'; 5 | import { CommentListComponent } from './commentlist/commentlist'; 6 | import { CommentDetailComponent } from './commentdetail/commentdetail'; 7 | 8 | const routes: Routes = [ 9 | { 10 | path: '', 11 | canActivateChild: [AuthGuard], 12 | component: CommentComponent, 13 | children: [ 14 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 15 | { path: 'list', component: CommentListComponent }, 16 | { path: 'detail/:id', component: CommentDetailComponent }, 17 | ], 18 | }, 19 | ]; 20 | 21 | @NgModule({ 22 | imports: [RouterModule.forChild(routes)], 23 | exports: [RouterModule], 24 | }) 25 | export class CommentRouting {} 26 | -------------------------------------------------------------------------------- /src/app/comment/commentdetail/commentdetail.html: -------------------------------------------------------------------------------- 1 | 2 |

评论详情

3 |
4 | 5 |
6 |
7 | 8 | 请求ip 9 | 10 | 11 | 12 | 13 | 文章标题 14 | 15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | 24 | 评论内容 25 | 26 | 27 | 28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 | 文章摘要 36 | 37 | 38 | 39 | 40 |
41 |
42 | 43 |
44 |
45 | 46 | 客户端类型 47 | 48 | 49 | 50 | 51 |
52 |
53 | 54 | 80 | 81 |
82 |
83 | 84 | 创建时间 85 | 86 | 87 | 88 | 89 | 创建者 90 | 91 | 92 | 93 | 94 |
95 |
96 | 97 | 111 | 112 |
113 |
114 | 115 |
116 |
117 | 118 |
-------------------------------------------------------------------------------- /src/app/comment/commentdetail/commentdetail.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class CommentDetailService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getComment (id: string) { 13 | return this.http.get('/comment/' + id); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/comment/commentdetail/commentdetail.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { CommentModel } from '../model/comment.model'; 6 | import { CommentDetailService } from './commentdetail.service'; 7 | 8 | @Component({ 9 | selector: 'app-comment-detail', 10 | templateUrl: './commentdetail.html', 11 | // styles: [``], 12 | }) 13 | export class CommentDetailComponent implements OnInit { 14 | 15 | public mainModel: CommentModel = new CommentModel(); 16 | @ViewChild('form') private form: NgForm; 17 | 18 | public checkedTag = {}; 19 | public typeAjaxList: any[] = []; 20 | 21 | constructor ( 22 | private router: Router, 23 | private route: ActivatedRoute, 24 | private commentDetailService: CommentDetailService, 25 | private notification: NzNotificationService, 26 | ) { } 27 | 28 | public ngOnInit () { 29 | this.route.params.subscribe((param) => { 30 | if (param.id) { 31 | this.getData(param.id); 32 | } 33 | }, (err) => { 34 | this.notification.warning('错误', '参数错误'); 35 | }); 36 | } 37 | 38 | public getData (id: string) { 39 | this.commentDetailService.getComment(id).subscribe((res: any) => { 40 | this.mainModel = res.data; 41 | }, (err: any) => { }); 42 | } 43 | 44 | public back () { 45 | this.router.navigate(['comment']); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/app/comment/commentlist/commentlist.html: -------------------------------------------------------------------------------- 1 |

评论列表

2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 | 27 |
28 |
29 |
30 | 31 | 41 | 42 | 43 | ID 44 | 请求ip 45 | 内容 46 | 文章 47 | 客户端 48 | 文章id 49 | 父级id 50 | 创建时间 51 | 操作 52 | 53 | 54 | 55 | 56 | {{data.id}} 57 | {{data.ip}} 58 | 59 |
{{data.content}}
60 | 61 | {{data.article?data.article.title:''}} 62 | 63 |
{{data.client}}
64 | 65 | {{data.article_id}} 66 | {{data.parent_id}} 67 | {{data.created_at}} 68 | 69 | 详情 70 | 删除 71 | 72 | 73 | 74 |
75 | -------------------------------------------------------------------------------- /src/app/comment/commentlist/commentlist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { Params } from '../../../utils/params.service'; 5 | 6 | @Injectable() 7 | export class CommentListService { 8 | constructor ( 9 | private http: HttpClient, 10 | private params: Params, 11 | ) {} 12 | 13 | public getCommentList (data: any) { 14 | return this.http.get('/comment?' + this.params.fmtpages(data)); 15 | } 16 | 17 | public deleteComment (id: string) { 18 | return this.http.delete('/comment/' + id); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/comment/commentlist/commentlist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | // import { NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { NzModalService } from 'ng-zorro-antd/modal'; 5 | import { CommentModel } from '../model/comment.model'; 6 | import { CommentListService } from './commentlist.service'; 7 | import { finalize } from 'rxjs'; 8 | 9 | @Component({ 10 | selector: 'app-comment-list', 11 | templateUrl: './commentlist.html', 12 | }) 13 | export class CommentListComponent implements OnInit { 14 | // @ViewChild('form') private form: NgForm; 15 | private timer: number = 0; 16 | public current_page = 1; 17 | public per_page = 10; 18 | public total = 1; 19 | public dataSet: CommentModel[] = []; 20 | public _loading = true; 21 | 22 | public value: any = {}; 23 | public isVisible = false; 24 | public isConfirmLoading = false; 25 | public deleteId: string; 26 | 27 | public options: object[]; 28 | 29 | constructor ( 30 | private router: Router, 31 | private modalService: NzModalService, 32 | private commentListService: CommentListService, 33 | ) { 34 | } 35 | 36 | public ngOnInit () { 37 | this.clear(); 38 | this.query(); 39 | } 40 | 41 | public query () { 42 | // if (cur_page) { 43 | // this.current_page = 1; 44 | // } 45 | this.value.current_page = this.current_page; 46 | this.value.per_page = this.per_page; 47 | this._loading = true; 48 | // clearTimeout(this.timer); 49 | // this.timer = setTimeout(() => { 50 | this.commentListService.getCommentList(this.value) 51 | .pipe(finalize(() => { this._loading = false; })) 52 | .subscribe((res: any) => { 53 | this.dataSet = res.data; 54 | this.total = res.meta.total; 55 | }, (e) => { }); 56 | // }); 57 | } 58 | 59 | public clear () { 60 | this.value = { 61 | ip: { 62 | val: '', 63 | exp: 'like', 64 | }, 65 | content: { 66 | val: '', 67 | exp: 'like', 68 | }, 69 | client: { 70 | val: '', 71 | exp: 'like', 72 | }, 73 | created_at: { 74 | val: '', 75 | exp: 'between', 76 | }, 77 | article_title: '', 78 | }; 79 | } 80 | 81 | public delComment (id: string) { 82 | const that = this; 83 | this.modalService.confirm({ 84 | nzTitle : '确认是否删除', 85 | nzContent: '删除后将无法找回这条评论', 86 | nzOkLoading: true, 87 | nzOnOk () { 88 | return new Promise((resolve) => { 89 | that.commentListService.deleteComment(id) 90 | .pipe(finalize(() => { resolve(); })) 91 | .subscribe((res: any) => { that.query(); }, (err: any) => { }); 92 | }); 93 | }, 94 | nzOnCancel () { }, 95 | }); 96 | } 97 | 98 | public ngDoDestory () { 99 | clearTimeout(this.timer); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/app/comment/model/comment.model.ts: -------------------------------------------------------------------------------- 1 | import { UserModel } from '@app/user/model/user.model'; 2 | import { ArticleModel } from '@app/article/model/article.model'; 3 | 4 | export class CommentModel { 5 | public id: string; 6 | public article_id: string; 7 | public content: string; 8 | public ip: string; 9 | public client: string; 10 | public parent_id: string; 11 | public created_by: string; 12 | public created_at: string; 13 | public updated_by: string; 14 | public updated_at: string; 15 | public deleted_by: string; 16 | public deleted_at: string; 17 | public version: number; 18 | public creator: UserModel = new UserModel(); 19 | public article: ArticleModel = new ArticleModel(); 20 | } 21 | -------------------------------------------------------------------------------- /src/app/dashboard/dashboard.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 | 13 | 14 | 15 |
16 | 28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
-------------------------------------------------------------------------------- /src/app/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 3 | import { NgModule } from '@angular/core'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { Dashboard } from './dashboard.component'; 6 | import { DashboardRouting } from './dashboard.routing'; 7 | import { DashBoardService } from './dashboard.service'; 8 | import { NzSelectModule } from '@/antd/module' 9 | import { ZorroAntdModule } from '@/antd/ngModule' 10 | 11 | @NgModule({ 12 | imports: [ 13 | FormsModule, 14 | CommonModule, 15 | DashboardRouting, 16 | // NgZorroAntdModule.forRoot(), 17 | ZorroAntdModule, 18 | // NzSelectModule, 19 | ], 20 | declarations: [ 21 | Dashboard, 22 | ], 23 | providers: [ 24 | DashBoardService, 25 | ], 26 | }) 27 | export default class DashboardModule {} 28 | -------------------------------------------------------------------------------- /src/app/dashboard/dashboard.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '../../utils/auth/auth-guard.service'; 4 | import { Dashboard } from './dashboard.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: '', 9 | component: Dashboard, 10 | canActivate: [AuthGuard], 11 | }, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule], 17 | }) 18 | export class DashboardRouting {} 19 | -------------------------------------------------------------------------------- /src/app/dashboard/dashboard.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpResponse } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | // import { Observable } from 'rxjs/Observable'; 4 | import { Params } from '@utils/params.service'; 5 | 6 | @Injectable() 7 | export class DashBoardService { 8 | constructor ( 9 | private params: Params, 10 | private http: HttpClient, 11 | ) {} 12 | 13 | public getSystemLogChina (source: string) { 14 | return this.http.get('/chart/syslogchina?' + this.params.fmtpages({source})); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/dashboard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard.component'; 2 | 3 | export * from './dashboard.module'; 4 | -------------------------------------------------------------------------------- /src/app/demos/demos.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 6 | import { DemosComponent } from './demos.component'; 7 | import { DemosRouting } from './demos.routing'; 8 | import { OutletComponent } from './out-let.component'; 9 | import { UploadFileModule } from '@components/upload-file/upload-file.module'; 10 | import { ZorroAntdModule } from '@/antd/ngModule' 11 | import { DemosService } from './demos.service'; 12 | 13 | @NgModule({ 14 | imports: [ 15 | FormsModule, ReactiveFormsModule, 16 | UploadFileModule, 17 | CommonModule, 18 | DemosRouting, 19 | // NgZorroAntdModule.forRoot(), 20 | ZorroAntdModule, 21 | ], 22 | declarations: [ 23 | OutletComponent, 24 | DemosComponent, 25 | ], 26 | providers: [ 27 | DemosService 28 | ], 29 | }) 30 | export default class DemosModule {} 31 | -------------------------------------------------------------------------------- /src/app/demos/demos.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { DemosComponent } from './demos.component'; 5 | import { OutletComponent } from './out-let.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | canActivateChild: [AuthGuard], 11 | component: OutletComponent, 12 | children: [ 13 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 14 | { path: 'list', component: DemosComponent }, 15 | ], 16 | }, 17 | ]; 18 | 19 | @NgModule({ 20 | imports: [RouterModule.forChild(routes)], 21 | exports: [RouterModule], 22 | }) 23 | export class DemosRouting {} 24 | -------------------------------------------------------------------------------- /src/app/demos/demos.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpParams } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | // import { Params } from '../../../utils/params.service'; 5 | 6 | @Injectable() 7 | export class DemosService { 8 | constructor ( 9 | private http: HttpClient, 10 | ) {} 11 | 12 | testStatus (params: HttpParams) { 13 | return this.http.get('/article', {params}); 14 | } 15 | 16 | testApi (url: string, data: any) { 17 | return this.http.get(url, {params: data}); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/demos/models/demo.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class UrlModel { 3 | public url: string; 4 | public method: string = 'GET'; 5 | public params: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/demos/out-let.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-demos-outlet', 5 | template: '', 6 | }) 7 | export class OutletComponent { } 8 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleball.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-doubleball', 5 | template: '', 6 | }) 7 | export class DoubleBallComponent { 8 | } 9 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleball.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { DoubleBallComponent } from './doubleball.component'; 6 | import { DoubleBallListComponent } from './doubleballlist/doubleballlist'; 7 | import { DoubleBallListService } from './doubleballlist/doubleballlist.service'; 8 | import { DoubleBallRouting } from './doubleball.routing'; 9 | import { DoubleBallDirective } from './doubleballlist/doubleball.directive'; 10 | import { ZorroAntdModule } from '@/antd/ngModule' 11 | 12 | @NgModule({ 13 | imports: [ 14 | FormsModule, 15 | CommonModule, 16 | DoubleBallRouting, 17 | // NgZorroAntdModule.forRoot(), 18 | ZorroAntdModule, 19 | ], 20 | declarations: [ 21 | DoubleBallComponent, 22 | DoubleBallListComponent, 23 | 24 | DoubleBallDirective, 25 | ], 26 | providers: [ 27 | DoubleBallListService, 28 | ], 29 | }) 30 | export default class DoubleBallModule {} 31 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleball.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { DoubleBallComponent } from './doubleball.component'; 5 | import { DoubleBallListComponent } from './doubleballlist/doubleballlist'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | canActivateChild: [AuthGuard], 11 | component: DoubleBallComponent, 12 | children: [ 13 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 14 | { path: 'list', component: DoubleBallListComponent }, 15 | ], 16 | }, 17 | ]; 18 | 19 | @NgModule({ 20 | imports: [RouterModule.forChild(routes)], 21 | exports: [RouterModule], 22 | }) 23 | export class DoubleBallRouting {} 24 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleballlist/doubleball.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ViewContainerRef, Input, ElementRef, Renderer2 } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[doubleballResult]', 5 | }) 6 | export class DoubleBallDirective { 7 | @Input('doubleballResult') public data: string; 8 | 9 | constructor ( 10 | private renderer: Renderer2, 11 | private ref: ElementRef, 12 | // private viewContainerRef: ViewContainerRef, 13 | ) { } 14 | 15 | public ngOnInit () { 16 | // this.renderer.appendChild(this.ref.nativeElement, _html.body.querySelector('div')); 17 | this.ref.nativeElement.insertAdjacentHTML('afterbegin', '
' + this.data.split(',').map((v, i) => { 18 | return `${v}`; 19 | }).join('') + '
'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleballlist/doubleballlist.html: -------------------------------------------------------------------------------- 1 |

双色球列表

2 |
3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 20 | 21 | 22 | 红色球 23 | 蓝色球 24 | 生成结果 25 | 开奖结果 26 | 创建时间 27 | 操作 28 | 29 | 30 | 31 | 32 | {{data.red_balls}} 33 | {{data.blue_ball}} 34 | {{data.gen_result}} 35 | 36 | {{data.created_at}} 37 | 38 | 39 | 删除 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleballlist/doubleballlist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { Params } from '../../../utils/params.service'; 5 | 6 | @Injectable() 7 | export class DoubleBallListService { 8 | constructor ( 9 | private http: HttpClient, 10 | private params: Params, 11 | ) {} 12 | 13 | public getDoubleBallList (data: any) { 14 | return this.http.get('/doubleball?' + this.params.fmtpages(data)); 15 | } 16 | 17 | public addDoubleBall () { 18 | return this.http.post('/doubleball', {}); 19 | } 20 | 21 | public deleteDoubleBall (id: string) { 22 | return this.http.delete('/doubleball/' + id); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/doubleball/doubleballlist/doubleballlist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | // import { DomSanitizer } from '@angular/platform-browser'; 3 | import { Router } from '@angular/router'; 4 | import { NzModalService } from 'ng-zorro-antd/modal'; 5 | import { DoubleBallModel } from '../model/doubleball.model'; 6 | import { DoubleBallListService } from './doubleballlist.service'; 7 | import { finalize } from 'rxjs'; 8 | 9 | @Component({ 10 | selector: 'app-doubleball-list', 11 | templateUrl: './doubleballlist.html', 12 | }) 13 | export class DoubleBallListComponent implements OnInit { 14 | 15 | public current_page = 1; 16 | public per_page = 10; 17 | public total = 1; 18 | public dataSet: DoubleBallModel[] = []; 19 | public _loading = true; 20 | 21 | public value: any = {}; 22 | public isVisible = false; 23 | public isConfirmLoading = false; 24 | public deleteId: string; 25 | 26 | public options: object[]; 27 | 28 | constructor ( 29 | private router: Router, 30 | private modalService: NzModalService, 31 | private doubleBallListService: DoubleBallListService, 32 | ) { 33 | } 34 | 35 | public ngOnInit () { 36 | this.clear(); 37 | this.query(); 38 | } 39 | 40 | public add () { 41 | this._loading = true; 42 | this.doubleBallListService.addDoubleBall() 43 | .pipe(finalize(() => { this._loading = false; })) 44 | .subscribe((res: any) => { 45 | this.query(); 46 | }, (e) => { }); 47 | } 48 | 49 | public query () { 50 | this._loading = true; 51 | this.value.current_page = this.current_page; 52 | this.value.per_page = this.per_page; 53 | this.doubleBallListService.getDoubleBallList(this.value) 54 | .pipe(finalize(() => { this._loading = false; })) 55 | .subscribe((res: any) => { 56 | this.dataSet = res.data; 57 | this.current_page = res.meta.current_page; 58 | this.total = res.meta.total; 59 | }, (e) => { }); 60 | } 61 | 62 | public clear () { 63 | this.value = { 64 | title: { 65 | val: '', 66 | exp: 'like', 67 | }, 68 | abstract: { 69 | val: '', 70 | exp: 'like', 71 | }, 72 | }; 73 | } 74 | 75 | public delArticle (id: string) { 76 | const that = this; 77 | this.modalService.confirm({ 78 | nzTitle : '确认是否删除', 79 | nzContent: '删除后将无法找回这条信息', 80 | nzOkLoading: true, 81 | nzOnOk () { 82 | return new Promise((resolve) => { 83 | that.doubleBallListService.deleteDoubleBall(id) 84 | .pipe(finalize(() => { resolve(); })) 85 | .subscribe((res: any) => { that.query(); }, (err) => { }); 86 | }); 87 | }, 88 | nzOnCancel () { }, 89 | }); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/app/doubleball/model/doubleball.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class DoubleBallModel { 3 | public id: string; 4 | public red_balls: string; 5 | public blue_ball: string; 6 | public gen_result: string; 7 | public award: string; 8 | public created_at: string; 9 | } 10 | 11 | export interface ITag { 12 | id: string; 13 | name: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 |
15 |
16 | 17 |
-------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy } from '@angular/core'; 2 | // import { Http, Response } from '@angular/http'; 3 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 4 | import { AuthService } from '@utils/auth/auth.service'; 5 | 6 | const _PROD_ = process.env.NODE_ENV === 'production'; 7 | 8 | @Component({ 9 | selector: 'home', 10 | templateUrl: './home.component.html', 11 | // styles: [``], 12 | }) 13 | export class HomeComponent implements OnDestroy { 14 | 15 | private counter: number = 0; 16 | private timer: any = null; 17 | private wsHost: string = (/^https:?/ig.test(location.protocol) ? 'wss' : 'ws') + '://' + `${location.host}/ws`; 18 | private ws: WebSocket; 19 | private wsInfo: WSInfoModel = new WSInfoModel(); 20 | 21 | private ab2str (ab: ArrayBuffer): string { 22 | const s = String.fromCharCode.apply(null, new Uint8Array(ab)); 23 | return decodeURIComponent(s); 24 | } 25 | 26 | private openWS () { 27 | if (!navigator.onLine) { 28 | this.notification.error('错误', '请检查网络连接!'); 29 | return; 30 | } 31 | this.ws = null; 32 | this.ws = new WebSocket(this.wsHost); 33 | this.ws.binaryType = 'arraybuffer'; 34 | this.ws.onopen = () => { 35 | this.counter = 0; 36 | this.ws.send('connect...'); 37 | }; 38 | // 39 | this.ws.onmessage = (mEvent: MessageEvent) => { 40 | const data: any = JSON.parse(this.ab2str(mEvent.data)); 41 | const opened = JSON.parse(localStorage.getItem('NOTICE_OPEN') ? localStorage.getItem('NOTICE_OPEN') : 'false'); 42 | 43 | console.log('mEvent:', data, opened) 44 | if (data && data.data && opened) { 45 | this.wsInfo = data.data; 46 | this.notification.blank('访问信息', 47 | `

ip: ${this.wsInfo.ip}

48 |

url: ${this.wsInfo.url}

49 |

客户端: ${this.wsInfo.agent}

50 |

位置: ${this.wsInfo.country_name_zh || '-'}/${this.wsInfo.subdivisions_name_zh || '-'}/${this.wsInfo.city_name_zh || '-'}

`, {}); 51 | } 52 | }; 53 | // 54 | this.ws.onclose = (data: any) => { 55 | console.log(data); 56 | this.reOpen(); 57 | }; 58 | // 59 | this.ws.onerror = (err: any) => { 60 | console.log(err); 61 | this.reOpen(); 62 | }; 63 | } 64 | 65 | private reOpen () { 66 | const NOTICE_OPEN = localStorage.getItem('NOTICE_OPEN'); 67 | const opened = JSON.parse(NOTICE_OPEN ? NOTICE_OPEN : 'false'); 68 | if (!opened) return; 69 | clearTimeout(this.timer); 70 | this.timer = setTimeout(() => { 71 | if (this.counter < 10) { 72 | if (this.ws.CLOSED === this.ws.readyState) { 73 | this.counter++; 74 | this.openWS(); 75 | } 76 | } else { 77 | this.notification.error('WebScoket连接失败', '请刷新网页重新连接通知!', {nzDuration: 0}); 78 | } 79 | }, 6000); 80 | 81 | } 82 | 83 | constructor (private authService: AuthService, private notification: NzNotificationService) { 84 | // this.wsHost = (_PROD_ ? 'wss' : 'ws') + '://' + this.host; 85 | } 86 | 87 | public ngOnChanges () { 88 | // console.log('ngOnChanges'); 89 | } 90 | 91 | public ngOnInit () { 92 | // console.log('ngOnInit'); 93 | } 94 | 95 | public ngDoCheck () { 96 | // console.log('ngDoCheck'); 97 | } 98 | 99 | public ngAfterContentInit () { 100 | // console.log('ngAfterContentInit'); 101 | } 102 | 103 | public ngAfterContentChecked () { 104 | // console.log('ngAfterContentChecked'); 105 | } 106 | 107 | public ngAfterViewInit () { 108 | // console.log('ngAfterViewInit'); 109 | if (this.authService.isLogged) { 110 | this.openWS(); 111 | } 112 | } 113 | 114 | public ngAfterViewChecked () { 115 | // console.log('ngAfterViewChecked'); 116 | } 117 | 118 | public ngOnDestroy () { 119 | clearTimeout(this.timer); 120 | } 121 | 122 | } 123 | 124 | class WSInfoModel { 125 | public ip: string; 126 | public created_at: string; 127 | public url: string; 128 | public agent: string; 129 | public country_name_zh: string; 130 | public subdivisions_name_zh: string; 131 | public city_name_zh: string; 132 | } 133 | -------------------------------------------------------------------------------- /src/app/home/index.ts: -------------------------------------------------------------------------------- 1 | export * from './home.component'; 2 | -------------------------------------------------------------------------------- /src/app/login/bubble.ts: -------------------------------------------------------------------------------- 1 | 2 | class Bubble { 3 | constructor(w = 0, h = 0) { 4 | this.canvasW = w 5 | this.canvasH = h 6 | this.setPosition(true); 7 | } 8 | 9 | canvasW = 0 10 | canvasH = 0 11 | x = 0 12 | y = 0 13 | radius = 0 14 | color = '' 15 | speedX = 0 16 | speedY = 0 17 | growth = 0 18 | 19 | setPosition(init = false) { 20 | this.radius = Math.random() * 50 + 2.5; // 初始半径 21 | this.growth = Math.random() * 0.02 + 0.01; // 增长速度 22 | this.speedY = Math.random() * 4 + 1; 23 | this.speedX = (Math.random() * 4 - 1) * 1; 24 | this.x = Math.random() * this.canvasW; 25 | this.y = init ? Math.random() * this.canvasH : this.canvasH + this.radius; 26 | this.color = this.getRandomColor(); // 随机颜色 27 | } 28 | 29 | draw(ctx: CanvasRenderingContext2D) { 30 | // console.log(this.x, this.y, this.radius) 31 | ctx.beginPath(); 32 | ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); 33 | ctx.fillStyle = this.color; 34 | ctx.closePath(); 35 | ctx.fill(); 36 | } 37 | 38 | update() { 39 | this.x += this.speedX; // 更新x坐标 40 | this.y -= this.speedY; // 更新y坐标 41 | this.radius += this.growth; // 气泡逐渐变大 42 | 43 | // 检查是否超出屏幕边界,如果是则重置 44 | if (this.y + this.radius < 0 || this.x + this.radius < 0 || this.x - this.radius > this.canvasW) { 45 | this.setPosition(); 46 | } 47 | } 48 | 49 | getRandomColor() { 50 | const letters = '0123456789ABCDEF'; 51 | // let color = '#00bfff' + Math.random().toString(16).slice(2,4); 52 | let color = '#'; 53 | for (let i = 0; i < 6; i++) { 54 | color += letters[Math.floor(Math.random() * 16)]; 55 | } 56 | return color; 57 | } 58 | } 59 | 60 | export const drawBubbles = (el: HTMLCanvasElement) => { 61 | const ctx = el.getContext('2d', { antialias: true }) as CanvasRenderingContext2D; 62 | const dpr = window.devicePixelRatio || 1; 63 | 64 | // set canvs width and height 65 | const canvasW = window.innerWidth * dpr; 66 | const canvasH = window.innerHeight * dpr; 67 | el.width = canvasW; 68 | el.height = canvasH; 69 | 70 | const bubbles: Bubble[] = []; 71 | const maxBubbles = 120; 72 | 73 | function createBubbles() { 74 | for (let i = 0; i < maxBubbles; i++) { 75 | bubbles.push(new Bubble(canvasW, canvasH)); 76 | } 77 | } 78 | createBubbles(); 79 | 80 | // animate 81 | function animate() { 82 | ctx.clearRect(0, 0, canvasW, canvasH); 83 | ctx.imageSmoothingEnabled = true; 84 | bubbles.forEach(bubble => { 85 | bubble.draw(ctx); 86 | bubble.update(); 87 | }); 88 | requestAnimationFrame(animate); 89 | } 90 | animate(); 91 | } -------------------------------------------------------------------------------- /src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { NgForm, NonNullableFormBuilder, Validators } from '@angular/forms'; 4 | import { AuthService } from '@utils/auth/auth.service'; 5 | import { finalize } from 'rxjs'; 6 | import { drawBubbles } from './bubble' 7 | 8 | @Component({ 9 | selector: 'app-login', 10 | templateUrl: './login.html', 11 | // styleUrl: './style.less', 12 | styles: [` 13 | canvas { 14 | position: absolute; 15 | z-index: 0; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | background: #f7f7f7; 21 | // background: linear-gradient(to bottom, #87ceeb55, #87ceeb); 22 | } 23 | .login-form { 24 | position: relative; 25 | width: 300px; 26 | margin: 0 auto; 27 | } 28 | 29 | .login-form-forgot { 30 | float: right; 31 | } 32 | 33 | .login-form-button { 34 | width: 100%; 35 | } 36 | `], 37 | }) 38 | export class LoginComponent implements OnInit { 39 | public loading: boolean = false; 40 | public _window: any; 41 | @ViewChild('canvas') private canvas: ElementRef; 42 | @ViewChild('form') private form: NgForm; 43 | public userInfo: UserModel = new UserModel(); 44 | loginForm: ValidateForm; 45 | 46 | constructor ( 47 | private http: HttpClient, 48 | private authService: AuthService, 49 | private fb: NonNullableFormBuilder 50 | ) { 51 | if (this.authService.isLogged) { 52 | location.href = '/dashboard'; 53 | } 54 | this.loginForm = this.fb.group({ 55 | username: ['', [Validators.required]], 56 | password: ['', [Validators.required]], 57 | remember: [false] 58 | }); 59 | } 60 | 61 | public ngOnInit () { 62 | // 63 | } 64 | 65 | ngAfterViewInit() { 66 | drawBubbles(this.canvas.nativeElement) 67 | } 68 | 69 | onSubmit() { 70 | if (this.loginForm.valid) { 71 | // 表单数据提交逻辑 72 | console.log(this.loginForm.value); 73 | } else { 74 | const controls = this.loginForm.controls 75 | Object.values(controls).forEach(control => { 76 | control.markAsDirty(); 77 | control.updateValueAndValidity(); 78 | }) 79 | } 80 | } 81 | 82 | public login () { 83 | const form = this.form.form 84 | const controls = form.controls 85 | console.log(form.valid, controls) 86 | for (const i in controls) { 87 | controls[ i ].markAsDirty(); 88 | controls[ i ].updateValueAndValidity(); 89 | } 90 | if (form.valid) { 91 | // this.authService.login(this.userInfo); 92 | // this.userInfo = new UserModel(); 93 | this.loading = true; 94 | this.http.post('/login', this.userInfo) 95 | .pipe(finalize(() => { this.loading = false; })) 96 | .subscribe((res: any) => { 97 | this.authService.isLogged = true; 98 | localStorage.setItem('ACCESS_TOKEN', res.msg); 99 | localStorage.setItem('USER_INFO', JSON.stringify(res.data)); 100 | location.href = !!this.authService.redirectUrl ? this.authService.redirectUrl : '/dashboard'; 101 | }, (err: any) => { }); 102 | } 103 | } 104 | 105 | } 106 | 107 | class UserModel { 108 | public username: string; 109 | public password: string; 110 | } 111 | -------------------------------------------------------------------------------- /src/app/login/login.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/login/style.less: -------------------------------------------------------------------------------- 1 | .login-form { 2 | max-width: 300px; 3 | margin: 0 auto; 4 | } 5 | 6 | .login-form-forgot { 7 | float: right; 8 | } 9 | 10 | .login-form-button { 11 | width: 100%; 12 | } -------------------------------------------------------------------------------- /src/app/systemlogs/model/systemlog.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class SystemLogModel { 3 | public id: string; 4 | public request_ip: string; 5 | public request_url: string; 6 | public request_method: string; 7 | public request_params: string; 8 | public request_client: string; 9 | public client_type: string; 10 | public client_version: string; 11 | public host: string; 12 | public hostname: string; 13 | public request_header: string; 14 | public path: string; 15 | public origin: string; 16 | public time: number; 17 | public msg: string; 18 | public source: string; 19 | public created_by: string; 20 | public created_at: string; 21 | public updated_by: string; 22 | public updated_at: string; 23 | public deleted_by: string; 24 | public deleted_at: string; 25 | public version: number; 26 | public creator: UserModel = new UserModel(); 27 | } 28 | 29 | class UserModel { 30 | public id: string; 31 | public username: string; 32 | public nick_name: string; 33 | public sex: number; 34 | public user_type: number; 35 | } 36 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemlog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-systemlog', 5 | template: '', 6 | }) 7 | export class SystemLogComponent { 8 | } 9 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemlog.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { DateTimeRangeModule } from '@components/datetime-picker/datetime-picker.module'; 6 | import { SystemLogComponent } from './systemlog.component'; 7 | import { SystemLogListComponent } from './systemloglist/systemloglist'; 8 | import { SystemLogListService } from './systemloglist/systemloglist.service'; 9 | import { SystemLogDetailComponent } from './systemlogdetail/systemlogdetail'; 10 | import { SystemLogDetailService } from './systemlogdetail/systemlogdetail.service'; 11 | import { SystemLogRouting } from './systemlog.routing'; 12 | import { ZorroAntdModule } from '@/antd/ngModule' 13 | import { NzFlexDirective, } from 'ng-zorro-antd/flex' 14 | import { NzGridModule, NzColDirective, NzRowDirective } from 'ng-zorro-antd/grid' 15 | 16 | @NgModule({ 17 | imports: [ 18 | FormsModule, 19 | CommonModule, 20 | SystemLogRouting, 21 | DateTimeRangeModule, 22 | // NgZorroAntdModule.forRoot(), 23 | ZorroAntdModule, 24 | // NzFlexDirective, 25 | NzGridModule, 26 | // NzColDirective, 27 | ], 28 | declarations: [ 29 | SystemLogComponent, 30 | SystemLogListComponent, 31 | SystemLogDetailComponent, 32 | ], 33 | providers: [ 34 | SystemLogListService, 35 | SystemLogDetailService, 36 | ], 37 | }) 38 | export default class SystemLogModule {} 39 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemlog.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '../../utils/auth/auth-guard.service'; 4 | import { SystemLogComponent } from './systemlog.component'; 5 | import { SystemLogListComponent } from './systemloglist/systemloglist'; 6 | import { SystemLogDetailComponent } from './systemlogdetail/systemlogdetail'; 7 | 8 | const routes: Routes = [ 9 | { 10 | path: '', 11 | canActivateChild: [AuthGuard], 12 | component: SystemLogComponent, 13 | children: [ 14 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 15 | { path: 'list', component: SystemLogListComponent }, 16 | { path: 'detail/:id', component: SystemLogDetailComponent }, 17 | ], 18 | }, 19 | ]; 20 | 21 | @NgModule({ 22 | imports: [RouterModule.forChild(routes)], 23 | exports: [RouterModule], 24 | }) 25 | export class SystemLogRouting {} 26 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemlogdetail/systemlogdetail.html: -------------------------------------------------------------------------------- 1 | 2 |

系统日志详情

3 |
4 | 5 |
6 |
7 | 8 | 请求URL 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 | 请求ip 20 | 21 | 22 | 23 | 24 | 请求方法 25 | 26 | 27 | 28 | 29 |
30 |
31 | 32 |
33 |
34 | 35 | 请求参数 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 | 44 |
45 |
46 | 47 | 客户端类型 48 | 49 | 50 | 51 | 52 | 客户端版本 53 | 54 | 55 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 63 | HOST 64 | 65 | 66 | 67 | 68 | Hostname 69 | 70 | 71 | 72 | 73 |
74 |
75 | 76 |
77 |
78 | 79 | 处理时间 80 | 81 | 82 | 83 | 84 | 消息Message 85 | 86 | 87 | 88 | 89 |
90 |
91 | 92 |
93 |
94 | 95 | 请求头 96 | 97 | 98 | 99 | 100 |
101 |
102 | 103 |
104 |
105 | 106 | 创建时间 107 | 108 | 109 | 110 | 111 | 创建者 112 | 113 | 114 | 115 | 116 |
117 |
118 | 119 |
120 |
121 | 122 |
123 |
124 | 125 |
-------------------------------------------------------------------------------- /src/app/systemlogs/systemlogdetail/systemlogdetail.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class SystemLogDetailService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getSystemLog (id: string) { 13 | return this.http.get('/systemlog/' + id); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemlogdetail/systemlogdetail.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { SystemLogModel } from '../model/systemlog.model'; 6 | import { SystemLogDetailService } from './systemlogdetail.service'; 7 | 8 | @Component({ 9 | selector: 'app-systemlog-detail', 10 | templateUrl: './systemlogdetail.html', 11 | // styles: [``], 12 | }) 13 | export class SystemLogDetailComponent implements OnInit { 14 | 15 | public mainModel: SystemLogModel = new SystemLogModel(); 16 | @ViewChild('form') private form: NgForm; 17 | 18 | public checkedTag = {}; 19 | public typeAjaxList: any[] = []; 20 | 21 | constructor ( 22 | private router: Router, 23 | private route: ActivatedRoute, 24 | private systemLogDetailService: SystemLogDetailService, 25 | private notification: NzNotificationService, 26 | ) { } 27 | 28 | public ngOnInit () { 29 | this.route.params.subscribe((param) => { 30 | if (param.id) { 31 | this.getData(param.id); 32 | } 33 | }, (err) => { 34 | this.notification.warning('错误', '参数错误'); 35 | }); 36 | } 37 | 38 | public getData (id: string) { 39 | this.systemLogDetailService.getSystemLog(id).subscribe((res: any) => { 40 | this.mainModel = res.data; 41 | }, (err: any) => { }); 42 | } 43 | 44 | public back () { 45 | this.router.navigate(['systemlog']); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemloglist/systemloglist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { Params } from '../../../utils/params.service'; 5 | 6 | @Injectable() 7 | export class SystemLogListService { 8 | constructor ( 9 | private http: HttpClient, 10 | private params: Params, 11 | ) {} 12 | 13 | public getSystemLogList (data: any) { 14 | return this.http.get('/systemlog?' + this.params.fmtpages(data)); 15 | } 16 | 17 | public deleteSystemLog (id: string) { 18 | return this.http.delete('/systemlog/' + id); 19 | } 20 | 21 | public syncGeoInfo () { 22 | return this.http.post('/system/geoinfo', {}); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/app/systemlogs/systemloglist/systemloglist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | // import { NgForm } from '@angular/forms'; 3 | // import { Router } from '@angular/router'; 4 | import { NzModalService } from 'ng-zorro-antd/modal'; 5 | import { SystemLogModel } from '../model/systemlog.model'; 6 | import { SystemLogListService } from './systemloglist.service'; 7 | // import * as Moment from 'moment' 8 | import { finalize } from 'rxjs'; 9 | // import { } from 'ng-zorro-antd/flex' 10 | 11 | @Component({ 12 | selector: 'app-systemlog-list', 13 | templateUrl: './systemloglist.html', 14 | }) 15 | export class SystemLogListComponent implements OnInit { 16 | // @ViewChild('form') private form: NgForm; 17 | private timer: number = 0; 18 | public current_page = 1; 19 | public per_page = 10; 20 | public total = 1; 21 | public dataSet: SystemLogModel[] = []; 22 | public _loading = true; 23 | 24 | public value: any = {}; 25 | public isVisible = false; 26 | public deleteId: string; 27 | public startDate: string; 28 | public endDate: string; 29 | 30 | public options: object[]; 31 | 32 | nzSpan = 6 33 | nzGutter = [12, 12] 34 | 35 | constructor ( 36 | // private router: Router, 37 | private modalService: NzModalService, 38 | private systemLogListService: SystemLogListService, 39 | ) { } 40 | 41 | public ngOnInit () { 42 | this.clear(); 43 | this.query(undefined); 44 | } 45 | 46 | public query (cur_page: number) { 47 | if (cur_page) { 48 | this.current_page = 1; 49 | } 50 | if(this.value.created_at.val.length) { 51 | this.value.created_at.val = this.value.created_at.val.map((d: Date, i: number) => { 52 | return i > 0 ? d['format']('YYYY/MM/DD 23:59:59:999') : d['format']('YYYY/MM/DD 00:00:00:000') 53 | }) 54 | 55 | console.log(this.value.created_at, 'this.value') 56 | } 57 | this.value.current_page = this.current_page; 58 | this.value.per_page = this.per_page; 59 | this._loading = true; 60 | this.systemLogListService.getSystemLogList(this.value) 61 | .pipe(finalize(() => { this._loading = false; })) 62 | .subscribe((res: any) => { 63 | this.dataSet = res.data; 64 | this.total = res.meta.total; 65 | }, (e) => { }); 66 | } 67 | 68 | public clear () { 69 | this.value = { 70 | request_ip: { 71 | val: '', 72 | exp: 'like', 73 | }, 74 | request_method: { 75 | val: '', 76 | exp: 'like', 77 | }, 78 | client_version: { 79 | val: '', 80 | exp: 'like', 81 | }, 82 | status: { 83 | val: '', 84 | exp: 'in', 85 | }, 86 | time: { 87 | val: '', 88 | exp: 'between', 89 | }, 90 | created_at: { 91 | val: '', 92 | exp: 'between', 93 | }, 94 | source: { 95 | val: '', 96 | exp: '=', 97 | }, 98 | }; 99 | } 100 | 101 | public delSystemLog (id: string) { 102 | const that = this; 103 | this.modalService.confirm({ 104 | nzTitle : '确认是否删除', 105 | nzContent: '删除后将无法找回这条日志', 106 | nzOkLoading: true, 107 | nzOnOk () { 108 | return new Promise((resolve) => { 109 | that.systemLogListService.deleteSystemLog(id) 110 | .pipe(finalize(() => { resolve(); })) 111 | .subscribe((res: any) => { that.query(undefined); }, (err) => { }); 112 | }); 113 | }, 114 | nzOnCancel () { }, 115 | }); 116 | } 117 | 118 | public getStatus (status: number) { 119 | let nzStatus = ''; 120 | switch (status) { 121 | case 200: 122 | case 201: 123 | nzStatus = 'success'; 124 | break; 125 | case 400: 126 | case 401: 127 | case 403: 128 | case 404: 129 | case 405: 130 | case 406: 131 | nzStatus = 'warning'; 132 | break; 133 | case 500: 134 | case 501: 135 | case 502: 136 | case 503: 137 | case 504: 138 | case 505: 139 | nzStatus = 'error'; 140 | break; 141 | 142 | default: 143 | nzStatus = 'default'; 144 | break; 145 | } 146 | return nzStatus; 147 | } 148 | 149 | public sync () { 150 | this._loading = true; 151 | this.systemLogListService.syncGeoInfo() 152 | .pipe(finalize(() => { this._loading = false; })) 153 | .subscribe((res: any) => { 154 | this.query(this.current_page); 155 | }, (e) => { }); 156 | } 157 | 158 | public ngDoDestory () { 159 | clearTimeout(this.timer); 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/app/tag/addtag/addtag.html: -------------------------------------------------------------------------------- 1 |

添加文章标签

2 |
3 |
4 |

基本信息

5 |
6 |
7 |
8 | 9 | 名称 10 | 11 | 12 |
必须填写!
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 | 备注 21 | 22 | 23 |
必须填写!
24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 |
-------------------------------------------------------------------------------- /src/app/tag/addtag/addtag.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class AddTagService { 6 | constructor ( 7 | private http: HttpClient, 8 | ) {} 9 | 10 | public addTag (data: any) { 11 | return this.http.post('/tag', data); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/tag/addtag/addtag.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { TagModel } from '../model/tag.model'; 6 | 7 | import { AddTagService } from './addtag.service'; 8 | 9 | @Component({ 10 | selector: 'app-add-tag', 11 | templateUrl: './addtag.html', 12 | // styles: [], 13 | }) 14 | export class AddTagComponent implements OnInit { 15 | public isConfirmLoading = false; 16 | public addTag: TagModel = new TagModel(); 17 | @ViewChild('form') private form: NgForm; 18 | 19 | constructor ( 20 | private router: Router, 21 | private addTagService: AddTagService, 22 | private notification: NzNotificationService, 23 | ) { 24 | } 25 | 26 | public ngOnInit () { 27 | // 28 | } 29 | 30 | public save () { 31 | for (const i in this.form.controls) { 32 | this.form.controls[ i ].markAsDirty(); 33 | } 34 | if (this.form.valid) { 35 | this.isConfirmLoading = true; 36 | this.addTagService.addTag(this.addTag).subscribe((res: any) => { 37 | this.isConfirmLoading = false; 38 | this.notification.success('成功', res.msg); 39 | this.router.navigate(['/tag']); 40 | }, (err: any) => { 41 | this.isConfirmLoading = false; 42 | }); 43 | } 44 | } 45 | 46 | public back () { 47 | this.router.navigate(['./tag']); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/app/tag/edittag/edittag.html: -------------------------------------------------------------------------------- 1 |

编辑文章标签

2 |
3 |
4 |

基本信息

5 |
6 |
7 |
8 | 9 | 名称 10 | 11 | 12 |
必须填写!
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 | 备注 21 | 22 | 23 |
必须填写!
24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 | 32 | 33 |
34 |
35 | 36 |
-------------------------------------------------------------------------------- /src/app/tag/edittag/edittag.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class EditTagService { 6 | constructor ( 7 | private http: HttpClient, 8 | ) {} 9 | 10 | public getTag (id: string) { 11 | return this.http.get(`/tag/${id}`); 12 | } 13 | 14 | public updateTag (data: any) { 15 | return this.http.put(`/tag/${data.id}`, data); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/tag/edittag/edittag.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { TagModel } from '../model/tag.model'; 6 | 7 | import { EditTagService } from './edittag.service'; 8 | import { finalize } from 'rxjs'; 9 | 10 | @Component({ 11 | selector: 'app-edit-tag', 12 | templateUrl: './edittag.html', 13 | // styles: [], 14 | }) 15 | export class EditTagComponent implements OnInit { 16 | public isConfirmLoading = false; 17 | public editTag: TagModel = new TagModel(); 18 | @ViewChild('form') private form: NgForm; 19 | 20 | constructor ( 21 | private router: Router, 22 | private route: ActivatedRoute, 23 | private EditTagService: EditTagService, 24 | private notification: NzNotificationService, 25 | ) { 26 | } 27 | 28 | public ngOnInit () { 29 | this.route.params.subscribe((param) => { 30 | if (param.id) { 31 | this.getData(param.id); 32 | } 33 | }, (err) => { 34 | this.notification.warning('错误', '参数错误'); 35 | }); 36 | } 37 | 38 | public getData (id: any) { 39 | this.EditTagService.getTag(id).subscribe((res: any) => { 40 | this.editTag = res.data; 41 | }); 42 | } 43 | 44 | public save () { 45 | for (const i in this.form.controls) { 46 | this.form.controls[ i ].markAsDirty(); 47 | } 48 | if (this.form.valid) { 49 | this.isConfirmLoading = true; 50 | this.EditTagService.updateTag(this.editTag) 51 | .pipe(finalize(() => this.isConfirmLoading = false)) 52 | .subscribe((res: any) => { 53 | this.router.navigate(['/tag']); 54 | }, (err: any) => { }); 55 | } 56 | } 57 | 58 | public back () { 59 | this.router.navigate(['./tag']); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/app/tag/index.ts: -------------------------------------------------------------------------------- 1 | export * from './tag.component'; 2 | -------------------------------------------------------------------------------- /src/app/tag/model/tag.model.ts: -------------------------------------------------------------------------------- 1 | class BaseModel { 2 | public current_page: number; 3 | public per_page: number = 10; 4 | public total: number; 5 | } 6 | 7 | export class TagModel extends BaseModel { 8 | public id: string; 9 | public name: string; 10 | public remark: string; 11 | public created_at: string; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/tag/tag.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-tag', 5 | template: '', 6 | }) 7 | export class TagComponent { 8 | } 9 | -------------------------------------------------------------------------------- /src/app/tag/tag.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { AddTagComponent } from './addtag/addtag'; 6 | import { AddTagService } from './addtag/addtag.service'; 7 | import { EditTagComponent } from './edittag/edittag'; 8 | import { EditTagService } from './edittag/edittag.service'; 9 | import { TagComponent } from './tag.component'; 10 | import { TagRouting } from './tag.routing'; 11 | import { TagListComponent } from './taglist/taglist'; 12 | import { TagListService } from './taglist/taglist.service'; 13 | import { ZorroAntdModule } from '@/antd/ngModule' 14 | 15 | @NgModule({ 16 | imports: [ 17 | FormsModule, 18 | CommonModule, 19 | TagRouting, 20 | // NgZorroAntdModule.forRoot(), 21 | ZorroAntdModule, 22 | ], 23 | declarations: [ 24 | TagComponent, 25 | TagListComponent, 26 | AddTagComponent, 27 | EditTagComponent, 28 | ], 29 | providers: [ 30 | TagListService, 31 | AddTagService, 32 | EditTagService, 33 | ], 34 | }) 35 | export default class TagModule {} 36 | -------------------------------------------------------------------------------- /src/app/tag/tag.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '../../utils/auth/auth-guard.service'; 4 | import { AddTagComponent } from './addtag/addtag'; 5 | import { EditTagComponent } from './edittag/edittag'; 6 | import { TagComponent } from './tag.component'; 7 | import { TagListComponent } from './taglist/taglist'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: '', 12 | canActivateChild: [AuthGuard], 13 | component: TagComponent, 14 | children: [ 15 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 16 | { path: 'list', component: TagListComponent }, 17 | { path: 'add', component: AddTagComponent }, 18 | { path: 'edit/:id', component: EditTagComponent }, 19 | ], 20 | }, 21 | ]; 22 | 23 | @NgModule({ 24 | imports: [RouterModule.forChild(routes)], 25 | exports: [RouterModule], 26 | }) 27 | export class TagRouting {} 28 | -------------------------------------------------------------------------------- /src/app/tag/taglist/taglist.html: -------------------------------------------------------------------------------- 1 |

标签列表

2 |
3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | 15 | 16 | 17 |
18 |
19 |
20 | 21 | 31 | 32 | 33 | ID 34 | 类型名称 35 | 备注 36 | 创建时间 37 | 操作 38 | 39 | 40 | 41 | 42 | {{data.id}} 43 | {{data.name}} 44 |
{{data.remark}}
45 | 46 | {{data.created_at}} 47 | 编辑 48 | 49 | 50 |
-------------------------------------------------------------------------------- /src/app/tag/taglist/taglist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class TagListService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getTagList (data: any) { 13 | return this.http.get('/tag?' + this.params.fmtpages(data)); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/tag/taglist/taglist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { TagListService } from './taglist.service'; 3 | import { finalize } from 'rxjs'; 4 | 5 | @Component({ 6 | selector: 'app-tag-list', 7 | templateUrl: './taglist.html', 8 | }) 9 | export class TagListComponent implements OnInit { 10 | 11 | public current_page = 1; 12 | public per_page = 10; 13 | public total = 1; 14 | public dataSet: any = []; 15 | public _loading = true; 16 | 17 | public value: any = {}; 18 | 19 | constructor ( 20 | private tagListService: TagListService, 21 | ) { } 22 | 23 | public ngOnInit () { 24 | this.clear(); 25 | this.query(); 26 | } 27 | 28 | public query () { 29 | this.value.current_page = this.current_page; 30 | this.value.per_page = this.per_page; 31 | this._loading = true; 32 | this.tagListService.getTagList(this.value) 33 | .pipe(finalize(() => this._loading = false)) 34 | .subscribe((res: any) => { 35 | this.dataSet = res.data; 36 | this.current_page = res.meta.current_page; 37 | this.total = res.meta.total; 38 | }, (err: any) => { }); 39 | } 40 | 41 | public clear () { 42 | this.value = { 43 | name: { 44 | val: '', 45 | exp: 'like', 46 | }, 47 | remark: { 48 | val: '', 49 | exp: 'like', 50 | }, 51 | created_at: { 52 | val: '', 53 | exp: 'between', 54 | }, 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/user/adduser/adduser.html: -------------------------------------------------------------------------------- 1 |

添加用户

2 |
3 |
4 |

基本信息

5 |
6 |
7 |
8 | 9 | 用户名称 10 | 11 | 12 |
必须填写!
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 | 用户密码 21 | 22 | 23 |
必须填写!
24 |
25 |
26 |
27 |
28 |
29 |
30 | 31 | 用户昵称 32 | 33 | 34 |
必须填写!
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 用户性别 43 | 44 | 45 | 46 | 47 | 48 |
必须填写!
49 |
50 |
51 |
52 |
53 |
54 |
55 | 56 | 用户类型 57 | 58 | 59 | 60 | 61 | 62 | 63 |
必须填写!
64 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 备注 72 | 73 | 74 | 75 | 76 |
77 |
78 | 79 |
80 |
81 | 82 | 83 |
84 |
85 | 86 |
-------------------------------------------------------------------------------- /src/app/user/adduser/adduser.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class AddUserService { 6 | constructor ( 7 | private http: HttpClient, 8 | ) {} 9 | 10 | public addUser (data: any) { 11 | return this.http.post('/user', data); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/user/adduser/adduser.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { UserModel } from '../model/user.model'; 6 | 7 | import { AddUserService } from './adduser.service'; 8 | 9 | @Component({ 10 | selector: 'app-add-user', 11 | templateUrl: './adduser.html', 12 | // styles: [], 13 | }) 14 | export class AddUserComponent implements OnInit { 15 | public isConfirmLoading = false; 16 | public addUser: UserModel = new UserModel(); 17 | @ViewChild('form') private form: NgForm; 18 | 19 | constructor ( 20 | private router: Router, 21 | private addUserService: AddUserService, 22 | private notification: NzNotificationService, 23 | ) { 24 | } 25 | 26 | public ngOnInit () { 27 | // 28 | } 29 | 30 | public save () { 31 | for (const i in this.form.controls) { 32 | this.form.controls[ i ].markAsDirty(); 33 | } 34 | if (this.form.valid) { 35 | this.isConfirmLoading = true; 36 | this.addUserService.addUser(this.addUser).subscribe((res: any) => { 37 | this.isConfirmLoading = false; 38 | this.notification.success('成功', res.msg); 39 | this.router.navigate(['/user']); 40 | }, (err: any) => { 41 | this.isConfirmLoading = false; 42 | }); 43 | } 44 | } 45 | 46 | public back () { 47 | this.router.navigate(['./user']); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/app/user/edituser/edituser.html: -------------------------------------------------------------------------------- 1 |

添加用户

2 |
3 |
4 |

基本信息

5 |
6 |
7 |
8 | 9 | 用户名称 10 | 11 | 12 |
必须填写!
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 | 用户密码 21 | 22 | 23 |
必须填写!
24 |
25 |
26 |
27 |
28 |
29 |
30 | 31 | 用户昵称 32 | 33 | 34 |
必须填写!
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 用户性别 43 | 44 | 45 | 46 | 47 | 48 |
必须填写!
49 |
50 |
51 |
52 |
53 |
54 |
55 | 56 | 用户类型 57 | 58 | 59 | 60 | 61 | 62 | 63 |
必须填写!
64 |
65 |
66 |
67 |
68 |
69 |
70 | 71 | 备注 72 | 73 | 74 | 75 | 76 |
77 |
78 | 79 |
80 |
81 | 82 | 83 |
84 |
85 | 86 |
-------------------------------------------------------------------------------- /src/app/user/edituser/edituser.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class EditUserService { 6 | constructor ( 7 | private http: HttpClient, 8 | ) {} 9 | 10 | public getUser (id: any) { 11 | return this.http.get(`/user/${id}`); 12 | } 13 | 14 | public updateUser (data: any) { 15 | return this.http.put(`/user/${data.id}`, data); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/user/edituser/edituser.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild } from '@angular/core'; 2 | import { NgForm } from '@angular/forms'; 3 | import { ActivatedRoute, Router } from '@angular/router'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | import { UserModel } from '../model/user.model'; 6 | 7 | import { EditUserService } from './edituser.service'; 8 | import { finalize } from 'rxjs'; 9 | 10 | @Component({ 11 | selector: 'app-edit-user', 12 | templateUrl: './edituser.html', 13 | // styles: [], 14 | }) 15 | export class EditUserComponent implements OnInit { 16 | public isConfirmLoading = false; 17 | public editUser: UserModel = new UserModel(); 18 | @ViewChild('form') private form: NgForm; 19 | 20 | constructor ( 21 | private router: Router, 22 | private route: ActivatedRoute, 23 | private editUserService: EditUserService, 24 | private notification: NzNotificationService, 25 | ) { 26 | } 27 | 28 | public ngOnInit () { 29 | this.route.params.subscribe((param) => { 30 | if (param.id) { 31 | this.getData(param.id); 32 | } 33 | }, (err) => { 34 | this.notification.warning('错误', '参数错误'); 35 | }); 36 | } 37 | 38 | public getData (id: any) { 39 | this.editUserService.getUser(id).subscribe((res: any) => { 40 | this.editUser = res.data; 41 | }); 42 | } 43 | 44 | public save () { 45 | for (const i in this.form.controls) { 46 | this.form.controls[ i ].markAsDirty(); 47 | } 48 | if (this.form.valid) { 49 | this.isConfirmLoading = true; 50 | this.editUserService.updateUser(this.editUser) 51 | .pipe(finalize(() => this.isConfirmLoading = false)) 52 | .subscribe((res: any) => { 53 | this.router.navigate(['/user']); 54 | }); 55 | } 56 | } 57 | 58 | public back () { 59 | this.router.navigate(['./user']); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/app/user/index.ts: -------------------------------------------------------------------------------- 1 | export * from './user.component'; 2 | -------------------------------------------------------------------------------- /src/app/user/model/user.model.ts: -------------------------------------------------------------------------------- 1 | 2 | export class UserModel { 3 | public id: string; 4 | public username: string; 5 | public password: string; 6 | public nick_name: string; 7 | public sex: number; 8 | public user_type: number; 9 | public remark: string; 10 | public created_at: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/user/user.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-user', 5 | template: '', 6 | }) 7 | export class UserComponent { 8 | } 9 | -------------------------------------------------------------------------------- /src/app/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | // import { NgZorroAntdModule } from 'ng-zorro-antd'; 5 | import { AddUserComponent } from './adduser/adduser'; 6 | import { AddUserService } from './adduser/adduser.service'; 7 | import { EditUserComponent } from './edituser/edituser'; 8 | import { EditUserService } from './edituser/edituser.service'; 9 | import { UserComponent } from './user.component'; 10 | import { UserRouting } from './user.routing'; 11 | import { UserListComponent } from './userlist/userlist'; 12 | import { UserListService } from './userlist/userlist.service'; 13 | import { ZorroAntdModule } from '@/antd/ngModule' 14 | 15 | @NgModule({ 16 | imports: [ 17 | FormsModule, 18 | CommonModule, 19 | UserRouting, 20 | // NgZorroAntModule.forRoot(), 21 | ZorroAntdModule, 22 | ], 23 | declarations: [ 24 | UserComponent, 25 | UserListComponent, 26 | AddUserComponent, 27 | EditUserComponent, 28 | ], 29 | providers: [ 30 | UserListService, 31 | AddUserService, 32 | EditUserService, 33 | ], 34 | }) 35 | export default class UserModule {} 36 | -------------------------------------------------------------------------------- /src/app/user/user.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | import { AuthGuard } from '@utils/auth/auth-guard.service'; 4 | import { AddUserComponent } from './adduser/adduser'; 5 | import { EditUserComponent } from './edituser/edituser'; 6 | import { UserComponent } from './user.component'; 7 | import { UserListComponent } from './userlist/userlist'; 8 | 9 | const routes: Routes = [ 10 | { 11 | path: '', 12 | // canActivateChild: [AuthGuard], 13 | component: UserComponent, 14 | children: [ 15 | { path: '', redirectTo: 'list', pathMatch: 'full' }, 16 | { path: 'list', component: UserListComponent }, 17 | { path: 'add', component: AddUserComponent }, 18 | { path: 'edit/:id', component: EditUserComponent }, 19 | ], 20 | }, 21 | ]; 22 | 23 | @NgModule({ 24 | imports: [RouterModule.forChild(routes)], 25 | exports: [RouterModule], 26 | }) 27 | export class UserRouting {} 28 | -------------------------------------------------------------------------------- /src/app/user/userlist/userlist.html: -------------------------------------------------------------------------------- 1 | 2 |

用户列表

3 |
4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 | 21 |
22 |
23 |
24 | 25 | 35 | 36 | 37 | ID 38 | 用户名称 39 | 用户昵称 40 | 性别 41 | 用户类型 42 | 备注 43 | 创建时间 44 | 操作 45 | 46 | 47 | 48 | 49 | {{data.id}} 50 | {{data.username}} 51 | {{data.nick_name}} 52 | {{data.sex}} 53 | {{data.user_type}} 54 |
{{data.remark}}
55 | 56 | {{data.created_at}} 57 | 58 | 编辑 59 | 删除 60 | 61 | 62 | 63 |
64 | 65 | 66 | 67 | 68 |

确认删除该条信息?

69 |
70 |
-------------------------------------------------------------------------------- /src/app/user/userlist/userlist.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Params } from '../../../utils/params.service'; 4 | 5 | @Injectable() 6 | export class UserListService { 7 | constructor ( 8 | private http: HttpClient, 9 | private params: Params, 10 | ) {} 11 | 12 | public getUserList (data: any) { 13 | return this.http.get('/user?' + this.params.fmtpages(data)); 14 | } 15 | 16 | public deleteUser (id: string) { 17 | return this.http.delete('/user/' + id); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/user/userlist/userlist.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { UserListService } from './userlist.service'; 3 | import { finalize } from 'rxjs'; 4 | 5 | @Component({ 6 | selector: 'app-user-list', 7 | templateUrl: './userlist.html', 8 | }) 9 | export class UserListComponent implements OnInit { 10 | 11 | public current_page = 1; 12 | public per_page = 10; 13 | public total = 1; 14 | public dataSet: any = []; 15 | public _loading = true; 16 | 17 | public value: any = {}; 18 | public isVisible = false; 19 | public isConfirmLoading = false; 20 | public deleteId: string; 21 | 22 | constructor ( 23 | private userListService: UserListService, 24 | ) { 25 | } 26 | 27 | public ngOnInit () { 28 | this.clear(); 29 | this.query(); 30 | } 31 | 32 | public query () { 33 | this.value.current_page = this.current_page; 34 | this.value.per_page = this.per_page; 35 | this._loading = true; 36 | this.userListService.getUserList(this.value) 37 | .pipe(finalize(() => { this._loading = false; })) 38 | .subscribe((res: any) => { 39 | this.dataSet = res.data; 40 | this.current_page = res.meta.current_page; 41 | this.total = res.meta.total; 42 | }, (err: any) => { }); 43 | } 44 | 45 | public clear () { 46 | this.value = { 47 | username: { 48 | val: '', 49 | exp: 'like', 50 | }, 51 | nick_name: { 52 | val: '', 53 | exp: 'like', 54 | }, 55 | remark: { 56 | val: '', 57 | exp: 'like', 58 | }, 59 | created_at: { 60 | val: '', 61 | exp: 'between', 62 | }, 63 | }; 64 | } 65 | 66 | public delUser (id: string) { 67 | if (id) { 68 | this.deleteId = id; 69 | this.isVisible = true; 70 | } else { 71 | this.isConfirmLoading = true; 72 | this.userListService.deleteUser(this.deleteId).subscribe((res: any) => { 73 | this.isVisible = false; 74 | this.query(); 75 | this.isConfirmLoading = false; 76 | }, (err: any) => { 77 | this.isConfirmLoading = false; 78 | }); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/assets/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Menus": { 3 | "Blog_Management": "Blog Management", 4 | "Article_List": "Article List", 5 | "ArticleType_List": "ArticleType List", 6 | "Tag_List": "Tag List", 7 | "User_List": "User List", 8 | "Comment_List": "Comment List", 9 | 10 | "Log_Management": "Log Management", 11 | "System_Log": "System Logs", 12 | 13 | "Chart_Management": "Chart Management", 14 | "Chart_Statistics": "Chart Statistics", 15 | 16 | "Tests": "Tests", 17 | "Test_Demo": "Test Demo" 18 | } 19 | } -------------------------------------------------------------------------------- /src/assets/i18n/zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "Menus": { 3 | "Blog_Management": "博客管理", 4 | "Article_List": "文章列表", 5 | "ArticleType_List": "文章类型", 6 | "Tag_List": "标签管理", 7 | "User_List": "用户管理", 8 | "Comment_List": "评论管理", 9 | 10 | "Log_Management": "日志管理", 11 | "System_Log": "系统日志", 12 | 13 | "Chart_Management": "图表管理", 14 | "Chart_Statistics": "图表统计", 15 | 16 | "Tests": "测试", 17 | "Test_Demo": "测试用例" 18 | } 19 | } -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/angular-typescript/d4daa8f288fc0fa9abfe9fd6531f55904687c56e/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/datetime-picker/datetime-picker.component.ts: -------------------------------------------------------------------------------- 1 | import { forwardRef, Component, ElementRef, Input, OnInit, Output, ViewChild } from '@angular/core'; 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; 3 | import { format } from 'date-fns' 4 | 5 | @Component({ 6 | selector: 'app-datetime-range', 7 | templateUrl: './datetime-range.html', 8 | styles: [` 9 | app-datetime-range{ 10 | display: block; 11 | } 12 | `], 13 | providers : [{ 14 | provide : NG_VALUE_ACCESSOR, 15 | useExisting: forwardRef(() => DateTimeRangeComponent), 16 | multi : true, 17 | }], 18 | }) 19 | export class DateTimeRangeComponent implements ControlValueAccessor, OnInit { 20 | @Input() public xSize: string = 'default'; 21 | @Input() public xFormat: string = 'YYYY-MM-DD'; 22 | @Input('dateRange') public _value: any; 23 | 24 | public spanStyle: object = {}; 25 | public dateStyle: object = {}; 26 | public startDate: any = null; 27 | public endDate: any = null; 28 | 29 | public onChange: any = Function.prototype; 30 | public onTouched: any = Function.prototype; 31 | 32 | constructor () {} 33 | 34 | public ngOnInit () { 35 | console.log(this.xFormat, this.xSize); 36 | this.dateStyle = { 37 | width: '48%', 38 | float: 'left', 39 | }; 40 | this.spanStyle = { 41 | 'float': 'left', 42 | 'line-height': this.getLineHeight(), 43 | 'text-align': 'center', 44 | 'width': '4%', 45 | }; 46 | } 47 | 48 | private getLineHeight () { 49 | if (this.xSize === 'default') { 50 | return '28px'; 51 | } else if (this.xSize === 'large') { 52 | return '32px'; 53 | } else { 54 | return '24px'; 55 | } 56 | } 57 | 58 | public ngOnChanges () { 59 | // this.show = !!this.baseUrl; 60 | } 61 | 62 | public startDateChange (event: any): void { 63 | console.log(event); 64 | } 65 | 66 | get dateRange () { 67 | return this._value; 68 | } 69 | 70 | set dateRange (val: any) { 71 | if ((this._value === val) || (((this._value === undefined) || (this._value === null)) && ((val === undefined) || (val === null)))) { 72 | return; 73 | } 74 | if (val !== this._value) { 75 | this._value = val; 76 | this.onChange(val); 77 | } 78 | } 79 | 80 | public changeSDate (date: any) { 81 | this.startDate = date; 82 | if (!this.endDate || this.startDate > this.endDate) { 83 | this.endDate = date; 84 | } 85 | this.setDateRange(); 86 | } 87 | 88 | public changeEDate (date: any) { 89 | this.endDate = date; 90 | if (!this.startDate || this.startDate > this.endDate) { 91 | this.startDate = date; 92 | } 93 | this.setDateRange(); 94 | } 95 | 96 | private setDateRange () { 97 | this.onChange([format(this.startDate, 'YYYY-MM-DD HH:mm:ss'), format(this.endDate, 'YYYY-MM-DD HH:mm:ss')]); 98 | } 99 | 100 | public writeValue (value: any): void { 101 | this.dateRange = value; 102 | } 103 | 104 | public registerOnChange (fn: (_: any) => {}): void { 105 | this.onChange = fn; 106 | } 107 | 108 | public registerOnTouched (fn: () => {}): void { 109 | this.onTouched = fn; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/components/datetime-picker/datetime-picker.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { DateTimeRangeComponent } from './datetime-picker.component'; 5 | import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; 6 | 7 | @NgModule({ 8 | imports: [ 9 | CommonModule, 10 | FormsModule, 11 | NzDatePickerModule, // important 12 | ], 13 | declarations: [ 14 | DateTimeRangeComponent, 15 | ], 16 | providers: [ 17 | // 18 | ], 19 | schemas: [ 20 | CUSTOM_ELEMENTS_SCHEMA, 21 | ], 22 | exports: [ 23 | DateTimeRangeComponent, 24 | ], 25 | }) 26 | export class DateTimeRangeModule {} 27 | -------------------------------------------------------------------------------- /src/components/datetime-picker/datetime-range.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | - 5 | 6 |
-------------------------------------------------------------------------------- /src/components/editor/editor.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /src/components/editor/editor.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { EditorComponent } from './editor.component'; 6 | 7 | @NgModule({ 8 | imports: [ 9 | CommonModule, 10 | FormsModule, 11 | ], 12 | declarations: [ 13 | EditorComponent, 14 | ], 15 | exports: [ 16 | EditorComponent, 17 | ], 18 | }) 19 | export class EditorModule {} 20 | -------------------------------------------------------------------------------- /src/components/shared/breadcrumb/breadcrumb.component.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/components/shared/breadcrumb/breadcrumb.component.less: -------------------------------------------------------------------------------- 1 | nz-breadcrumb-item{ 2 | span{ 3 | display: inline-block; 4 | cursor: pointer; 5 | } 6 | } -------------------------------------------------------------------------------- /src/components/shared/breadcrumb/breadcrumb.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ActivatedRoute, Router } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'app-breadcrumb', 6 | templateUrl: './breadcrumb.component.html', 7 | // styleUrls : ['./breadcrumb.component.less'], 8 | }) 9 | export class BreadCrumbComponent implements OnInit { 10 | public currentTitle: string = ''; 11 | public currentUrl: string = ''; 12 | 13 | constructor ( 14 | private router: Router, 15 | private route: ActivatedRoute, 16 | ) { 17 | this.currentUrl = router.url; 18 | const children = router.config[0].children; 19 | } 20 | 21 | public ngOnInit () { 22 | // 23 | } 24 | 25 | public dashBoard () { 26 | this.router.navigate(['./dashboard']); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/shared/header/header.component.html: -------------------------------------------------------------------------------- 1 |
6 |
11 | 22 | Angular Zone 23 |
24 | 25 |
26 |
27 | 28 |
29 | 30 |
    31 |
  • Username
  • 32 |
  • 中文
  • 33 |
  • {{noticeOpened ? '关闭' : '开启'}}WS通知
  • 34 |
  • 退出登录({{userInfo.username}})
  • 35 |
36 |
37 |
38 | 39 |
-------------------------------------------------------------------------------- /src/components/shared/header/header.component.less: -------------------------------------------------------------------------------- 1 | .logo{ 2 | display: inline-block; 3 | margin: 15px; 4 | width:34px; 5 | height:34px; 6 | background: url('../../../assets/images/logo.svg') no-repeat center center; 7 | background-size: cover; 8 | // animation: rotate 6s linear 0s infinite normal running; 9 | // transform-origin: center center; 10 | /*transition: all 0.3s;*/ 11 | 12 | &:hover{ 13 | animation-play-state: paused; 14 | } 15 | } 16 | .sys-name{ 17 | font-size: 16px; 18 | color: #fff; 19 | margin: 28px 0 0; 20 | display: inline-block; 21 | vertical-align: top; 22 | } 23 | .user-info{ 24 | float: right; 25 | margin: 20px 20px 0 0; 26 | } 27 | 28 | @keyframes rotate{ 29 | from{ 30 | transform: rotateZ(0deg) 31 | } 32 | to{ 33 | transform: rotateZ(360deg) 34 | } 35 | } 36 | 37 | .bar-right{ 38 | display: flex; 39 | height: 100%; 40 | position: absolute; 41 | top: 0; 42 | right: 0; 43 | align-items: center; 44 | padding-right: 10px; 45 | } 46 | .bar-right .lang{ 47 | margin-right: 10px; 48 | } 49 | .bar-right .anticon{ 50 | color: #fff; 51 | font-size: 24px; 52 | cursor: pointer; 53 | } 54 | -------------------------------------------------------------------------------- /src/components/shared/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { en_US, zh_CN, NzI18nService } from 'ng-zorro-antd/i18n'; 3 | import { AuthService } from '@utils/auth/auth.service'; 4 | 5 | @Component({ 6 | selector: 'app-header', 7 | templateUrl: './header.component.html', 8 | // styleUrls : ['./header.component.less'], 9 | styles: [` 10 | header{position: relative} 11 | .logo{ 12 | // display: inline-block; 13 | // margin: 10px; 14 | width:44px; 15 | height:44px; 16 | // animation: rotate 6s linear 0s infinite normal running; 17 | // transform-origin: center center; 18 | } 19 | .logo:hover{ 20 | animation-play-state: paused; 21 | } 22 | .sys-name{ 23 | font-size: 16px; 24 | color: #fff; 25 | // margin: 28px 0 0; 26 | // display: inline-block; 27 | // vertical-align: top; 28 | } 29 | // .user-info{ 30 | // float: right; 31 | // margin: 20px 20px 0 0; 32 | // } 33 | 34 | @keyframes rotate{ 35 | from{ 36 | transform: rotateZ(0deg) 37 | } 38 | to{ 39 | transform: rotateZ(360deg) 40 | } 41 | } 42 | 43 | .bar-right{ 44 | display: flex; 45 | height: 100%; 46 | position: absolute; 47 | top: 0; 48 | right: 0; 49 | align-items: center; 50 | padding-right: 10px; 51 | } 52 | .bar-right .lang{ 53 | margin-right: 10px; 54 | } 55 | .bar-right .anticon{ 56 | color: #fff; 57 | font-size: 24px; 58 | cursor: pointer; 59 | } 60 | `], 61 | }) 62 | export class HeaderComponent implements OnInit { 63 | public store: any; 64 | public noticeOpened: boolean; 65 | public userInfo: object = {}; 66 | public isVertical = false 67 | 68 | constructor (private authService: AuthService, private nzI18nService: NzI18nService) { 69 | this.store = localStorage; 70 | this.noticeOpened = JSON.parse(this.store.getItem('NOTICE_OPEN') ? this.store.getItem('NOTICE_OPEN') : 'false'); 71 | } 72 | 73 | public ngOnInit () { 74 | this.userInfo = JSON.parse(this.store.getItem('USER_INFO')) || {}; 75 | } 76 | 77 | public toggleLang () { 78 | const lang: string = this.nzI18nService.getLocale().locale; 79 | console.log(lang, this.nzI18nService.getLocale()); 80 | if (/zh/ig.test(lang)) { 81 | this.nzI18nService.setLocale(en_US); 82 | } else { 83 | this.nzI18nService.setLocale(zh_CN); 84 | } 85 | } 86 | 87 | public toggleNotice () { 88 | this.noticeOpened = !this.noticeOpened; 89 | this.store.setItem('NOTICE_OPEN', this.noticeOpened); 90 | } 91 | 92 | public logout () { 93 | this.authService.logout(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/components/shared/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sidebar/sidebar.component'; 2 | export * from './header/header.component'; 3 | export * from './breadcrumb/breadcrumb.component'; 4 | -------------------------------------------------------------------------------- /src/components/shared/sidebar/sidebar.component.html: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /src/components/shared/sidebar/sidebar.component.less: -------------------------------------------------------------------------------- 1 | div{ 2 | display: block; 3 | } -------------------------------------------------------------------------------- /src/components/shared/sidebar/sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-sidebar', 5 | templateUrl: './sidebar.component.html', 6 | // styleUrls : ['./sidebar.component.less'], 7 | }) 8 | export class SidebarComponent implements OnInit { 9 | 10 | public isOpen: AnyObject = { 11 | one: true, 12 | two: false, 13 | three: false, 14 | four: false, 15 | five: false, 16 | }; 17 | 18 | private store: object; 19 | 20 | constructor () { 21 | // this.store = localStorage; 22 | } 23 | 24 | public openChange (value: string) { 25 | Object.keys(this.isOpen).forEach((v, i) => { 26 | if (value == v) { 27 | this.isOpen[v] = true; 28 | } else { 29 | this.isOpen[v] = false; 30 | } 31 | }); 32 | } 33 | 34 | public ngOnInit () { 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/upload-file/upload-file.directvie.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, HostListener, Input, OnDestroy } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[preViewImg]', 5 | }) 6 | export class PreViewDirective { 7 | 8 | constructor (private eleRef: ElementRef) { } 9 | 10 | public wrapEle: any; 11 | public divEle: any; 12 | public btnEle: any; 13 | public imgEle: any; 14 | public timer: any; 15 | 16 | @Input('preViewImg') private preViewImgSrc: string; 17 | 18 | @HostListener('click') 19 | public onClick () { 20 | if (this.preViewImgSrc) 21 | document.body.appendChild(this.createModal()); 22 | } 23 | 24 | public ngOnInit () { 25 | // 26 | } 27 | 28 | public createModal () { 29 | if (!this.wrapEle) { 30 | this.wrapEle = document.createElement('div'); 31 | this.wrapEle.className = 'pre-view-wrap'; 32 | } 33 | if (!this.divEle) { 34 | this.divEle = document.createElement('div'); 35 | this.divEle.className = 'pre-view-content'; 36 | } else { 37 | this.divEle.className = 'pre-view-content'; 38 | } 39 | if (!this.btnEle) { 40 | this.btnEle = document.createElement('button'); 41 | this.btnEle.className = 'pre-close-btn'; 42 | } 43 | if (!this.imgEle) { 44 | this.imgEle = document.createElement('img'); 45 | this.imgEle.src = this.preViewImgSrc; 46 | } 47 | this.divEle.appendChild(this.btnEle); 48 | this.divEle.appendChild(this.imgEle); 49 | this.wrapEle.appendChild(this.divEle); 50 | 51 | this.divEle.addEventListener('click', (e: any) => {e.stopPropagation(); }); 52 | this.wrapEle.addEventListener('click', this.closeModal.bind(this), false); 53 | this.btnEle.addEventListener('click', this.closeModal.bind(this), false); 54 | return this.wrapEle; 55 | } 56 | 57 | public closeModal (event: any) { 58 | this.divEle.className = 'pre-view-content view-fade-out'; 59 | this.timer = setTimeout(() => { 60 | const wrapEle = document.getElementsByClassName('pre-view-wrap')[0]; 61 | if (wrapEle) { 62 | document.body.removeChild(wrapEle); 63 | } 64 | }, 300); 65 | } 66 | 67 | // 68 | public ngOnDestroy () { 69 | clearTimeout(this.timer); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/components/upload-file/upload-file.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 7 | 8 | 正在上传... 9 |
10 |
11 | 12 | 图片加载失败 13 | 14 |
15 |
16 | 图片大小不超过{{maxSize}}K 17 |
18 |
-------------------------------------------------------------------------------- /src/components/upload-file/upload-file.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { UploadFileComponent } from './upload-file.component'; 6 | import { PreViewDirective } from './upload-file.directvie'; 7 | 8 | @NgModule({ 9 | imports: [ 10 | CommonModule, 11 | FormsModule, 12 | ], 13 | declarations: [ 14 | UploadFileComponent, 15 | PreViewDirective, 16 | ], 17 | providers: [ 18 | // 19 | ], 20 | exports: [ 21 | UploadFileComponent, 22 | ], 23 | }) 24 | export class UploadFileModule {} 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // index.ts 2 | 3 | // import '@utils/tools' 4 | // import './polyfills.ts'; 5 | // import './vendor.ts'; 6 | import 'zone.js' 7 | import './app'; 8 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | // Polyfills 2 | // import 'reflect-metadata'; 3 | import 'core-js/es6/array'; 4 | import 'core-js/es6/date'; 5 | import 'core-js/es6/function'; 6 | import 'core-js/es6/map'; 7 | import 'core-js/es6/math'; 8 | import 'core-js/es6/number'; 9 | import 'core-js/es6/object'; 10 | import 'core-js/es6/parse-float'; 11 | import 'core-js/es6/parse-int'; 12 | import 'core-js/es6/promise'; 13 | import 'core-js/es6/reflect'; 14 | import 'core-js/es6/regexp'; 15 | import 'core-js/es6/set'; 16 | import 'core-js/es6/string'; 17 | import 'core-js/es6/symbol'; 18 | import 'core-js/es6/typed'; 19 | import 'core-js/es6/weak-map'; 20 | import 'core-js/es6/weak-set'; 21 | import 'core-js/es7/reflect'; 22 | import 'zone.js/dist/zone'; 23 | 24 | import 'rxjs/add/observable/of'; 25 | import 'rxjs/add/operator/do'; 26 | import 'rxjs/add/operator/finally'; 27 | import 'rxjs/add/operator/map'; 28 | import 'rxjs/add/operator/mergeMap'; 29 | -------------------------------------------------------------------------------- /src/styles/index.less: -------------------------------------------------------------------------------- 1 | @import './theme.less'; 2 | @import './global.less'; -------------------------------------------------------------------------------- /src/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | /* styles.css */ 2 | @import 'tailwindcss/base'; 3 | @import 'tailwindcss/components'; 4 | @import 'tailwindcss/utilities'; -------------------------------------------------------------------------------- /src/styles/theme.less: -------------------------------------------------------------------------------- 1 | :global { 2 | --main-color: #8514f5; 3 | } 4 | 5 | 6 | @import "../../node_modules/ng-zorro-antd/ng-zorro-antd.less"; 7 | 8 | // overwrite 9 | // @primary-color: var(--main-color); -------------------------------------------------------------------------------- /src/template/index_base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CMS-管理后台 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /src/types/custome.d.ts: -------------------------------------------------------------------------------- 1 | import { FormGroup, FormControl } from '@angular/forms' 2 | 3 | declare global { 4 | 5 | type FormFields = { 6 | [P in keyof T]: FormControl 7 | } 8 | 9 | type ValidateForm = FormGroup> 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/types/demo.ts: -------------------------------------------------------------------------------- 1 | 2 | export type APIForm = { 3 | email?: string 4 | url: string 5 | method: string 6 | params: string 7 | res: string 8 | } -------------------------------------------------------------------------------- /src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | 2 | interface Date { 3 | format: (s: string) => string 4 | } 5 | 6 | type AnyObject = Record 7 | 8 | 9 | declare const classes: Readonly> 10 | 11 | declare module '*.less' { 12 | export default classes 13 | } 14 | 15 | declare module '*.module.less' { 16 | export default classes 17 | } 18 | -------------------------------------------------------------------------------- /src/types/login.ts: -------------------------------------------------------------------------------- 1 | 2 | interface LoginForm { 3 | username: string 4 | password: string 5 | remember: boolean 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/auth/auth-guard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | ActivatedRouteSnapshot, 4 | CanActivate, 5 | CanActivateChild, 6 | CanLoad, 7 | Route, 8 | Router, 9 | RouterStateSnapshot, 10 | } from '@angular/router'; 11 | import { AuthService } from './auth.service'; 12 | 13 | @Injectable() 14 | export class AuthGuard implements CanActivate, CanActivateChild, CanLoad { 15 | constructor (private authService: AuthService) {} 16 | 17 | public canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { 18 | const url: string = state.url; 19 | return this.checkLogin(url); 20 | } 21 | 22 | public canActivateChild (route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { 23 | return this.canActivate(route, state); 24 | } 25 | 26 | public canLoad (route: Route): boolean { 27 | const url = `/${route.path}`; 28 | return this.checkLogin(url); 29 | } 30 | 31 | public checkLogin (url: string): boolean { 32 | return true; 33 | if (this.authService.isLogged) { 34 | return true; 35 | } else { 36 | console.log(url); 37 | this.authService.redirectUrl = url; 38 | location.href = 'login'; 39 | return false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/auth/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | 4 | @Injectable() 5 | export class AuthService { 6 | public store: Storage; 7 | public isLogged: boolean = false; 8 | 9 | constructor (private http: HttpClient) { 10 | this.store = localStorage; 11 | this.isLogged = this.store.getItem('ACCESS_TOKEN') 12 | && this.store.getItem('ACCESS_TOKEN').length == 64 13 | && this.store.getItem('USER_INFO') ? true : false; 14 | } 15 | 16 | get redirectUrl () { 17 | return sessionStorage.getItem('RedirectUrl') || ''; 18 | } 19 | 20 | set redirectUrl (url: string) { 21 | sessionStorage.setItem('RedirectUrl', url); 22 | } 23 | 24 | public login (userInfo: object) { 25 | this.http.post('/login', userInfo).subscribe((res: any) => { 26 | this.isLogged = true; 27 | this.store.setItem('ACCESS_TOKEN', res.msg); 28 | this.store.setItem('USER_INFO', JSON.stringify(res.data)); 29 | location.href = !!this.redirectUrl ? this.redirectUrl : '/dashboard'; 30 | }, (err: any) => { }); 31 | } 32 | 33 | public logout (): void { 34 | this.http.post('/logout', {}).subscribe((res: any) => { 35 | this.isLogged = false; 36 | this.store.clear(); 37 | sessionStorage.clear(); 38 | setTimeout(() => { 39 | location.href = 'login'; 40 | }, 1000); 41 | }, (err: any) => { }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/utils/echarts/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * echarts 3 | */ 4 | // const Echarts = require('echarts/lib/echarts'); 5 | import * as Echarts from 'echarts/core' 6 | import { VisualMapComponentOption, TitleComponentOption } from 'echarts/components' 7 | import { 8 | TitleComponent, 9 | TooltipComponent, 10 | ToolboxComponent, 11 | LegendComponent, 12 | LegendScrollComponent, 13 | VisualMapComponent, 14 | } from 'echarts/components' 15 | import { CanvasRenderer } from 'echarts/renderers' 16 | 17 | Echarts.use([ 18 | CanvasRenderer, 19 | TitleComponent, 20 | TooltipComponent, 21 | ToolboxComponent, 22 | LegendComponent, 23 | LegendScrollComponent, 24 | VisualMapComponent, 25 | ]) 26 | 27 | export { 28 | Echarts, 29 | }; 30 | -------------------------------------------------------------------------------- /src/utils/funs.ts: -------------------------------------------------------------------------------- 1 | 2 | export const storage = { 3 | get: (key: string): string => { 4 | const value = localStorage.getItem(key) 5 | return value || '' 6 | }, 7 | 8 | set: (key: string, value: string) => { 9 | if (value !== null && value !== undefined) { 10 | localStorage.setItem(key, value) 11 | } 12 | }, 13 | 14 | remove: (key: string): void => { 15 | localStorage.removeItem(key) 16 | }, 17 | 18 | clear(exclude = false) { 19 | if(exclude) { 20 | } else { 21 | localStorage.clear() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/httpInterceptor/helper.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { storage } from '@utils/funs'; 4 | import { NzNotificationService } from 'ng-zorro-antd/notification'; 5 | 6 | @Injectable() 7 | export class HelperService { 8 | public store: any; 9 | public seStore: any; 10 | 11 | constructor (private notification: NzNotificationService) { 12 | this.store = localStorage; 13 | this.seStore = sessionStorage; 14 | } 15 | 16 | public successHelper (res: HttpResponse): void { 17 | switch (res.status) { 18 | case 201: 19 | const arr = res.url.split('/api'); 20 | if (arr[arr.length - 1] === '/login') { 21 | this.notification.success('成功', '登陆成功'); 22 | } else if (arr[arr.length - 1] === '/upload-file') { 23 | this.notification.success('成功', '文件上传成功'); 24 | } else { 25 | this.notification.success('成功', '操作成功'); 26 | } 27 | break; 28 | default: 29 | // 30 | break; 31 | } 32 | } 33 | 34 | public errorHelper (err: HttpErrorResponse): void { 35 | switch (err.status) { 36 | case 400: 37 | const arr = err.url.split('/api'); 38 | if (arr[arr.length - 1] === '/login') { 39 | this.notification.error('错误', '用户名或密码错误'); 40 | } else if (arr[arr.length - 1] === '/upload-file') { 41 | this.notification.error('失败', '文件上传失败'); 42 | } else { 43 | this.notification.error('请求错误', err.error.msg || err.error.data); 44 | } 45 | break; 46 | case 401: 47 | storage.clear(); 48 | this.notification.error('未授权', '请重新登录'); 49 | sessionStorage.setItem('RedirectUrl', location.pathname); 50 | setTimeout(() => { 51 | location.href = 'login'; 52 | }, 1000); 53 | break; 54 | case 403: 55 | this.notification.error('错误', '禁止访问'); 56 | break; 57 | case 404: 58 | this.notification.error('未找到', '未找到资源,请检查'); 59 | break; 60 | case 405: 61 | this.notification.error('错误', '此方法不允许'); 62 | break; 63 | case 406: 64 | this.notification.error('错误', '此方法不接受,请检查'); 65 | break; 66 | case 406: 67 | this.notification.error('错误', '此方法不接受,请检查'); 68 | break; 69 | case 500: 70 | this.notification.error('错误', err.error.msg || err.error.data); 71 | break; 72 | case 503: 73 | this.notification.error('连接被拒绝', '服务不可用'); 74 | break; 75 | case 504: 76 | this.notification.error('网关超时', '请与运维小郭联系'); 77 | break; 78 | default: 79 | this.notification.error('错误', '服务端未知错误'); 80 | break; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/utils/httpInterceptor/httpInterceptor.service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpErrorResponse, 3 | HttpEvent, 4 | HttpHandler, 5 | HttpInterceptor, 6 | HttpRequest, 7 | HttpResponse, 8 | } from '@angular/common/http'; 9 | import { Injectable } from '@angular/core'; 10 | import { Observable, finalize } from 'rxjs'; 11 | import { HelperService } from './helper.service'; 12 | 13 | @Injectable() 14 | export class HttpClientInterceptor implements HttpInterceptor { 15 | public baseUrl: string = '/api'; 16 | public store: any; 17 | 18 | constructor (private helper: HelperService) { 19 | this.store = localStorage; 20 | } 21 | 22 | public intercept (req: HttpRequest, next: HttpHandler): Observable> { 23 | const isHttpEntry = /^http/.test(req.url) 24 | const url = `${isHttpEntry ? '' : this.baseUrl}${req.url}` 25 | const request = req.clone({ 26 | url, 27 | setHeaders: { 28 | 'X-Requested-With': 'XMLHttpRequest', 29 | 'Authorization-User': this.store.getItem('ACCESS_TOKEN') || 'no_token', 30 | }, 31 | // withCredentials: true, // same origin not use 32 | }); 33 | return next.handle(request).pipe((res) => { 34 | if (res instanceof HttpResponse) { 35 | this.helper.successHelper(res); 36 | } 37 | return res; 38 | }, (err) => { 39 | if (err instanceof HttpErrorResponse) { 40 | this.helper.errorHelper(err); 41 | } 42 | return err; 43 | }, finalize(() => { 44 | // 45 | })); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/utils/httpInterceptor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './httpInterceptor.service'; 2 | -------------------------------------------------------------------------------- /src/utils/params.service.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Params { 3 | constructor () {} 4 | 5 | public format (data: any) { 6 | const arr = []; 7 | for (const i in data) { 8 | if (data[i] !== undefined && data[i] !== '' && data[i] !== null) { 9 | const s = encodeURIComponent(i) + '=' + encodeURIComponent(data[i]); 10 | arr.push(s); 11 | } 12 | } 13 | arr.push('_=' + Date.now()); 14 | return arr.join('&'); 15 | } 16 | 17 | public fmtpages (data: any) { 18 | const arr: any = []; 19 | let n: number = 0; 20 | if (data !== null && typeof data === 'object') { 21 | for (const i in data) { 22 | if (typeof data[i] !== 'object') { 23 | if (data[i] !== undefined && data[i] !== '' && data[i] !== null) { 24 | const s = encodeURIComponent(i) + '=' + encodeURIComponent(data[i]); 25 | arr.push(s); 26 | } 27 | } else { 28 | if (data[i].val !== undefined && data[i].val !== '' && data[i].val !== null) { 29 | const num = n++; 30 | arr.push(encodeURIComponent('colFilter[' + num + '][col]') + '=' + i); 31 | arr.push(encodeURIComponent('colFilter[' + num + '][exp]') + '=' + encodeURIComponent(data[i].exp ? data[i].exp : '=')); 32 | arr.push(encodeURIComponent('colFilter[' + num + '][val]') + '=' + encodeURIComponent(data[i].val)); 33 | } 34 | } 35 | } 36 | } 37 | arr.push('_=' + Date.now()); 38 | return arr.join('&'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/utils/tools.ts: -------------------------------------------------------------------------------- 1 | 2 | const prototypeFun = () => { 3 | Date.prototype['format'] = function format(fmt: string) { 4 | if(Object.prototype.toString.call(this) !== '[object Date]') { 5 | throw new Error('this caller must be a Date type.') 6 | } 7 | if(!fmt) fmt = 'YYYY-MM-DD HH:mm:ss:SSS' 8 | let d: Date = this 9 | let o = { 10 | 'Y+': d.getFullYear(), 11 | 'M+': (d.getMonth() + 1), 12 | 'D+': d.getDate(), 13 | 'H+': d.getHours(), 14 | 'm+': d.getMinutes(), 15 | 's+': d.getSeconds(), 16 | 'S+': d.getMilliseconds() 17 | } 18 | for(let k in o) { 19 | let matched = fmt.match(k) 20 | let _k = matched ? matched[0] : null 21 | const v = o[k as keyof typeof o] 22 | fmt = fmt.replace(_k, (`${v > 9 ? v : '0'}${v}`)) 23 | } 24 | return fmt 25 | } 26 | } 27 | 28 | export default prototypeFun() -------------------------------------------------------------------------------- /src/vendor.ts: -------------------------------------------------------------------------------- 1 | // Angular 2 | import '@angular/core'; 3 | import '@angular/common'; 4 | import '@angular/animations'; 5 | import '@angular/forms'; 6 | import '@angular/http'; 7 | import '@angular/platform-browser'; 8 | import '@angular/platform-browser-dynamic'; 9 | import '@angular/router'; 10 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpioneer/angular-typescript/d4daa8f288fc0fa9abfe9fd6531f55904687c56e/static/favicon.ico -------------------------------------------------------------------------------- /static/logo.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Angular", 3 | "icons": [ 4 | { 5 | "src": "logo.svg", 6 | "sizes": "192x192", 7 | "type": "image/svg" 8 | } 9 | ], 10 | "theme_color": "#ffffff", 11 | "background_color": "#ffffff", 12 | "start_url": "/Angular-PWA/", 13 | "display": "standalone" 14 | } -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | // tailwind.config.js 2 | module.exports = { 3 | mode: 'jit', 4 | // purge: ['./src/**/*.{html,js}'], // 用于清除未使用的 CSS 5 | content: [ 6 | // './src/**/*.{html,js,ts,tsx}', 7 | './src/**/*.html' 8 | ], 9 | darkMode: false, // 可以设置为 'media' 或 'class' 来启用暗模式 10 | theme: { 11 | extend: {}, 12 | }, 13 | variants: { 14 | extend: {}, 15 | }, 16 | plugins: [], 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "sourceMap": false, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "removeComments": false, 10 | "noImplicitAny": true, 11 | "lib": [ "es2015", "dom" ], 12 | "baseUrl": "./src", 13 | "paths": { 14 | "@/*": ["*"], 15 | "@app/*": ["app/*"], 16 | "@assets/*": ["assets/*"], 17 | "@components/*": ["components/*"], 18 | "@utils/*": ["utils/*"] 19 | } 20 | }, 21 | "compileOnSave": true, 22 | "exclude": [ 23 | "node_modules" 24 | ] 25 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": ["src/"], 4 | "rules": { 5 | "forin": false, 6 | "no-empty": false, 7 | "variable-name": false, 8 | "import-spacing": false, 9 | "ordered-imports": false, 10 | "max-line-length": false, 11 | "object-literal-sort-keys": false, 12 | "quotemark": [true, "single", "avoid-escape"], 13 | "no-console": false, 14 | "member-ordering": false, 15 | "max-classes-per-file": [false, 1], 16 | "indent": [true, "spaces", 2], 17 | "curly": false, 18 | "space-before-function-paren": [true, "always"], 19 | "one-variable-per-declaration": false, 20 | "no-var-requires": false, 21 | "no-shadowed-variable": false, 22 | "no-irregular-whitespace": false, 23 | "object-literal-key-quotes": false, 24 | "whitespace": [ 25 | true, 26 | "check-branch", 27 | "check-decl", 28 | "check-operator", 29 | "check-module", 30 | "check-separator", 31 | "check-rest-spread", 32 | "check-typecast", 33 | "check-type", 34 | "check-type-operator", 35 | "check-preblock" 36 | ], 37 | "triple-equals": false, 38 | "eofline": true, 39 | "interface-name": [true, "always-prefix"], 40 | "semicolon": [true, "always", "ignore-interfaces", "ignore-bound-class-methods"] 41 | } 42 | } --------------------------------------------------------------------------------