修改路径

This commit is contained in:
小海
2020-05-16 22:18:45 +08:00
parent abc792a561
commit 42177a7721
683 changed files with 92 additions and 18398 deletions

View File

@@ -0,0 +1,41 @@
<div class="inner-content">
<nz-card nzTitle="文章管理" nzSize="small">
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="page"
[nzPageSize]="pageSize" [nzLoading]="loading"
(nzPageIndexChange)="getArticle()" nzFrontPagination="false">
<thead>
<th>标题</th>
<th>发布日期</th>
<th>更新日期</th>
<th>文章类型</th>
<th>阅读量</th>
<th>是否可见</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td nz-typography nzEllipsis="true" [nzTooltipTitle]="data.title" nzTooltipPlacement="right"
nz-tooltip>{{data.title}}</td>
<td>{{data.publishDateFormat}}</td>
<td>{{data.updateDateFormat}}</td>
<td>
<nz-tag nzColor="green" *ngIf="data.original">原创</nz-tag>
<nz-tag nzColor="#ff5500" *ngIf="!data.original">转载</nz-tag>
</td>
<td>
<nz-tag [nzColor]="'purple'">{{data.readingNumber}}</nz-tag>
</td>
<td><input type="checkbox" [checked]="data.open" disabled></td>
<td>
<a routerLink="/write" [queryParams]="{id:data.id}" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a [routerLink]="'/article'+data.id" class="show-opr">查看</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这篇文章吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="deleteArticle(data.id)" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-card>
</div>

View File

@@ -0,0 +1,3 @@
td {
max-width: 200px;
}

View File

@@ -0,0 +1,50 @@
import {Component, OnInit} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd';
import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp';
import {Article} from '../../../class/Article';
import {Title} from '@angular/platform-browser';
@Component({
selector: 'app-admin-article',
templateUrl: './admin-article.component.html',
styleUrls: ['./admin-article.component.less']
})
export class AdminArticleComponent implements OnInit {
constructor(private apiService: ApiService, private nzMessage: NzMessageService, private title: Title) {
}
page: number = 1;
pageSize: number = 10;
pageList: PageList<Article> = new PageList<Article>();
loading: boolean = true;
ngOnInit(): void {
this.title.setTitle('小海博客 | 文章管理')
this.getArticle();
}
getArticle = () => this.apiService.adminArticles(this.page, this.pageSize).subscribe({
next: data => this.pageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
deleteArticle(id) {
this.loading = true;
this.apiService.deleteArticle(id).subscribe({
next: data => {
this.nzMessage.success('删除成功')
this.loading = false;
this.getArticle();
},
error: err => {
this.nzMessage.error(err.msg)
this.loading = false
}
})
}
}

View File

@@ -0,0 +1,31 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminArticleComponent} from './admin-article.component';
import {
NzCardModule,
NzDividerModule,
NzPopconfirmModule,
NzTableModule, NzTagModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
@NgModule({
declarations: [
AdminArticleComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminArticleComponent}]),
NzTableModule,
NzTypographyModule,
NzToolTipModule,
NzCardModule,
NzDividerModule,
NzPopconfirmModule,
NzTagModule,
]
})
export class AdminArticleModule {
}

View File

@@ -0,0 +1,42 @@
<div class="inner-content">
<nz-card nzTitle="评论管理" nzSize="small">
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" [nzLoading]="loading"
(nzPageIndexChange)="getComment()" nzFrontPagination="false">
<thead>
<th>文章标题</th>
<th>评论内容</th>
<th>评论者</th>
<th>评论日期</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td nz-typography nzEllipsis="true" [nzTooltipTitle]="data.articleTitle" nzTooltipPlacement="right"
nz-tooltip>{{data.articleTitle}}</td>
<td nz-typography nzEllipsis="true" [nzTooltipTitle]="data.content" nzTooltipPlacement="right"
nz-tooltip style="min-width: 100px;max-width: 400px">
<span *ngIf="!editInfo.editFocus||data.id!==editInfo.id">{{data.content}}</span>
<nz-input-group *ngIf="editInfo.editFocus&&data.id===editInfo.id"
[nzPrefix]="tagIcon" style="width: 50%" (blur)="editInfo.editFocus=false">
<input type="text" nz-input [(ngModel)]="editInfo.content.content" nzSize="small"
[autofocus]="editInfo.editFocus&&data.id===editInfo.id"
(keyup.enter)="edit()">
<button nz-button (click)="edit()" nzSize="small">更新</button>
<button nz-button (click)="editInfo.editFocus=false" nzSize="small">取消</button>
</nz-input-group>
</td>
<td>{{data.authorName}}</td>
<td>{{data.date}}</td>
<td>
<a (click)="editFocus(data)" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这篇文章吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="deleteComment(data.id)" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-card>
</div>
<ng-template #tagIcon><i nz-icon nzType="message" nzTheme="outline"></i></ng-template>

View File

@@ -0,0 +1,3 @@
td {
max-width: 300px;
}

View File

@@ -0,0 +1,102 @@
import {Component, OnInit} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd';
import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp';
import {Comment, CommentReq} from '../../../class/Comment';
import {GlobalUserService} from '../../../services/global-user.service';
@Component({
selector: 'app-admin-comment',
templateUrl: './admin-comment.component.html',
styleUrls: ['./admin-comment.component.less']
})
export class AdminCommentComponent implements OnInit {
constructor(private apiService: ApiService, private messageService: NzMessageService, private userService: GlobalUserService) {
this.userService.watchUserInfo({
next: data => {
if (data.result) {
if (data.result.role === 'admin') {
this.getComment = this.getCommentForAdmin;
} else {
this.getComment = this.getCommentForUser;
}
} else {
this.getComment = this.getCommentForUser;
}
this.getComment()
},
error: null,
complete: null
})
}
loading: boolean = true;
pageIndex: number = 1;
pageSize: number = 10;
pageList: PageList<Comment> = new PageList<Comment>();
editInfo = {
id: null,
content: new CommentReq(true),
editFocus: false,
}
getComment: any;// 存放获取评论的方法
ngOnInit(): void {
}
getCommentForAdmin = () => this.apiService.getCommentByTypeForAdmin(true, this.pageIndex, this.pageSize).subscribe({
next: data => this.pageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
getCommentForUser = () => this.apiService.getCommentByTypeForUser(true, this.pageIndex, this.pageSize).subscribe({
next: data => this.pageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
deleteComment(id: number) {
this.loading = true;
this.apiService.deleteComment(id).subscribe({
next: () => {
this.messageService.success('删除评论成功');
this.getComment();
},
error: err => {
this.loading = false;
this.messageService.error(err.msg);
},
complete: () => this.loading = false
})
}
edit() {
this.editInfo.editFocus = false;
this.loading = true;
this.apiService.updateComment(this.editInfo.content).subscribe({
next: data => {
this.messageService.success('更新评论成功');
this.getComment();
},
error: err => {
this.loading = false;
this.messageService.success(err.msg);
},
complete: () => this.loading = false
})
}
editFocus(data: Comment) {
this.editInfo.id = data.id;
this.editInfo.content.content = data.content;
this.editInfo.content.id = data.id;
this.editInfo.content.articleID = data.articleID;
this.editInfo.content.pid = data.pid;
this.editInfo.content.responseId = data.responseId;
this.editInfo.editFocus = true;
}
}

View File

@@ -0,0 +1,37 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminCommentComponent} from './admin-comment.component';
import {
NzButtonModule,
NzCardModule,
NzDividerModule, NzIconModule, NzInputModule,
NzPopconfirmModule,
NzTableModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [
AdminCommentComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminCommentComponent}]),
NzCardModule,
NzTableModule,
NzDividerModule,
NzPopconfirmModule,
NzTypographyModule,
NzToolTipModule,
NzInputModule,
FormsModule,
NzIconModule,
NzButtonModule
]
})
export class AdminCommentModule {
}

