公共组件 #18

Merged
xiaohai2271 merged 45 commits from dev into master 2020-07-11 10:41:50 +08:00
42 changed files with 4643 additions and 4076 deletions

6836
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,41 +11,41 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^9.1.2", "@angular/animations": "^10.0.3",
"@angular/common": "^9.1.2", "@angular/common": "^10.0.3",
"@angular/compiler": "^9.1.2", "@angular/compiler": "^10.0.3",
"@angular/core": "^9.1.2", "@angular/core": "^10.0.3",
"@angular/forms": "^9.1.2", "@angular/forms": "^10.0.3",
"@angular/platform-browser": "^9.1.2", "@angular/platform-browser": "^10.0.3",
"@angular/platform-browser-dynamic": "^9.1.2", "@angular/platform-browser-dynamic": "^10.0.3",
"@angular/router": "^9.1.2", "@angular/router": "^10.0.3",
"@angular/service-worker": "^9.1.2", "@angular/service-worker": "^10.0.3",
"jquery": "^3.5.0", "jquery": "^3.5.1",
"ng-zorro-antd": "^9.0.1", "ng-zorro-antd": "^9.3.0",
"nrm": "^1.2.1", "nrm": "^1.2.1",
"rxjs": "^6.5.5", "rxjs": "^6.6.0",
"tslib": "^1.11.1", "tslib": "^2.0.0",
"zone.js": "^0.10.3" "zone.js": "^0.10.3"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^0.901.1", "@angular-devkit/build-angular": "^0.1000.2",
"@angular/cli": "^9.1.1", "@angular/cli": "^10.0.2",
"@angular/compiler-cli": "^9.1.2", "@angular/compiler-cli": "^10.0.3",
"@angular/language-service": "^9.1.2", "@angular/language-service": "^10.0.3",
"@types/jasmine": "^3.5.10", "@types/jasmine": "^3.5.11",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^13.11.1", "@types/node": "^14.0.22",
"codelyzer": "^5.2.2", "codelyzer": "^6.0.0",
"jasmine-core": "^3.5.0", "jasmine-core": "^3.5.0",
"jasmine-spec-reporter": "^5.0.1", "jasmine-spec-reporter": "^5.0.2",
"karma": "^5.0.1", "karma": "^5.1.0",
"karma-chrome-launcher": "^3.1.0", "karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^2.1.1", "karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^3.1.1", "karma-jasmine": "^3.3.1",
"karma-jasmine-html-reporter": "^1.5.3", "karma-jasmine-html-reporter": "^1.5.4",
"protractor": "^5.4.3", "protractor": "^7.0.0",
"ts-node": "^8.8.2", "ts-node": "^8.10.2",
"tslint": "^6.1.1", "tslint": "^6.1.2",
"typescript": "^3.8.3" "typescript": "^3.9.6"
} }
} }

View File