View File

@@ -0,0 +1,67 @@
<div *ngIf="userInfo&&userInfo.role==='admin'">
<div nz-row>
<nz-card nzTitle="统计" nz-col nzSpan="12" nzSize="small">
<nz-row [nzGutter]="24">
<nz-col [nzSpan]="6">
<nz-statistic [nzValue]="(counts.articleCount | number)!" nzTitle="文章数量"></nz-statistic>
</nz-col>
<nz-col [nzSpan]="6">
<nz-statistic [nzValue]="(counts.tagCount | number)!" nzTitle="标签量"></nz-statistic>
</nz-col>
<nz-col [nzSpan]="6">
<nz-statistic [nzValue]="(counts.categoryCount | number)!" nzTitle="分类数量"></nz-statistic>
</nz-col>
<nz-col [nzSpan]="6">
<nz-statistic [nzValue]="(counts.commentCount | number)!" nzTitle="评论量"></nz-statistic>
</nz-col>
</nz-row>
</nz-card>
<nz-card nzTitle="信息" nz-col nzSpan="11" nzOffset="1" nzSize="small">
<nz-row [nzGutter]="24">
<nz-col [nzSpan]="8">
<nz-statistic [nzValue]="(counts.visitorCount | number)!" nzTitle="总访问量"></nz-statistic>
</nz-col>
<nz-col [nzSpan]="8">
<nz-statistic [nzValue]="(dayVisitCount | number)!" nzTitle="日访问量"></nz-statistic>
</nz-col>
<nz-col [nzSpan]="8">
<nz-statistic [nzValue]="userInfo.recentlyLandedDate?userInfo.recentlyLandedDate:''"
nzTitle="上次登录"></nz-statistic>
</nz-col>
</nz-row>
</nz-card>
</div>
<div nz-row style="margin-top: 30px">
<nz-card style="width:100%;" nzSize="small" nzTitle="日志" [nzExtra]="reload">
<ng-template #reload>
<a (click)="getLog()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a>
</ng-template>
<nz-spin [nzSpinning]="logLoading" style="width: 100%;">
<pre style="width: 100%;max-height: 500px;overflow: auto;">{{logText}}</pre>
</nz-spin>
</nz-card>
</div>
</div>
<div *ngIf="userInfo&&userInfo.role==='user'">
<div nz-row>
<nz-card nzTitle="信息" nz-col nzSpan="6" nzOffset="1" nzSize="small">
<nz-statistic [nzValue]="userInfo.recentlyLandedDate?userInfo.recentlyLandedDate:''"
nzTitle="上次登录"></nz-statistic>
</nz-card>
<nz-card nzTitle="关于此博客" nzSize="small" nz-col nzSpan="6" nzOffset="2">
<p>此博客由 <a href="https://github.com/xiaohai2271" target="_blank">禾几海(郑海)</a> 设计并实现的</p>
<p>博客自2019年3月开始开发编写 5月开始正式运行至今</p>
<p>博客所有代码都是开源的,你可以随意修改,运行和发布</p>
<p>
<a href="https://github.com/xiaohai2271/blog-backEnd" target="_blank">后端代码可以在此处找到</a>
<nz-divider nzType="vertical"></nz-divider>
<a href="https://github.com/xiaohai2271/blog-frontEnd" target="_blank">前端代码可以在此处找到</a>
</p>
<p>如果觉得博客还不错请前往Github支持我给我点一个star吧</p>
</nz-card>
<nz-card nz-col nzSpan="6" nzOffset="2">
<p style="font-style: italic">坚强的信心,能使平凡的人做出惊人的事业。</p>
<p style="text-align: right"> ——马尔顿</p>
</nz-card>
</div>
</div>

View File

@@ -0,0 +1,61 @@
import {Component, OnInit} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {ApiService} from '../../../api/api.service';
import {GlobalUserService} from '../../../services/global-user.service';
import {User} from '../../../class/User';
@Component({
selector: 'app-admin-dashboard',
templateUrl: './admin-dashboard.component.html',
styleUrls: ['./admin-dashboard.component.less']
})
export class AdminDashboardComponent implements OnInit {
constructor(private apiService: ApiService, private userService: GlobalUserService, private http: HttpClient) {
this.getUserInfo();
}
logLoading: boolean = true;
logText: string = null;
counts: {
articleCount: number,
visitorCount: number,
categoryCount: number,
leaveMsgCount: number,
tagCount: number,
commentCount: number
} = {articleCount: 0, visitorCount: 0, categoryCount: 0, tagCount: 0, commentCount: 0, leaveMsgCount: 0}
dayVisitCount: number = 0;
userInfo: User = new User();
ngOnInit(): void {
}
getLog() {
this.http.get('https://api.celess.cn/blog.log', {responseType: 'text'}).subscribe(data => {
this.logText = data;
this.logLoading = false
});
}
getCounts = () => this.apiService.counts().subscribe({
next: data => this.counts = data.result
})
getDayVisitCount = () => this.apiService.dayVisitCount().subscribe({
next: data => this.dayVisitCount = data.result
})
getUserInfo = () => this.userService.watchUserInfo({
next: data => {
this.userInfo = data.result
if (data.result && data.result.role === 'admin') {
this.getLog();
this.getCounts();
this.getDayVisitCount();
}
},
error: null,
complete: null
})
}

View File

@@ -0,0 +1,31 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AdminDashboardComponent} from './admin-dashboard.component';
import {RouterModule} from '@angular/router';
import {
NzButtonModule,
NzCardModule,
NzDividerModule,
NzGridModule,
NzIconModule,
NzSpinModule,
NzStatisticModule
} from 'ng-zorro-antd';
@NgModule({
declarations: [AdminDashboardComponent],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminDashboardComponent}]),
NzGridModule,
NzCardModule,
NzButtonModule,
NzSpinModule,
NzIconModule,
NzStatisticModule,
NzDividerModule
]
})
export class AdminDashboardModule {
}

View File

@@ -0,0 +1,62 @@
<div class="inner-content">
<nz-card nzTitle="友链管理" nzSize="small">
<button nz-button (click)="addLink()" style="margin-bottom: 15px">新增</button>
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" [nzLoading]="loading"
(nzPageIndexChange)="getLinks()" nzFrontPagination="false">
<thead>
<th>友链名称</th>
<th>友链地址</th>
<th>是否可见</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td>{{data.name}}</td>
<td><a [href]="data.url" target="_blank">{{data.url}}</a></td>
<td>
<input type="checkbox" disabled [checked]="data.open">
</td>
<td>
<a (click)="showEdit(data)" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这条友链吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="delete(data.id)" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-card>
</div>
<nz-modal [(nzVisible)]="modalVisible" [nzTitle]="modalTitle" (nzOnOk)="modalConfirm()"
(nzOnCancel)="modalVisible = false" [nzClosable]="true" [nzOkDisabled]="!formGroup.valid">
<form nz-form [formGroup]="formGroup">
<nz-form-item>
<nz-form-label nzRequired>网站名称</nz-form-label>
<nz-form-control nzErrorTip="网站名称不可为空">
<input nz-input formControlName="name">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzRequired>网站链接</nz-form-label>
<nz-form-control [nzErrorTip]="nameErrTip">
<input nz-input formControlName="url">
<ng-template #nameErrTip>
<div *ngIf="formGroup.controls.url.hasError('required')">网站链接不可为空</div>
<div *ngIf="formGroup.controls.url.hasError('pattern')">网站链接格式不正确</div>
<div></div>
</ng-template>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzRequired>是否公开</nz-form-label>
<nz-form-control nzErrorTip="不可为空">
<nz-select nzPlaceHolder="请选择" formControlName="open" [nzAllowClear]="true">
<nz-option [nzValue]="true" nzLabel="公开"></nz-option>
<nz-option [nzValue]="false" nzLabel="不公开"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
</form>
</nz-modal>

View File

@@ -0,0 +1,91 @@
import {Component, OnInit} from '@angular/core';
import {PageList, Response} from '../../../class/HttpReqAndResp';
import {Link} from '../../../class/Link';
import {ApiService} from '../../../api/api.service';
import {NzMessageService} from 'ng-zorro-antd';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {Observable} from 'rxjs';
@Component({
selector: 'app-admin-link',
templateUrl: './admin-link.component.html',
styleUrls: ['./admin-link.component.less']
})
export class AdminLinkComponent implements OnInit {
constructor(private apiService: ApiService, private messageService: NzMessageService) {
this.formGroup = new FormGroup({
id: new FormControl(null),
name: new FormControl(null, [Validators.required]),
url: new FormControl(null, [Validators.required, Validators.pattern(/^(https:\/\/|http:\/\/|)([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/)]),
open: new FormControl(null, [Validators.required]),
oper: new FormControl(null)
})
}
pageList: PageList<Link> = new PageList<Link>();
loading: boolean = true;
pageIndex: number = 1;
pageSize: number = 10;
modalVisible: boolean = false;
modalTitle: string = '';
formGroup: FormGroup;
getLinks = () => this.apiService.adminLinks(this.pageSize, this.pageIndex).subscribe({
next: data => this.pageList = data.result,
error: () => this.loading = false,
complete: () => this.loading = false,
})
ngOnInit(): void {
this.getLinks();
}
delete(id: number) {
this.apiService.deleteLink(id).subscribe({
next: data => {
this.messageService.success('删除成功');
this.getLinks();
},
error: () => {
this.loading = false;
this.messageService.error('删除失败');
},
complete: () => this.loading = false,
})
}
showEdit(data: Link) {
this.modalVisible = true;
this.modalTitle = '编辑友链信息';
this.formGroup.patchValue(data);
this.formGroup.controls.oper.setValue('edit')
}
modalConfirm() {
this.modalVisible = false;
const linkReq: Link = new Link();
linkReq.name = this.formGroup.value.name;
linkReq.url = this.formGroup.value.url;
linkReq.open = this.formGroup.value.open;
const oper = this.formGroup.value.oper;
let observable: Observable<Response<Link>>;
if (oper === 'edit') {
linkReq.id = this.formGroup.value.id;
observable = this.apiService.updateLink(linkReq);
} else if (oper === 'add') {
observable = this.apiService.createLink(linkReq);
}
observable.subscribe({
next: data => this.messageService.success('操作成功'),
error: err => this.messageService.success('操作失败,', err.msg),
complete: () => this.getLinks()
})
}
addLink() {
this.modalVisible = true;
this.modalTitle = '新增友链信息';
this.formGroup.controls.oper.setValue('add')
}
}

View File

@@ -0,0 +1,37 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminLinkComponent} from './admin-link.component';
import {
NzButtonModule,
NzCardModule,
NzDividerModule,
NzFormModule, NzInputModule,
NzModalModule,
NzPopconfirmModule, NzSelectModule,
NzTableModule
} from 'ng-zorro-antd';
import {ReactiveFormsModule} from '@angular/forms';
@NgModule({
declarations: [
AdminLinkComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminLinkComponent}]),
NzCardModule,
NzTableModule,
NzDividerModule,
NzPopconfirmModule,
NzModalModule,
NzFormModule,
ReactiveFormsModule,
NzInputModule,
NzSelectModule,
NzButtonModule
]
})
export class AdminLinkModule {
}

View File