@@ -23,6 +23,7 @@ export class HttpService {
} }
Service<T>(request: RequestObj) { Service<T>(request: RequestObj) {
request.url = null;
// 设置默认值 // 设置默认值
request.contentType = request.contentType == null ? 'application/x-www-form-urlencoded' : request.contentType; request.contentType = request.contentType == null ? 'application/x-www-form-urlencoded' : request.contentType;
request.header = { request.header = {
@@ -32,7 +33,7 @@ export class HttpService {
if (token != null) { if (token != null) {
request.header.Authorization = token; request.header.Authorization = token;
} }
request.path = this.checkUrl(request); request.url = this.checkUrl(request);
let observable: Observable<HttpResponse<Response<T>>>; let observable: Observable<HttpResponse<Response<T>>>;
switch (request.method) { switch (request.method) {
@@ -73,7 +74,7 @@ export class HttpService {
} }
private get<T>(request: RequestObj) { private get<T>(request: RequestObj) {
return this.httpClient.get<T>(request.path, return this.httpClient.get<T>(request.url,
{ {
headers: request.header, headers: request.header,
withCredentials: true, withCredentials: true,
@@ -82,7 +83,7 @@ export class HttpService {
} }
private post<T>(request: RequestObj) { private post<T>(request: RequestObj) {
return this.httpClient.post<T>(request.path, request.data, return this.httpClient.post<T>(request.url, request.data,
{ {
headers: request.header, headers: request.header,
withCredentials: true, withCredentials: true,
@@ -91,7 +92,7 @@ export class HttpService {
} }
private put<T>(request: RequestObj) { private put<T>(request: RequestObj) {
return this.httpClient.put<T>(request.path, request.data, return this.httpClient.put<T>(request.url, request.data,
{ {
headers: request.header, headers: request.header,
withCredentials: true, withCredentials: true,
@@ -100,7 +101,7 @@ export class HttpService {
} }
private delete<T>(request: RequestObj) { private delete<T>(request: RequestObj) {
return this.httpClient.delete<T>(request.path, return this.httpClient.delete<T>(request.url,
{ {
headers: request.header, headers: request.header,
withCredentials: true, withCredentials: true,

View File

@@ -2,6 +2,7 @@ import {HttpHeaders} from '@angular/common/http';
export class RequestObj { export class RequestObj {
path: string; path: string;
url?: string; // 仅在httpService里面进行使用
method: 'GET' | 'POST' | 'PUT' | 'DELETE'; method: 'GET' | 'POST' | 'PUT' | 'DELETE';
data?: {}; data?: {};
contentType?: 'application/json' | 'application/x-www-form-urlencoded'; contentType?: 'application/json' | 'application/x-www-form-urlencoded';

View File

@@ -1,59 +1,32 @@
<div class="inner-content"> <common-table cardTitle="文章管理"
<nz-card nzTitle="文章管理" nzSize="small" [nzExtra]="reload"> #commonTableComponent
<nz-table #table [nzData]="pageList.list" [headData]="headData"
[nzTotal]="pageList.total" [request]="request"
[(nzPageIndex)]="page" [template]="{
[nzPageSize]="pageSize" original:{temp:original,param:{true:'原创',false:'转载'}},
[nzLoading]="loading" readingNumber:{temp:readingNumber},
[nzScroll]="{x:'1100px'}" likeCount:{temp:likeCount},
(nzPageIndexChange)="getArticle()" dislikeCount:{temp:dislikeCount},
nzFrontPagination="false" open:{temp:open}
nzTableLayout="fixed"> }">
<thead> </common-table>
<th>标题</th>
<th>发布日期</th>
<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>
<nz-tag [nzColor]="'blue'">{{data.likeCount}}</nz-tag>
</td>
<td>
<nz-tag [nzColor]="'magenta'">{{data.dislikeCount}}</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>
<ng-template #reload> <ng-template let-value="value" let-originValue="originValue" #original>
<a (click)="getArticle()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a> <nz-tag [nzColor]="originValue?'green':'#ff5500'">{{value}}</nz-tag>
</ng-template>
<ng-template let-value="value" #readingNumber>
<nz-tag nzColor="purple">{{value}}</nz-tag>
</ng-template>
<ng-template let-value="value" #likeCount>
<nz-tag nzColor="blue">{{value}}</nz-tag>
</ng-template>
<ng-template let-value="value" #dislikeCount>
<nz-tag nzColor="magenta">{{value}}</nz-tag>
</ng-template>
<ng-template #open let-value="value">
<label nz-checkbox nzDisabled [ngModel]="value"></label>
</ng-template> </ng-template>
</nz-table>
</nz-card>
</div>

View File

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

View File

@@ -1,49 +1,70 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd'; import {NzMessageService} from 'ng-zorro-antd';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp'; import {RequestObj} from '../../../class/HttpReqAndResp';
import {Article} from '../../../class/Article'; import {Article} from '../../../class/Article';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {Data} from '../components/common-table/data';
import {CommonTableComponent} from '../components/common-table/common-table.component';
import {Router} from '@angular/router';
@Component({ @Component({
selector: 'app-admin-article', selector: 'app-admin-article',
templateUrl: './admin-article.component.html', templateUrl: './admin-article.component.html'
styleUrls: ['./admin-article.component.less']
}) })
export class AdminArticleComponent implements OnInit { export class AdminArticleComponent implements OnInit {
constructor(private apiService: ApiService, private nzMessage: NzMessageService, private title: Title) { constructor(private apiService: ApiService, private nzMessage: NzMessageService, private title: Title,
private router: Router) {
this.request = {
path: '/admin/articles',
method: 'GET',
queryParam: {
page: 1,
count: 10
}
}
} }
page: number = 1; request: RequestObj;
pageSize: number = 10; headData: Data<Article>[]
@ViewChild('commonTableComponent') private commonTableComponent: CommonTableComponent<Article>
pageList: PageList<Article> = new PageList<Article>();
loading: boolean = true;
ngOnInit(): void { ngOnInit(): void {
this.title.setTitle('小海博客 | 文章管理') this.title.setTitle('小海博客 | 文章管理')
this.getArticle(); this.headData = [
{title: '主键', fieldValue: 'id', show: false, primaryKey: true},
{title: '标题', fieldValue: 'title', show: true},
{title: '分类', fieldValue: 'category', show: true},
{title: '文章类型', fieldValue: 'original', show: true},
{title: '阅读量', fieldValue: 'readingNumber', show: true},
{title: '👍数', fieldValue: 'likeCount', show: true},
{title: '👎数', fieldValue: 'dislikeCount', show: true},
{title: '发布日期', fieldValue: 'publishDateFormat', show: true},
{title: '更新日期', fieldValue: 'updateDateFormat', show: true},
{title: '状态', fieldValue: 'open', show: true},
{title: '简介', fieldValue: 'summary', show: false},
{title: '作者', fieldValue: 'author.displayName', show: false},
{title: '标签数', fieldValue: 'tags.length', show: false},
{
title: '操作', fieldValue: '', show: true, isActionColumns: true,
action: [
{name: '查看', click: (d) => this.router.navigateByUrl(`/article/${d.id}`)},
{name: '删除', color: '#ff0000', needConfirm: true, click: (d) => this.deleteArticle(d)},
{name: '编辑', color: '#2db7f5', click: (d) => this.router.navigateByUrl(`/write?id=${d.id}`)},
]
}
]
} }
getArticle = () => this.apiService.adminArticles(this.page, this.pageSize).subscribe({ deleteArticle(article: Article) {
next: data => this.pageList = data.result, this.apiService.deleteArticle(article.id).subscribe({
complete: () => this.loading = false,
error: err => this.loading = false
})
deleteArticle(id) {
this.loading = true;
this.apiService.deleteArticle(id).subscribe({
next: data => { next: data => {
this.nzMessage.success('删除成功') this.nzMessage.success('删除成功')
this.loading = false; this.commonTableComponent.getData();
this.getArticle();
}, },
error: err => { error: err => {
this.nzMessage.error(err.msg) this.nzMessage.error(err.msg)
this.loading = false
} }
}) })
} }

View File

@@ -2,14 +2,9 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminArticleComponent} from './admin-article.component'; import {AdminArticleComponent} from './admin-article.component';
import { import {CommonTableModule} from '../components/common-table/common-table.module';
NzCardModule, import {FormsModule} from '@angular/forms';
NzDividerModule, NzIconModule, import {NzCheckboxModule, NzTagModule} from 'ng-zorro-antd';
NzPopconfirmModule,
NzTableModule, NzTagModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -18,14 +13,10 @@ import {
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminArticleComponent}]), RouterModule.forChild([{path: '', component: AdminArticleComponent}]),
NzTableModule, CommonTableModule,
NzTypographyModule, FormsModule,
NzToolTipModule,
NzCardModule,
NzDividerModule,
NzPopconfirmModule,
NzTagModule, NzTagModule,
NzIconModule, NzCheckboxModule,
] ]
}) })
export class AdminArticleModule { export class AdminArticleModule {

View File

@@ -1,49 +1,44 @@
<div class="inner-content"> <common-table #commonTableComponent
<nz-card nzTitle="评论管理" nzSize="small" [nzExtra]="reload"> [request]="request"
<nz-table #table [nzData]="pageList.list" [headData]="headData"
[nzTotal]="pageList.total" cardTitle="评论管理"
[(nzPageIndex)]="pageIndex" [template]="{status:{temp:status,param:{'0':' 正常 ','3':'已删除'}},content:{temp:content}}">
[nzPageSize]="pageSize" </common-table>
[nzLoading]="loading"
[nzScroll]="{x:'800px'}" <ng-template let-originValue="originValue" let-value="value" #status>
(nzPageIndexChange)="getComment()" <nz-tag nzColor="geekblue" *ngIf="originValue==0">{{value}}</nz-tag>
nzFrontPagination="false" <nz-tag nzColor="#f50" *ngIf="originValue==3">{{value}}</nz-tag>
nzTableLayout="fixed">
<thead>
<th nzAlign="center">评论页面</th>
<th nzAlign="center">评论内容</th>
<th nzAlign="center">评论日期</th>
<th nzAlign="center">操作</th>
</thead>
<tbody>
<tr *ngFor="let data of table.data">
<td nzAlign="center"><a [href]="data.pagePath">{{data.pagePath}}</a></td>
<td nzAlign="center" 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 nzAlign="center">{{data.date}}</td>
<td nzAlign="center">
<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>
<ng-template #reload>
<a (click)="getComment()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a>
</ng-template> </ng-template>
<ng-template #content let-value="value" let-data="data">
<editable-tag #editableTagComponent
[key]="data.id"
[showBorder]="false"
[text]="value"
[showConfirmModal]="true"
(modalOK)="textChange($event,data)">
</editable-tag>
</ng-template>
<nz-modal nzTitle="查看" [nzClosable]="true" [(nzVisible)]="modalData.visible" (nzOnOk)="modalData.visible=false"
[nzCancelText]="null">
<ng-template #commentTemplateRef let-comment="comment">
<nz-comment [nzAuthor]="comment && comment.fromUser.displayName" [nzDatetime]="comment&&comment.date">
<nz-avatar nz-comment-avatar nzIcon="user"
[nzSrc]="comment && comment.fromUser && comment.fromUser.avatarImgUrl"></nz-avatar>
<nz-comment-content>
<p>{{ comment && comment.content }}</p>
</nz-comment-content>
<!-- <nz-comment-action>Reply to</nz-comment-action>-->
<ng-container *ngIf="comment&&comment.children && comment.children.length">
<ng-template ngFor let-child [ngForOf]="comment&&comment.children">
<ng-template [ngTemplateOutlet]="commentTemplateRef" [ngTemplateOutletContext]="{ comment: child }">
</ng-template>
</ng-template>
</ng-container>
</nz-comment>
</ng-template>
<ng-template [ngTemplateOutlet]="commentTemplateRef" [ngTemplateOutletContext]="{ comment: modalData.comment }">
</ng-template>
</nz-modal>

View File

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

View File

@@ -1,15 +1,17 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd'; import {NzMessageService} from 'ng-zorro-antd';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp'; import {RequestObj} from '../../../class/HttpReqAndResp';
import {Comment, CommentReq} from '../../../class/Comment'; import {Comment, CommentReq} from '../../../class/Comment';
import {GlobalUserService} from '../../../services/global-user.service'; import {GlobalUserService} from '../../../services/global-user.service';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {Data} from '../components/common-table/data';
import {EditableTagComponent} from '../components/editable-tag/editable-tag.component';
import {CommonTableComponent} from '../components/common-table/common-table.component';
@Component({ @Component({
selector: 'app-admin-comment', selector: 'app-admin-comment',
templateUrl: './admin-comment.component.html', templateUrl: './admin-comment.component.html',
styleUrls: ['./admin-comment.component.less']
}) })
export class AdminCommentComponent implements OnInit { export class AdminCommentComponent implements OnInit {
@@ -18,92 +20,102 @@ export class AdminCommentComponent implements OnInit {
this.title.setTitle('小海博客 | 评论管理') this.title.setTitle('小海博客 | 评论管理')
this.userService.watchUserInfo({ this.userService.watchUserInfo({
next: data => { next: data => {
let pathStr;
if (data.result) { if (data.result) {
if (data.result.role === 'admin') { if (data.result.role === 'admin') {
this.getComment = this.getCommentForAdmin; pathStr = '/admin/comment/pagePath/*'
} else { } else {
this.getComment = this.getCommentForUser; pathStr = '/user/comment/pagePath/*'
}
this.request = {
path: pathStr,
method: 'GET',
queryParam: {
page: 1,
count: 10
}
} }
} else {
this.getComment = this.getCommentForUser;
} }
if (this.requested) return;
this.getComment()
this.requested = true
}, },
error: null, error: () => null,
complete: null complete: () => null
}) })
} }
loading: boolean = true; request: RequestObj;
pageIndex: number = 1;
pageSize: number = 10;
pageList: PageList<Comment> = new PageList<Comment>();
editInfo = { editInfo = {
id: null, id: null,
content: new CommentReq(null), content: new CommentReq(null),
editFocus: false,
} }
getComment: any;// 存放获取评论的方法 headData: Data<Comment>[];
private requested: boolean = false; modalData = {
visible: false,
comment: null
}
@ViewChild('editableTagComponent') editableTagComponent: EditableTagComponent;
@ViewChild('commonTableComponent') commonTableComponent: CommonTableComponent<Comment>;
ngOnInit(): void { ngOnInit(): void {
this.headData = [
{title: '主键', fieldValue: 'id', show: false, primaryKey: true},
{title: '评论路径', fieldValue: 'pagePath', show: true},
{title: '评论创建者昵称', fieldValue: 'fromUser.displayName', show: true},
{title: '评论内容', fieldValue: 'content', show: true},
{title: '评论接收者昵称', fieldValue: 'toUser.displayName', show: true},
{title: '评论日期', fieldValue: 'date', show: true},
{title: '父评论id', fieldValue: 'pid', show: false},
{title: '状态', fieldValue: 'status', show: true},
{
title: '操作',
fieldValue: '',
show: true,
isActionColumns: true,
action: [
{
name: '查看',
click: data => {
this.modalData.visible = true
this.modalData.comment = data;
}
},
{name: '删除', color: 'red', click: data => this.deleteComment(data), needConfirm: true},
{name: '编辑', color: '#2db7f5', click: data => this.editableTagComponent.getFocus(data.id)},
]
}
];
} }
deleteComment(data: Comment) {
// TODO:: pagePath if (data.status === 3) {
getCommentForAdmin = () => this.apiService.getCommentByTypeForAdmin('*', this.pageIndex, this.pageSize).subscribe({ this.messageService.error('该数据已被删除');
next: data => this.pageList = data.result, return
complete: () => this.loading = false, }
error: err => this.loading = false this.apiService.deleteComment(data.id).subscribe({
}) next: () => this.messageService.success('删除评论成功'),
error: err => this.messageService.error(err.msg),
getCommentForUser = () => this.apiService.getCommentByTypeForUser('*', this.pageIndex, this.pageSize).subscribe({ complete: () => this.commonTableComponent.getData()
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() { edit() {
this.editInfo.editFocus = false;
this.loading = true;
this.apiService.updateComment(this.editInfo.content).subscribe({ this.apiService.updateComment(this.editInfo.content).subscribe({
next: data => { next: data => {
this.messageService.success('更新评论成功'); this.messageService.success('更新评论成功');
this.getComment();
}, },
error: err => { error: err => {
this.loading = false;
this.messageService.success(err.msg); this.messageService.success(err.msg);
}, },
complete: () => this.loading = false complete: () => null
}) })
} }
editFocus(data: Comment) { textChange(value: { value: string; originalValue: string; changed: boolean }, data: Comment) {
if (value.changed) {
this.editInfo.id = data.id; 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.pid = data.pid;
// this.editInfo.content.responseId = data.responseId; this.editInfo.content.id = data.id;
this.editInfo.editFocus = true; this.editInfo.content.content = value.value;
this.edit()
}
} }
} }

View File

@@ -2,16 +2,9 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminCommentComponent} from './admin-comment.component'; import {AdminCommentComponent} from './admin-comment.component';
import { import {CommonTableModule} from '../components/common-table/common-table.module';
NzButtonModule, import {NzAvatarModule, NzCommentModule, NzModalModule, NzTagModule} from 'ng-zorro-antd';
NzCardModule, import {EditableTagModule} from '../components/editable-tag/editable-tag.module';
NzDividerModule, NzIconModule, NzInputModule,
NzPopconfirmModule,
NzTableModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms';
@NgModule({ @NgModule({
@@ -21,16 +14,12 @@ import {FormsModule} from '@angular/forms';
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminCommentComponent}]), RouterModule.forChild([{path: '', component: AdminCommentComponent}]),
NzCardModule, CommonTableModule,
NzTableModule, NzTagModule,
NzDividerModule, EditableTagModule,
NzPopconfirmModule, NzModalModule,
NzTypographyModule, NzCommentModule,
NzToolTipModule, NzAvatarModule,
NzInputModule,
FormsModule,
NzIconModule,
NzButtonModule
] ]
}) })
export class AdminCommentModule { export class AdminCommentModule {

View File

@@ -1,36 +1,18 @@
<div class="inner-content"> <common-table #commonTableComponent
<nz-card nzTitle="友链管理" nzSize="small" [nzExtra]="reload"> cardTitle="友链管理"
<button nz-button (click)="addLink()" style="margin-bottom: 15px">新增</button> [request]="request"
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex" [headData]="headData"
[nzPageSize]="pageSize" [nzLoading]="loading" [nzScroll]="{x:'1200px'}" [template]="{open:{temp:open,param:{true:'可见',false:'不可见'}},delete:{temp:deleteTemp,param:{true:'已删除',false:'未删除'}}}"
(nzPageIndexChange)="getLinks()" nzFrontPagination="false"> >
<thead> </common-table>
<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>
<ng-template #reload> <ng-template #open let-value="value">
<a (click)="getLinks()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a> <label nz-checkbox nzDisabled [ngModel]="value"></label>
</ng-template>
<ng-template let-value="value" let-originValue="originValue" #deleteTemp>
<nz-tag [nzColor]="'blue'" *ngIf="originValue=='false'">{{value}}</nz-tag>
<nz-tag [nzColor]="'#ff5500'" *ngIf="originValue!='false'">{{value}}</nz-tag>
</ng-template> </ng-template>
<nz-modal [(nzVisible)]="modalVisible" [nzTitle]="modalTitle" (nzOnOk)="modalConfirm()" <nz-modal [(nzVisible)]="modalVisible" [nzTitle]="modalTitle" (nzOnOk)="modalConfirm()"

View File

@@ -1,16 +1,17 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {PageList, Response} from '../../../class/HttpReqAndResp'; import {RequestObj, Response} from '../../../class/HttpReqAndResp';
import {Link} from '../../../class/Link'; import {Link} from '../../../class/Link';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {NzMessageService} from 'ng-zorro-antd'; import {NzMessageService} from 'ng-zorro-antd';
import {FormControl, FormGroup, Validators} from '@angular/forms'; import {FormControl, FormGroup, Validators} from '@angular/forms';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {CommonTableComponent} from '../components/common-table/common-table.component';
import {Data} from '../components/common-table/data';
@Component({ @Component({
selector: 'app-admin-link', selector: 'app-admin-link',
templateUrl: './admin-link.component.html', templateUrl: './admin-link.component.html'
styleUrls: ['./admin-link.component.less']
}) })
export class AdminLinkComponent implements OnInit { export class AdminLinkComponent implements OnInit {
@@ -25,35 +26,51 @@ export class AdminLinkComponent implements OnInit {
}) })
} }
pageList: PageList<Link> = new PageList<Link>();
loading: boolean = true;
pageIndex: number = 1;
pageSize: number = 10;
modalVisible: boolean = false; modalVisible: boolean = false;
modalTitle: string = ''; modalTitle: string = '';
formGroup: FormGroup; formGroup: FormGroup;
request: RequestObj;
getLinks = () => this.apiService.adminLinks(this.pageSize, this.pageIndex).subscribe({ @ViewChild('commonTableComponent') commonTableComponent: CommonTableComponent<Link>
next: data => this.pageList = data.result, headData: Data<Link>[];
error: () => this.loading = false,
complete: () => this.loading = false,
})
ngOnInit(): void { ngOnInit(): void {
this.getLinks(); this.request = {
path: '/admin/links',
method: 'GET',
queryParam: {
count: 10,
page: 1
}
}
this.headData = [
{title: '主键', fieldValue: 'id', show: false, primaryKey: true},
{title: '友链名称', fieldValue: 'name', show: true},
{title: '友链地址', fieldValue: 'url', show: true},
{title: '是否可见', fieldValue: 'open', show: true},
{title: '描述', fieldValue: 'desc', show: false},
{title: '图标', fieldValue: 'iconPath', show: false},
{title: '状态', fieldValue: 'delete', show: true},
{
title: '操作', fieldValue: '', show: true, isActionColumns: true, action: [
{name: '访问', click: (data) => window.open(data.url)},
{name: '编辑', click: (data) => this.showEdit(data)},
{name: '删除', color: 'red', needConfirm: true, click: (data) => this.delete(data.id)},
]
},
];
} }
delete(id: number) { delete(id: number) {
this.apiService.deleteLink(id).subscribe({ this.apiService.deleteLink(id).subscribe({
next: data => { next: data => {
this.messageService.success('删除成功'); this.messageService.success('删除成功');
this.getLinks(); this.commonTableComponent.getData();
}, },
error: () => { error: () => {
this.loading = false;
this.messageService.error('删除失败'); this.messageService.error('删除失败');
}, },
complete: () => this.loading = false, complete: () => null,
}) })
} }
@@ -84,7 +101,7 @@ export class AdminLinkComponent implements OnInit {
observable.subscribe({ observable.subscribe({
next: data => this.messageService.success('操作成功'), next: data => this.messageService.success('操作成功'),
error: err => this.messageService.error('操作失败,' + err.msg), error: err => this.messageService.error('操作失败,' + err.msg),
complete: () => this.getLinks() complete: () => this.commonTableComponent.getData()
}) })
} }

View File

@@ -2,16 +2,9 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminLinkComponent} from './admin-link.component'; import {AdminLinkComponent} from './admin-link.component';
import { import {CommonTableModule} from '../components/common-table/common-table.module';
NzButtonModule, import {NzCheckboxModule, NzFormModule, NzInputModule, NzModalModule, NzSelectModule, NzTagModule} from 'ng-zorro-antd';
NzCardModule, import {FormsModule, ReactiveFormsModule} from '@angular/forms';
NzDividerModule,
NzFormModule, NzIconModule, NzInputModule,
NzModalModule,
NzPopconfirmModule, NzSelectModule,
NzTableModule
} from 'ng-zorro-antd';
import {ReactiveFormsModule} from '@angular/forms';
@NgModule({ @NgModule({
@@ -21,17 +14,16 @@ import {ReactiveFormsModule} from '@angular/forms';
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminLinkComponent}]), RouterModule.forChild([{path: '', component: AdminLinkComponent}]),
NzCardModule, CommonTableModule,
NzTableModule, NzCheckboxModule,
NzDividerModule,
NzPopconfirmModule,
NzModalModule, NzModalModule,
FormsModule,
NzFormModule, NzFormModule,
ReactiveFormsModule, ReactiveFormsModule,
NzInputModule, NzInputModule,
NzSelectModule, NzSelectModule,
NzButtonModule, NzTagModule,
NzIconModule
] ]
}) })
export class AdminLinkModule { export class AdminLinkModule {

View File

@@ -45,6 +45,10 @@ const routes: Routes = [
loadChildren: () => import('./admin-visitor/admin-visitor.module').then(mod => mod.AdminVisitorModule), loadChildren: () => import('./admin-visitor/admin-visitor.module').then(mod => mod.AdminVisitorModule),
// canActivate: [AuthGuard] // canActivate: [AuthGuard]
}, },
// {
// path: 'test',
// loadChildren: () => import('./test-common-table/test-common-table.module').then(Mod => Mod.TestCommonTableModule)
// },
{ {
path: '**', path: '**',
loadChildren: () => import('./admin-dashboard/admin-dashboard.module').then(mod => mod.AdminDashboardModule), loadChildren: () => import('./admin-dashboard/admin-dashboard.module').then(mod => mod.AdminDashboardModule),

View File

@@ -2,96 +2,43 @@
<nz-card nzTitle="" nzSize="small"> <nz-card nzTitle="" nzSize="small">
<nz-tabset [nzTabBarExtraContent]="reload"> <nz-tabset [nzTabBarExtraContent]="reload">
<nz-tab nzTitle="分类管理" (nzClick)="tabChanged('tag')"> <nz-tab nzTitle="分类管理" (nzClick)="tabChanged('tag')">
<div style="margin-bottom: 15px;"> <div style="margin-bottom: 15px;width: 150px">
<nz-input-group *ngIf="editInfo.editFocus&&editInfo.isAdd" [nzPrefix]="tagIcon" <editable-tag [showBorder]="false"
style="width: 200px"> [showEditIcon]="false"
<input type="text" nz-input [(ngModel)]="editInfo.name" (keyup.enter)="addCategory()" [doubleClick]="false"
[autofocus]="editInfo.editFocus" size="default"
(blur)="editInfo.editFocus=false"> [autoClear]="true"
</nz-input-group> (valueChange)="addCategory($event)"
<button nz-button (click)="addCategory()">新增分类</button> >
<button nz-button (click)="editInfo.editFocus=false" *ngIf="editInfo.editFocus&&editInfo.isAdd">取消 <button nz-button>新增</button>
</button> </editable-tag>
</div> </div>
<nz-table #table [nzData]="categoryList" [nzTotal]="categoryList.length" <common-table #categoryCTComponent
(nzPageIndexChange)="getCategory()" [nzScroll]="{x:'800px'}" [headData]="categoryCTData.headData"
nzFrontPagination="false" [nzLoading]="loading"> [request]="categoryCTData.request"
<thead> [template]="{name:{temp:nameTemplate}}">
<th>分类名</th> </common-table>
<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>
<nz-tab nzTitle="标签管理" (nzClick)="tabChanged('category')"> <nz-tab nzTitle="标签管理" (nzClick)="tabChanged('category')">
<nz-table #tagTable [nzData]="tagPageList.list" [nzTotal]="tagPageList.total" <common-table #tagCTComponent
[(nzPageIndex)]="pageIndex" [nzScroll]="{x:'800px'}" [headData]="tagCTData.headData"
[nzPageSize]="pageSize" (nzPageIndexChange)="getTag()" nzFrontPagination="false"> [request]="tagCTData.request"
<thead> [template]="{name:{temp:nameTemplate}}">
<th>标签名</th> </common-table>
<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-tab>
</nz-tabset> </nz-tabset>
</nz-card> </nz-card>
</div> </div>
<ng-template #tagIcon><i nz-icon nzType="tag" nzTheme="outline"></i></ng-template>
<ng-template #reload> <ng-template #reload>
<a (click)="getData()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a> <a (click)="getData()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a>
</ng-template> </ng-template>
<ng-template #nameTemplate let-value="value" let-data="data">
<editable-tag #editableTagComponent
[key]="data.id"
[showBorder]="false"
[text]="value"
[showConfirmModal]="true"
(modalOK)="textChange($event,data)">
</editable-tag>
</ng-template>

View File

@@ -1,151 +1,151 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd'; import {NzMessageService} from 'ng-zorro-antd';
import {Category, Tag} from '../../../class/Tag'; import {Category, Tag} from '../../../class/Tag';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp'; import {PageList, RequestObj} from '../../../class/HttpReqAndResp';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {Data} from '../components/common-table/data';
import {CommonTableComponent} from '../components/common-table/common-table.component';
import {Router} from '@angular/router';
import {EditableTagComponent} from '../components/editable-tag/editable-tag.component';
@Component({ @Component({
selector: 'app-admin-tag', selector: 'app-admin-tag',
templateUrl: './admin-tag.component.html', templateUrl: './admin-tag.component.html'
styleUrls: ['./admin-tag.component.less']
}) })
export class AdminTagComponent implements OnInit { export class AdminTagComponent implements OnInit {
constructor(private apiService: ApiService, private nzMessageService: NzMessageService, private title: Title) { constructor(private apiService: ApiService, private nzMessageService: NzMessageService, private title: Title, private router: Router) {
} }
loading: boolean = true; categoryCTData: { headData: Data<Category>[], commonTable: CommonTableComponent<Category>, request: RequestObj } = {
headData: null,
categoryList: Category[] = []; commonTable: null,
editInfo = { request: null
id: null,
name: null,
editFocus: false,
isAdd: false
} }
tagPageList: PageList<Tag> = new PageList<Tag>(); tagCTData: { headData: Data<Category>[], commonTable: CommonTableComponent<Tag>, request: RequestObj } = {
headData: null,
pageIndex: number = 1; commonTable: null,
pageSize: number = 10; request: null
}
@ViewChild('categoryCTComponent', {static: true}) categoryCTComponent: CommonTableComponent<Category>
@ViewChild('tagCTComponent', {static: true}) tagCTComponent: CommonTableComponent<Tag>
@ViewChild('editableTagComponent') editableTagComponent: EditableTagComponent
private updateData: any;
getData: any; getData: any;
ngOnInit(): void { ngOnInit(): void {
this.title.setTitle('小海博客 | 标签分类管理') this.title.setTitle('小海博客 | 标签分类管理')
this.getCategory(); this.categoryCTData = {
this.getTag(); commonTable: this.categoryCTComponent,
this.getData = this.getTag; headData: [
{fieldValue: 'id', title: '主键', show: false, primaryKey: true},
{fieldValue: 'name', title: '分类名', show: true},
{fieldValue: 'articles.length', title: '文章数量', show: true},
{
fieldValue: '', title: '操作', isActionColumns: true, show: true,
action: [
{name: '查看', click: (data) => this.router.navigateByUrl(`/categories/${data.name}`)},
{name: '编辑', color: 'blue', click: (data) => this.editableTagComponent.getFocus(data.id)},
{
name: '删除',
color: 'red',
needConfirm: true,
click: (data) => this.delete(data.id, 'category')
},
]
},
],
request: {
path: '/categories',
method: 'GET',
queryParam: {
page: 1,
count: 1000
}
}
}
this.tagCTData = {
commonTable: this.tagCTComponent,
headData: [
{fieldValue: 'id', primaryKey: true, show: false, title: '主键'},
{fieldValue: 'name', show: true, title: '标签名'},
{
fieldValue: '', show: true, title: '操作', isActionColumns: true, action: [
{name: '查看', click: data => this.router.navigateByUrl(`/tags/${data.name}`)},
{name: '编辑', color: 'blue', click: data => this.editableTagComponent.getFocus(data.id)},
{name: '删除', color: 'red', needConfirm: true, click: data => this.delete(data.id, 'tag')},
]
},
],
request: {
path: '/tags',
method: 'GET',
queryParam: {
page: 1,
count: 10
}
}
}
this.getData = this.categoryCTComponent.getData;
} }
getCategory = () => this.apiService.categories().subscribe({
next: data => this.categoryList = data.result.list,
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') { delete(id, mode: 'tag' | 'category') {
this.loading = true;
if (mode === 'tag') { if (mode === 'tag') {
this.apiService.deleteTag(id).subscribe({ this.apiService.deleteTag(id).subscribe({
next: data => { next: data => {
this.nzMessageService.success('删除成功') this.nzMessageService.success('删除成功')
this.getTag(); this.tagCTComponent.getData();
}, },
complete: () => this.loading = false, complete: () => null,
error: err => { error: err => this.nzMessageService.error(err.msg)
this.nzMessageService.error(err.msg)
this.loading = false
}
}) })
} else if (mode === 'category') { } else if (mode === 'category') {
this.apiService.deleteCategory(id).subscribe({ this.apiService.deleteCategory(id).subscribe({
next: data => { next: data => {
this.nzMessageService.success('删除成功') this.nzMessageService.success('删除成功')
this.getCategory(); this.categoryCTComponent.getData();
}, },
complete: () => this.loading = false, complete: () => null,
error: err => { error: err => this.nzMessageService.error(err.msg)
this.nzMessageService.error(err.msg)
this.loading = false
}
}) })
} }
} }
editFocus(data: Category) { addCategory($event: { value: string; originalValue: string; changed: boolean }) {
this.editInfo.isAdd = false; if (!$event.value || !$event.changed) return
this.editInfo.id = data.id; this.apiService.createCategory($event.value).subscribe({
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 => { next: data => {
this.nzMessageService.success('新增成功') this.nzMessageService.success('新增成功')
this.getCategory(); this.getData = this.categoryCTComponent.getData();
}, },
complete: () => this.loading = false, complete: () => null,
error: err => { error: err => this.nzMessageService.error(err.msg)
this.nzMessageService.error(err.msg)
this.loading = false
}
}); });
this.editInfo.editFocus = false
this.editInfo.isAdd = false
this.editInfo.name = null
} }
tabChanged(mode: 'tag' | 'category') { tabChanged(mode: 'tag' | 'category') {
this.editInfo.editFocus = false if (mode === 'tag') {
if (mode === 'tag') this.getData = this.categoryCTComponent.getData;
this.getData = this.getTag; this.updateData = this.apiService.updateTag;
else } else {
this.getData = this.getCategory; this.getData = this.tagCTComponent.getData;
this.updateData = this.apiService.updateCategory
}
}
textChange(value: { value: string; originalValue: string; changed: boolean }, textData: Category | Tag) {
this.updateData(textData.id, value.value).subscribe({
next: data => {
this.nzMessageService.success('更新成功')
this.tagCTComponent.getData();
this.categoryCTComponent.getData();
},
complete: () => null,
error: err => this.nzMessageService.error(err.msg)
});
} }
} }

View File

@@ -2,14 +2,10 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminTagComponent} from './admin-tag.component'; 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'; import {FormsModule} from '@angular/forms';
import {CommonTableModule} from '../components/common-table/common-table.module';
import {EditableTagModule} from '../components/editable-tag/editable-tag.module';
import {NzButtonModule, NzCardModule, NzIconModule, NzTabsModule} from "ng-zorro-antd";
@NgModule({ @NgModule({
@@ -19,16 +15,13 @@ import {FormsModule} from '@angular/forms';
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminTagComponent}]), RouterModule.forChild([{path: '', component: AdminTagComponent}]),
NzCardModule,
NzTableModule,
NzDividerModule,
NzInputModule,
FormsModule, FormsModule,
CommonTableModule,
EditableTagModule,
NzCardModule,
NzTabsModule, NzTabsModule,
NzPopconfirmModule,
NzButtonModule,
NzIconModule, NzIconModule,
NzTagModule, NzButtonModule,
] ]
}) })
export class AdminTagModule { export class AdminTagModule {

View File

@@ -1,35 +1,8 @@
<div class="inner-content"> <common-table [request]="request" [headData]="headData" cardTitle="更新管理">
<nz-card nzTitle="更新内容管理" nzSize="small" [nzExtra]="reload"> <button nz-button (click)="showModal()">新增</button>
<button nz-button (click)="showModal()" style="margin-bottom: 15px;">新增</button> </common-table>
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex"
[nzPageSize]="pageSize" [nzLoading]="loading" [nzScroll]="{x:'800px'}"
(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" <nz-modal [(nzVisible)]="modalData.visible" [nzClosable]="true" (nzOnCancel)="modalData.visible = false"
(nzOnOk)="confirm()" [nzTitle]="modalData.title"> (nzOnOk)="confirm()" [nzTitle]="modalData.title">
<textarea nz-input [(ngModel)]="modalData.content" [nzAutosize]="{ minRows: 2, maxRows: 8 }"></textarea> <textarea nz-input [(ngModel)]="modalData.content" [nzAutosize]="{ minRows: 2, maxRows: 8 }"></textarea>
</nz-modal> </nz-modal>
<ng-template #reload>
<a (click)="getUpdateInfo()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a>
</ng-template>

View File

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

View File

@@ -3,13 +3,13 @@ import {NzMessageService} from 'ng-zorro-antd';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {PageList, Response} from '../../../class/HttpReqAndResp'; import {PageList, RequestObj, Response} from '../../../class/HttpReqAndResp';
import {UpdateInfo} from '../../../class/UpdateInfo'; import {UpdateInfo} from '../../../class/UpdateInfo';
import {Data} from '../components/common-table/data';
@Component({ @Component({
selector: 'app-admin-update', selector: 'app-admin-update',
templateUrl: './admin-update.component.html', templateUrl: './admin-update.component.html'
styleUrls: ['./admin-update.component.less']
}) })
export class AdminUpdateComponent implements OnInit { export class AdminUpdateComponent implements OnInit {
@@ -17,49 +17,47 @@ export class AdminUpdateComponent implements OnInit {
constructor(private apiService: ApiService, private nzMessage: NzMessageService, private title: Title) { 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 = { modalData = {
visible: false, visible: false,
content: null, content: null,
id: null, id: null,
title: null title: null
}; };
headData: Data<UpdateInfo>[];
request: RequestObj;
ngOnInit(): void { ngOnInit(): void {
this.title.setTitle('小海博客 | 更新信息管理') this.title.setTitle('小海博客 | 更新信息管理')
this.getUpdateInfo(); this.headData = [
{fieldValue: 'id', show: false, title: '主键', primaryKey: true},
{fieldValue: 'info', show: true, title: '更新内容'},
{fieldValue: 'time', show: true, title: '更新日期'},
{
fieldValue: '', show: true, title: '操作', isActionColumns: true, action: [
{name: '编辑', click: data => this.showModal(data)},
{name: '删除', color: 'red', needConfirm: true, click: data => this.deleteUpdateInfo(data.id)}
]
}
];
this.request = {
path: '/webUpdate/pages',
method: 'GET',
queryParam: {
count: 1,
page: 10,
}
}
} }
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) { deleteUpdateInfo(id) {
this.loading = true;
this.apiService.deleteWebUpdateInfo(id).subscribe({ this.apiService.deleteWebUpdateInfo(id).subscribe({
next: data => { next: data => this.nzMessage.success('删除成功'),
this.nzMessage.success('删除成功') error: err => this.nzMessage.error(err.msg)
this.loading = false;
this.getUpdateInfo();
},
error: err => {
this.nzMessage.error(err.msg)
this.loading = false
}
}) })
} }
confirm() { confirm() {
this.loading = true;
this.modalData.visible = false; this.modalData.visible = false;
let observable: Observable<Response<UpdateInfo>> let observable: Observable<Response<UpdateInfo>>
if (this.modalData.id) { if (this.modalData.id) {
@@ -68,17 +66,9 @@ export class AdminUpdateComponent implements OnInit {
observable = this.apiService.createWebUpdateInfo(this.modalData.content) observable = this.apiService.createWebUpdateInfo(this.modalData.content)
} }
observable.subscribe({ observable.subscribe({
next: data => { next: data => this.nzMessage.success('操作成功'),
this.nzMessage.success('操作成功') error: err => this.nzMessage.error(err.msg)
this.loading = false;
this.getUpdateInfo();
},
error: err => {
this.nzMessage.error(err.msg)
this.loading = false
}
}) })
console.log(this.modalData);
} }
showModal(data?: UpdateInfo) { showModal(data?: UpdateInfo) {

View File

@@ -2,16 +2,10 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminUpdateComponent} from './admin-update.component'; import {AdminUpdateComponent} from './admin-update.component';
import {
NzButtonModule,
NzCardModule,
NzDividerModule, NzIconModule, NzInputModule, NzModalModule,
NzPopconfirmModule,
NzTableModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms'; import {FormsModule} from '@angular/forms';
import {CommonTableModule} from '../components/common-table/common-table.module';
import {NzButtonModule, NzInputModule, NzModalModule} from 'ng-zorro-antd';
@NgModule({ @NgModule({
@@ -21,17 +15,11 @@ import {FormsModule} from '@angular/forms';
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminUpdateComponent}]), RouterModule.forChild([{path: '', component: AdminUpdateComponent}]),
NzCardModule,
NzTableModule,
NzTypographyModule,
NzToolTipModule,
NzDividerModule,
NzPopconfirmModule,
NzModalModule,
FormsModule, FormsModule,
NzButtonModule, CommonTableModule,
NzModalModule,
NzInputModule, NzInputModule,
NzIconModule NzButtonModule
] ]
}) })
export class AdminUpdateModule { export class AdminUpdateModule {

View File

@@ -1,40 +1,17 @@
<div class="inner-content"> <common-table [headData]="headData"
<nz-card nzTitle="用户管理" nzSize="small" [nzExtra]="reload"> [request]="request"
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex" cardTitle="用户信息管理"
[nzPageSize]="pageSize" [nzLoading]="loading" [nzScroll]="{x:'800px'}" [template]="{role:{temp:role},emailStatus:{temp:emailStatus,param:{true:'已验证',false:'未验证'}}}"
(nzPageIndexChange)="getUser()" nzFrontPagination="false"> >
<thead> </common-table>
<th>邮箱</th> <ng-template let-value="value" #role>
<th>昵称</th> <nz-tag [nzColor]="'blue'" *ngIf="value == 'admin'">{{value}}</nz-tag>
<th>角色</th> <nz-tag [nzColor]="'purple'" *ngIf="value == 'user'">{{value}}</nz-tag>
<th>邮箱验证状态</th> </ng-template>
<th>操作</th> <ng-template let-value="value" let-originValue="originValue" #emailStatus>
</thead> <nz-tag [nzColor]="'green'" *ngIf="originValue !='false'">{{value}}</nz-tag>
<tbody> <nz-tag [nzColor]="'red'" *ngIf="originValue !='true'">{{value}}</nz-tag>
<tr *ngFor="let data of table.data"> </ng-template>
<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" <nz-modal [(nzVisible)]="modalData.visible" [nzClosable]="true" [nzTitle]="modalData.title"
(nzOnCancel)="modalData.visible = false" (nzOnOk)="modalConfirm()" (nzOnCancel)="modalData.visible = false" (nzOnOk)="modalConfirm()"
@@ -115,8 +92,3 @@
</ng-template> </ng-template>
</nz-modal> </nz-modal>
<ng-template #reload>
<a (click)="getUser()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a>
</ng-template>

View File

@@ -2,15 +2,15 @@ import {Component, OnInit} from '@angular/core';
import {NzMessageService} from 'ng-zorro-antd'; import {NzMessageService} from 'ng-zorro-antd';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {FormControl, FormGroup} from '@angular/forms'; import {FormControl, FormGroup} from '@angular/forms';
import {PageList} from '../../../class/HttpReqAndResp'; import {RequestObj} from '../../../class/HttpReqAndResp';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {User} from '../../../class/User'; import {User} from '../../../class/User';
import {GlobalUserService} from '../../../services/global-user.service'; import {GlobalUserService} from '../../../services/global-user.service';
import {Data} from '../components/common-table/data';
@Component({ @Component({
selector: 'app-admin-user', selector: 'app-admin-user',
templateUrl: './admin-user.component.html', templateUrl: './admin-user.component.html'
styleUrls: ['./admin-user.component.less']
}) })
export class AdminUserComponent implements OnInit { export class AdminUserComponent implements OnInit {
@@ -32,12 +32,7 @@ export class AdminUserComponent implements OnInit {
}) })
} }
pageIndex: number = 1;
pageSize: number = 10;
pageList: PageList<User> = new PageList<User>();
user: User; user: User;
loading: boolean = true;
modalData = { modalData = {
visible: false, visible: false,
title: null, title: null,
@@ -46,29 +41,44 @@ export class AdminUserComponent implements OnInit {
} }
formGroup: FormGroup; formGroup: FormGroup;
headData: Data<User>[];
request: RequestObj;
ngOnInit(): void { ngOnInit(): void {
this.title.setTitle('小海博客 | 用户管理') this.title.setTitle('小海博客 | 用户管理')
this.getUser(); this.request = {
path: '/admin/users',
method: 'GET',
queryParam: {
count: 1,
page: 10
}
};
this.headData = [
{fieldValue: 'id', title: '主键', primaryKey: true, show: false},
{fieldValue: 'email', title: '邮箱', show: true},
{fieldValue: 'displayName', title: '昵称', show: true},
{fieldValue: 'role', title: '角色', show: true},
{fieldValue: 'emailStatus', title: '邮箱验证状态', show: true},
{fieldValue: 'desc', title: '描述', show: false},
{fieldValue: 'avatarImgUrl', title: '头像', show: false},
{fieldValue: 'recentlyLandedDate', title: '最近登录日期', show: false},
{
fieldValue: '', title: '操作', show: true, isActionColumns: true,
action: [
{name: '查看', click: data => this.showModal(false, data)},
{name: '编辑', color: 'blue', click: data => this.showModal(true, data)},
{name: '删除', color: 'red', needConfirm: true, click: data => this.deleteUser(data.id)}
]
},
];
} }
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) { deleteUser(id) {
this.loading = true;
this.apiService.deleteUser(id).subscribe({ this.apiService.deleteUser(id).subscribe({
next: data => { next: data => this.messageService.success('删除成功'),
this.messageService.success('删除成功') error: err => this.messageService.error(err.msg)
this.loading = false;
this.getUser();
},
error: err => {
this.messageService.error(err.msg)
this.loading = false
}
}) })
} }
@@ -84,7 +94,6 @@ export class AdminUserComponent implements OnInit {
this.modalData.visible = false this.modalData.visible = false
this.apiService.adminUpdateUser(this.formGroup.value).subscribe({ this.apiService.adminUpdateUser(this.formGroup.value).subscribe({
next: data => { next: data => {
this.getUser();
this.messageService.success('修改用户信息成功'); this.messageService.success('修改用户信息成功');
this.userService.refreshUserInfo(); this.userService.refreshUserInfo();
} }

View File

@@ -2,16 +2,17 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminUserComponent} from './admin-user.component'; import {AdminUserComponent} from './admin-user.component';
import {ReactiveFormsModule} from '@angular/forms';
import {CommonTableModule} from '../components/common-table/common-table.module';
import { import {
NzButtonModule, NzButtonModule,
NzCardModule, NzFormModule,
NzDividerModule, NzFormModule, NzIconModule, NzInputModule, NzGridModule,
NzModalModule, NzIconModule,
NzPopconfirmModule, NzRadioModule, NzSelectModule, NzInputModule, NzModalModule,
NzTableModule, NzRadioModule,
NzTagModule NzSelectModule, NzTagModule
} from 'ng-zorro-antd'; } from 'ng-zorro-antd';
import {ReactiveFormsModule} from '@angular/forms';
@NgModule({ @NgModule({
@@ -21,19 +22,17 @@ import {ReactiveFormsModule} from '@angular/forms';
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminUserComponent}]), RouterModule.forChild([{path: '', component: AdminUserComponent}]),
NzCardModule,
NzTableModule,
NzPopconfirmModule,
NzDividerModule,
NzTagModule,
NzModalModule,
NzButtonModule,
NzFormModule,
ReactiveFormsModule, ReactiveFormsModule,
CommonTableModule,
NzGridModule,
NzButtonModule,
NzInputModule, NzInputModule,
NzSelectModule, NzIconModule,
NzRadioModule, NzRadioModule,
NzIconModule NzSelectModule,
NzFormModule,
NzModalModule,
NzTagModule
] ]
}) })

View File

@@ -1,27 +1,4 @@
<div class="inner-content"> <common-table [request]="request" [headData]="headData" cardTitle="访客信息管理">
<nz-card nzTitle="访客信息管理" nzSize="small" [nzExtra]="reload">
<nz-table #table [nzData]="pageList.list" [nzTotal]="pageList.total" [(nzPageIndex)]="pageIndex" </common-table>
[nzPageSize]="pageSize" [nzLoading]="loading" [nzScroll]="{x:'800px'}"
(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>
<ng-template #reload>
<a (click)="getVisitors()" title="刷新"><i nz-icon nzType="reload" nzTheme="outline"></i></a>
</ng-template>

View File

@@ -1,34 +1,48 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {ApiService} from '../../../api/api.service'; import {ApiService} from '../../../api/api.service';
import {PageList} from '../../../class/HttpReqAndResp'; import {RequestObj} from '../../../class/HttpReqAndResp';
import {Visitor} from '../../../class/Visitor'; import {Visitor} from '../../../class/Visitor';
import {Data} from '../components/common-table/data';
@Component({ @Component({
selector: 'app-admin-visitor', selector: 'app-admin-visitor',
templateUrl: './admin-visitor.component.html', templateUrl: './admin-visitor.component.html'
styleUrls: ['./admin-visitor.component.less']
}) })
export class AdminVisitorComponent implements OnInit { export class AdminVisitorComponent implements OnInit {
constructor(private apiService: ApiService, private title: Title) { constructor(private apiService: ApiService, private title: Title) {
} }
pageIndex: number = 1; headData: Data<Visitor>[];
pageSize: number = 10; request: RequestObj
pageList: PageList<Visitor> = new PageList<Visitor>();
loading: boolean = true;
/***
* browserName: "Chrome 8"
browserVersion: "83.0.4103.116"
date: "2020-07-11 09:30:13"
id: 3131
ip: "127.0.0.1"
osname: "Windows 10"
*/
ngOnInit(): void { ngOnInit(): void {
this.title.setTitle('小海博客 | 访客信息管理') this.title.setTitle('小海博客 | 访客信息管理')
this.getVisitors(); this.request = {
path: '/admin/visitor/page',
method: 'GET',
queryParam: {
count: 1,
page: 10,
showLocation: location
}
}
this.headData = [
{fieldValue: 'id', title: '主键', show: false, primaryKey: true},
{fieldValue: 'date', title: '主键', show: true},
{fieldValue: 'browserName', title: '主键', show: true},
{fieldValue: 'ip', title: '主键', show: true},
{fieldValue: 'browserVersion', title: '主键', show: true},
{fieldValue: 'osname', title: '主键', show: true}
]
} }
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

@@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {AdminVisitorComponent} from './admin-visitor.component'; import {AdminVisitorComponent} from './admin-visitor.component';
import {NzButtonModule, NzCardModule, NzDividerModule, NzIconModule, NzTableModule} from 'ng-zorro-antd'; import {CommonTableModule} from '../components/common-table/common-table.module';
@NgModule({ @NgModule({
@@ -12,11 +12,7 @@ import {NzButtonModule, NzCardModule, NzDividerModule, NzIconModule, NzTableModu
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{path: '', component: AdminVisitorComponent}]), RouterModule.forChild([{path: '', component: AdminVisitorComponent}]),
NzCardModule, CommonTableModule
NzTableModule,
NzButtonModule,
NzDividerModule,
NzIconModule
] ]
}) })
export class AdminVisitorModule { export class AdminVisitorModule {

View File

@@ -0,0 +1,72 @@
<nz-card *ngIf="cardTitle" nzSize="small" [nzExtra]="refresh" [nzTitle]="cardTitle" [nzLoading]="loading">
<ng-container *ngTemplateOutlet="table"></ng-container>
</nz-card>
<ng-container [ngTemplateOutlet]="table" *ngIf="!cardTitle"></ng-container>
<ng-template #refresh>
<i nz-icon nzType="reload" nzTheme="outline" (click)="getData()" title="刷新" style="cursor: pointer"></i>
</ng-template>
<ng-template #table>
<ng-content></ng-content>
<nz-table nzTableLayout="fixed"
[nzData]="dataList.list"
[nzTotal]="dataList.total"
[(nzPageIndex)]="dataList.pageNum"
[nzPageSize]="dataList.pageSize"
(nzPageIndexChange)="getData()"
nzFrontPagination="false"
[nzScroll]="{x:'1300px'}"
[nzLoading]="loading">
<thead>
<tr>
<ng-container *ngFor="let data of headData">
<th *ngIf="data.show">
{{data.title}}
</th>
</ng-container>
</tr>
</thead>
<tbody>
<tr *ngFor="let t of dataList.list;let index = index">
<ng-container *ngFor="let data of headData">
<td *ngIf="data.show"
nz-typography
nzEllipsis
[nzEllipsisRows]="data.isActionColumns?3:1"
[nzTooltipTitle]="data.isActionColumns ? null : data.title+' : '+getValue(index,data.fieldValue)"
nzTooltipPlacement="top"
nz-tooltip>
<ng-template [ngIf]="!data.isActionColumns">
<ng-template [ngIf]="template[data.fieldValue]">
<ng-container
*ngTemplateOutlet="template[data.fieldValue].temp; context:getContext(data.fieldValue,index) ">
</ng-container>
</ng-template>
<ng-template [ngIf]="!template[data.fieldValue]">
{{ getValue(index, data.fieldValue) }}
</ng-template>
</ng-template>
<ng-container *ngIf="data.isActionColumns">
<a *ngFor="let action of data.action; let i = index"
(mouseenter)="action.hover(t)"
(mouseout)="null"
[ngStyle]="{'color':action.color,'font-size':action.fontSize}"
nz-popconfirm
[nzPopconfirmTitle]="'是否确认'+action.name+'该数据?'"
[nzCondition]="!action.needConfirm"
(nzOnConfirm)="action.click(t)"
[title]="action.name">
{{action.name}}
<ng-template [ngIf]="i!=data.action.length-1">
<nz-divider nzType="vertical"></nz-divider>
</ng-template>
</a>
</ng-container>
</td>
</ng-container>
</tr>
</tbody>
</nz-table>
</ng-template>

View File

@@ -0,0 +1,103 @@
import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, TemplateRef} from '@angular/core';
import {Data} from './data';
import {PageList, RequestObj} from '../../../../class/HttpReqAndResp';
import {HttpService} from '../../../../api/http/http.service';
@Component({
selector: 'common-table',
templateUrl: './common-table.component.html',
styleUrls: ['./common-table.component.less']
})
export class CommonTableComponent<T> implements OnInit, OnChanges {
constructor(private httpService: HttpService) {
}
/**
* 设置readonly data 因为后面有使用eval 为了安全
*/
@Input() headData: Data<T>[];
@Input() request: RequestObj;
@Input() cardTitle: string | null;
@Input() template: {
[fieldValue: string]: {
temp: TemplateRef<any>,
param?: { [key: string]: string }
}
};
@Output() pageInfo = new EventEmitter<{ page: number, pageSize: number }>();
loading: boolean = true;
dataList: PageList<T> = new PageList<T>();
ngOnInit(): void {
if (!this.template) this.template = {}
this.headData.forEach(dat => {
if (!dat.action) return;
dat.action.forEach(act => {
if (!act.hover) {
act.hover = () => null;
}
})
});
if (!this.request || !this.request.path) return
this.getData();
}
getData = () => {
this.loading = true;
const pageValue = this.dataList.pageNum ? this.dataList.pageNum : 1;
const countValue = this.dataList.pageSize ? this.dataList.pageSize : 10
this.request.queryParam = {
page: pageValue,
count: countValue
}
this.pageInfo.emit({page: pageValue, pageSize: countValue})
return this.httpService.Service<PageList<T>>(this.request).subscribe({
next: resp => {
this.dataList = resp.result;
setTimeout(() => this.loading = false, 10)
},
error: err => this.loading = false
});
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.request && !changes.request.isFirstChange()) {
console.log(changes.request)
this.request = changes.request.currentValue;
this.getData().unsubscribe();
this.getData();
}
}
getValue(index: number, fieldValue: string): string {
let value = this.dataList.list[index];
try {
for (const key of fieldValue.split('.')) value = value[key]
} catch (e) {
// ignore
}
return (value != null) ? value.toString() : '————';
}
getContext = (fieldValue: string, index: number) => {
const valueData = this.getValue(index, fieldValue);
let context: { value: string, originValue?: string, data: T };
if (this.template[fieldValue].param) {
context = {
value: this.template[fieldValue].param[valueData],
originValue: valueData,
data: this.dataList.list[index]
}
} else {
context = {
value: valueData,
data: this.dataList.list[index]
}
}
return context;
}
}

View File

@@ -0,0 +1,34 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {CommonTableComponent} from './common-table.component';
import {
NzCardModule,
NzDividerModule,
NzIconModule, NzOutletModule, NzPopconfirmModule,
NzTableModule,
NzToolTipModule,
NzTypographyModule
} from 'ng-zorro-antd';
@NgModule({
declarations: [
CommonTableComponent
],
exports: [
CommonTableComponent
],
imports: [
CommonModule,
NzTableModule,
NzDividerModule,
NzTypographyModule,
NzToolTipModule,
NzCardModule,
NzIconModule,
NzOutletModule,
NzPopconfirmModule
]
})
export class CommonTableModule {
}

View File

@@ -0,0 +1,24 @@
import {TemplateRef} from '@angular/core';
export class Data<T> {
title: string;
fieldValue: string;
show: boolean = true;
primaryKey?: boolean = false;
isActionColumns?: boolean = false;
template?: {
template: TemplateRef<any>,
keymap?: {
[value: string]: string
}
};
action ?: {
name: string,
color?: string,
order?: number,
fontSize?: string,
needConfirm?: boolean,
click: (data: T) => void,
hover?: (data: T) => void | null;
}[] = []
}

View File

@@ -0,0 +1,141 @@
import {
Component,
ElementRef,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
ViewChild
} from '@angular/core';
import {NzModalRef, NzModalService} from 'ng-zorro-antd';
@Component({
selector: 'editable-tag',
template: `
<nz-tag *ngIf="!inputVisible" title="双击进入编辑" [nzColor]="color" nzNoAnimation
(click)="showInput(this.doubleClick)"
[style.border-style]="showBorder ? 'solid': 'none'">
{{text}}
<ng-content></ng-content>
</nz-tag>
<input #inputElement
nz-input
[nzSize]="size"
*ngIf="inputVisible"
type="text"
[(ngModel)]="inputValue"
(blur)="handleInputConfirm()"
(keydown.enter)="handleInputConfirm()"
/>
<i nz-icon *ngIf="showEditIcon"
nzType="edit"
nzTheme="fill"
style="cursor: pointer;margin-right: 8px;"
(click)="showInput(false)">
</i>
`
})
export class EditableTagComponent implements OnInit, OnChanges {
private static instanceArray: EditableTagComponent[] = []
constructor(private modal: NzModalService) {
EditableTagComponent.instanceArray.push(this);
}
inputVisible = false;
inputValue = '';
@ViewChild('inputElement', {static: false}) inputElement?: ElementRef;
@Output() valueChange = new EventEmitter<{ value: string, originalValue: string, changed: boolean }>();
@Input() color: string;
@Input() showEditIcon: boolean;
@Input() showBorder: boolean;
@Input() text: string;
@Input() key: any;
@Input() showConfirmModal: boolean;
@Input() doubleClick: boolean;
@Input() autoClear: boolean;
@Input() size: 'small' | 'default' | 'large';
@Output() modalOK = new EventEmitter<{ value: string, originalValue: string, changed: boolean }>();
@Output() modalCancel = new EventEmitter<{ value: string, originalValue: string, changed: boolean }>();
private tmpKey: any;
private doubleClickInfo = {
date: null,
};
confirmModal?: NzModalRef;
ngOnInit(): void {
if (this.showEditIcon == null) {
this.showEditIcon = true;
}
if (this.showBorder == null) {
this.showBorder = true;
}
if (this.doubleClick == null) {
this.doubleClick = true;
}
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.key && !changes.key.isFirstChange()) {
this.key = changes.key.currentValue;
this.getFocus(this.tmpKey);
}
}
showInput(doubleClick: boolean): void {
this.inputValue = this.text;
if (this.doubleClick && doubleClick) {
if (!this.doubleClickInfo.date) {
this.doubleClickInfo.date = new Date().getTime();
return
}
if (new Date().getTime() - this.doubleClickInfo.date < 200) {
this.inputVisible = true;
setTimeout(() => this.inputElement?.nativeElement.focus(), 10);
}
this.doubleClickInfo.date = new Date().getTime();
} else {
this.inputVisible = true;
setTimeout(() => this.inputElement?.nativeElement.focus(), 10);
}
}
getFocus(key: any) {
this.tmpKey = key;
EditableTagComponent.instanceArray.forEach(tag => {
if (tag.key === this.tmpKey) {
tag.showInput(false);
}
})
}
handleInputConfirm(): void {
const value = {
value: this.inputValue,
originalValue: this.text,
changed: this.inputValue !== this.text
}
this.valueChange.emit(value)
this.text = this.inputValue;
this.inputValue = '';
this.inputVisible = false;
if (this.showConfirmModal && value.changed && this.text != null) {
this.confirmModal = this.modal.confirm({
nzTitle: '数据变更',
nzContent: '是否提交修改,点击确定提交修改,点击取消则恢复原数据',
nzOnOk: () => this.modalOK.emit(value),
nzOnCancel: () => this.modalCancel.emit(value)
});
}
if (this.autoClear) {
this.text = null
}
}
}

View File

@@ -0,0 +1,22 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {EditableTagComponent} from './editable-tag.component';
import {NzIconModule, NzInputModule, NzTagModule} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [EditableTagComponent],
exports: [
EditableTagComponent
],
imports: [
CommonModule,
NzTagModule,
FormsModule,
NzInputModule,
NzIconModule
]
})
export class EditableTagModule {
}

View File

@@ -0,0 +1,28 @@
<!--<c-common-table [data]="data" [request]="req" cardTitle="文章管理"
[template]="{
dislikeCount:{temp:tag},
readingNumber:{temp:readingNumber},
open:{temp:open},
original:{temp:original,param:{true:'原创',false:'转载'}
}}">-->
<!--</c-common-table>-->
<ng-template #tag let-value="value">
<nz-tag [nzColor]="'#87d068'">{{value}}</nz-tag>
</ng-template>
<ng-template #readingNumber let-value="value">
<nz-tag [nzColor]="'#f50'">{{value}}</nz-tag>
</ng-template>
<ng-template #original let-value="value" let-originValue="originValue">
<nz-tag [nzColor]="originValue?'#87d068':'#f50'">{{value}}</nz-tag>
</ng-template>
<ng-template #open let-value="value">
<label nz-checkbox nzDisabled [ngModel]="value"></label>
</ng-template>
<editable-tag color="green">hhh</editable-tag>
<editable-tag color="green" [showEditIcon]="false">hhh</editable-tag>
<editable-tag color="green" [showBorder]="false">hhh</editable-tag>

View File

@@ -0,0 +1,78 @@
import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
import {Data} from '../components/common-table/data';
import {Article} from '../../../class/Article';
import {RequestObj} from '../../../class/HttpReqAndResp';
@Component({
selector: 'app-test-common-table',
templateUrl: './test-common-table.component.html',
styleUrls: ['./test-common-table.component.less']
})
export class TestCommonTableComponent implements OnInit {
/*
* author: {id: 1, email: "a@celess.cn", displayName: "禾几海",…}
category: "前端"
dislikeCount: 0
id: 1293
likeCount: 0
open: true
original: true
publishDateFormat: "2020-03-17 01:22:35"
readingNumber: 234
summary: a
tags: [{id: 26, name: "脚本"}, {id: 27, name: "网课"}]
title: "教你动手写一个刷课脚本"
updateDateFormat: "2020-05-27 00:55:05"*/
// @ViewChild('tag') tagTemp: TemplateRef<any>;
constructor() {
this.data = [
{title: '主键', fieldValue: 'id', show: false, primaryKey: true},
{title: '标题', fieldValue: 'title', show: true},
{title: '发布日期', fieldValue: 'publishDateFormat', show: true},
{title: '更新日期', fieldValue: 'updateDateFormat', show: true},
{title: '文章类型', fieldValue: 'original', show: true},
{title: '阅读量', fieldValue: 'readingNumber', show: true},
{title: '分类', fieldValue: 'category', show: true},
{title: '👎数', fieldValue: 'dislikeCount', show: true},
{title: '👍数', fieldValue: 'likeCount', show: true},
{title: '状态', fieldValue: 'open', show: true},
{title: '简介', fieldValue: 'summary', show: false},
{title: '作者', fieldValue: 'author.displayName', show: true},
{title: '标签数', fieldValue: 'tags.length', show: true},
{
title: '操作', fieldValue: '', show: true, isActionColumns: true,
action: [
{
name: '新增',
click: (d) => console.log('新增', d)
}, {
name: '删除',
color: '#ff0000',
click: (d) => console.log('删除', d)
}, {
name: '编辑',
color: 'blue',
click: (d) => console.log('编辑', d)
},
]
}
]
}
data: Data<Article>[];
req: RequestObj;
ngOnInit(): void {
this.req = {
path: '/admin/articles',
method: 'GET',
queryParam: {
page: 1,
count: 10
}
}
}
}

View File

@@ -0,0 +1,24 @@
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {TestCommonTableComponent} from './test-common-table.component';
import {Router, RouterModule} from '@angular/router';
import {CommonTableModule} from '../components/common-table/common-table.module';
import {NzCheckboxModule, NzTagModule} from 'ng-zorro-antd';
import {FormsModule} from '@angular/forms';
import {EditableTagModule} from '../components/editable-tag/editable-tag.module';
@NgModule({
declarations: [TestCommonTableComponent],
imports: [
CommonModule,
RouterModule.forChild([{path: '', component: TestCommonTableComponent}]),
CommonTableModule,
NzTagModule,
NzCheckboxModule,
FormsModule,
EditableTagModule
]
})
export class TestCommonTableModule {
}