@@ -0,0 +1,65 @@
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AdminComponent} from './admin.component';
import {AuthGuard} from './auth.guard';
const routes: Routes = [
{
path: '',
component: AdminComponent,
// canActivate: [AuthGuard],
children: [
{
path: 'article',
loadChildren: () => import('./admin-article/admin-article.module').then(mod => mod.AdminArticleModule),
canActivate: [AuthGuard]
},
{
path: 'comment',
loadChildren: () => import('./admin-comment/admin-comment.module').then(mod => mod.AdminCommentModule),
canActivate: [AuthGuard]
},
{
path: 'link',
loadChildren: () => import('./admin-link/admin-link.module').then(mod => mod.AdminLinkModule),
canActivate: [AuthGuard]
},
{
path: 'tag',
loadChildren: () => import('./admin-tag/admin-tag.module').then(mod => mod.AdminTagModule),
canActivate: [AuthGuard]
},
{
path: 'update',
loadChildren: () => import('./admin-update/admin-update.module').then(mod => mod.AdminUpdateModule),
canActivate: [AuthGuard]
},
{
path: 'user',
loadChildren: () => import('./admin-user/admin-user.module').then(mod => mod.AdminUserModule),
canActivate: [AuthGuard]
},
{
path: 'visitor',
loadChildren: () => import('./admin-visitor/admin-visitor.module').then(mod => mod.AdminVisitorModule),
canActivate: [AuthGuard]
},
{
path: '**',
loadChildren: () => import('./admin-dashboard/admin-dashboard.module').then(mod => mod.AdminDashboardModule),
canActivate: [AuthGuard]
}
]
}
];
@NgModule({
imports: [
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class AdminRoutingModule {
}

View File

@@ -0,0 +1,92 @@
<div class="inner-content">
<nz-card nzTitle="" nzSize="small">
<nz-tabset>
<nz-tab nzTitle="分类管理" (nzClick)="editInfo.editFocus=false">
<div style="margin-bottom: 15px;">
<nz-input-group *ngIf="editInfo.editFocus&&editInfo.isAdd" [nzPrefix]="tagIcon"
style="width: 200px">
<input type="text" nz-input [(ngModel)]="editInfo.name" (keyup.enter)="addCategory()"
[autofocus]="editInfo.editFocus"
(blur)="editInfo.editFocus=false">
</nz-input-group>
<button nz-button (click)="addCategory()">新增分类</button>
<button nz-button (click)="editInfo.editFocus=false" *ngIf="editInfo.editFocus&&editInfo.isAdd">取消
</button>
</div>
<nz-table #table [nzData]="categoryList" [nzTotal]="categoryList.length"
(nzPageIndexChange)="getCategory()"
nzFrontPagination="false" [nzLoading]="loading">
<thead>
<th>分类名</th>
<th>分类文章数量</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td>
<span *ngIf="!editInfo.editFocus||data.id!==editInfo.id">{{data.name}}</span>
<nz-input-group *ngIf="!editInfo.isAdd&&editInfo.editFocus&&data.id===editInfo.id"
[nzPrefix]="tagIcon" style="width: 300px">
<input type="text" nz-input [(ngModel)]="editInfo.name" nzSize="small"
[autofocus]="editInfo.editFocus&&data.id===editInfo.id"
(keyup.enter)="edit('category')" (blur)="editInfo.editFocus=false">
<button nz-button (click)="edit('category')" nzSize="small">更新</button>
<button nz-button (click)="editInfo.editFocus=false" nzSize="small">取消</button>
</nz-input-group>
</td>
<td>
<nz-tag [nzColor]="'purple'">{{data.articles ? data.articles.length : 0}}</nz-tag>
</td>
<td>
<a (click)="editFocus(data)" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a [routerLink]="'/categories/'+data.name" class="show-opr">查看</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这个分类吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="delete(data.id,'category')" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-tab>
<nz-tab nzTitle="标签管理" (nzClick)="editInfo.editFocus=false">
<nz-table #tagTable [nzData]="tagPageList.list" [nzTotal]="tagPageList.total"
[(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" (nzPageIndexChange)="getTag()" nzFrontPagination="false">
<thead>
<th>标签名</th>
<th>分类文章数量</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of tagTable.data">
<td>
<span *ngIf="!editInfo.editFocus||data.id!==editInfo.id">{{data.name}}</span>
<nz-input-group *ngIf="!editInfo.isAdd&&editInfo.editFocus&&data.id===editInfo.id"
[nzPrefix]="tagIcon" style="width: 300px">
<input type="text" nz-input [(ngModel)]="editInfo.name" nzSize="small"
[autofocus]="editInfo.editFocus&&data.id===editInfo.id"
(keyup.enter)="edit('tag')" (blur)="editInfo.editFocus=false">
<button nz-button (click)="edit('tag')" nzSize="small">更新</button>
<button nz-button (click)="editInfo.editFocus=false" nzSize="small">取消</button>
</nz-input-group>
</td>
<td>
<nz-tag [nzColor]="'purple'">{{data.articles ? data.articles.length : 0}}</nz-tag>
</td>
<td>
<a (click)="editFocus(data)" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a [routerLink]="'/tags/'+data.name" class="show-opr">查看</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这个标签吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="delete(data.id,'tag')" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-tab>
</nz-tabset>
</nz-card>
</div>
<ng-template #tagIcon><i nz-icon nzType="tag" nzTheme="outline"></i></ng-template>

View File

@@ -0,0 +1,141 @@
import {Component, OnInit} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd';
import {Category, Tag} from '../../../class/Tag';
import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp';
import {Title} from '@angular/platform-browser';
@Component({
selector: 'app-admin-tag',
templateUrl: './admin-tag.component.html',
styleUrls: ['./admin-tag.component.less']
})
export class AdminTagComponent implements OnInit {
constructor(private apiService: ApiService, private nzMessageService: NzMessageService, private title: Title) {
}
loading: boolean = true;
categoryList: Category[] = [];
editInfo = {
id: null,
name: null,
editFocus: false,
isAdd: false
}
tagPageList: PageList<Tag> = new PageList<Tag>();
pageIndex: number = 1;
pageSize: number = 10;
ngOnInit(): void {
this.title.setTitle('小海博客 | 标签分类管理')
this.getCategory();
this.getTag();
}
getCategory = () => this.apiService.categories().subscribe({
next: data => this.categoryList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
getTag = () => this.apiService.tags(this.pageIndex, this.pageSize).subscribe({
next: data => this.tagPageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
delete(id, mode: 'tag' | 'category') {
this.loading = true;
if (mode === 'tag') {
this.apiService.deleteTag(id).subscribe({
next: data => {
this.nzMessageService.success('删除成功')
this.getTag();
},
complete: () => this.loading = false,
error: err => {
this.nzMessageService.error(err.msg)
this.loading = false
}
})
} else if (mode === 'category') {
this.apiService.deleteCategory(id).subscribe({
next: data => {
this.nzMessageService.success('删除成功')
this.getCategory();
},
complete: () => this.loading = false,
error: err => {
this.nzMessageService.error(err.msg)
this.loading = false
}
})
}
}
editFocus(data: Category) {
this.editInfo.isAdd = false;
this.editInfo.id = data.id;
this.editInfo.name = data.name;
this.editInfo.editFocus = true;
}
edit(mode: 'tag' | 'category') {
this.loading = true;
if (mode === 'tag') {
this.apiService.updateTag(this.editInfo.id, this.editInfo.name).subscribe({
next: data => {
this.nzMessageService.success('更新成功')
this.getTag();
},
complete: () => this.loading = false,
error: err => {
this.nzMessageService.error(err.msg)
this.loading = false
}
})
} else if (mode === 'category') {
this.apiService.updateCategory(this.editInfo.id, this.editInfo.name).subscribe({
next: data => {
this.nzMessageService.success('更新成功')
this.getCategory();
},
complete: () => this.loading = false,
error: err => {
this.nzMessageService.error(err.msg)
this.loading = false
}
})
}
this.editInfo.editFocus = false
this.editInfo.name = null
}
addCategory() {
this.editInfo.isAdd = true
if (!this.editInfo.editFocus && this.editInfo.isAdd) {
this.editInfo.name = null;
this.editInfo.id = null;
this.editInfo.editFocus = true;
return
}
this.apiService.createCategory(this.editInfo.name).subscribe({
next: data => {
this.nzMessageService.success('新增成功')
this.getCategory();
},
complete: () => this.loading = false,
error: err => {
this.nzMessageService.error(err.msg)
this.loading = false
}
});
this.editInfo.editFocus = false
this.editInfo.isAdd = false
this.editInfo.name = null
}
}

View File

@@ -0,0 +1,35 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminTagComponent} from './admin-tag.component';
import {
NzButtonModule,
NzCardModule,
NzDividerModule, NzIconModule,
NzInputModule, NzPopconfirmModule,
NzTableModule, NzTabsModule, NzTagModule,
} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [
AdminTagComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminTagComponent}]),
NzCardModule,
NzTableModule,
NzDividerModule,
NzInputModule,
FormsModule,
NzTabsModule,
NzPopconfirmModule,
NzButtonModule,
NzIconModule,
NzTagModule,
]
})
export class AdminTagModule {
}

View File

@@ -0,0 +1,32 @@
<div class="inner-content">
<nz-card nzTitle="更新内容管理" nzSize="small">
<button nz-button (click)="showModal()" style="margin-bottom: 15px;">新增</button>
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" [nzLoading]="loading"
(nzPageIndexChange)="getUpdateInfo()" nzFrontPagination="false">
<thead>
<th>更新内容</th>
<th>更新日期</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td nz-typography nzEllipsis="true" [nzTooltipTitle]="data.info" nzTooltipPlacement="top"
nz-tooltip>{{data.info}}</td>
<td>{{data.time}}</td>
<td>
<a (click)="showModal(data)" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这个更新吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="deleteUpdateInfo(data.id)" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-card>
</div>
<nz-modal [(nzVisible)]="modalData.visible" [nzClosable]="true" (nzOnCancel)="modalData.visible = false"
(nzOnOk)="confirm()" [nzTitle]="modalData.title">
<textarea nz-input [(ngModel)]="modalData.content" [nzAutosize]="{ minRows: 2, maxRows: 8 }"></textarea>
</nz-modal>

View File

@@ -0,0 +1,3 @@
td {
max-width: 300px;
}

View File

@@ -0,0 +1,95 @@
import {Component, OnInit} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd';
import {Title} from '@angular/platform-browser';
import {Observable} from 'rxjs';
import {ApiService} from '../../../api/api.service';
import {PageList, Response} from '../../../class/HttpReqAndResp';
import {UpdateInfo} from '../../../class/UpdateInfo';
@Component({
selector: 'app-admin-update',
templateUrl: './admin-update.component.html',
styleUrls: ['./admin-update.component.less']
})
export class AdminUpdateComponent implements OnInit {
constructor(private apiService: ApiService, private nzMessage: NzMessageService, private title: Title) {
}
pageIndex: number = 1;
pageSize: number = 10;
pageList: PageList<UpdateInfo> = new PageList();
loading: boolean = true;
modalData = {
visible: false,
content: null,
id: null,
title: null
};
ngOnInit(): void {
this.title.setTitle('小海博客 | 更新信息管理')
this.getUpdateInfo();
}
getUpdateInfo = () => this.apiService.webUpdatePage(this.pageSize, this.pageIndex).subscribe({
next: data => this.pageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
deleteUpdateInfo(id) {
this.loading = true;
this.apiService.deleteWebUpdateInfo(id).subscribe({
next: data => {
this.nzMessage.success('删除成功')
this.loading = false;
this.getUpdateInfo();
},
error: err => {
this.nzMessage.error(err.msg)
this.loading = false
}
})
}
confirm() {
this.loading = true;
this.modalData.visible = false;
let observable: Observable<Response<UpdateInfo>>
if (this.modalData.id) {
observable = this.apiService.updateWebUpdateInfo(this.modalData.id, this.modalData.content)
} else {
observable = this.apiService.createWebUpdateInfo(this.modalData.content)
}
observable.subscribe({
next: data => {
this.nzMessage.success('操作成功')
this.loading = false;
this.getUpdateInfo();
},
error: err => {
this.nzMessage.error(err.msg)
this.loading = false
}
})
console.log(this.modalData);
}
showModal(data?: UpdateInfo) {
this.modalData.id = null;
this.modalData.title = '新增更新信息';
this.modalData.content = null;
if (data) {
this.modalData.id = data.id;
this.modalData.content = data.info;
this.modalData.title = '编辑更新信息';
}
this.modalData.visible = true;
}
}

View File

@@ -0,0 +1,37 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminUpdateComponent} from './admin-update.component';
import {
NzButtonModule,
NzCardModule,
NzDividerModule, NzInputModule, NzModalModule,
NzPopconfirmModule,
NzTableModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [
AdminUpdateComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminUpdateComponent}]),
NzCardModule,
NzTableModule,
NzTypographyModule,
NzToolTipModule,
NzDividerModule,
NzPopconfirmModule,
NzModalModule,
FormsModule,
NzButtonModule,
NzInputModule
]
})
export class AdminUpdateModule {
}

View File

@@ -0,0 +1,117 @@
<div class="inner-content">
<nz-card nzTitle="用户管理" nzSize="small">
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" [nzLoading]="loading"
(nzPageIndexChange)="getUser()" nzFrontPagination="false">
<thead>
<th>邮箱</th>
<th>昵称</th>
<th>角色</th>
<th>邮箱验证状态</th>
<th>操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td>{{data.email}}</td>
<td>{{data.displayName}}</td>
<td>
<nz-tag [nzColor]="'blue'" *ngIf="data.role == 'admin'">{{data.role}}</nz-tag>
<nz-tag [nzColor]="'purple'" *ngIf="data.role == 'user'">{{data.role}}</nz-tag>
</td>
<td>
<nz-tag [nzColor]="'green'" *ngIf="data.emailStatus">已验证</nz-tag>
<nz-tag [nzColor]="'red'" *ngIf="!data.emailStatus">未验证</nz-tag>
</td>
<td>
<a (click)="showModal(true, data)" class="edit-opr">编辑</a>
<nz-divider nzType="vertical"></nz-divider>
<a (click)="showModal(false, data)" class="show-opr">查看</a>
<nz-divider nzType="vertical"></nz-divider>
<a nz-popconfirm nzPopconfirmTitle="确定要删除这个用户吗?" nzOkText="删除" nzCancelText="点错了"
(nzOnConfirm)="deleteUser(data.id)" class="del-opr">删除</a>
</td>
</tr>
</tbody>
</nz-table>
</nz-card>
</div>
<nz-modal [(nzVisible)]="modalData.visible" [nzClosable]="true" [nzTitle]="modalData.title"
(nzOnCancel)="modalData.visible = false" (nzOnOk)="modalConfirm()"
[nzFooter]="modalData.isEdit?editContentFooter:showContentFooter"
[nzContent]="showContent">
<ng-template #showContent>
<form nz-form [formGroup]="formGroup" (ngSubmit)="modalConfirm()">
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired>邮箱</nz-form-label>
<nz-form-control nzSpan="18">
<input type="email" nz-input formControlName="email"
[disabled]="!modalData.isEdit">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired>昵称</nz-form-label>
<nz-form-control nzSpan="18">
<input type="text" nz-input formControlName="displayName" [disabled]="!modalData.isEdit">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired>角色</nz-form-label>
<nz-form-control nzSpan="18">
<nz-select formControlName="role" [nzDisabled]="!modalData.isEdit||formGroup.value.id==user.id">
<nz-option nzValue="admin" nzLabel="admin"></nz-option>
<nz-option nzValue="user" nzLabel="user"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4" nzRequired>状态</nz-form-label>
<nz-form-control nzSpan="18">
<nz-radio-group formControlName="emailStatus" [nzDisabled]="!modalData.isEdit">
<label nz-radio [nzValue]="true">邮箱已验证</label>
<label nz-radio [nzValue]="false">邮箱未验证</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="modalData.isEdit">
<nz-form-label nzSpan="4">密码</nz-form-label>
<nz-form-control nzSpan="18">
<a *ngIf="!modalData.resetPwd" (click)="modalData.resetPwd = true">
重设密码<i nz-icon nzType="edit" nzTheme="twotone" style="margin-left: 10px;"></i>
</a>
<nz-input-group *ngIf="modalData.resetPwd" [nzSuffix]="cancelBtn" nzSize="small">
<input type="password" nz-input formControlName="pwd" autocomplete="new-password"
[disabled]="!modalData.isEdit">
<ng-template #cancelBtn>
<button nz-button (click)="modalData.resetPwd = false" nzSize="small" nzType="link">取消
</button>
</ng-template>
</nz-input-group>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzSpan="4">描述</nz-form-label>
<nz-form-control nzSpan="18">
<textarea nz-input [nzAutosize]="{ minRows: 2, maxRows: 4 }" formControlName="desc"
[disabled]="!modalData.isEdit"></textarea>
</nz-form-control>
</nz-form-item>
</form>
</ng-template>
<ng-template #showContentFooter>
<button nz-button (click)="modalData.visible = false">关闭</button>
</ng-template>
<ng-template #editContentFooter>
<button nz-button (click)="modalData.visible = false">取消</button>
<button nz-button (click)="modalConfirm()" nzType="primary">提交</button>
</ng-template>
</nz-modal>

View File

@@ -0,0 +1,93 @@
import {Component, OnInit} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd';
import {Title} from '@angular/platform-browser';
import {FormControl, FormGroup} from '@angular/forms';
import {PageList} from '../../../class/HttpReqAndResp';
import {ApiService} from '../../../api/api.service';
import {User} from '../../../class/User';
import {GlobalUserService} from '../../../services/global-user.service';
@Component({
selector: 'app-admin-user',
templateUrl: './admin-user.component.html',
styleUrls: ['./admin-user.component.less']
})
export class AdminUserComponent implements OnInit {
constructor(private apiService: ApiService, private title: Title, private messageService: NzMessageService,
private userService: GlobalUserService) {
this.formGroup = new FormGroup({
id: new FormControl(null),
email: new FormControl(''),
displayName: new FormControl(''),
emailStatus: new FormControl(null),
desc: new FormControl(null),
role: new FormControl(null),
pwd: new FormControl(''),
});
this.userService.watchUserInfo({
next: data => this.user = data.result,
error: null,
complete: null
})
}
pageIndex: number = 1;
pageSize: number = 10;
pageList: PageList<User> = new PageList<User>();
user: User;
loading: boolean = true;
modalData = {
visible: false,
title: null,
isEdit: false,
resetPwd: false
}
formGroup: FormGroup;
ngOnInit(): void {
this.title.setTitle('小海博客 | 用户管理')
this.getUser();
}
getUser = () => this.apiService.adminUsers(this.pageSize, this.pageIndex).subscribe({
next: data => this.pageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
deleteUser(id) {
this.loading = true;
this.apiService.deleteUser(id).subscribe({
next: data => {
this.messageService.success('删除成功')
this.loading = false;
this.getUser();
},
error: err => {
this.messageService.error(err.msg)
this.loading = false
}
})
}
showModal(isEdit: boolean, data: User) {
this.modalData.visible = true;
this.modalData.isEdit = isEdit;
this.modalData.title = isEdit ? '编辑用户' : '查看用户'
this.formGroup.reset();
this.formGroup.patchValue(data);
}
modalConfirm() {
this.modalData.visible = false
this.apiService.adminUpdateUser(this.formGroup.value).subscribe({
next: data => {
this.getUser();
this.messageService.success('修改用户信息成功');
this.userService.refreshUserInfo();
}
})
}
}

View File

@@ -0,0 +1,41 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminUserComponent} from './admin-user.component';
import {
NzButtonModule,
NzCardModule,
NzDividerModule, NzFormModule, NzIconModule, NzInputModule,
NzModalModule,
NzPopconfirmModule, NzRadioModule, NzSelectModule,
NzTableModule,
NzTagModule
} from 'ng-zorro-antd';
import {ReactiveFormsModule} from '@angular/forms';
@NgModule({
declarations: [
AdminUserComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminUserComponent}]),
NzCardModule,
NzTableModule,
NzPopconfirmModule,
NzDividerModule,
NzTagModule,
NzModalModule,
NzButtonModule,
NzFormModule,
ReactiveFormsModule,
NzInputModule,
NzSelectModule,
NzRadioModule,
NzIconModule
]
})
export class AdminUserModule {
}

View File

@@ -0,0 +1,24 @@
<div class="inner-content">
<nz-card nzTitle="访客信息管理" nzSize="small">
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" [nzLoading]="loading"
(nzPageIndexChange)="getVisitors()" nzFrontPagination="false">
<thead>
<th>ip地址</th>
<th>访问日期</th>
<th>浏览器类型</th>
<th>浏览器版本</th>
<th>系统</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td>{{data.ip}}</td>
<td>{{data.date}}</td>
<td>{{data.browserName}}</td>
<td>{{data.browserVersion}}</td>
<td>{{data.osname}}</td>
</tr>
</tbody>
</nz-table>
</nz-card>
</div>

View File

@@ -0,0 +1,34 @@
import {Component, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp';
import {Visitor} from '../../../class/Visitor';
@Component({
selector: 'app-admin-visitor',
templateUrl: './admin-visitor.component.html',
styleUrls: ['./admin-visitor.component.less']
})
export class AdminVisitorComponent implements OnInit {
constructor(private apiService: ApiService, private title: Title) {
}
pageIndex: number = 1;
pageSize: number = 10;
pageList: PageList<Visitor> = new PageList<Visitor>();
loading: boolean = true;
ngOnInit(): void {
this.title.setTitle('小海博客 | 访客信息管理')
this.getVisitors();
}
getVisitors = () => this.apiService.adminVisitors(false, this.pageSize, this.pageIndex).subscribe({
next: data => this.pageList = data.result,
complete: () => this.loading = false,
error: err => this.loading = false
})
}

View File

@@ -0,0 +1,22 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
import {AdminVisitorComponent} from './admin-visitor.component';
import {NzButtonModule, NzCardModule, NzDividerModule, NzTableModule} from 'ng-zorro-antd';
@NgModule({
declarations: [
AdminVisitorComponent
],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: AdminVisitorComponent}]),
NzCardModule,
NzTableModule,
NzButtonModule,
NzDividerModule
]
})
export class AdminVisitorModule {
}

View File

@@ -0,0 +1,159 @@
<c-admin-header (infoClicked)="showInfoDrawer()"></c-admin-header>
<nz-layout class="layout">
<nz-sider nzCollapsible
[(nzCollapsed)]="isCollapsed"
[nzBreakpoint]="'lg'"
[nzCollapsedWidth]="0"
[nzZeroTrigger]="zeroTrigger"
nzTheme="light"
*ngIf="user">
<ul nz-menu nzTheme="light" nzMode="inline" [nzInlineCollapsed]="isCollapsed">
<li nz-menu-item routerLink="/admin">
<i nz-icon nzType="dashboard" nzTheme="outline"></i>
<span>后台首页</span>
</li>
<li nz-submenu nzTitle="文章管理" nzIcon="file" *ngIf="user.role=='admin'">
<ul>
<li nz-menu-item>
<a routerLink="/write">
<i nz-icon nzType="form" nzTheme="outline"></i>
<span>新增文章</span>
</a>
</li>
<li nz-menu-item routerLink="/admin/article">
<i nz-icon nzType="ordered-list" nzTheme="outline"></i>
<span>文章列表</span>
</li>
</ul>
</li>
<li nz-menu-item routerLink="/admin/comment">
<i nz-icon nzType="message" nzTheme="outline"></i>
<span>评论管理</span>
</li>
<li nz-menu-item routerLink="/admin/tag" *ngIf="user.role=='admin'">
<i nz-icon nzType="tags" nzTheme="outline"></i>
<span>标签管理</span>
</li>
<!-- <li nz-menu-item routerLink="/admin/category" *ngIf="user.role=='admin'">-->
<!-- <i nz-icon nzType="appstore" nzTheme="outline"></i>-->
<!-- <span>分类管理</span>-->
<!-- </li>-->
<li nz-menu-item routerLink="/admin/user" *ngIf="user.role=='admin'">
<i nz-icon nzType="user" nzTheme="outline"></i>
<span>用户管理</span>
</li>
<li nz-menu-item routerLink="/admin/link" *ngIf="user.role=='admin'">
<i nz-icon nzType="link" nzTheme="outline"></i>
<span>友链管理</span>
</li>
<li nz-menu-item routerLink="/admin/visitor" *ngIf="user.role=='admin'">
<i nz-icon nzType="chrome" nzTheme="outline"></i>
<span>访问管理</span>
</li>
<li nz-menu-item routerLink="/admin/update" *ngIf="user.role=='admin'">
<i nz-icon nzType="arrow-up" nzTheme="outline"></i>
<span>更新管理</span>
</li>
<li nz-menu-item (click)="infoDrawerVisible = true">
<i nz-icon nzType="idcard" nzTheme="outline"></i>
<span>查看信息</span>
</li>
<!--TODO : do something here ..... -->
<nz-card class="myCard" *ngIf="!isCollapsed&&user.role=='admin'">
<p>别管别人言语</p>
<p>做最好的自己</p>
</nz-card>
<nz-card class="myCard" *ngIf="!isCollapsed&&user.role=='user'">
<p>欢迎来访小海博客</p>
</nz-card>
</ul>
</nz-sider>
<nz-layout>
<nz-content>
<div class="inner-content">
<router-outlet></router-outlet>
</div>
</nz-content>
<nz-footer>© <a href="https://www.celess.cn">小海博客</a> - Design by 小海</nz-footer>
</nz-layout>
</nz-layout>
<nz-drawer [nzClosable]="false" [nzVisible]="infoDrawerVisible" nzPlacement="right"
[nzTitle]="sayHelloTemp" (nzOnClose)="infoDrawerVisible = false">
<p>您最近一次登录是在:</p>
<p>{{user.recentlyLandedDate}}</p>
<br><br>
<nz-descriptions [nzColumn]="1">
<nz-descriptions-item nzTitle="邮箱">
<!-- 抽屉的宽度是256px -->
<div style="width: 256px">
<i nz-icon nzType="mail" class="icon" nzTheme="twotone"></i>
<span>{{user.email}}</span>
<i nz-icon nzType="edit" class="edit-icon" nzTheme="twotone" (click)="showEditInfoModal()"></i>
</div>
</nz-descriptions-item>
<nz-descriptions-item nzTitle="昵称">
<div style="width: 256px">
<i nz-icon nzType="crown" class="icon" nzTheme="twotone"></i>
<span>{{user.displayName}}</span>
<i nz-icon nzType="edit" class="edit-icon" nzTheme="twotone" (click)="showEditInfoModal()"></i>
</div>
</nz-descriptions-item>
<nz-descriptions-item nzTitle="描述" *ngIf="user.desc">
<div style="width: 256px">
<i nz-icon nzType="info-circle" class="icon" nzTheme="twotone"></i>
<span>{{user.desc}}</span>
<i nz-icon nzType="edit" class="edit-icon" nzTheme="twotone" (click)="showEditInfoModal()"></i>
</div>
</nz-descriptions-item>
</nz-descriptions>
<div nz-row style="text-align: center">
<a (click)="logout()" style="width: 100%">注销</a>
</div>
<!-- TODO: 展示更多信息 -->
</nz-drawer>
<nz-modal [(nzVisible)]="editInfoModalVisible" (nzOnOk)="modalConfirm()" (nzOnCancel)="editInfoModalVisible=false"
nzTitle="编辑信息">
<form nz-form [formGroup]="editInfoFormGroup" (ngSubmit)="modalConfirm()">
<nz-form-item>
<nz-form-label>邮箱</nz-form-label>
<nz-form-control>
<input nz-input disabled formControlName="email">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>昵称</nz-form-label>
<nz-form-control>
<input nz-input formControlName="displayName" placeholder="默认为你的邮箱地址">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label>描述</nz-form-label>
<nz-form-control>
<input nz-input formControlName="desc" placeholder="请输入自我介绍">
</nz-form-control>
</nz-form-item>
</form>
</nz-modal>
<ng-template #zeroTrigger>
<i nz-icon nzType="menu-fold" nzTheme=outline></i>
</ng-template>
<ng-template #sayHelloTemp>
<span>{{sayHelloContent}}</span>
<i nz-icon [nzType]="'smile'" [nzTheme]="'twotone'" nzTwotoneColor="#52c41a" style="margin-left: 5px"></i>
</ng-template>

View File

@@ -0,0 +1,48 @@
.myCard {
width: 180px;
margin-left: 10px;
}
nz-layout, nz-sider {
min-height: 100%;
}
.layout {
padding-top: 80px;
}
p {
text-align: center;
}
nz-content {
margin-left: 30px;
margin-right: 30px;
}
.inner-content {
padding: 15px;
background: #fff;
min-height: 560px;
height: 100%;
}
.icon {
margin-right: 5px;
}
.edit-icon{
margin-left: 10px;
cursor: pointer;
}
nz-footer {
text-align: center;
}
@media only screen and (max-width: 768px) {
nz-content {
margin-left: 10px;
margin-right: 10px;
}
}

View File

@@ -0,0 +1,92 @@
import {Component, OnInit} from '@angular/core';
import {FormControl, FormGroup} from '@angular/forms';
import {NzMessageService} from 'ng-zorro-antd';
import {Router} from '@angular/router';
import {GlobalUserService} from '../../services/global-user.service';
import {User} from '../../class/User';
import {ApiService} from '../../api/api.service';
@Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.less']
})
export class AdminComponent implements OnInit {
constructor(public gUserService: GlobalUserService, private apiService: ApiService, private messageService: NzMessageService,
private router: Router) {
this.gUserService.watchUserInfo({
complete: () => null,
error: (err) => null,
next: data => {
console.log('更新user')
this.user = data.result
if (data.result) this.initHelloWords()
}
}
)
}
user: User;
isCollapsed: boolean = false;
infoDrawerVisible: boolean = false;
sayHelloContent: string;
editInfoModalVisible: boolean = false;
editInfoFormGroup: FormGroup;
showInfoDrawer = () => this.infoDrawerVisible = !this.infoDrawerVisible;
logout() {
this.gUserService.logout();
this.router.navigateByUrl('/')
}
ngOnInit(): void {
this.editInfoFormGroup = new FormGroup({
desc: new FormControl(),
displayName: new FormControl(),
email: new FormControl({value: null, disabled: true})
});
}
private initHelloWords() {
const hours = new Date().getHours();
if (hours < 6) {
this.sayHelloContent = `夜深了,注意早点休息哦!${this.user.displayName}`
} else if (hours < 10) {
this.sayHelloContent = `早上好呀!${this.user.displayName}`
} else if (hours < 14) {
this.sayHelloContent = `中午好呀!${this.user.displayName}`
} else if (hours < 19) {
this.sayHelloContent = `下午好呀!${this.user.displayName}`
} else if (hours < 22) {
this.sayHelloContent = `晚上好呀!${this.user.displayName}`
} else {
this.sayHelloContent = `时间不早了,注意休息哦!${this.user.displayName}`
}
}
showEditInfoModal() {
this.editInfoModalVisible = true;
this.infoDrawerVisible = false;
this.editInfoFormGroup.patchValue(this.user);
}
modalConfirm() {
const desc = this.editInfoFormGroup.value.desc;
const displayName = this.editInfoFormGroup.value.displayName;
this.apiService.updateUserInfo(desc, displayName).subscribe({
next: data => {
this.messageService.success('修改信息成功')
this.gUserService.refreshUserInfo();
},
error: err => {
this.messageService.error(err.msg);
this.gUserService.refreshUserInfo();
},
complete: null
});
this.editInfoModalVisible = false;
}
}

View File

@@ -0,0 +1,25 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {AdminRoutingModule} from './admin-routing.module';
import {AdminComponent} from './admin.component';
import {NgZorroAntdModule} from 'ng-zorro-antd';
import {NzSpaceModule} from 'ng-zorro-antd/space';
import {AdminHeaderComponent} from '../../components/admin-header/admin-header.component';
import {ReactiveFormsModule} from '@angular/forms';
@NgModule({
declarations: [
AdminHeaderComponent,
AdminComponent
],
imports: [
CommonModule,
AdminRoutingModule,
NgZorroAntdModule,
NzSpaceModule,
ReactiveFormsModule
]
})
export class AdminModule {
}

View File

@@ -0,0 +1,70 @@
import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router} from '@angular/router';
import {Observable, Observer} from 'rxjs';
import {User} from '../../class/User';
import {GlobalUserService} from '../../services/global-user.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private userService: GlobalUserService, private router: Router) {
// this.userService.refreshUserInfo();
}
userInfo: User;
visitCount: number = 0; // 记录一共走过几次canActivate
private path: string;
private readonly loginPath: string = '/user/login';
private observable: Observable<boolean>;
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
this.path = state.url.indexOf('?') > 0 ? state.url.substr(0, state.url.indexOf('?')) : state.url;
this.visitCount++;
this.observable = new Observable<boolean>(observer => {
if (!this.userInfo) {
this.watchUserInfo(observer);
} else {
this.checkPath(observer);
}
});
return this.observable;
}
watchUserInfo(observer: Observer<boolean>) {
this.userService.watchUserInfo({
complete: null,
error: (err) => {
// 请求重复
if (err.code !== -1) {
observer.next(false);
this.router.navigateByUrl(this.loginPath);
}
},
next: data => {
this.userInfo = data.result;
this.checkPath(observer);
}
})
}
checkPath(observer: Observer<boolean>) {
switch (this.path) {
case '/admin/article':
case '/admin/link':
case '/admin/tag':
case '/admin/update':
case '/admin/user':
case '/admin/visitor':
if (this.userInfo.role !== 'admin') {
observer.next(false)
if (this.visitCount === 1) this.router.navigateByUrl('/admin')
return;
}
}
observer.next(true);
}
}