Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ea8f63abc | ||
|
|
f2791ee150 | ||
|
|
df944335da | ||
|
|
d8eaa0d471 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
dist
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
|
.idea
|
||||||
.editorconfig
|
.editorconfig
|
||||||
|
|||||||
31
.gitlab-ci.yml
Normal file
31
.gitlab-ci.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
image: node:latest
|
||||||
|
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- node_modules/
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
script:
|
||||||
|
# build
|
||||||
|
- npm install -g @angular/cli
|
||||||
|
- cd index && npm install
|
||||||
|
- ng build --prod
|
||||||
|
- cd ./dist/index/ && tar -cf index.tar ./*
|
||||||
|
- cp index.tar ../../../
|
||||||
|
# build
|
||||||
|
- cd ../../../admin && npm install
|
||||||
|
- ng build --prod
|
||||||
|
- cd ./dist/admin/ && sed '6s/\"\/\"/\"\/admin\/\"/g' index.html > index.txt && cp index.txt index.html
|
||||||
|
- cd .. && tar -cf admin.tar ./admin/
|
||||||
|
- cp admin.tar ../../ && cd ../../
|
||||||
|
# deploy
|
||||||
|
- eval $(ssh-agent -s)
|
||||||
|
- ssh-add <(echo "$SSH_PRIVATE_KEY" | base64 --decode)
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- chmod 700 ~/.ssh
|
||||||
|
- ssh-keyscan celess.cn >> ~/.ssh/known_hosts
|
||||||
|
- chmod 644 ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- scp index.tar admin.tar root@celess.cn:/www/wwwroot/celess.cn
|
||||||
|
- ssh root@celess.cn "cd /www/wwwroot/celess.cn && bash deploy.sh"
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ export class AppRoutingModule {
|
|||||||
if (!this.userService.userInfo) {
|
if (!this.userService.userInfo) {
|
||||||
this.userService.getUserInfo().subscribe(data => {
|
this.userService.getUserInfo().subscribe(data => {
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
|
this.userService.userInfo = data.result;
|
||||||
this.checkPermission(event);
|
this.checkPermission(event);
|
||||||
} else if (data.code === 301) {
|
} else if (data.code === 301) {
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export class UserService {
|
|||||||
avatarHost: string = 'http://cdn.celess.cn';
|
avatarHost: string = 'http://cdn.celess.cn';
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
constructor(public http: HttpService) {
|
||||||
this.getUserInfo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userPage: Page<User>[] = [];
|
userPage: Page<User>[] = [];
|
||||||
@@ -24,13 +23,7 @@ export class UserService {
|
|||||||
* 获取用户信息
|
* 获取用户信息
|
||||||
*/
|
*/
|
||||||
getUserInfo() {
|
getUserInfo() {
|
||||||
const observable = this.http.get('/user/userInfo');
|
return this.http.get('/user/userInfo');
|
||||||
observable.subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.userInfo = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
27
index/README.md
Normal file
27
index/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Index
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.20.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||||
@@ -5,7 +5,11 @@
|
|||||||
"projects": {
|
"projects": {
|
||||||
"index": {
|
"index": {
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"schematics": {},
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "less"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": "",
|
"root": "",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
@@ -29,19 +33,20 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/assets/editor.md/css/editormd.css",
|
"src/assets/editor/css/editormd.css",
|
||||||
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
|
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
|
||||||
"src/styles.css"
|
"src/styles.less"
|
||||||
],
|
],
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"src/assets/editor.md/lib/marked.min.js",
|
"./node_modules/jquery/dist/jquery.min.js",
|
||||||
"src/assets/editor.md/lib/prettify.min.js",
|
"src/assets/editor/lib/marked.min.js",
|
||||||
"src/assets/editor.md/lib/raphael.min.js",
|
"src/assets/editor/lib/prettify.min.js",
|
||||||
"src/assets/editor.md/lib/underscore.min.js",
|
"src/assets/editor/lib/raphael.min.js",
|
||||||
"src/assets/editor.md/lib/sequence-diagram.min.js",
|
"src/assets/editor/lib/underscore.min.js",
|
||||||
"src/assets/editor.md/lib/flowchart.min.js",
|
"src/assets/editor/lib/sequence-diagram.min.js",
|
||||||
"src/assets/editor.md/lib/jquery.flowchart.min.js",
|
"src/assets/editor/lib/flowchart.min.js",
|
||||||
"src/assets/editor.md/editormd.min.js"
|
"src/assets/editor/lib/jquery.flowchart.min.js",
|
||||||
|
"src/assets/editor/editormd.min.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
@@ -66,6 +71,11 @@
|
|||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "2mb",
|
"maximumWarning": "2mb",
|
||||||
"maximumError": "5mb"
|
"maximumError": "5mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "6kb",
|
||||||
|
"maximumError": "10kb"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -101,7 +111,7 @@
|
|||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
|
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
|
||||||
"src/styles.css"
|
"src/styles.less"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
}
|
}
|
||||||
@@ -134,5 +144,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultProject": "index"
|
"defaultProject": "index",
|
||||||
|
"cli": {
|
||||||
|
"analytics": "f8f677a4-927d-4754-9267-533986f4ecb6"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,31 +2,32 @@
|
|||||||
// Protractor configuration file, see link for more information
|
// Protractor configuration file, see link for more information
|
||||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
const {SpecReporter} = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type { import("protractor").Config }
|
* @type { import("protractor").Config }
|
||||||
*/
|
*/
|
||||||
exports.config = {
|
exports.config = {
|
||||||
allScriptsTimeout: 11000,
|
allScriptsTimeout: 11000,
|
||||||
specs: [
|
specs: [
|
||||||
'./src/**/*.e2e-spec.ts'
|
'./src/**/*.e2e-spec.ts'
|
||||||
],
|
],
|
||||||
capabilities: {
|
capabilities: {
|
||||||
'browserName': 'chrome'
|
browserName: 'chrome'
|
||||||
},
|
},
|
||||||
directConnect: true,
|
directConnect: true,
|
||||||
baseUrl: 'http://localhost:4200/',
|
baseUrl: 'http://localhost:4200/',
|
||||||
framework: 'jasmine',
|
framework: 'jasmine',
|
||||||
jasmineNodeOpts: {
|
jasmineNodeOpts: {
|
||||||
showColors: true,
|
showColors: true,
|
||||||
defaultTimeoutInterval: 30000,
|
defaultTimeoutInterval: 30000,
|
||||||
print: function() {}
|
print: function () {
|
||||||
},
|
}
|
||||||
onPrepare() {
|
},
|
||||||
require('ts-node').register({
|
onPrepare() {
|
||||||
project: require('path').join(__dirname, './tsconfig.json')
|
require('ts-node').register({
|
||||||
});
|
project: require('path').join(__dirname, './tsconfig.json')
|
||||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
});
|
||||||
}
|
jasmine.getEnv().addReporter(new SpecReporter({spec: {displayStacktrace: true}}));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
import { AppPage } from './app.po';
|
import {AppPage} from './app.po';
|
||||||
import { browser, logging } from 'protractor';
|
import {browser, logging} from 'protractor';
|
||||||
|
|
||||||
describe('workspace-project App', () => {
|
describe('workspace-project App', () => {
|
||||||
let page: AppPage;
|
let page: AppPage;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
page = new AppPage();
|
page = new AppPage();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
it('should display welcome message', () => {
|
||||||
page.navigateTo();
|
page.navigateTo();
|
||||||
expect(page.getTitleText()).toEqual('Welcome to blog!');
|
expect(page.getTitleText()).toEqual('index app is running!');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
// Assert that there are no errors emitted from the browser
|
// Assert that there are no errors emitted from the browser
|
||||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||||
expect(logs).not.toContain(jasmine.objectContaining({
|
expect(logs).not.toContain(jasmine.objectContaining({
|
||||||
level: logging.Level.SEVERE,
|
level: logging.Level.SEVERE,
|
||||||
} as logging.Entry));
|
} as logging.Entry));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { browser, by, element } from 'protractor';
|
import {browser, by, element} from 'protractor';
|
||||||
|
|
||||||
export class AppPage {
|
export class AppPage {
|
||||||
navigateTo() {
|
navigateTo() {
|
||||||
return browser.get(browser.baseUrl) as Promise<any>;
|
return browser.get(browser.baseUrl) as Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTitleText() {
|
getTitleText() {
|
||||||
return element(by.css('app-root h1')).getText() as Promise<string>;
|
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,31 +2,31 @@
|
|||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
basePath: '',
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
plugins: [
|
plugins: [
|
||||||
require('karma-jasmine'),
|
require('karma-jasmine'),
|
||||||
require('karma-chrome-launcher'),
|
require('karma-chrome-launcher'),
|
||||||
require('karma-jasmine-html-reporter'),
|
require('karma-jasmine-html-reporter'),
|
||||||
require('karma-coverage-istanbul-reporter'),
|
require('karma-coverage-istanbul-reporter'),
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
],
|
],
|
||||||
client: {
|
client: {
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
coverageIstanbulReporter: {
|
||||||
dir: require('path').join(__dirname, './coverage/blog'),
|
dir: require('path').join(__dirname, './coverage/index'),
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
reports: ['html', 'lcovonly', 'text-summary'],
|
||||||
fixWebpackSourcePaths: true
|
fixWebpackSourcePaths: true
|
||||||
},
|
},
|
||||||
reporters: ['progress', 'kjhtml'],
|
reporters: ['progress', 'kjhtml'],
|
||||||
port: 9876,
|
port: 9876,
|
||||||
colors: true,
|
colors: true,
|
||||||
logLevel: config.LOG_INFO,
|
logLevel: config.LOG_INFO,
|
||||||
autoWatch: true,
|
autoWatch: true,
|
||||||
browsers: ['Chrome'],
|
browsers: ['Chrome'],
|
||||||
singleRun: false,
|
singleRun: false,
|
||||||
restartOnFileChange: true
|
restartOnFileChange: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
11371
index/package-lock.json
generated
11371
index/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,38 +11,39 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "~8.0.1",
|
"@angular/animations": "^9.1.0",
|
||||||
"@angular/common": "~8.0.1",
|
"@angular/common": "^9.1.0",
|
||||||
"@angular/compiler": "~8.0.1",
|
"@angular/compiler": "^9.1.0",
|
||||||
"@angular/core": "~8.0.1",
|
"@angular/core": "^9.1.0",
|
||||||
"@angular/forms": "~8.0.1",
|
"@angular/forms": "^9.1.0",
|
||||||
"@angular/platform-browser": "~8.0.1",
|
"@angular/platform-browser": "^9.1.0",
|
||||||
"@angular/platform-browser-dynamic": "~8.0.1",
|
"@angular/platform-browser-dynamic": "^9.1.0",
|
||||||
"@angular/router": "~8.0.1",
|
"@angular/router": "^9.1.0",
|
||||||
"ng-zorro-antd": "^8.0.3",
|
"jquery": "^3.4.1",
|
||||||
"rxjs": "~6.4.0",
|
"ng-zorro-antd": "^8.5.2",
|
||||||
"tslib": "^1.9.0",
|
"rxjs": "^6.5.5",
|
||||||
"zone.js": "~0.9.1"
|
"tslib": "^1.11.1",
|
||||||
|
"zone.js": "^0.10.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "~0.800.0",
|
"@angular-devkit/build-angular": "^0.901.0",
|
||||||
"@angular/cli": "~8.0.4",
|
"@angular/cli": "^9.1.0",
|
||||||
"@angular/compiler-cli": "~8.0.1",
|
"@angular/compiler-cli": "^9.1.0",
|
||||||
"@angular/language-service": "~8.0.1",
|
"@angular/language-service": "^9.1.0",
|
||||||
"@types/node": "~8.9.4",
|
"@types/jasmine": "^3.5.10",
|
||||||
"@types/jasmine": "~3.3.8",
|
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"codelyzer": "^5.0.0",
|
"@types/node": "^13.11.0",
|
||||||
"jasmine-core": "~3.4.0",
|
"codelyzer": "^5.2.2",
|
||||||
"jasmine-spec-reporter": "~4.2.1",
|
"jasmine-core": "^3.5.0",
|
||||||
"karma": "~4.1.0",
|
"jasmine-spec-reporter": "^5.0.1",
|
||||||
"karma-chrome-launcher": "~2.2.0",
|
"karma": "^4.4.1",
|
||||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
"karma-chrome-launcher": "^3.1.0",
|
||||||
"karma-jasmine": "~2.0.1",
|
"karma-coverage-istanbul-reporter": "^2.1.1",
|
||||||
"karma-jasmine-html-reporter": "^1.4.0",
|
"karma-jasmine": "^3.1.1",
|
||||||
"protractor": "~5.4.0",
|
"karma-jasmine-html-reporter": "^1.5.3",
|
||||||
"ts-node": "~7.0.0",
|
"protractor": "^5.4.3",
|
||||||
"tslint": "~5.15.0",
|
"ts-node": "^8.8.2",
|
||||||
"typescript": "~3.4.3"
|
"tslint": "^6.1.1",
|
||||||
|
"typescript": "^3.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
index/src/app/api/api.service.spec.ts
Normal file
12
index/src/app/api/api.service.spec.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {ApiService} from './api.service';
|
||||||
|
|
||||||
|
describe('ApiService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: ApiService = TestBed.get(ApiService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
345
index/src/app/api/api.service.ts
Normal file
345
index/src/app/api/api.service.ts
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {Article} from '../class/Article';
|
||||||
|
import {HttpService} from './http/http.service';
|
||||||
|
import {PageList} from '../class/pageList';
|
||||||
|
import {ErrDispatch} from '../class/ErrDispatch';
|
||||||
|
import {ArticleReq} from '../class/ArticleReq';
|
||||||
|
import {Category} from '../class/Category';
|
||||||
|
import {Comment} from '../class/Comment';
|
||||||
|
import {CommentReq} from '../class/CommentReq';
|
||||||
|
import {Link} from '../class/Link';
|
||||||
|
import {User} from '../class/User';
|
||||||
|
import {LoginReq} from '../class/LoginReq';
|
||||||
|
import {Observable, Observer, of} from 'rxjs';
|
||||||
|
import {Response} from '../class/Response';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {LocalStorageService} from '../utils/local-storage.service';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ApiService extends HttpService {
|
||||||
|
|
||||||
|
constructor(httpClient: HttpClient,
|
||||||
|
localStorageService: LocalStorageService) {
|
||||||
|
super(httpClient, localStorageService);
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrDispatch(errDispatch: ErrDispatch) {
|
||||||
|
super.setErrDispatch(errDispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
createArticle(article: ArticleReq) {
|
||||||
|
article.id = null;
|
||||||
|
return super.Service<Article>({
|
||||||
|
path: '/admin/article/create',
|
||||||
|
contentType: 'application/json',
|
||||||
|
method: 'POST',
|
||||||
|
data: article
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
articles(pageNumber: number = 1, pageSize: number = 5) {
|
||||||
|
return super.Service<PageList<Article>>({
|
||||||
|
path: '/articles',
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
page: pageNumber,
|
||||||
|
count: pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateArticle(article: ArticleReq) {
|
||||||
|
return super.Service<Article>({
|
||||||
|
path: '/admin/article/update',
|
||||||
|
method: 'PUT',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: article
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getArticle(articleId: number, is4Update: boolean = false) {
|
||||||
|
return super.Service<Article>({
|
||||||
|
path: `/article/articleID/${articleId}`,
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {update: is4Update},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
articlesByCategory(category: string, pageNumber: number = 1, pageSize: number = 10) {
|
||||||
|
return super.Service<PageList<Article>>({
|
||||||
|
path: `/articles/category/${category}`,
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
page: pageNumber,
|
||||||
|
count: pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
articlesByTag(tag: string, pageNumber: number = 1, pageSize: number = 10) {
|
||||||
|
return super.Service<PageList<Article>>({
|
||||||
|
path: `/articles/tag/${tag}`,
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
page: pageNumber,
|
||||||
|
count: pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
categories() {
|
||||||
|
return super.Service<Category[]>({
|
||||||
|
path: '/categories',
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tags(pageNumber: number = 1, pageSize: number = 10) {
|
||||||
|
return super.Service<Category[]>({
|
||||||
|
path: '/tags',
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
page: pageNumber,
|
||||||
|
count: pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tagsNac() {
|
||||||
|
return super.Service<{ name: string, size: number }[]>({
|
||||||
|
path: '/tags/nac',
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommentByPid(pid: number, pageNumber: number = 1, pageSize: number = 10) {
|
||||||
|
return super.Service<PageList<Comment>[]>({
|
||||||
|
path: `/comment/pid/${pid}`,
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
page: pageNumber,
|
||||||
|
count: pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
comments(articleID: number, pageSize: number = 10, pageNumber: number = 1) {
|
||||||
|
return super.Service<PageList<Comment>>({
|
||||||
|
path: '/comments',
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
articleId: articleID,
|
||||||
|
count: pageSize,
|
||||||
|
page: pageNumber
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveMsg(pageSize: number = 10, pageNumber: number = 1) {
|
||||||
|
return super.Service<PageList<Comment>>({
|
||||||
|
path: '/leaveMsg',
|
||||||
|
method: 'GET',
|
||||||
|
queryParam: {
|
||||||
|
count: pageSize,
|
||||||
|
page: pageNumber
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createComment(commentReq: CommentReq) {
|
||||||
|
return super.Service<Comment>({
|
||||||
|
path: '/user/comment/create',
|
||||||
|
method: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: commentReq
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
counts() {
|
||||||
|
return super.Service<{
|
||||||
|
articleCount: number,
|
||||||
|
visitorCount: number,
|
||||||
|
categoryCount: number,
|
||||||
|
leaveMsgCount: number,
|
||||||
|
tagCount: number,
|
||||||
|
commentCount: number
|
||||||
|
}>({
|
||||||
|
path: '/counts',
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
applyLink(link: Link) {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/apply',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {
|
||||||
|
name: link.name,
|
||||||
|
url: link.url
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
links() {
|
||||||
|
return super.Service<Link[]>({
|
||||||
|
path: '/links',
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyImgCode(codeStr: string) {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/verCode',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {code: codeStr}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
login(loginReq: LoginReq) {
|
||||||
|
const observable = super.Service<User>({
|
||||||
|
path: '/login',
|
||||||
|
method: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: loginReq
|
||||||
|
});
|
||||||
|
let observer: Observer<Response<User>>;
|
||||||
|
const oob = new Observable<Response<User>>(o => observer = o);
|
||||||
|
observable.subscribe({
|
||||||
|
next: o => {
|
||||||
|
if (o.code === 0) {
|
||||||
|
// 登录成功
|
||||||
|
this.localStorageService.setToken(o.result.token);
|
||||||
|
this.localStorageService.setUser(o.result);
|
||||||
|
}
|
||||||
|
observer.next(o);
|
||||||
|
observer.complete();
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
observer.error(err);
|
||||||
|
observer.complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return oob;
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.localStorageService.clear();
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/logout',
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
registration(emailStr: string, pwd: string) {
|
||||||
|
return super.Service<boolean>({
|
||||||
|
path: '/registration',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {
|
||||||
|
email: emailStr,
|
||||||
|
password: pwd
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPwd(idStr: string, emailStr: string, pwdStr: string) {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/resetPwd',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {
|
||||||
|
verifyId: idStr,
|
||||||
|
email: emailStr,
|
||||||
|
pwd: pwdStr
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
emailVerify(idStr: string, emailStr: string) {
|
||||||
|
return super.Service<void>({
|
||||||
|
path: '/emailVerify',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {
|
||||||
|
verifyId: idStr,
|
||||||
|
email: emailStr
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sendResetPwdEmail(emailStr: string) {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/sendResetPwdEmail',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {email: emailStr}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendVerifyEmail(emailStr: string) {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/sendVerifyEmail',
|
||||||
|
method: 'POST',
|
||||||
|
queryParam: {email: emailStr}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo() {
|
||||||
|
// 判断本地缓存的用户信息是否符合要求,符合要求返回本地缓存
|
||||||
|
const user = this.localStorageService.getUser();
|
||||||
|
if (this.localStorageService.isLogin() && user && !this.localStorageService.checkNeedNet()) {
|
||||||
|
return of<Response<User>>(new Response<User>(user));
|
||||||
|
}
|
||||||
|
// 不符合 请求网络数据并更新缓存
|
||||||
|
const observable = super.Service<User>({
|
||||||
|
path: '/user/userInfo',
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
let observer: Observer<Response<User>>;
|
||||||
|
const oob = new Observable<Response<User>>(o => observer = o);
|
||||||
|
observable.subscribe({
|
||||||
|
next: o => {
|
||||||
|
this.localStorageService.setUser(o.result);
|
||||||
|
observer.next(o);
|
||||||
|
observer.complete();
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
// console.debug('登录过期 token错误 等等');
|
||||||
|
this.localStorageService.removeToken();
|
||||||
|
observer.error(err);
|
||||||
|
observer.complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return oob;
|
||||||
|
}
|
||||||
|
|
||||||
|
visit() {
|
||||||
|
return super.Service<User>({
|
||||||
|
path: '/visit',
|
||||||
|
method: 'POST',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
webUpdate() {
|
||||||
|
return super.Service<{ id: number, info: string, time: string }[]>({
|
||||||
|
path: '/webUpdate',
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lastestUpdateTime() {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/lastestUpdateTime',
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bingPic() {
|
||||||
|
return super.Service<string>({
|
||||||
|
path: '/bingPic',
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
15
index/src/app/api/http/http.service.spec.ts
Normal file
15
index/src/app/api/http/http.service.spec.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {HttpService} from './http.service';
|
||||||
|
|
||||||
|
describe('HttpService', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({}));
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
const service: HttpService = TestBed.get(HttpService);
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('should be valid', () => {
|
||||||
|
const service: HttpService = TestBed.get(HttpService);
|
||||||
|
});
|
||||||
|
});
|
||||||
127
index/src/app/api/http/http.service.ts
Normal file
127
index/src/app/api/http/http.service.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {RequestObj} from '../../class/Request';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {environment} from '../../../environments/environment';
|
||||||
|
import {LocalStorageService} from '../../utils/local-storage.service';
|
||||||
|
import {Response} from '../../class/Response';
|
||||||
|
import {Observable, Observer, Subject} from 'rxjs';
|
||||||
|
import {ErrDispatch} from '../../class/ErrDispatch';
|
||||||
|
import {multicast} from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class HttpService {
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient,
|
||||||
|
protected localStorageService: LocalStorageService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private errorDispatch: ErrDispatch;
|
||||||
|
|
||||||
|
setErrDispatch(errDispatch: ErrDispatch) {
|
||||||
|
this.errorDispatch = errDispatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
Service<T>(request: RequestObj) {
|
||||||
|
// 设置默认值
|
||||||
|
request.contentType = request.contentType == null ? 'application/x-www-form-urlencoded' : 'application/json';
|
||||||
|
request.header = {
|
||||||
|
'Content-Type': request.contentType
|
||||||
|
};
|
||||||
|
const token = this.localStorageService.getToken();
|
||||||
|
if (token != null) {
|
||||||
|
request.header.Authorization = token;
|
||||||
|
}
|
||||||
|
request.path = this.checkUrl(request);
|
||||||
|
|
||||||
|
let observable: Observable<Response<T>>;
|
||||||
|
switch (request.method) {
|
||||||
|
case 'GET':
|
||||||
|
observable = this.get<Response<T>>(request);
|
||||||
|
break;
|
||||||
|
case 'DELETE':
|
||||||
|
observable = this.delete<Response<T>>(request);
|
||||||
|
break;
|
||||||
|
case 'PUT':
|
||||||
|
observable = this.put<Response<T>>(request);
|
||||||
|
break;
|
||||||
|
case 'POST':
|
||||||
|
observable = this.post<Response<T>>(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let observer: Observer<Response<T>>;
|
||||||
|
|
||||||
|
const oob = new Observable<Response<T>>(o => observer = o);
|
||||||
|
|
||||||
|
observable.subscribe(o => {
|
||||||
|
if (o.code) {
|
||||||
|
observer.error(o);
|
||||||
|
if (this.errorDispatch) {
|
||||||
|
this.errorDispatch.errHandler(o.code, o.msg, request);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
observer.next(o);
|
||||||
|
}
|
||||||
|
observer.complete();
|
||||||
|
});
|
||||||
|
return oob;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get<T>(request: RequestObj) {
|
||||||
|
return this.httpClient.get<T>(request.path,
|
||||||
|
{
|
||||||
|
headers: request.header,
|
||||||
|
withCredentials: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private post<T>(request: RequestObj) {
|
||||||
|
return this.httpClient.post<T>(request.path, request.data,
|
||||||
|
{
|
||||||
|
headers: request.header,
|
||||||
|
withCredentials: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private put<T>(request: RequestObj) {
|
||||||
|
return this.httpClient.put<T>(request.path, request.data,
|
||||||
|
{
|
||||||
|
headers: request.header,
|
||||||
|
withCredentials: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private delete<T>(request: RequestObj) {
|
||||||
|
return this.httpClient.delete<T>(request.path,
|
||||||
|
{
|
||||||
|
headers: request.header,
|
||||||
|
withCredentials: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证并且处理拼接 URl
|
||||||
|
* @param req Request
|
||||||
|
*/
|
||||||
|
private checkUrl(req: RequestObj): string {
|
||||||
|
let tmpUrl = environment.host;
|
||||||
|
if (req.path.length === 0) {
|
||||||
|
return tmpUrl;
|
||||||
|
}
|
||||||
|
if (req.path.substr(0, 1) !== '/') {
|
||||||
|
tmpUrl += '/';
|
||||||
|
}
|
||||||
|
let queryStr = '';
|
||||||
|
const keys = req.queryParam == null ? [] : Object.keys(req.queryParam);
|
||||||
|
if (keys.length === 0) {
|
||||||
|
return tmpUrl + req.path;
|
||||||
|
}
|
||||||
|
for (const key of keys) {
|
||||||
|
queryStr += '&' + key + '=' + req.queryParam[key];
|
||||||
|
}
|
||||||
|
queryStr = queryStr.substr(1, queryStr.length);
|
||||||
|
return tmpUrl + req.path + '?' + queryStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +1,32 @@
|
|||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {Routes, RouterModule} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
|
|
||||||
import {IndexComponent} from './pages/index/index.component';
|
|
||||||
import {UpdateComponent} from './pages/update/update.component';
|
|
||||||
import {CategoryComponent} from './pages/categories/category.component';
|
|
||||||
import {TagComponent} from './pages/tag/tag.component';
|
|
||||||
import {LeaveMsgComponent} from './pages/leave-msg/leave-msg.component';
|
|
||||||
import {PartnerSitesComponent} from './pages/partner-sites/partner-sites.component';
|
|
||||||
import {ArticleComponent} from './pages/article/article.component';
|
|
||||||
import {EmailVerifyComponent} from './pages/email-verify/email-verify.component';
|
|
||||||
import {ResetPwdComponent} from './pages/reset-pwd/reset-pwd.component';
|
|
||||||
import {NotFoundComponent} from './pages/not-found/not-found.component';
|
|
||||||
import {WriteComponent} from './pages/write/write.component';
|
|
||||||
import {LoginComponent} from './pages/login/login.component';
|
|
||||||
import {RegistrationComponent} from './pages/registration/registration.component';
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', component: IndexComponent},
|
{path: '', pathMatch: 'full', loadChildren: () => import('./view/index/index.module').then(mod => mod.IndexModule)},
|
||||||
{path: 'update', component: UpdateComponent},
|
{path: 'update', loadChildren: () => import('./view/update/update.module').then(mod => mod.UpdateModule)},
|
||||||
{path: 'category', component: CategoryComponent},
|
{path: 'article/:id', loadChildren: () => import('./view/article/article.module').then(mod => mod.ArticleModule)},
|
||||||
{path: 'tag', component: TagComponent},
|
{path: 'tags', loadChildren: () => import('./view/tag/tag.module').then(mod => mod.TagModule)},
|
||||||
{path: 'leaveMsg', component: LeaveMsgComponent},
|
{path: 'categories', loadChildren: () => import('./view/category/category.module').then(mod => mod.CategoryModule)},
|
||||||
{path: 'links', component: PartnerSitesComponent},
|
// {path: 'leaveMsg', loadChildren: () => import('./view/leave-msg/leave-msg.module').then(mod => mod.LeaveMsgModule)},
|
||||||
{path: 'article/:id', component: ArticleComponent},
|
{path: 'emailVerify', loadChildren: () => import('./view/email-verify/email-verify.module').then(mod => mod.EmailVerifyModule)},
|
||||||
{path: 'write', component: WriteComponent},
|
{path: 'resetPwd', loadChildren: () => import('./view/reset-pwd/reset-pwd.module').then(mod => mod.ResetPwdModule)},
|
||||||
{path: 'resetPwd', component: ResetPwdComponent},
|
{path: 'write', loadChildren: () => import('./view/write/write.module').then(mod => mod.WriteModule)},
|
||||||
{path: 'emailVerify', component: EmailVerifyComponent},
|
{path: 'links', loadChildren: () => import('./view/link/link.module').then(mod => mod.LinkModule)},
|
||||||
{path: 'login', component: LoginComponent},
|
{
|
||||||
{path: 'registration', component: RegistrationComponent},
|
path: 'user', loadChildren: () => import('./view/login-registration/login-registration.module')
|
||||||
{path: '404', component: NotFoundComponent},
|
.then(mod => mod.LoginRegistrationModule)
|
||||||
{path: '**', component: NotFoundComponent}
|
},
|
||||||
|
{path: '**', loadChildren: () => import('./view/page-not-found/page-not-found.module').then(mod => mod.PageNotFoundModule)}
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO lazyLoad
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [
|
||||||
exports: [RouterModule]
|
RouterModule.forRoot(routes)
|
||||||
|
],
|
||||||
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
|
|
||||||
export class AppRoutingModule {
|
export class AppRoutingModule {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,31 @@
|
|||||||
<app-header></app-header>
|
<app-header (loginEvent)="login()" (registrationEvent)="registration()" #headerComponent></app-header>
|
||||||
<div style="height: 80px"></div>
|
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|
||||||
<div style="height: 60px"></div>
|
|
||||||
<app-footer></app-footer>
|
<app-footer></app-footer>
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="userService.loginModalVisible" nzClosable="true"
|
|
||||||
(nzOnCancel)="userService.loginModalVisible=false" [nzFooter]="footerButton">
|
<nz-back-top [nzTemplate]="backToTop"></nz-back-top>
|
||||||
<ng-template [ngIf]="userService.loginModalType=='registration'">
|
|
||||||
<app-registration></app-registration>
|
<ng-template #backToTop>
|
||||||
</ng-template>
|
<button style=" height: 60px;width: 60px;border-radius: 50%;" nz-button title="回到顶部">
|
||||||
<ng-template [ngIf]="userService.loginModalType=='login'">
|
<i nz-icon nzType="rocket" nzTheme="outline"></i>
|
||||||
<app-login></app-login>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
|
||||||
|
<nz-modal
|
||||||
|
[(nzVisible)]="loginModal" (nzOnCancel)="loginModal = !loginModal"
|
||||||
|
[nzContent]="content" [nzFooter]="null" nzWidth="400">
|
||||||
|
<ng-template #content>
|
||||||
|
<c-login (loginStatus)="loginStatus($event)" [showSendEmail]="false"></c-login>
|
||||||
|
</ng-template>
|
||||||
</nz-modal>
|
</nz-modal>
|
||||||
|
|
||||||
<ng-template #footerButton>
|
<nz-modal
|
||||||
<small style="width:100%;text-align: center">小海博客</small>
|
[(nzVisible)]="regModal" (nzOnCancel)="regModal = !regModal" [nzContent]="content2"
|
||||||
</ng-template>
|
[nzFooter]="null" nzWidth="400">
|
||||||
|
<ng-template #content2>
|
||||||
|
<c-registration (regStatus)="regModal = !$event" (regAccount)="cons($event)"></c-registration>
|
||||||
|
</ng-template>
|
||||||
|
</nz-modal>
|
||||||
20
index/src/app/app.component.less
Normal file
20
index/src/app/app.component.less
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#slider-container {
|
||||||
|
width: 400px;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #4ffff5;
|
||||||
|
z-index: 100;
|
||||||
|
padding: 18px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#article-container {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 430px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
@@ -1,35 +1,35 @@
|
|||||||
import { TestBed, async } from '@angular/core/testing';
|
import {TestBed, async} from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
import { AppComponent } from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterTestingModule
|
RouterTestingModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent
|
AppComponent
|
||||||
],
|
],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create the app', () => {
|
it('should create the app', () => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
const app = fixture.debugElement.componentInstance;
|
const app = fixture.debugElement.componentInstance;
|
||||||
expect(app).toBeTruthy();
|
expect(app).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should have as title 'blog'`, () => {
|
it(`should have as title 'index'`, () => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
const app = fixture.debugElement.componentInstance;
|
const app = fixture.debugElement.componentInstance;
|
||||||
expect(app.title).toEqual('blog');
|
expect(app.title).toEqual('index');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render title in a h1 tag', () => {
|
it('should render title', () => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const compiled = fixture.debugElement.nativeElement;
|
const compiled = fixture.debugElement.nativeElement;
|
||||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to blog!');
|
expect(compiled.querySelector('.content span').textContent).toContain('index app is running!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,16 +1,38 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component, ElementRef, OnInit, TemplateRef, ViewChild} from '@angular/core';
|
||||||
import {UserService} from './services/user/user.service';
|
import {LoginReq} from './class/LoginReq';
|
||||||
|
import {HeaderComponent} from './components/header/header.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.css']
|
styleUrls: ['./app.component.less']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'blog';
|
loginModal: boolean = false;
|
||||||
|
regModal: boolean = false;
|
||||||
|
@ViewChild('headerComponent') header: HeaderComponent;
|
||||||
|
|
||||||
constructor(public userService: UserService) {
|
registration() {
|
||||||
}
|
// todo :: 登录
|
||||||
|
console.log('registration');
|
||||||
|
this.regModal = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
// TODO :: 注册
|
||||||
|
console.log('login');
|
||||||
|
this.loginModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cons($event: LoginReq) {
|
||||||
|
console.log($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
loginStatus(e: boolean) {
|
||||||
|
if (e) {
|
||||||
|
this.header.getInfo();
|
||||||
|
}
|
||||||
|
this.loginModal = !e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
import {AppRoutingModule} from './app-routing.module';
|
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import {NgZorroAntdModule, NZ_I18N, zh_CN} from 'ng-zorro-antd';
|
import {NgZorroAntdModule, NZ_I18N, zh_CN} from 'ng-zorro-antd';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
@@ -9,84 +7,32 @@ import {HttpClientModule} from '@angular/common/http';
|
|||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
import {registerLocaleData} from '@angular/common';
|
import {registerLocaleData} from '@angular/common';
|
||||||
import zh from '@angular/common/locales/zh';
|
import zh from '@angular/common/locales/zh';
|
||||||
|
|
||||||
import {EditorMdDirective} from './pages/write/editor/editor-md.directive';
|
|
||||||
|
|
||||||
// components
|
|
||||||
import {HeaderComponent} from './components/header/header.component';
|
import {HeaderComponent} from './components/header/header.component';
|
||||||
import {FooterComponent} from './components/footer/footer.component';
|
import {FooterComponent} from './components/footer/footer.component';
|
||||||
|
import {AppRoutingModule} from './app-routing.module';
|
||||||
|
import {LoginRegistrationModule} from './view/login-registration/login-registration.module';
|
||||||
|
|
||||||
// pages
|
|
||||||
import {IndexComponent} from './pages/index/index.component';
|
|
||||||
import {UpdateComponent} from './pages/update/update.component';
|
|
||||||
import {CategoryComponent} from './pages/categories/category.component';
|
|
||||||
import {TagComponent} from './pages/tag/tag.component';
|
|
||||||
import {LeaveMsgComponent} from './pages/leave-msg/leave-msg.component';
|
|
||||||
import {PartnerSitesComponent} from './pages/partner-sites/partner-sites.component';
|
|
||||||
import {ArticleComponent} from './pages/article/article.component';
|
|
||||||
import {EmailVerifyComponent} from './pages/email-verify/email-verify.component';
|
|
||||||
import {ResetPwdComponent} from './pages/reset-pwd/reset-pwd.component';
|
|
||||||
import {NotFoundComponent} from './pages/not-found/not-found.component';
|
|
||||||
import {LoginComponent} from './pages/login/login.component';
|
|
||||||
import {RegistrationComponent} from './pages/registration/registration.component';
|
|
||||||
import {WriteComponent} from './pages/write/write.component';
|
|
||||||
|
|
||||||
// services
|
|
||||||
import {HttpService} from './services/http.service';
|
|
||||||
import {UserService} from './services/user/user.service';
|
|
||||||
import {ArticleService} from './services/article/article.service';
|
|
||||||
import {CategoryService} from './services/category/category.service';
|
|
||||||
import {CountService} from './services/count/count.service';
|
|
||||||
import {CommentService} from './services/comment/comment.service';
|
|
||||||
import {TagService} from './services/tag/tag.service';
|
|
||||||
import {WebUpdateService} from './services/update/web-update.service';
|
|
||||||
import {LinkService} from './services/link/link.service';
|
|
||||||
|
|
||||||
registerLocaleData(zh);
|
registerLocaleData(zh);
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
FooterComponent,
|
FooterComponent,
|
||||||
EditorMdDirective,
|
],
|
||||||
|
imports: [
|
||||||
IndexComponent,
|
BrowserModule,
|
||||||
UpdateComponent,
|
AppRoutingModule,
|
||||||
CategoryComponent,
|
NgZorroAntdModule,
|
||||||
TagComponent,
|
FormsModule,
|
||||||
LeaveMsgComponent,
|
HttpClientModule,
|
||||||
PartnerSitesComponent,
|
BrowserAnimationsModule,
|
||||||
ArticleComponent,
|
LoginRegistrationModule
|
||||||
EmailVerifyComponent,
|
],
|
||||||
ResetPwdComponent,
|
providers: [{provide: NZ_I18N, useValue: zh_CN}],
|
||||||
NotFoundComponent,
|
exports: [],
|
||||||
LoginComponent,
|
bootstrap: [AppComponent]
|
||||||
RegistrationComponent,
|
|
||||||
WriteComponent
|
|
||||||
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
AppRoutingModule,
|
|
||||||
NgZorroAntdModule,
|
|
||||||
FormsModule,
|
|
||||||
HttpClientModule,
|
|
||||||
BrowserAnimationsModule
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{provide: NZ_I18N, useValue: zh_CN},
|
|
||||||
HttpService,
|
|
||||||
UserService,
|
|
||||||
ArticleService,
|
|
||||||
CountService,
|
|
||||||
CommentService,
|
|
||||||
TagService,
|
|
||||||
WebUpdateService,
|
|
||||||
CategoryService,
|
|
||||||
LinkService
|
|
||||||
],
|
|
||||||
bootstrap: [AppComponent]
|
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
}
|
}
|
||||||
|
|||||||
12
index/src/app/class/Comment.ts
Normal file
12
index/src/app/class/Comment.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export class Comment {
|
||||||
|
id?: number;
|
||||||
|
authorName?: string;
|
||||||
|
authorAvatarImgUrl?: string;
|
||||||
|
content: string;
|
||||||
|
articleID: number;
|
||||||
|
date?: string;
|
||||||
|
responseId: string;
|
||||||
|
pid: number;
|
||||||
|
comment: boolean;
|
||||||
|
respComment: Comment[];
|
||||||
|
}
|
||||||
27
index/src/app/class/EditorConfig.ts
Normal file
27
index/src/app/class/EditorConfig.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import {environment} from '../../environments/environment';
|
||||||
|
|
||||||
|
export class EditorConfig {
|
||||||
|
public width = '100%';
|
||||||
|
public height = '400';
|
||||||
|
public path = 'assets/editor/lib/';
|
||||||
|
public codeFold: true;
|
||||||
|
public searchReplace = true;
|
||||||
|
public toolbar = true;
|
||||||
|
public placeholder = '欢迎来到小海的创作中心';
|
||||||
|
public emoji = true;
|
||||||
|
public taskList = true;
|
||||||
|
public tex = true;
|
||||||
|
public readOnly = false;
|
||||||
|
public tocm = true;
|
||||||
|
public watch = true;
|
||||||
|
public previewCodeHighlight = true;
|
||||||
|
public saveHTMLToTextarea = true;
|
||||||
|
public markdown = '';
|
||||||
|
public flowChart = true;
|
||||||
|
public syncScrolling = true;
|
||||||
|
public sequenceDiagram = true;
|
||||||
|
public imageUpload = true;
|
||||||
|
public imageFormats = ['jpg', 'jpeg', 'gif', 'png', 'bmp', 'webp'];
|
||||||
|
public imageUploadURL = environment.host + '/imgUpload';
|
||||||
|
|
||||||
|
}
|
||||||
5
index/src/app/class/ErrDispatch.ts
Normal file
5
index/src/app/class/ErrDispatch.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import {RequestObj} from './Request';
|
||||||
|
|
||||||
|
export interface ErrDispatch {
|
||||||
|
errHandler(code: number, msg: string, request?: RequestObj): void;
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export class LeaveMsg {
|
|
||||||
id: number;
|
|
||||||
type: number;
|
|
||||||
authorName: string;
|
|
||||||
authorAvatarImgUrl: string;
|
|
||||||
content: string;
|
|
||||||
date: string;
|
|
||||||
pid: number;
|
|
||||||
responseId: string;
|
|
||||||
child: LeaveMsg[];
|
|
||||||
}
|
|
||||||
5
index/src/app/class/Link.ts
Normal file
5
index/src/app/class/Link.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export class Link {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
12
index/src/app/class/Request.ts
Normal file
12
index/src/app/class/Request.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import {HttpHeaders} from '@angular/common/http';
|
||||||
|
|
||||||
|
export class RequestObj {
|
||||||
|
path: string;
|
||||||
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||||
|
data?: {};
|
||||||
|
contentType?: 'application/json' | 'application/x-www-form-urlencoded';
|
||||||
|
queryParam?: {};
|
||||||
|
header?: HttpHeaders | {
|
||||||
|
[header: string]: string | string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
11
index/src/app/class/Response.ts
Normal file
11
index/src/app/class/Response.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export class Response<T> {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
result: T;
|
||||||
|
date: number;
|
||||||
|
|
||||||
|
constructor(t: T) {
|
||||||
|
this.code = 0;
|
||||||
|
this.result = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,19 @@
|
|||||||
export class Article {
|
export class Article {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
mdContent?: string;
|
mdContent?: string;
|
||||||
original?: boolean;
|
original?: boolean;
|
||||||
url?: string;
|
url?: string;
|
||||||
publishDateFormat?: string;
|
publishDateFormat?: string;
|
||||||
updateDateFormat?: string;
|
updateDateFormat?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
authorName?: string;
|
authorName?: string;
|
||||||
preArticleId?: number;
|
preArticleId?: number;
|
||||||
nextArticleId?: number;
|
nextArticleId?: number;
|
||||||
preArticleTitle?: string;
|
preArticleTitle?: string;
|
||||||
nextArticleTitle?: string;
|
nextArticleTitle?: string;
|
||||||
readingNumber?: number;
|
readingNumber?: number;
|
||||||
open?: string;
|
open?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
export class ArticleReq {
|
export class ArticleReq {
|
||||||
category: string;
|
category: string;
|
||||||
id?: number;
|
id?: number;
|
||||||
mdContent: string;
|
mdContent: string;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
tags: string;
|
tags: string;
|
||||||
title: string;
|
title: string;
|
||||||
type: boolean;
|
type: boolean;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.type = true;
|
this.type = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export class Category {
|
export class Category {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
articles: string;
|
articles?: number[];
|
||||||
size?: number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
export class CommentReq {
|
export class CommentReq {
|
||||||
articleID: number;
|
id?: number;
|
||||||
comment: boolean;
|
comment: boolean;
|
||||||
content: string;
|
content: string;
|
||||||
id: number;
|
pid: number;
|
||||||
pid: number;
|
articleID: number;
|
||||||
responseId: string;
|
responseId: string;
|
||||||
|
|
||||||
constructor(comment: boolean) {
|
constructor(comment: boolean) {
|
||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
this.responseId = '';
|
this.responseId = '';
|
||||||
if (!comment) {
|
if (!comment) {
|
||||||
this.articleID = -1;
|
this.articleID = -1;
|
||||||
|
}
|
||||||
|
this.pid = -1;
|
||||||
|
this.id = null;
|
||||||
}
|
}
|
||||||
this.pid = -1;
|
|
||||||
this.id = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
export class Count {
|
|
||||||
visitorCount: number = 0;
|
|
||||||
leaveMsgCount: number = 0;
|
|
||||||
tagCount: number = 0;
|
|
||||||
articleCount: number = 0;
|
|
||||||
commentCount: number = 0;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export class Data {
|
|
||||||
code: number;
|
|
||||||
msg: string;
|
|
||||||
result: any;
|
|
||||||
date: number;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import {environment} from '../../environments/environment';
|
|
||||||
|
|
||||||
export class EditorConfig {
|
|
||||||
public width = '100%';
|
|
||||||
public height = '400';
|
|
||||||
public path = 'assets/editor.md/lib/';
|
|
||||||
public codeFold: true;
|
|
||||||
public searchReplace = true;
|
|
||||||
public toolbar = true;
|
|
||||||
public placeholder = '欢迎来到小海的创作中心';
|
|
||||||
public emoji = true;
|
|
||||||
public taskList = true;
|
|
||||||
public tex = true;
|
|
||||||
public readOnly = false;
|
|
||||||
public tocm = true;
|
|
||||||
public watch = true;
|
|
||||||
public previewCodeHighlight = true;
|
|
||||||
public saveHTMLToTextarea = true;
|
|
||||||
public markdown = '';
|
|
||||||
public flowChart = true;
|
|
||||||
public syncScrolling = true;
|
|
||||||
public sequenceDiagram = true;
|
|
||||||
public imageUpload = true;
|
|
||||||
public imageFormats = ['jpg', 'jpeg', 'gif', 'png', 'bmp', 'webp'];
|
|
||||||
public imageUploadURL = environment.host + '/imgUpload';
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
export class LoginReq {
|
export class LoginReq {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
isRememberMe: boolean;
|
||||||
isRememberMe: boolean = false;
|
password: string;
|
||||||
|
|
||||||
|
constructor(email: string, isRememberMe: boolean, password: string) {
|
||||||
|
this.email = email;
|
||||||
|
this.isRememberMe = isRememberMe;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
export class Page<T> {
|
|
||||||
total: number;
|
|
||||||
list: T[];
|
|
||||||
pageNum: number;
|
|
||||||
pageSize: number;
|
|
||||||
size: number;
|
|
||||||
startRow: number;
|
|
||||||
endRow: number;
|
|
||||||
pages: number;
|
|
||||||
prePage: number;
|
|
||||||
nextPage: number;
|
|
||||||
isFirstPage: boolean;
|
|
||||||
isLastPage: boolean;
|
|
||||||
hasPreviousPage: boolean;
|
|
||||||
hasNextPage: boolean;
|
|
||||||
navigatePages: number;
|
|
||||||
navigatepageNums: number[];
|
|
||||||
navigateFirstPage: number;
|
|
||||||
navigateLastPage: number;
|
|
||||||
}
|
|
||||||
20
index/src/app/class/pageList.ts
Normal file
20
index/src/app/class/pageList.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
export class PageList<T> {
|
||||||
|
total: number;
|
||||||
|
list: T[];
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
size: number;
|
||||||
|
startRow: number;
|
||||||
|
endRow: number;
|
||||||
|
pages: number;
|
||||||
|
prePage: number;
|
||||||
|
nextPage: number;
|
||||||
|
isFirstPage: boolean;
|
||||||
|
isLastPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
navigatePages: number;
|
||||||
|
navigatepageNums: number[];
|
||||||
|
navigateFirstPage: number;
|
||||||
|
navigateLastPage: number;
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
export class Tag {
|
export class Tag {
|
||||||
id?: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
articles?: string;
|
articles?: number[];
|
||||||
size: number;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
export class UpdateInfo {
|
|
||||||
id: number;
|
|
||||||
info: string;
|
|
||||||
time: string;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
export class User {
|
export class User {
|
||||||
id: number;
|
id: number;
|
||||||
email: string;
|
email: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
emailStatus: boolean;
|
emailStatus: boolean;
|
||||||
avatarImgUrl: string;
|
avatarImgUrl: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
role: string;
|
role: string;
|
||||||
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<div class="footer">
|
<div class="footer" *ngIf="show">
|
||||||
<hr>
|
<nz-divider></nz-divider>
|
||||||
<div>
|
|
||||||
<a href="http://www.miitbeian.gov.cn" target="_blank">
|
|
||||||
鄂ICP备18023929号
|
|
||||||
</a>
|
|
||||||
<div>
|
<div>
|
||||||
© 2019 <a href="https://www.celess.cn">小海博客</a> - <i class="fa fa-coffee" style="margin: 0 5px"></i>郑海 版权所有
|
<a href="http://www.miitbeian.gov.cn" target="_blank">
|
||||||
|
鄂ICP备18023929号
|
||||||
|
</a>
|
||||||
|
<div>
|
||||||
|
© 2019 <a href="https://www.celess.cn">小海博客</a> -
|
||||||
|
<span>郑海 </span> <span *ngIf="gName">& {{gName}} </span>版权所有
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1,15 +1,29 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {filter} from 'rxjs/operators';
|
||||||
|
import {NavigationEnd, Route, Router, RouterEvent} from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-footer',
|
selector: 'app-footer',
|
||||||
templateUrl: './footer.component.html',
|
templateUrl: './footer.component.html',
|
||||||
styleUrls: ['./footer.component.css']
|
styleUrls: ['./footer.component.less']
|
||||||
})
|
})
|
||||||
export class FooterComponent implements OnInit {
|
export class FooterComponent implements OnInit {
|
||||||
|
show: boolean;
|
||||||
|
|
||||||
constructor() { }
|
constructor(private router: Router) {
|
||||||
|
this.show = true;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
readonly gName: string;
|
||||||
}
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe((e: RouterEvent) => {
|
||||||
|
const indexOf = e.url.lastIndexOf('/');
|
||||||
|
const prefix = e.url.substr(0, indexOf === 0 ? e.url.length : indexOf);
|
||||||
|
if (prefix === '/user' || prefix === '/write') {
|
||||||
|
this.show = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,136 +0,0 @@
|
|||||||
header {
|
|
||||||
height: 50px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
opacity: 0.8;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
header img {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
margin: 5px 5px 5px 30px;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerButton {
|
|
||||||
border: none;
|
|
||||||
background: #3F66FF;
|
|
||||||
color: #ffffff !important;
|
|
||||||
margin-right: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 8px 13px;
|
|
||||||
line-height: 50px
|
|
||||||
}
|
|
||||||
|
|
||||||
#landr {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loged {
|
|
||||||
float: right;
|
|
||||||
margin-right: 20px;
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blogTitle,
|
|
||||||
#desc {
|
|
||||||
display: block;
|
|
||||||
margin-left: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blogTitle :hover {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #797979;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blogTitle {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blogTitle :hover {
|
|
||||||
font-size: 23px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#desc {
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[nz-button] {
|
|
||||||
margin-right: 8px;
|
|
||||||
margin-top: 9px;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 768px) {
|
|
||||||
/**导航栏*/
|
|
||||||
.nav-desktop {
|
|
||||||
position: absolute;
|
|
||||||
width: auto;
|
|
||||||
left: 50%;
|
|
||||||
top: 0;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-phone {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-desktop li {
|
|
||||||
float: left;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-desktop li:hover {
|
|
||||||
background: #ececec;
|
|
||||||
color: #797979;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-desktop li a {
|
|
||||||
height: 100%;
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and ( max-width: 768px) {
|
|
||||||
.nav-desktop {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-phone {
|
|
||||||
display: block;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ul {
|
|
||||||
width: 300px;
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.ul li {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: 1px solid #ececec
|
|
||||||
}
|
|
||||||
|
|
||||||
#click-main {
|
|
||||||
line-height: 50px;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +1,36 @@
|
|||||||
<header>
|
<div id="header" nz-row [class.containBg]="size =='large'">
|
||||||
<a href="/">
|
<div id="header-logo-title" nz-col nzSpan="6">
|
||||||
<div>
|
<img src="https://56462271.oss-cn-beijing.aliyuncs.com/web/logo.jpg"
|
||||||
<img src="https://56462271.oss-cn-beijing.aliyuncs.com/web/logo.png"/>
|
alt="logo" id="logo">
|
||||||
|
<span id="header-title"><a routerLink="/">小海博客</a></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
<ul id="nav" nz-col nzSpan="12" [ngStyle]="{'display':showList?'block':'none'}">
|
||||||
<div>
|
<ng-template *ngFor="let item of pageList" [ngIf]="item.show">
|
||||||
<a href="/" id="blogTitle"><span>小海博客</span></a>
|
<li (click)="dealLink(item.path)" style="user-select: none;cursor: pointer">
|
||||||
<span id="desc">记录学习成长历程</span>
|
<i nz-icon [nzType]="item.icon" [nzTheme]="item.iconType"></i>
|
||||||
</div>
|
{{item.name}}
|
||||||
|
</li>
|
||||||
|
</ng-template>
|
||||||
<ul class="nav-desktop">
|
</ul>
|
||||||
<li><a class="top_bar" routerLink="/" style="cursor: pointer;"><i nz-icon nzType="home" nzTheme="fill"></i> 首页</a></li>
|
<div id="header-user-login" *ngIf="!userInfo">
|
||||||
<li><a class="top_bar" routerLink="/category" style="cursor: pointer;"><i nz-icon nzType="project" nzTheme="fill"></i> 分类</a>
|
<button nz-button nzType="primary" (click)="login()">登录</button>
|
||||||
</li>
|
<button nz-button nzType="primary" (click)="registration()">注册</button>
|
||||||
<li><a class="top_bar" routerLink="/tag" style="cursor: pointer;"><i nz-icon nzType="tags" nzTheme="fill"></i> 标签</a>
|
</div>
|
||||||
</li>
|
<div *ngIf="userInfo" id="info">
|
||||||
<li><a class="top_bar" routerLink="/leaveMsg" style="cursor: pointer;"><i nz-icon nzType="profile" nzTheme="fill"></i> 留言</a>
|
<img [src]="userInfo.avatarImgUrl" alt="avatar" id="avatar">
|
||||||
</li>
|
<button nz-button nzType="link" class="info-name"
|
||||||
<li><a class="top_bar" routerLink="/update" style="cursor: pointer;"><i nz-icon nzType="up-square" nzTheme="fill"></i> 更新</a>
|
nz-dropdown [nzDropdownMenu]="menu" nzPlacement="bottomRight" nzTrigger="click">
|
||||||
</li>
|
{{userInfo.displayName}}<i nz-icon nzType="caret-down" nzTheme="outline"></i>
|
||||||
<li><a class="top_bar" routerLink="/links" style="cursor: pointer;"><i nz-icon nzType="link" nzTheme="outline"></i> 友链</a></li>
|
</button>
|
||||||
</ul>
|
<nz-dropdown-menu #menu="nzDropdownMenu">
|
||||||
|
<ul nz-menu nzSelectable>
|
||||||
|
<li nz-menu-item (click)="toAdminPage()"><i nz-icon nzType="info-circle" nzTheme="outline"></i>管理后台</li>
|
||||||
<div class="nav-phone">
|
<hr style="opacity: 0.5">
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzTrigger="click" [nzClickHide]="false" [(nzVisible)]="visibleOfMenu"
|
<li nz-menu-item (click)="logout()"><i nz-icon nzType="logout" nzTheme="outline"></i>注销登录</li>
|
||||||
id="click-main">
|
</ul>
|
||||||
<i nz-icon nzType="menu" nzTheme="outline"></i>
|
</nz-dropdown-menu>
|
||||||
</a>
|
</div>
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
<button id="header-menu" nz-button [style.top.px]="size=='large'?25:10" (click)="changeMenuStatus()">
|
||||||
<ul nz-menu class="ul">
|
<i nz-icon [nzType]="showList?'arrow-left':'menu'" nzTheme="outline"></i>
|
||||||
<li nz-menu-item><a class="top_bar" routerLink="/" style="cursor: pointer;"><i nz-icon nzType="home" nzTheme="fill"></i> 首页</a></li>
|
</button>
|
||||||
<li nz-menu-item><a class="top_bar" routerLink="/category" style="cursor: pointer;"><i nz-icon nzType="project" nzTheme="fill"></i> 分类</a></li>
|
</div>
|
||||||
<li nz-menu-item><a class="top_bar" routerLink="/tag" style="cursor: pointer;"><i nz-icon nzType="tags" nzTheme="fill"></i> 标签</a></li>
|
|
||||||
<li nz-menu-item><a class="top_bar" routerLink="/leaveMsg" style="cursor: pointer;"><i nz-icon nzType="profile" nzTheme="fill"></i> 留言</a></li>
|
|
||||||
<li nz-menu-item><a class="top_bar" routerLink="/update" style="cursor: pointer;"><i nz-icon nzType="up-square" nzTheme="fill"></i> 更新</a></li>
|
|
||||||
<li nz-menu-item><a class="top_bar" routerLink="/links" style="cursor: pointer;"><i nz-icon nzType="link" nzTheme="outline"></i> 友链</a></li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="loged" *ngIf="userService.userInfo">
|
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzTrigger="click" [nzClickHide]="false" [(nzVisible)]="visible">
|
|
||||||
{{userService.userInfo.displayName ? userService.userInfo.displayName : userService.userInfo.email}}
|
|
||||||
<i nz-icon nzType="down"></i>
|
|
||||||
</a>
|
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
|
||||||
<ul nz-menu>
|
|
||||||
<li nz-menu-item><a href="/admin/">{{userService.userInfo.role == 'admin' ? '网站后台管理' : '个人中心'}}</a></li>
|
|
||||||
<hr style="margin: 10px 0 5px 0;">
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a (click)="logout()">退出登录</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="landr" *ngIf="!userService.userInfo">
|
|
||||||
<button nz-button nzType="primary" (click)="userService.showModal('login')">登录</button>
|
|
||||||
<button nz-button nzType="primary" (click)="userService.showModal('registration')">注册</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|||||||
160
index/src/app/components/header/header.component.less
Normal file
160
index/src/app/components/header/header.component.less
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
@import "../../global-variables";
|
||||||
|
|
||||||
|
.containBg {
|
||||||
|
background-image: url("src/assets/img/bg_header.jpg") !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
min-height: @header-min-height;
|
||||||
|
background-position: center center !important;
|
||||||
|
background-size: cover !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
padding-top: 15px !important;
|
||||||
|
|
||||||
|
.info-name {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
// 设置header背景
|
||||||
|
background: rgba(255, 255, 255, 0.55);
|
||||||
|
color: black;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, opensans, Optima, "Microsoft Yahei", sans-serif;
|
||||||
|
padding-top: 0px;
|
||||||
|
position: relative;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
div {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#avatar {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
// 设置logo的宽高
|
||||||
|
width: @header-logo-width;
|
||||||
|
height: @header-logo-height;
|
||||||
|
border-radius: 50%;
|
||||||
|
//position: relative;
|
||||||
|
//top: 0;
|
||||||
|
//left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-title {
|
||||||
|
//position: relative;
|
||||||
|
//top: 0;
|
||||||
|
//left: @logo_wh;
|
||||||
|
font-size: xx-large;
|
||||||
|
font-weight: lighter;
|
||||||
|
min-width: 130px;
|
||||||
|
max-width: 50%;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-user-login, #info {
|
||||||
|
float: right;
|
||||||
|
margin-right: 15px;
|
||||||
|
line-height: 50px;
|
||||||
|
|
||||||
|
|
||||||
|
[nz-button] {
|
||||||
|
margin-right: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-name {
|
||||||
|
color: black;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav {
|
||||||
|
@item-width: 80px;
|
||||||
|
width: auto;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
li:hover {
|
||||||
|
background: #ececec;
|
||||||
|
//color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
float: left;
|
||||||
|
height: 50px;
|
||||||
|
width: @item-width;
|
||||||
|
line-height: 50px;
|
||||||
|
//color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* max-width:910px */
|
||||||
|
@media screen and (max-width: @max-width) {
|
||||||
|
#header {
|
||||||
|
#header-logo-title {
|
||||||
|
position: static;
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav {
|
||||||
|
display: none;
|
||||||
|
background: white;
|
||||||
|
opacity: 0.5;
|
||||||
|
position: relative;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
li {
|
||||||
|
clear: both;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 40px;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:hover {
|
||||||
|
background: #bce672;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-user-login {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-menu {
|
||||||
|
display: block !important;
|
||||||
|
position: absolute;
|
||||||
|
right: 30px;
|
||||||
|
top: 25px
|
||||||
|
}
|
||||||
|
|
||||||
|
#info {
|
||||||
|
display: block !important;
|
||||||
|
position: absolute;
|
||||||
|
right: 40px;
|
||||||
|
top: 15px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,149 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
import {UserService} from '../../services/user/user.service';
|
import {windowWidthChange} from '../../utils/util';
|
||||||
|
import {NavigationEnd, Router, RouterEvent} from '@angular/router';
|
||||||
|
import {filter} from 'rxjs/operators';
|
||||||
|
import {ApiService} from '../../api/api.service';
|
||||||
|
import {User} from '../../class/User';
|
||||||
|
import {LocalStorageService} from '../../utils/local-storage.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
templateUrl: './header.component.html',
|
templateUrl: './header.component.html',
|
||||||
styleUrls: ['./header.component.css']
|
styleUrls: ['./header.component.less']
|
||||||
})
|
})
|
||||||
export class HeaderComponent implements OnInit {
|
export class HeaderComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor(private router: Router,
|
||||||
|
private apiService: ApiService) {
|
||||||
|
this.pageList = [
|
||||||
|
{name: '首页', path: '/', icon: 'home', iconType: 'fill', show: true},
|
||||||
|
{name: '分类', path: '/categories', icon: 'project', iconType: 'fill', show: true},
|
||||||
|
{name: '标签', path: '/tags', icon: 'tags', iconType: 'fill', show: true},
|
||||||
|
// {name: '留言', path: '/leaveMsg', icon: 'carry-out', iconType: 'fill', show: true},
|
||||||
|
{name: '更新', path: '/update', icon: 'up-square', iconType: 'fill', show: true},
|
||||||
|
{name: '友链', path: '/links', icon: 'link', iconType: 'outline', show: true},
|
||||||
|
{name: '登录', path: '/login', icon: 'login', iconType: 'outline', show: false},
|
||||||
|
{name: '注册', path: '/registration', icon: 'user', iconType: 'outline', show: false}
|
||||||
|
];
|
||||||
|
|
||||||
constructor(public userService: UserService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 菜单是否可见
|
this.showList = window.innerWidth > this.mobileMaxWidth;
|
||||||
public visible: boolean = false;
|
this.changeLoginButtonV();
|
||||||
// 导航是否可见(手机显示时)
|
// 监听宽度变化
|
||||||
public visibleOfMenu: boolean = false;
|
windowWidthChange(() => {
|
||||||
|
this.showList = window.innerWidth > this.mobileMaxWidth;
|
||||||
|
this.changeLoginButtonV();
|
||||||
|
});
|
||||||
|
|
||||||
ngOnInit() {
|
this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe((e: RouterEvent) => {
|
||||||
this.userService.getUserInfo();
|
// indexOf ==> -1/index
|
||||||
this.userService.http.visit();
|
const indexOfParam = e.url.indexOf('?');
|
||||||
}
|
const path = e.url.substr(0, indexOfParam === -1 ? e.url.length : indexOfParam);
|
||||||
|
// lastIndexOf ==> 0/index
|
||||||
|
const indexOf = path.lastIndexOf('/');
|
||||||
|
const prefix = path.substr(0, indexOf === 0 ? path.length : indexOf);
|
||||||
|
this.currentPath = prefix;
|
||||||
|
if (prefix === '/user' || prefix === '/write' || prefix === '/update') {
|
||||||
|
this.size = 'default';
|
||||||
|
} else {
|
||||||
|
this.size = 'large';
|
||||||
|
}
|
||||||
|
this.getInfo();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
logout() {
|
@Output() loginEvent = new EventEmitter();
|
||||||
this.userService.logout();
|
@Output() registrationEvent = new EventEmitter();
|
||||||
}
|
size: 'large' | 'default';
|
||||||
|
currentPath: string;
|
||||||
|
|
||||||
|
|
||||||
|
public pageList: {
|
||||||
|
path: string;
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
iconType: 'outline' | 'fill' | 'twotone';
|
||||||
|
show: boolean;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
|
||||||
|
public showList = true;
|
||||||
|
// css 样式中设置移动端最大宽度为910px 见src/app/global-variables.less
|
||||||
|
private readonly mobileMaxWidth = 940;
|
||||||
|
|
||||||
|
@Input() userInfo: User;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
changeMenuStatus() {
|
||||||
|
this.showList = !this.showList;
|
||||||
|
this.changeLoginButtonV();
|
||||||
|
}
|
||||||
|
|
||||||
|
private changeLoginButtonV() {
|
||||||
|
this.pageList.forEach(e => {
|
||||||
|
if (e.name === '登录' || e.name === '注册') {
|
||||||
|
if (this.userInfo) {
|
||||||
|
e.show = false;
|
||||||
|
} else {
|
||||||
|
e.show = (this.showList && window.innerWidth < this.mobileMaxWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dealLink(path: string) {
|
||||||
|
this.showList = window.innerWidth > this.mobileMaxWidth;
|
||||||
|
if (path === '/login') {
|
||||||
|
this.login();
|
||||||
|
} else if (path === '/registration') {
|
||||||
|
this.registration();
|
||||||
|
} else {
|
||||||
|
this.router.navigateByUrl(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
this.showList = window.innerWidth > this.mobileMaxWidth;
|
||||||
|
if (this.currentPath === '/article' || this.currentPath === '/write') {
|
||||||
|
this.loginEvent.emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.router.navigateByUrl('/user/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
registration() {
|
||||||
|
this.showList = window.innerWidth > this.mobileMaxWidth;
|
||||||
|
if (this.currentPath === '/article' || this.currentPath === '/write') {
|
||||||
|
this.registrationEvent.emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.router.navigateByUrl('/user/registration');
|
||||||
|
}
|
||||||
|
|
||||||
|
getInfo() {
|
||||||
|
this.apiService.userInfo().subscribe(data => {
|
||||||
|
this.userInfo = data.result;
|
||||||
|
this.changeLoginButtonV();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.apiService.logout().subscribe(data => {
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.userInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
toAdminPage() {
|
||||||
|
window.location.href = '/admin';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
index/src/app/global-variables.less
Normal file
13
index/src/app/global-variables.less
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// 定义less 中的全局变量
|
||||||
|
// 使用的时候导入本文件
|
||||||
|
|
||||||
|
/** 移动端适配时的分割宽度 */
|
||||||
|
@max-width: 940px;
|
||||||
|
|
||||||
|
|
||||||
|
/**** header ****/
|
||||||
|
// header的最小高度
|
||||||
|
@header-min-height: 300px;
|
||||||
|
@header-logo-width: 50px;
|
||||||
|
@header-logo-height: 50px;
|
||||||
|
/**** header ****/
|
||||||
@@ -1,330 +0,0 @@
|
|||||||
/* markdown Css style */
|
|
||||||
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group li {
|
|
||||||
/* margin-top: 10px;*/
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arUl {
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arUl li {
|
|
||||||
margin-right: 12px;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arUl li i {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arTypeOriginal {
|
|
||||||
background: #5eb95e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arTypeReprint {
|
|
||||||
background: #F37B1D;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arType {
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 0.8em;
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-titlea {
|
|
||||||
font-size: 150%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-meta {
|
|
||||||
width: 100%;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-meta a {
|
|
||||||
color: #666666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-road {
|
|
||||||
margin-left: 2%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secd {
|
|
||||||
margin-left: 30%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#title {
|
|
||||||
word-break: break-all;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 2em;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-text {
|
|
||||||
word-break: break-all
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-tag {
|
|
||||||
margin-left: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*文章底部的tag标签*/
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
color: #666666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-bAnda {
|
|
||||||
width: 90%;
|
|
||||||
margin-top: 2%;
|
|
||||||
margin-left: 5%;
|
|
||||||
margin-right: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.articlePublishDate,
|
|
||||||
.originalAuthor,
|
|
||||||
.categories {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-input-textarea {
|
|
||||||
border-color: #aaaaaa;
|
|
||||||
border-width: 2px;
|
|
||||||
border-radius: 10px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100px;
|
|
||||||
max-height: 700px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-submit {
|
|
||||||
float: right;
|
|
||||||
color: white;
|
|
||||||
background: #3bb4f2;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 3px 8px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-list {
|
|
||||||
margin: 50px 10% 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-input {
|
|
||||||
border-color: #ececec;
|
|
||||||
border-width: 1px;
|
|
||||||
outline: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-top: 21px;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-comment {
|
|
||||||
margin: 0 10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-input-coverText {
|
|
||||||
text-align: center;
|
|
||||||
background-color: white;
|
|
||||||
margin: 5px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-area {
|
|
||||||
padding-top: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonDisable {
|
|
||||||
pointer-events: none
|
|
||||||
}
|
|
||||||
|
|
||||||
.articleButton {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.articleButton:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentUser {
|
|
||||||
background: #5eb95e;
|
|
||||||
padding: 3px 8px;
|
|
||||||
border-radius: 3px;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
|
|
||||||
.commentItem {
|
|
||||||
margin-top: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
position: fixed;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading img {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%)
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagination {
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag i {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-last,
|
|
||||||
.article-next {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#over {
|
|
||||||
display: block;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
border-radius: 50%;
|
|
||||||
line-height: 80px;
|
|
||||||
margin: 15px auto;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 2em;
|
|
||||||
background: #3bb4f2;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
|
|
||||||
#copyright {
|
|
||||||
width: 90%;
|
|
||||||
margin: 15px 5%;
|
|
||||||
border-left: 5px solid #FF1700;
|
|
||||||
padding: 10px;
|
|
||||||
background: #ececec
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-bottom: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment {
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content p {
|
|
||||||
word-break: break-all
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding-left: 8px;
|
|
||||||
padding-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
padding: 0 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.noToc{
|
|
||||||
width: 65% !important;
|
|
||||||
margin: 0 auto !important;
|
|
||||||
height: auto;
|
|
||||||
position: static !important;
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 768px) {
|
|
||||||
|
|
||||||
.article-content {
|
|
||||||
left: 400px;
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
margin-right: 500px;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 10px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-toc-main{
|
|
||||||
border-radius: 10px;
|
|
||||||
background: #fff;
|
|
||||||
position: fixed;
|
|
||||||
left: 40px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 320px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#article-toc{
|
|
||||||
max-height: 700px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
|
||||||
.article-content {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: -80px;
|
|
||||||
padding-top: 60px;
|
|
||||||
margin-right:0;
|
|
||||||
border-radius: 0;
|
|
||||||
margin-left: 0!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-toc-main{
|
|
||||||
position:relative;
|
|
||||||
padding: 10px;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.noToc{
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
<ng-template [ngIf]="article">
|
|
||||||
<nz-spin [nzSpinning]="!loadOk">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="article-content am-article" [ngClass]="{'noToc':!showToc}">
|
|
||||||
<div style="text-align: center;word-break: break-all">
|
|
||||||
<h1 class="article-title" id="title">{{article.title}}</h1>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<ul class="arUl">
|
|
||||||
<li>
|
|
||||||
<span class="arType"
|
|
||||||
[ngClass]="{'arTypeOriginal': article.original,'arTypeReprint':!article.original}">{{article.original ? "原创" : "转载"}}</span>
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="calendar" nzTheme="outline"></i>{{article.publishDateFormat}}</li>
|
|
||||||
<li><i nz-icon nzType="user" nzTheme="outline"></i>{{article.authorName}}</li>
|
|
||||||
<li><i nz-icon nzType="folder" nzTheme="outline"></i>
|
|
||||||
<a [routerLink]="['/category']" [queryParams]="{'name':article.category}">
|
|
||||||
<span>{{article.category}}</span></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<hr/>
|
|
||||||
<div class="article-text am-text-break am-article-bd">
|
|
||||||
<!-- <div id="content" [innerHTML]="article.htmlContent">
|
|
||||||
</div> -->
|
|
||||||
<div class="article-toc-main" *ngIf="showToc">
|
|
||||||
<!-- fixme: 不同文章切换时 无法生效 -->
|
|
||||||
<span><strong>目录:</strong></span><br>
|
|
||||||
<div id="article-toc" class="markdown-body editormd-preview-container">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="content">
|
|
||||||
<textarea></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<span id="over">over</span>
|
|
||||||
</div>
|
|
||||||
<!-- 文章版权 -->
|
|
||||||
<div id="copyright">
|
|
||||||
<p>本文作者:{{article.authorName}} </p>
|
|
||||||
<p>{{article.original ? "本文" : "原文"}}链接:{{article.original ? copyRightUrl : article.url}}</p>
|
|
||||||
<p>版权声明:转载请注明出处</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="article-tag" id="tag">
|
|
||||||
<!-- TODO -->
|
|
||||||
<span *ngFor="let item of (article.tags||'')" class="tag">
|
|
||||||
<i nz-icon nzType="tag" nzTheme="fill"></i>
|
|
||||||
<a class="tag" [routerLink]="['/tag']" [queryParams]="{name:item}">{{item}}</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
<div class="article-bAnda">
|
|
||||||
<span class="article-last">
|
|
||||||
<button (click)="toArticle(article.nextArticleId)" class="articleButton"
|
|
||||||
[ngClass]="{'buttonDisable': article.nextArticleId==-1}">
|
|
||||||
<i nz-icon nzType="caret-up"
|
|
||||||
nzTheme="outline"></i> 上一篇文章:{{article.nextArticleTitle}}</button>
|
|
||||||
</span>
|
|
||||||
<span class="article-next">
|
|
||||||
<button (click)="toArticle(article.preArticleId)" class="articleButton"
|
|
||||||
[ngClass]="{'buttonDisable': article.preArticleId==-1}">
|
|
||||||
<i nz-icon nzType="caret-down"
|
|
||||||
nzTheme="outline"></i> 下一篇文章篇文章:{{article.preArticleTitle}}</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<span *ngIf="!userService.userInfo" style="display: block;text-align: center">若要评论,请先
|
|
||||||
<a style="color: blue !important;text-decoration: underline"
|
|
||||||
(click)="userService.showModal('login')">登录</a>哟~~~~</span>
|
|
||||||
<nz-comment *ngIf="userService.userInfo" style="width: 60%;margin:15px auto">
|
|
||||||
<nz-comment-content>
|
|
||||||
<nz-form-item>
|
|
||||||
<textarea [(ngModel)]="comment4submit" nz-input style="height: 130px;width: 100%;"></textarea>
|
|
||||||
</nz-form-item>
|
|
||||||
<nz-form-item>
|
|
||||||
<button nz-button nzType="primary" [disabled]="!comment4submit" (click)="submitComment()">评论</button>
|
|
||||||
</nz-form-item>
|
|
||||||
</nz-comment-content>
|
|
||||||
</nz-comment>
|
|
||||||
|
|
||||||
<!-- 展示 -->
|
|
||||||
<nz-card id="leaveMsgs" [nzLoading]="!commentService.commentPage.pageSize">
|
|
||||||
<ng-template [ngIf]="commentService.commentPage.pageSize">
|
|
||||||
<nz-comment *ngFor="let comment of commentService.commentPage.list; let i = index"
|
|
||||||
[nzAuthor]="comment.authorName"
|
|
||||||
[nzDatetime]="comment.date">
|
|
||||||
<nz-avatar nz-comment-avatar nzIcon="user" [nzSrc]="comment.authorAvatarImgUrl"></nz-avatar>
|
|
||||||
<nz-comment-content class="comment">
|
|
||||||
<p>
|
|
||||||
{{comment.content}}
|
|
||||||
</p>
|
|
||||||
</nz-comment-content>
|
|
||||||
<nz-comment-action><span (click)="replyTo(comment.id,comment.authorName,i)">
|
|
||||||
<i nz-icon nzType="message" nzTheme="fill"></i> 回复</span>
|
|
||||||
</nz-comment-action>
|
|
||||||
|
|
||||||
<!-- 二级评论 -->
|
|
||||||
<ng-container *ngIf="comment.child && comment.child.length">
|
|
||||||
|
|
||||||
<nz-comment *ngFor="let secComment of comment.child" [nzAuthor]="secComment.authorName"
|
|
||||||
[nzDatetime]="secComment.date">
|
|
||||||
<nz-avatar nz-comment-avatar nzIcon="user" [nzSrc]="secComment.authorAvatarImgUrl"></nz-avatar>
|
|
||||||
<nz-comment-content class="comment">
|
|
||||||
<p>
|
|
||||||
{{secComment.content}}
|
|
||||||
</p>
|
|
||||||
</nz-comment-content>
|
|
||||||
<!-- <nz-comment-action><span (click)="replyTo(secComment.id,secComment.authorName,i)">
|
|
||||||
<i nz-icon nzType="message" nzTheme="fill"></i> 回复</span>
|
|
||||||
</nz-comment-action> -->
|
|
||||||
|
|
||||||
</nz-comment>
|
|
||||||
|
|
||||||
</ng-container>
|
|
||||||
<!-- 二级评论的回复框 -->
|
|
||||||
<nz-comment *ngIf="responseComment.pid!=null&&relyIndex==i">
|
|
||||||
<nz-comment>
|
|
||||||
<nz-comment-content>
|
|
||||||
<nz-form-item>
|
|
||||||
<textarea nz-input [(ngModel)]="responseComment.content"
|
|
||||||
style="height: 130px;width: 80%;padding: 10px;border-radius: 5px;"></textarea>
|
|
||||||
</nz-form-item>
|
|
||||||
<nz-form-item>
|
|
||||||
<button nz-button nzType="primary" [disabled]="!responseComment.content" (click)="reply()"> 回复
|
|
||||||
</button>
|
|
||||||
<button nz-button nzType="default" style="margin-left: 15px;" (click)="responseComment.pid=null"> 取消
|
|
||||||
</button>
|
|
||||||
</nz-form-item>
|
|
||||||
</nz-comment-content>
|
|
||||||
</nz-comment>
|
|
||||||
</nz-comment>
|
|
||||||
</nz-comment>
|
|
||||||
|
|
||||||
<nz-pagination style="text-align: center" [nzPageIndex]="pageNum"
|
|
||||||
[nzTotal]="commentService.commentPage.total"
|
|
||||||
[nzPageSize]="pageSize" [nzHideOnSinglePage]="true"
|
|
||||||
(nzPageIndexChange)="toPage($event)"></nz-pagination>
|
|
||||||
|
|
||||||
</ng-template>
|
|
||||||
</nz-card>
|
|
||||||
|
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
|
||||||
</nz-spin>
|
|
||||||
</ng-template>
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
import {Component, OnInit, ViewEncapsulation} from '@angular/core';
|
|
||||||
import {ActivatedRoute} from '@angular/router';
|
|
||||||
import {Router} from '@angular/router';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {Location} from '@angular/common';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {ArticleService} from '../../services/article/article.service';
|
|
||||||
import {CommentService} from '../../services/comment/comment.service';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {CommentReq} from '../../class/commentReq';
|
|
||||||
import {Article} from '../../class/article';
|
|
||||||
|
|
||||||
declare var editormd;
|
|
||||||
declare var $;
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-article',
|
|
||||||
templateUrl: './article.component.html',
|
|
||||||
styleUrls: ['./article.component.css']
|
|
||||||
})
|
|
||||||
export class ArticleComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private articleService: ArticleService,
|
|
||||||
private routerinfo: ActivatedRoute,
|
|
||||||
private router: Router,
|
|
||||||
private message: NzMessageService,
|
|
||||||
private titleService: Title,
|
|
||||||
private location: Location,
|
|
||||||
public commentService: CommentService,
|
|
||||||
public userService: UserService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
copyRightUrl: string;
|
|
||||||
|
|
||||||
public pageNum: number = 1;
|
|
||||||
public pageSize: number = 10;
|
|
||||||
|
|
||||||
public articleId: number;
|
|
||||||
|
|
||||||
public article: Article = new Article();
|
|
||||||
|
|
||||||
public comment4submit: string = '';
|
|
||||||
|
|
||||||
loadOk: boolean = false; // 文章的加载
|
|
||||||
|
|
||||||
loading: boolean = true; // 评论的加载
|
|
||||||
|
|
||||||
relyIndex: number;
|
|
||||||
|
|
||||||
public responseComment: CommentReq;
|
|
||||||
|
|
||||||
public showToc: boolean = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* editor.md preview
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public preview(markdownContent) {
|
|
||||||
editormd.markdownToHTML('content', {
|
|
||||||
markdown: markdownContent,
|
|
||||||
// htmlDecode : true, // 开启 HTML 标签解析,为了安全性,默认不开启
|
|
||||||
htmlDecode: 'style,script,iframe', // you can filter tags decode
|
|
||||||
toc : true,
|
|
||||||
tocm : true, // Using [TOCM]
|
|
||||||
tocContainer : '#article-toc', // 自定义 ToC 容器层
|
|
||||||
// gfm : false,
|
|
||||||
tocDropdown: false,
|
|
||||||
// markdownSourceCode : true, // 是否保留 Markdown 源码,即是否删除保存源码的 Textarea 标签
|
|
||||||
emoji: true,
|
|
||||||
taskList: true,
|
|
||||||
// tex : true, //科学公式 默认不解析
|
|
||||||
flowChart: true, // 默认不解析
|
|
||||||
sequenceDiagram: true, // 默认不解析
|
|
||||||
});
|
|
||||||
this.checkALink();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.articleId = +this.routerinfo.snapshot.paramMap.get('id');
|
|
||||||
this.responseComment = new CommentReq(true);
|
|
||||||
this.getArticle();
|
|
||||||
this.getPageComment();
|
|
||||||
this.responseComment.articleID = this.articleId;
|
|
||||||
this.copyRightUrl = location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取并处理文章
|
|
||||||
*/
|
|
||||||
getArticle() {
|
|
||||||
this.articleService.getArticleById(this.articleId).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
// 清空远先的markdown 内容
|
|
||||||
document.getElementById('content').innerHTML = '';
|
|
||||||
this.article = data.result;
|
|
||||||
this.preview(data.result.mdContent);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
this.titleService.setTitle(data.result.title);
|
|
||||||
// 修改url栏的地址
|
|
||||||
this.location.replaceState('article/' + data.result.id);
|
|
||||||
this.copyRightUrl = location.href;
|
|
||||||
this.loadOk = true;
|
|
||||||
} else if (data.code === 201) {
|
|
||||||
// 文章不存在
|
|
||||||
this.router.navigateByUrl('404');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 跳转id文章
|
|
||||||
* @param id 文章id
|
|
||||||
*/
|
|
||||||
toArticle(id: number) {
|
|
||||||
if (id == null || id <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.articleId = id;
|
|
||||||
this.loadOk = false;
|
|
||||||
this.getArticle();
|
|
||||||
this.getPageComment();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评论调到某一页
|
|
||||||
* @param a 页码数
|
|
||||||
*/
|
|
||||||
toPage(a: number) {
|
|
||||||
if (a === this.pageNum) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.pageNum = a;
|
|
||||||
this.getPageComment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 评论
|
|
||||||
getPageComment() {
|
|
||||||
this.commentService.getPageComment(this.articleId, this.pageNum, this.pageSize).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.loading = false;
|
|
||||||
this.commentService.getResponseComment();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一级评论的创建
|
|
||||||
*/
|
|
||||||
submitComment() {
|
|
||||||
if (this.comment4submit == null || this.comment4submit === '') {
|
|
||||||
this.message.info('内容不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const submitBody: CommentReq = new CommentReq(true);
|
|
||||||
submitBody.content = this.comment4submit;
|
|
||||||
submitBody.articleID = this.articleId;
|
|
||||||
submitBody.pid = -1;
|
|
||||||
|
|
||||||
this.commentService.submitComment(submitBody);
|
|
||||||
this.comment4submit = null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建文本输入框的过程
|
|
||||||
* @param id 父评论的id
|
|
||||||
* @param name 富评论的作者名
|
|
||||||
* @param index 索引 便于显示输入框
|
|
||||||
*/
|
|
||||||
replyTo(id, name, index) {
|
|
||||||
if (!this.userService.userInfo) {
|
|
||||||
this.message.info('请先登录哟~~~');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.responseComment.pid = id;
|
|
||||||
this.responseComment.content = ' @' + name + ' ';
|
|
||||||
this.relyIndex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回复的数据提交
|
|
||||||
*/
|
|
||||||
reply() {
|
|
||||||
if (this.responseComment.content == null || this.responseComment.content === '') {
|
|
||||||
this.message.info('内容不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.responseComment.pid == null) {
|
|
||||||
this.message.error('非法操作');
|
|
||||||
}
|
|
||||||
this.commentService.rely(this.responseComment).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
if (this.commentService.commentPage.list[this.relyIndex].child == null) {
|
|
||||||
this.commentService.commentPage.list[this.relyIndex].child = [];
|
|
||||||
}
|
|
||||||
this.commentService.commentPage.list[this.relyIndex].child.unshift(data.result);
|
|
||||||
this.responseComment.content = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 曲线救国 重新设置a的href值
|
|
||||||
checkALink() {
|
|
||||||
const as = document.getElementsByTagName('a');
|
|
||||||
let hrefStr: string = null ;
|
|
||||||
let count: number = 0;
|
|
||||||
// tslint:disable-next-line:prefer-for-of
|
|
||||||
for (let i = 0; i < as.length; i++) {
|
|
||||||
hrefStr = decodeURI(as[i].href);
|
|
||||||
// console.log(as[i].getAttribute('level'));
|
|
||||||
if (as[i].getAttribute('level') != null) {
|
|
||||||
// 截取锚点名称
|
|
||||||
const anchorName: string = hrefStr.substr(hrefStr.indexOf('#'), hrefStr.length);
|
|
||||||
// 重新获取url 并拼接锚点名称
|
|
||||||
as[i].href = location.origin + location.pathname + anchorName;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count === 0) {
|
|
||||||
this.showToc = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#main{
|
|
||||||
width:60%;
|
|
||||||
margin:0 auto;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
#category{
|
|
||||||
float: left;
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #ececec;
|
|
||||||
box-shadow: 5px 5px 5px #888888;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
#detail{
|
|
||||||
clear: both;
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.singleTag{
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 5px;
|
|
||||||
line-height: 15px;
|
|
||||||
margin: 5px 10px;
|
|
||||||
float: left;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
padding: 5px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul{
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.art{
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ececec;
|
|
||||||
box-shadow: 5px 5px 5px #aaaaaa;
|
|
||||||
margin: 20px 0 ;
|
|
||||||
}
|
|
||||||
.title:hover{
|
|
||||||
animation: 1s move ;
|
|
||||||
}
|
|
||||||
@keyframes move{
|
|
||||||
from{
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
to{
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.active{
|
|
||||||
background: #6DAB90;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (max-width:768px){
|
|
||||||
|
|
||||||
#main{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<div id="main">
|
|
||||||
|
|
||||||
<div id="category">
|
|
||||||
<ul *ngIf="categoryService.categories">
|
|
||||||
<li *ngFor="let category of categoryService.categories" (click)="changeCategory(category.name)">
|
|
||||||
<span class="singleTag" [ngClass]="{active:currentCategoryName==category.name}"
|
|
||||||
[nzTitle]="'此分类有'+(category.articles.split(',').length-1)+'篇文章'" nzPlacement="topCenter" nz-tooltip>
|
|
||||||
<i nz-icon nzType="folder" nzTheme="fill"></i> {{category.name}}</span></li>
|
|
||||||
</ul>
|
|
||||||
<h2 *ngIf="!categoryService.categories">暂时没有分类</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul id="detail" *ngIf="currentArticleList">
|
|
||||||
<li *ngFor="let article of currentArticleList.list">
|
|
||||||
<div class="art">
|
|
||||||
<h2><a [routerLink]="'/article/'+article.id" class="title">{{article.title}}</a></h2>
|
|
||||||
<hr>
|
|
||||||
<div> {{article.summary}}</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div *ngIf="!currentArticleList">
|
|
||||||
<h2 style="text-align: center">该分类暂无文章</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {ActivatedRoute} from '@angular/router';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {Location} from '@angular/common';
|
|
||||||
import {CategoryService} from '../../services/category/category.service';
|
|
||||||
import {ArticleService} from '../../services/article/article.service';
|
|
||||||
import {Page} from '../../class/page';
|
|
||||||
import {Article} from '../../class/article';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-categories',
|
|
||||||
templateUrl: './category.component.html',
|
|
||||||
styleUrls: ['./category.component.css']
|
|
||||||
})
|
|
||||||
export class CategoryComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private routerinfo: ActivatedRoute,
|
|
||||||
private titleService: Title,
|
|
||||||
private location: Location,
|
|
||||||
public categoryService: CategoryService,
|
|
||||||
public articleService: ArticleService) {
|
|
||||||
titleService.setTitle('小海博客|分类');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前timeliness展示的分类
|
|
||||||
public currentCategoryName: string;
|
|
||||||
public currentArticleList: Page<Article>;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.currentCategoryName = this.routerinfo.snapshot.queryParams.name;
|
|
||||||
if (this.categoryService.categories == null) {
|
|
||||||
this.categoryService.getAllCategory().subscribe((data) => {
|
|
||||||
// 有分类数据
|
|
||||||
if (data.code === 0 && data.result.length > 0) {
|
|
||||||
// 是否更具url的参数获取数据
|
|
||||||
if (this.currentCategoryName == null) {
|
|
||||||
this.currentCategoryName = data.result[0].name;
|
|
||||||
}
|
|
||||||
this.getArticle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (this.currentCategoryName == null) {
|
|
||||||
this.currentCategoryName = this.categoryService.categories[0].name;
|
|
||||||
}
|
|
||||||
this.getArticle();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 切换 分类
|
|
||||||
* @param name 分类名称
|
|
||||||
*/
|
|
||||||
changeCategory(name: string) {
|
|
||||||
if (this.currentCategoryName === name) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.currentCategoryName = name;
|
|
||||||
this.getArticle();
|
|
||||||
this.location.replaceState('category', '?name=' + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getArticle() {
|
|
||||||
this.articleService.getArticleByCategory(this.currentCategoryName).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.currentArticleList = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#main{
|
|
||||||
width: 60%;
|
|
||||||
height: 50px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 15% 0;
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {Router, ActivatedRoute} from '@angular/router';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-email-verify',
|
|
||||||
templateUrl: './email-verify.component.html',
|
|
||||||
styleUrls: ['./email-verify.component.css']
|
|
||||||
})
|
|
||||||
export class EmailVerifyComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private titleService: Title,
|
|
||||||
public userService: UserService,
|
|
||||||
private router: Router,
|
|
||||||
public routerinfo: ActivatedRoute) {
|
|
||||||
titleService.setTitle('小海博客|邮箱验证');
|
|
||||||
}
|
|
||||||
|
|
||||||
type: string = 'info';
|
|
||||||
message: string = '正在验证,请稍等';
|
|
||||||
desc: string = '';
|
|
||||||
|
|
||||||
|
|
||||||
private email: string;
|
|
||||||
private verifyId: string;
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.email = this.routerinfo.snapshot.queryParams.email;
|
|
||||||
this.verifyId = this.routerinfo.snapshot.queryParams.verifyId;
|
|
||||||
if (this.email == null || this.verifyId == null) {
|
|
||||||
this.type = 'warning';
|
|
||||||
this.message = '数据不全';
|
|
||||||
this.desc = '链接可能被修改了,请重新点击邮箱中的链接,或者重新发送邮件';
|
|
||||||
}
|
|
||||||
const reqBody = {
|
|
||||||
email: this.email,
|
|
||||||
verifyId: this.verifyId
|
|
||||||
};
|
|
||||||
this.userService.emailVerify(reqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.type = 'success';
|
|
||||||
this.message = '验证成功';
|
|
||||||
// this.desc = "5秒后转跳到后台"
|
|
||||||
// setTimeout(() => {
|
|
||||||
// window.location.href = "admin"
|
|
||||||
// }, 5000);
|
|
||||||
} else {
|
|
||||||
this.type = 'error';
|
|
||||||
this.message = data.msg;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
hr {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main button {
|
|
||||||
width: 45px;
|
|
||||||
height: 45px;
|
|
||||||
margin-right: 15px;
|
|
||||||
margin-left: 15px;
|
|
||||||
margin-top: 10px;
|
|
||||||
background: none;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact {
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* info */
|
|
||||||
.main {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
width: 350px;
|
|
||||||
margin-bottom: 50px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
word-break: break-all
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.countInfo i {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
.countInfo li{
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* article */
|
|
||||||
|
|
||||||
.article {
|
|
||||||
min-height: 200px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aUl {
|
|
||||||
margin: 20px 0 0 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aUl li {
|
|
||||||
margin-right: 12px;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aUl li i {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article .aTitle {
|
|
||||||
margin: 0;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** todo : 动画效果 */
|
|
||||||
.aTitle:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article .aType {
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 0.8em;
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aTypeOriginal {
|
|
||||||
background: #5eb95e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aTypeReprint {
|
|
||||||
background: #F37B1D;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aSummary {
|
|
||||||
width: 98%;
|
|
||||||
padding-top: 10px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
line-height: 2em;
|
|
||||||
color: #666666;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 自动换行 */
|
|
||||||
.aTitle, .aSummary {
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tags {
|
|
||||||
margin-top: 10px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about-contact-icon:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pagination {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 768px) {
|
|
||||||
.left {
|
|
||||||
width: 380px;
|
|
||||||
height: auto;
|
|
||||||
flex-grow: 0;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-left: 80px;
|
|
||||||
padding-bottom: 80px;
|
|
||||||
direction: ltr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
height: auto;
|
|
||||||
max-width: 1000px;
|
|
||||||
flex-grow: 1;
|
|
||||||
margin-left: 80px;
|
|
||||||
margin-right: 80px;
|
|
||||||
direction: ltr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
direction: rtl
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and ( max-width: 768px ) {
|
|
||||||
#bloger {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article {
|
|
||||||
margin: 0 10px 30px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
width: 94%;
|
|
||||||
margin-left: 3%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.left {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
<div class="container">
|
|
||||||
|
|
||||||
|
|
||||||
<h2 *ngIf="!articleService.currentPage" style="width: 100%;text-align: center">.暂时还未发布文章.</h2>
|
|
||||||
|
|
||||||
<div class="right" *ngIf="articleService.currentPage">
|
|
||||||
<nz-card class="article am-animation-slide-right" *ngFor="let article of articleService.currentPage.list"
|
|
||||||
[nzLoading]="!articleService.currentPage">
|
|
||||||
|
|
||||||
<a [routerLink]="'/article/'+article.id"><h2 class="aTitle">{{article.title}}</h2></a>
|
|
||||||
<ul class="aUl">
|
|
||||||
<li>
|
|
||||||
<span class="aType" [ngClass]="{'aTypeOriginal': article.original,'aTypeReprint':!article.original}">
|
|
||||||
{{article.original ? "原创" : "转载"}}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="calendar" nzTheme="outline"></i>{{article.publishDateFormat}}</li>
|
|
||||||
<li><i nz-icon nzType="user" nzTheme="outline"></i>{{article.authorName}}</li>
|
|
||||||
<li>
|
|
||||||
<i nz-icon nzType="folder" nzTheme="outline"></i>
|
|
||||||
<a [routerLink]="['/category']" [queryParams]="{'name':article.category}">{{article.category}}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="aSummary">
|
|
||||||
<p>{{article.summary}}</p>
|
|
||||||
</div>
|
|
||||||
<a [routerLink]="'/article/'+article.id" style="font-size: 1.2em;">
|
|
||||||
阅读全文
|
|
||||||
<i nz-icon nzType="double-right" nzTheme="outline"></i>
|
|
||||||
</a>
|
|
||||||
<hr>
|
|
||||||
<div class="tags">
|
|
||||||
<span *ngFor="let item of article.tags">
|
|
||||||
<i nz-icon nzType="tag" nzTheme="outline"></i>
|
|
||||||
<a [routerLink]="['/tag']" [queryParams]="{name:item}">{{item}}</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</nz-card>
|
|
||||||
|
|
||||||
<nz-pagination id="pagination" [nzPageIndex]="pageNum" [nzTotal]="articleService.currentPage.total"
|
|
||||||
[nzPageSize]="pageSize"
|
|
||||||
[nzHideOnSinglePage]="true" (nzPageIndexChange)="getPageArticle($event)"></nz-pagination>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="left">
|
|
||||||
<!-- 关于我 -->
|
|
||||||
<div class="main am-animation-slide-left" id="bloger">
|
|
||||||
<span class="title">关于我</span>
|
|
||||||
<hr>
|
|
||||||
<div style="text-align: center;">
|
|
||||||
<div class="am-center" align="center">
|
|
||||||
<img [src]="imagePath" width="100px" height="100px" alt="logo">
|
|
||||||
<h2>小海</h2>
|
|
||||||
</div>
|
|
||||||
<div class="about-desc">
|
|
||||||
<span>一个爱好瞎捣鼓的技术宅 : )</span>
|
|
||||||
</div>
|
|
||||||
<div class="about-contact">
|
|
||||||
<button class="about-contact-icon" (mouseenter)="showWxImg()" (mouseleave)="reset()">
|
|
||||||
<i nz-icon nzType="wechat" nzTheme="outline"></i>
|
|
||||||
</button>
|
|
||||||
<button class="about-contact-icon" (mouseenter)="showQQImg()" (mouseleave)="reset()">
|
|
||||||
<i nz-icon nzType="qq" nzTheme="outline"></i>
|
|
||||||
</button>
|
|
||||||
<a href="https://github.com/xiaohai2271">
|
|
||||||
<button class="about-contact-icon">
|
|
||||||
<i nz-icon nzType="github" nzTheme="outline"></i>
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 标签云 -->
|
|
||||||
<div class="main am-animation-slide-left">
|
|
||||||
<span class="title">标签云</span>
|
|
||||||
<hr>
|
|
||||||
<div style="margin: 10px;">
|
|
||||||
<span *ngIf="!tagService.tagCloudList">暂无标签</span>
|
|
||||||
<div *ngIf="tagService.tagCloudList">
|
|
||||||
<a *ngFor="let item of tagService.tagCloudList" style="max-width: 90%;word-break: break-all;margin: 0 4px;"
|
|
||||||
[routerLink]="['/tag']" [queryParams]="{name:item.name}">
|
|
||||||
<font [size]="item.size+1" [nzTitle]="item.name" nzPlacement="topCenter" nz-tooltip>{{item.name}}</font>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 网站信息 -->
|
|
||||||
<div class="main am-animation-slide-left">
|
|
||||||
<span class="title">网站信息</span>
|
|
||||||
<hr>
|
|
||||||
<div style="margin: 15px;" *ngIf="countService.count">
|
|
||||||
<ul class="countInfo">
|
|
||||||
<li><i nz-icon nzType="file" nzTheme="outline"></i><span>文章总数</span>:{{countService.count.articleCount}} 篇
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="tags" nzTheme="outline"></i><span>标签总数</span>:{{countService.count.tagCount}} 个
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="profile" nzTheme="outline"></i><span>留言总数</span>:{{countService.count.leaveMsgCount}} 条
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="message" nzTheme="outline"></i><span>评论总数</span>:{{countService.count.commentCount}} 条
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="eye" nzTheme="outline"></i><span>总访客量</span>:{{countService.count.visitorCount}} 条
|
|
||||||
</li>
|
|
||||||
<li><i nz-icon nzType="arrow-up" nzTheme="outline"></i><span>最后更新</span>:<span
|
|
||||||
class="siteUpdateTime">{{webUpdateService.lastestUpdateTime}}</span></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="!countService.count" style="margin-left: 15px;">暂无更多信息</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {ActivatedRoute} from '@angular/router';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {Location} from '@angular/common';
|
|
||||||
import {TagService} from '../../services/tag/tag.service';
|
|
||||||
import {CountService} from '../../services/count/count.service';
|
|
||||||
import {ArticleService} from '../../services/article/article.service';
|
|
||||||
import {WebUpdateService} from '../../services/update/web-update.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-index',
|
|
||||||
templateUrl: './index.component.html',
|
|
||||||
styleUrls: ['./index.component.css']
|
|
||||||
})
|
|
||||||
export class IndexComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public tagService: TagService,
|
|
||||||
public countService: CountService,
|
|
||||||
public articleService: ArticleService,
|
|
||||||
public webUpdateService: WebUpdateService,
|
|
||||||
private routerinfo: ActivatedRoute, private title: Title,
|
|
||||||
private location: Location) {
|
|
||||||
title.setTitle('小海博客');
|
|
||||||
}
|
|
||||||
|
|
||||||
public pageNum: number;
|
|
||||||
public pageSize: number;
|
|
||||||
|
|
||||||
imagePath: string;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.pageNum = this.routerinfo.snapshot.queryParams.page;
|
|
||||||
this.pageSize = this.routerinfo.snapshot.queryParams.count;
|
|
||||||
// 数据合法性验证
|
|
||||||
this.pageNum = (this.pageNum == null || this.pageNum < 1) ? 1 : this.pageNum;
|
|
||||||
this.pageSize = (this.pageSize == null || this.pageSize < 1) ? 5 : this.pageSize;
|
|
||||||
// 获取数据
|
|
||||||
|
|
||||||
if (this.tagService.tagCloudList == null) {
|
|
||||||
this.tagService.getTagCloud();
|
|
||||||
}
|
|
||||||
if (this.countService.count == null) {
|
|
||||||
this.countService.getCount();
|
|
||||||
}
|
|
||||||
this.articleService.getArticle(this.pageNum, this.pageSize);
|
|
||||||
if (this.webUpdateService.updateInfoList == null) {
|
|
||||||
this.webUpdateService.getUpdateInfo();
|
|
||||||
}
|
|
||||||
if (!this.webUpdateService.lastestUpdateTime) {
|
|
||||||
this.webUpdateService.getLastestUpdateTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置imagePath的初始值
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
showQQImg() {
|
|
||||||
this.imagePath = 'https://56462271.oss-cn-beijing.aliyuncs.com/web/qq.jpg';
|
|
||||||
}
|
|
||||||
|
|
||||||
showWxImg() {
|
|
||||||
this.imagePath = 'https://56462271.oss-cn-beijing.aliyuncs.com/web/wx.jpg';
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.imagePath = 'https://56462271.oss-cn-beijing.aliyuncs.com/web/logo.png';
|
|
||||||
}
|
|
||||||
|
|
||||||
getPageArticle(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
// 修改地址栏
|
|
||||||
this.location.replaceState('', '?page=' + e + '&count=' + this.pageSize);
|
|
||||||
this.articleService.getArticle(this.pageNum, this.pageSize);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaveMsg-input {
|
|
||||||
width: 60%;
|
|
||||||
margin-left: 20%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaveMsg-input textarea {
|
|
||||||
padding: 10px;
|
|
||||||
max-height: 400px;
|
|
||||||
min-height: 60px;
|
|
||||||
width: 500px;
|
|
||||||
height: 100px;
|
|
||||||
border: 1px solid #4398ED;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#leaveMsg {
|
|
||||||
width: 70%;
|
|
||||||
height: 80%;
|
|
||||||
margin-top: 45px;
|
|
||||||
margin-left: 15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-btn {
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment {
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#leaveMsgs {
|
|
||||||
width: 60%;
|
|
||||||
margin: 15px auto
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and ( max-width:768px) {
|
|
||||||
#leaveMsgs {
|
|
||||||
width: 96%;
|
|
||||||
margin-left: 2%;
|
|
||||||
}
|
|
||||||
#input-area {
|
|
||||||
width: 80%;
|
|
||||||
margin-left: 10%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<div>
|
|
||||||
|
|
||||||
<span *ngIf="!userService.userInfo" style="display: block;text-align: center">
|
|
||||||
若要评论,请先<a style="color: blue !important;" (click)="userService.showModal('login')">登录</a>哟~~~~
|
|
||||||
</span>
|
|
||||||
<nz-comment *ngIf="userService.userInfo" style="width: 60%;margin:15px auto">
|
|
||||||
<nz-comment-content>
|
|
||||||
<nz-form-item>
|
|
||||||
<textarea [(ngModel)]="content" nz-input style="height: 130px;width: 80%;"></textarea>
|
|
||||||
</nz-form-item>
|
|
||||||
<nz-form-item>
|
|
||||||
<button nz-button nzType="primary" [disabled]="!content" (click)="submitComment()">
|
|
||||||
评论
|
|
||||||
</button>
|
|
||||||
</nz-form-item>
|
|
||||||
</nz-comment-content>
|
|
||||||
</nz-comment>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 展示 -->
|
|
||||||
<nz-card id="leaveMsgs" [nzLoading]="!leaveMsgService.leaveMsgPage">
|
|
||||||
<nz-comment *ngFor="let leaveMsg of leaveMsgService.leaveMsgPage.list; let i = index"
|
|
||||||
[nzAuthor]="leaveMsg.authorName"
|
|
||||||
[nzDatetime]="leaveMsg.date">
|
|
||||||
<nz-avatar nz-comment-avatar nzIcon="user" [nzSrc]="leaveMsg.authorAvatarImgUrl"></nz-avatar>
|
|
||||||
<nz-comment-content class="comment">
|
|
||||||
<p>
|
|
||||||
{{leaveMsg.content}}
|
|
||||||
</p>
|
|
||||||
</nz-comment-content>
|
|
||||||
<nz-comment-action><span (click)="replyTo(leaveMsg.id,leaveMsg.authorName,i)">
|
|
||||||
<i nz-icon nzType="message" nzTheme="fill"></i> 回复</span>
|
|
||||||
</nz-comment-action>
|
|
||||||
|
|
||||||
<!-- 二级评论 -->
|
|
||||||
<ng-container *ngIf="leaveMsg.child && leaveMsg.child.length">
|
|
||||||
|
|
||||||
<nz-comment *ngFor="let secLeaveMsg of leaveMsg.child" [nzAuthor]="secLeaveMsg.authorName"
|
|
||||||
[nzDatetime]="secLeaveMsg.date">
|
|
||||||
<nz-avatar nz-comment-avatar nzIcon="user" [nzSrc]="secLeaveMsg.authorAvatarImgUrl"></nz-avatar>
|
|
||||||
<nz-comment-content class="comment">
|
|
||||||
<p>
|
|
||||||
{{secLeaveMsg.content}}
|
|
||||||
</p>
|
|
||||||
</nz-comment-content>
|
|
||||||
<!-- <nz-comment-action><span (click)="replyTo(secLeaveMsg.id,secLeaveMsg.authorName,i)">
|
|
||||||
<i nz-icon nzType="message" nzTheme="fill"></i> 回复</span>
|
|
||||||
</nz-comment-action> -->
|
|
||||||
|
|
||||||
</nz-comment>
|
|
||||||
|
|
||||||
</ng-container>
|
|
||||||
<!-- 二级评论的回复框 -->
|
|
||||||
<nz-comment *ngIf="responseComment.pid!=null&&relyIndex==i">
|
|
||||||
<nz-comment>
|
|
||||||
<nz-comment-content>
|
|
||||||
<nz-form-item>
|
|
||||||
<textarea [(ngModel)]="responseComment.content" nz-input
|
|
||||||
style="height: 130px;width: 80%;padding: 10px;border-radius: 5px;"></textarea>
|
|
||||||
</nz-form-item>
|
|
||||||
<nz-form-item>
|
|
||||||
<button nz-button nzType="primary" [disabled]="!responseComment.content"
|
|
||||||
(click)="reply()"> 回复
|
|
||||||
</button>
|
|
||||||
<button nz-button nzType="default" style="margin-left: 15px;" (click)="responseComment.pid=null"> 取消
|
|
||||||
</button>
|
|
||||||
</nz-form-item>
|
|
||||||
</nz-comment-content>
|
|
||||||
</nz-comment>
|
|
||||||
</nz-comment>
|
|
||||||
</nz-comment>
|
|
||||||
|
|
||||||
|
|
||||||
<nz-pagination style="text-align: center" [nzPageIndex]="pageNum" [nzTotal]="leaveMsgService.leaveMsgPage.total"
|
|
||||||
[nzPageSize]="pageSize"
|
|
||||||
[nzHideOnSinglePage]="true" (nzPageIndexChange)="toPage($event)"></nz-pagination>
|
|
||||||
|
|
||||||
|
|
||||||
</nz-card>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {CommentService} from '../../services/comment/comment.service';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {CommentReq} from '../../class/commentReq';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-leave-msg',
|
|
||||||
templateUrl: './leave-msg.component.html',
|
|
||||||
styleUrls: ['./leave-msg.component.css']
|
|
||||||
})
|
|
||||||
export class LeaveMsgComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public leaveMsgService: CommentService,
|
|
||||||
private message: NzMessageService,
|
|
||||||
public userService: UserService,
|
|
||||||
private titleService: Title) {
|
|
||||||
titleService.setTitle('小海博客|留言');
|
|
||||||
// todo ::: @ {pid} 的name
|
|
||||||
}
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
|
|
||||||
pageSize: number = 10;
|
|
||||||
|
|
||||||
content: string = null;
|
|
||||||
|
|
||||||
// 当前的回复框的所处位置
|
|
||||||
relyIndex: number;
|
|
||||||
|
|
||||||
public responseComment: CommentReq = new CommentReq(false);
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getPageLeaveMsg();
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPageLeaveMsg() {
|
|
||||||
this.leaveMsgService.getLeaveMsg(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 点击回复 显示输入框 及准备数据
|
|
||||||
* @param id 父级评论的id
|
|
||||||
* @param name 父级评论者的name
|
|
||||||
* @param index 索引
|
|
||||||
*/
|
|
||||||
replyTo(id, name, index) {
|
|
||||||
if (this.userService.userInfo == null) {
|
|
||||||
this.message.info('请先登录哟~~~');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.responseComment.pid = id;
|
|
||||||
this.responseComment.content = ' @' + name + ' ';
|
|
||||||
this.relyIndex = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toPage(a: number) {
|
|
||||||
if (a === this.pageNum) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.pageNum = a;
|
|
||||||
this.getPageLeaveMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 留言
|
|
||||||
*/
|
|
||||||
submitComment() {
|
|
||||||
if (this.content == null || this.content === '') {
|
|
||||||
this.message.info('内容不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const submitBody: CommentReq = new CommentReq(false);
|
|
||||||
submitBody.content = this.content;
|
|
||||||
this.leaveMsgService.submitComment(submitBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回复的数据提交
|
|
||||||
*/
|
|
||||||
reply() {
|
|
||||||
if (this.responseComment.content == null || this.responseComment.content === '') {
|
|
||||||
this.message.info('内容不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.responseComment.pid == null) {
|
|
||||||
this.message.error('非法操作');
|
|
||||||
}
|
|
||||||
this.responseComment.articleID = -1;
|
|
||||||
this.leaveMsgService.rely(this.responseComment).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
if (this.leaveMsgService.leaveMsgPage.list[this.relyIndex].child == null) {
|
|
||||||
this.leaveMsgService.leaveMsgPage.list[this.relyIndex].child = [];
|
|
||||||
}
|
|
||||||
this.leaveMsgService.leaveMsgPage.list[this.relyIndex].child.unshift(data.result);
|
|
||||||
this.responseComment.content = null;
|
|
||||||
this.responseComment.pid = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
.main {
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
width: 500px;
|
|
||||||
position: relative;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateX(-50%)
|
|
||||||
}
|
|
||||||
|
|
||||||
#email, #password {
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid #999999;
|
|
||||||
border-radius: 5px;
|
|
||||||
height: 32px;
|
|
||||||
background: #ffffff
|
|
||||||
}
|
|
||||||
|
|
||||||
.br-text, .forget {
|
|
||||||
clear: both;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
border: none;
|
|
||||||
padding: 4px 6px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login {
|
|
||||||
background: #0E90D2;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
|
||||||
.main-content {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<div class="main">
|
|
||||||
<div class="main-content">
|
|
||||||
<form>
|
|
||||||
<h1 style="text-align: center"><strong>小海</strong></h1>
|
|
||||||
<label for="email">邮箱:</label>
|
|
||||||
<br>
|
|
||||||
<input type="email" name="email" id="email" value="" [(ngModel)]="submitBody.email">
|
|
||||||
<br>
|
|
||||||
<label for="password">密码:</label>
|
|
||||||
<br>
|
|
||||||
<input type="password" name="password" id="password" value="" [(ngModel)]="submitBody.password">
|
|
||||||
<br>
|
|
||||||
<label for="remember-me">
|
|
||||||
<input id="remember-me" type="checkbox" name="isRemember" [(ngModel)]="submitBody.isRememberMe">
|
|
||||||
记住密码
|
|
||||||
</label>
|
|
||||||
<div class="br-text">
|
|
||||||
<p>
|
|
||||||
<span>还没有账号?</span>
|
|
||||||
<a style="color: blue" (click)="userService.showModal('registration')">注册</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<div>
|
|
||||||
<button type="submit" (click)="doLogin()" class="btn login">登 录</button>
|
|
||||||
<button type="button" class="btn forget" (click)="showForgetPwd=!showForgetPwd">忘记密码 ^_^?</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showForgetPwd" nzTitle="重置密码" (nzOnCancel)="handleCancel()" (nzOnOk)="handleOk()">
|
|
||||||
<input type="email" nz-input placeholder="注册的邮箱" [(ngModel)]="email4Forgot"/>
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import {Component, OnInit, ViewChild} from '@angular/core';
|
|
||||||
import {ActivatedRoute} from '@angular/router';
|
|
||||||
import {Router} from '@angular/router';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {LoginReq} from '../../class/loginReq';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-login',
|
|
||||||
templateUrl: './login.component.html',
|
|
||||||
styleUrls: ['./login.component.css']
|
|
||||||
})
|
|
||||||
export class LoginComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public userService: UserService,
|
|
||||||
private routerinfo: ActivatedRoute,
|
|
||||||
private router: Router,
|
|
||||||
private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public submitBody: LoginReq = new LoginReq();
|
|
||||||
|
|
||||||
|
|
||||||
showForgetPwd: boolean = false;
|
|
||||||
|
|
||||||
email4Forgot: string;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
if (this.userService.tempUser) {
|
|
||||||
this.submitBody.email = this.userService.tempUser.email;
|
|
||||||
this.submitBody.password = this.userService.tempUser.password;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 登录
|
|
||||||
doLogin() {
|
|
||||||
if (this.submitBody.email == null || this.submitBody.email === '') {
|
|
||||||
this.message.warning('邮箱不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.submitBody.password == null || this.submitBody.password === '') {
|
|
||||||
this.message.warning('密码不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const regExp = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
|
|
||||||
if (!regExp.test(this.submitBody.email)) {
|
|
||||||
this.message.error('邮箱格式不合法');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userService.login(this.submitBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
// 登录成功
|
|
||||||
// 置空
|
|
||||||
this.userService.tempUser = null;
|
|
||||||
this.message.success('登录成功,欢迎你' + data.result.displayName);
|
|
||||||
} else {
|
|
||||||
// 登录失败
|
|
||||||
this.message.error('登录失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
handleCancel() {
|
|
||||||
this.showForgetPwd = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发生重置密码的邮件
|
|
||||||
*/
|
|
||||||
handleOk() {
|
|
||||||
if (this.email4Forgot == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const regExp = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
|
|
||||||
if (!regExp.test(this.email4Forgot)) {
|
|
||||||
this.message.error('邮箱格式不合法');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showForgetPwd = false;
|
|
||||||
this.userService.sendResetPwdEmail(this.email4Forgot).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('发送成功,请前往邮箱进行操作');
|
|
||||||
} else {
|
|
||||||
this.message.error(data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
div,
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6,
|
|
||||||
p,
|
|
||||||
img,
|
|
||||||
strong,
|
|
||||||
b,
|
|
||||||
i,
|
|
||||||
dl,
|
|
||||||
dt,
|
|
||||||
dd,
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
li,
|
|
||||||
fieldset,
|
|
||||||
form,
|
|
||||||
label,
|
|
||||||
legend,
|
|
||||||
table,
|
|
||||||
caption,
|
|
||||||
tbody,
|
|
||||||
tfoot,
|
|
||||||
thead,
|
|
||||||
tr,
|
|
||||||
th,
|
|
||||||
td,
|
|
||||||
footer,
|
|
||||||
header,
|
|
||||||
hgroup,
|
|
||||||
menu,
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
textarea {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
background: transparent;
|
|
||||||
font-family: 'Microsoft Yahei', '\65B0\5B8B\4F53', '\5B8B\4F53', Verdana
|
|
||||||
}
|
|
||||||
|
|
||||||
.error404 {
|
|
||||||
width: 1100px;
|
|
||||||
height: 460px;
|
|
||||||
background: url(../../../assets/img/404.jpg) 50px;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
margin: 3px auto 0
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #00c0ff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wenzi {
|
|
||||||
padding-top: 326px;
|
|
||||||
text-align: center;
|
|
||||||
font-family: "微软雅黑";
|
|
||||||
font-size: 26px;
|
|
||||||
color: #686e6e
|
|
||||||
}
|
|
||||||
|
|
||||||
.wenzi {
|
|
||||||
height: 56px;
|
|
||||||
line-height: 56px;
|
|
||||||
color: #888888;
|
|
||||||
display: block;
|
|
||||||
border-bottom: 1px solid #d0cfcf
|
|
||||||
}
|
|
||||||
|
|
||||||
.wenzi_2 span {
|
|
||||||
color: #319898;
|
|
||||||
font-size: 30px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-style: italic
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width:768px) {
|
|
||||||
.error404 {
|
|
||||||
width: 100%;
|
|
||||||
background: url(../../../assets/img/404-m.jpg) -10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {Router, NavigationError} from '@angular/router';
|
|
||||||
import {Location} from '@angular/common';
|
|
||||||
|
|
||||||
import {filter} from 'rxjs/operators';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-not-found',
|
|
||||||
templateUrl: './not-found.component.html',
|
|
||||||
styleUrls: ['./not-found.component.css']
|
|
||||||
})
|
|
||||||
export class NotFoundComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(router: Router, location: Location, private titleService: Title) {
|
|
||||||
titleService.setTitle('小海博客|404');
|
|
||||||
router.events.pipe(
|
|
||||||
filter(event => event instanceof NavigationError)
|
|
||||||
).subscribe((event: NavigationError) => {
|
|
||||||
router.navigate(['/404'], {skipLocationChange: true})
|
|
||||||
.then(() => location.go(event.url));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<div class="site-middle am-animation-slide-top">
|
|
||||||
<div class="title">
|
|
||||||
<i nz-icon nzType="smile" nzTheme="outline" class="titleTag"></i><span class="title">友情链接</span>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<ul class="partner-sites">
|
|
||||||
<li *ngFor="let link of linkService.Links">
|
|
||||||
<i nz-icon nzType="link" nzTheme="outline"></i>
|
|
||||||
<a [href]="link.url" target="_blank" [title]="link.name">{{link.name}}</a>
|
|
||||||
</li>
|
|
||||||
<li class="applylink" (click)="showModal=!showModal">申请友链</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="placard am-animation-slide-bottom">
|
|
||||||
<div class="title">
|
|
||||||
<i nz-icon nzType="smile" nzTheme="outline" class="titleTag"></i><span class="title">友链公告</span>
|
|
||||||
</div>
|
|
||||||
<ul class="placard-content">
|
|
||||||
<li>请确认贵站可正常访问</li>
|
|
||||||
<li>原创博客、技术博客、游记博客优先</li>
|
|
||||||
<li>博客内容时常更新</li>
|
|
||||||
<li><strong>提交申请时若为https链接请带上https否则将视为http</strong></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showModal" [nzTitle]="modalTitle" [nzContent]="modalContent" [nzFooter]="modalFooter"
|
|
||||||
(nzOnCancel)="cancel()">
|
|
||||||
<ng-template #modalTitle>
|
|
||||||
<h2 style="text-align: center">申请友链</h2>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #modalContent>
|
|
||||||
<div class="am-modal-bd">
|
|
||||||
<div class="article-setting">
|
|
||||||
<label>网站名称:</label>
|
|
||||||
<input class="contentinput" placeholder="请输入网站名称" [(ngModel)]="link.name">
|
|
||||||
<br>
|
|
||||||
<label>网站链接:</label>
|
|
||||||
<input class="contentinput" placeholder="请输入网站链接" [(ngModel)]="link.url">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #modalFooter>
|
|
||||||
<button class="btn cancel" (click)="cancel()">取消</button>
|
|
||||||
<button class="btn submit" (click)="apply()">提交</button>
|
|
||||||
</ng-template>
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {LinkService} from '../../services/link/link.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-partner-sites',
|
|
||||||
templateUrl: './partner-sites.component.html',
|
|
||||||
styleUrls: ['./partner-sites.component.css']
|
|
||||||
})
|
|
||||||
export class PartnerSitesComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public linkService: LinkService,
|
|
||||||
private message: NzMessageService,
|
|
||||||
private titleService: Title) {
|
|
||||||
titleService.setTitle('小海博客|友链');
|
|
||||||
}
|
|
||||||
|
|
||||||
showModal: boolean = false;
|
|
||||||
|
|
||||||
// 申请时的链接
|
|
||||||
link = {
|
|
||||||
name: '',
|
|
||||||
url: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
if (this.linkService.Links == null) {
|
|
||||||
this.linkService.getLinks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply() {
|
|
||||||
if (this.link.name === '') {
|
|
||||||
this.message.error('网站名称不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.link.url === '') {
|
|
||||||
this.message.error('网站链接不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const regExp = /^(https:\/\/|http:\/\/|)([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/;
|
|
||||||
if (!regExp.test(this.link.url)) {
|
|
||||||
this.message.error('网站链接输入不合法');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showModal = false;
|
|
||||||
this.linkService.apply(this.link).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('提交成功,请稍等,即将为你处理');
|
|
||||||
} else {
|
|
||||||
this.message.error('提交失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.showModal = false;
|
|
||||||
this.link.name = null;
|
|
||||||
this.link.url = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
.main {
|
|
||||||
width: 500px;
|
|
||||||
position: relative;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ioc_text {
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.remain {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
|
||||||
margin: 20px 0 0 12%;
|
|
||||||
height: 32px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 75%;
|
|
||||||
height: 32px;
|
|
||||||
background: #fafafa;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verStatus {
|
|
||||||
width: 10px;
|
|
||||||
line-height: 32px;
|
|
||||||
margin-left: -20px;
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.br-text {
|
|
||||||
margin-left: 12%;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 80%;
|
|
||||||
height: 40px;
|
|
||||||
margin-left: 10%;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
background: turquoise;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #3385FF
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 全屏遮罩 */
|
|
||||||
.fullS {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 100px;
|
|
||||||
height: 50px;
|
|
||||||
background: none;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading span {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
|
||||||
.main {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<div>
|
|
||||||
<div class="main">
|
|
||||||
<div class="ioc_text">
|
|
||||||
<h1><strong>小海</strong></h1>
|
|
||||||
</div>
|
|
||||||
<form>
|
|
||||||
<div class="remain">
|
|
||||||
<div class="input-group mb-4 bootint" id="username">
|
|
||||||
<!-- <div class="input-group-prepend">
|
|
||||||
<span class="input-group-text"><i class="fa fa-user"></i></span>
|
|
||||||
</div> -->
|
|
||||||
<input type="text" name="email" class="form-control" placeholder="请输入你的邮箱" [(ngModel)]="email">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mb-4 bootint" id="password">
|
|
||||||
<!-- <div class="input-group-prepend">
|
|
||||||
<span class="input-group-text"><i class="fa fa-unlock-alt"></i></span>
|
|
||||||
</div> -->
|
|
||||||
<input type="password" name="password" class="form-control" placeholder="请输入你要设置的密码(8位以上)"
|
|
||||||
[(ngModel)]="password">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group mb-4 bootint" id="repassword">
|
|
||||||
<input type="password" name="repaassword" class="form-control" placeholder="请再次输入密码" [(ngModel)]="rePassword">
|
|
||||||
<i nz-icon class="verStatus" [hidden]="rePassword==null" [nzType]="password==rePassword?'check-circle':'close-circle'" nzTheme="outline"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" name="code" placeholder="验证码" (blur)="handleKeyUp()" [(ngModel)]="imgCode"
|
|
||||||
class="form-control" style="width: 60%;" id="verifyImgCode">
|
|
||||||
<i nz-icon class="verStatus" [hidden]="imgCode==''" [nzType]="imgCodeStatus?'check-circle':'close-circle'" nzTheme="outline"></i>
|
|
||||||
<img [src]="imgCodeUrl" (click)="changeImg()" alt="Code" title="点击更换验证码"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="br-text">
|
|
||||||
<p>
|
|
||||||
<span>已有账号了?</span>
|
|
||||||
<a (click)="userService.showModal('login')">登录</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="padding-top: 10px">
|
|
||||||
<button type="submit" class="btn" (click)="doRegistration()">注册</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="fullS" *ngIf="show">
|
|
||||||
<nz-spin [nzSpinning]="show" class="loading">
|
|
||||||
<div class="loading">
|
|
||||||
<span>加载中..</span>
|
|
||||||
</div>
|
|
||||||
</nz-spin>
|
|
||||||
</div>
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {Router} from '@angular/router';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {environment} from '../../../environments/environment';
|
|
||||||
import {LoginReq} from '../../class/loginReq';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-registration',
|
|
||||||
templateUrl: './registration.component.html',
|
|
||||||
styleUrls: ['./registration.component.css']
|
|
||||||
})
|
|
||||||
export class RegistrationComponent implements OnInit {
|
|
||||||
|
|
||||||
|
|
||||||
imgCodeUrl: string = environment.host + '/imgCode';
|
|
||||||
|
|
||||||
// 遮罩
|
|
||||||
show = false;
|
|
||||||
// 输入框的验证码
|
|
||||||
imgCode: string = '';
|
|
||||||
email: string = null;
|
|
||||||
password: string = null;
|
|
||||||
rePassword: string = null;
|
|
||||||
// 验证码验证状态
|
|
||||||
public imgCodeStatus: boolean;
|
|
||||||
|
|
||||||
constructor(public userService: UserService,
|
|
||||||
private router: Router,
|
|
||||||
private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeImg() {
|
|
||||||
this.imgCodeUrl = environment.host + '/imgCode?time=' + (new Date()).getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码验证
|
|
||||||
*/
|
|
||||||
handleKeyUp() {
|
|
||||||
if (this.imgCode.length === 4) {
|
|
||||||
this.userService.imgCodeVerify(this.imgCode).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.imgCodeStatus = true;
|
|
||||||
} else {
|
|
||||||
this.imgCodeStatus = false;
|
|
||||||
this.message.warning('验证码验证失败');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册的数据提交
|
|
||||||
*/
|
|
||||||
doRegistration() {
|
|
||||||
if (this.imgCodeStatus) {
|
|
||||||
if (this.email == null || this.password == null || this.rePassword == null) {
|
|
||||||
this.message.warning('用户名和密码均不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.rePassword !== this.password) {
|
|
||||||
this.message.warning('两次密码不匹配');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.show = true;
|
|
||||||
|
|
||||||
this.userService.registration(this.email, this.password).subscribe(data => {
|
|
||||||
this.show = false;
|
|
||||||
this.userService.tempUser = new LoginReq();
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.userService.tempUser.email = this.email;
|
|
||||||
this.userService.tempUser.password = this.password;
|
|
||||||
// 注册成功
|
|
||||||
this.message.success('注册成功!');
|
|
||||||
setTimeout(() => {
|
|
||||||
// 换成登录的modal
|
|
||||||
this.userService.loginModalType = 'login';
|
|
||||||
}, 300);
|
|
||||||
} else {
|
|
||||||
this.message.error('注册失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
document.getElementById('verifyImgCode').focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {Router, ActivatedRoute} from '@angular/router';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-reset-pwd',
|
|
||||||
templateUrl: './reset-pwd.component.html',
|
|
||||||
styleUrls: ['./reset-pwd.component.css']
|
|
||||||
})
|
|
||||||
export class ResetPwdComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private message: NzMessageService,
|
|
||||||
public userService: UserService,
|
|
||||||
private router: Router,
|
|
||||||
private routerinfo: ActivatedRoute) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private pwd: string;
|
|
||||||
private rePwd: string;
|
|
||||||
|
|
||||||
private email: string;
|
|
||||||
private verifyId: string;
|
|
||||||
|
|
||||||
iserror: boolean = false;
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.email = this.routerinfo.snapshot.queryParams.email;
|
|
||||||
this.verifyId = this.routerinfo.snapshot.queryParams.verifyId;
|
|
||||||
if (this.email == null || this.verifyId == null) {
|
|
||||||
this.iserror = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
|
||||||
if (this.pwd == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.pwd.length > 16) {
|
|
||||||
this.message.error('密码过长');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.pwd.length < 6) {
|
|
||||||
this.message.error('密码过短');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.pwd !== this.rePwd) {
|
|
||||||
this.message.warning('两次密码不一致');
|
|
||||||
}
|
|
||||||
|
|
||||||
const reqBody = {
|
|
||||||
email: this.email,
|
|
||||||
verifyId: this.verifyId,
|
|
||||||
pwd: this.pwd
|
|
||||||
};
|
|
||||||
this.userService.resetPWd(reqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('重置密码成功,5秒后转跳到登录页面。');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.router.navigateByUrl('/login');
|
|
||||||
// window.location.href = '/login';
|
|
||||||
}, 5000);
|
|
||||||
} else {
|
|
||||||
this.message.error(data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#main{
|
|
||||||
width:60%;
|
|
||||||
margin:0 auto;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
background: #ffffff;
|
|
||||||
}
|
|
||||||
#tag{
|
|
||||||
float: left;
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #ececec;
|
|
||||||
box-shadow: 5px 5px 5px #888888;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
#detail{
|
|
||||||
clear: both;
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.singleTag{
|
|
||||||
background: #ffffff;
|
|
||||||
border-radius: 5px;
|
|
||||||
line-height: 15px;
|
|
||||||
margin: 5px 10px;
|
|
||||||
float: left;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid #000000;
|
|
||||||
padding: 5px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul{
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.art{
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ececec;
|
|
||||||
box-shadow: 5px 5px 5px #aaaaaa;
|
|
||||||
margin: 20px 0 ;
|
|
||||||
}
|
|
||||||
.title:hover{
|
|
||||||
animation: 1s move ;
|
|
||||||
}
|
|
||||||
@keyframes move{
|
|
||||||
from{
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
to{
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.active{
|
|
||||||
background: #6DAB90;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width:768px){
|
|
||||||
|
|
||||||
#main{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<div id="main">
|
|
||||||
|
|
||||||
<div id="tag">
|
|
||||||
<ul>
|
|
||||||
<li *ngFor="let tag of tagService.tagCloudList" (click)="changeTag(tag.name)">
|
|
||||||
<span class="singleTag" [ngClass]="{active: currentTagName==tag.name}" [nzTitle]="'此标签有'+tag.size+'篇文章'"
|
|
||||||
nzPlacement="topCenter" nz-tooltip>
|
|
||||||
<i nz-icon nzType="tag" nzTheme="fill"></i> {{tag.name}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul id="detail" *ngIf="curremtArticlePage">
|
|
||||||
<li *ngFor="let article of curremtArticlePage.list">
|
|
||||||
<div class="art">
|
|
||||||
<h2><a [routerLink]="'/article/'+article.id" class="title">{{article.title}}</a></h2>
|
|
||||||
<hr>
|
|
||||||
<div> {{article.summary}}</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div *ngIf="!curremtArticlePage">
|
|
||||||
<h2 style="text-align: center">该分类暂无文章</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {Router, ActivatedRoute} from '@angular/router';
|
|
||||||
import {Location} from '@angular/common';
|
|
||||||
import {TagService} from '../../services/tag/tag.service';
|
|
||||||
import {ArticleService} from '../../services/article/article.service';
|
|
||||||
import {Page} from '../../class/page';
|
|
||||||
import {Article} from '../../class/article';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-tags',
|
|
||||||
templateUrl: './tag.component.html',
|
|
||||||
styleUrls: ['./tag.component.css']
|
|
||||||
})
|
|
||||||
|
|
||||||
export class TagComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private titleService: Title,
|
|
||||||
public tagService: TagService,
|
|
||||||
public articleService: ArticleService,
|
|
||||||
private router: Router,
|
|
||||||
private routerinfo: ActivatedRoute,
|
|
||||||
private location: Location) {
|
|
||||||
titleService.setTitle('小海博客|标签');
|
|
||||||
}
|
|
||||||
|
|
||||||
public currentTagName: string;
|
|
||||||
public curremtArticlePage: Page<Article>;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
this.currentTagName = this.routerinfo.snapshot.queryParams.name;
|
|
||||||
|
|
||||||
if (this.tagService.tagCloudList == null) {
|
|
||||||
this.tagService.getTagCloud().subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
// 根据当前获取到的tag name获取数据
|
|
||||||
if (this.currentTagName == null) {
|
|
||||||
this.currentTagName = data.result[0].name;
|
|
||||||
}
|
|
||||||
this.getArticle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (this.currentTagName == null) {
|
|
||||||
this.currentTagName = this.tagService.tagCloudList[0].name;
|
|
||||||
}
|
|
||||||
this.getArticle();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
changeTag(name) {
|
|
||||||
this.currentTagName = name;
|
|
||||||
this.location.replaceState('tag', '?name=' + name);
|
|
||||||
this.getArticle();
|
|
||||||
}
|
|
||||||
|
|
||||||
getArticle() {
|
|
||||||
this.articleService.getArticleByTag(this.currentTagName).subscribe(data => {
|
|
||||||
this.curremtArticlePage = data.result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
@media screen and (min-width: 768px) {
|
|
||||||
.site-inner{
|
|
||||||
margin: 0 19%;
|
|
||||||
}
|
|
||||||
.word p{
|
|
||||||
text-indent: 7em;
|
|
||||||
}
|
|
||||||
.word{
|
|
||||||
padding: 20px 25px;
|
|
||||||
}
|
|
||||||
.zh-update{
|
|
||||||
margin: 0 25%;
|
|
||||||
}
|
|
||||||
.update-leave-message{
|
|
||||||
margin: 100px 10%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.site-inner{
|
|
||||||
margin: 0 5%;
|
|
||||||
}
|
|
||||||
.word p{
|
|
||||||
text-indent: 2em;
|
|
||||||
}
|
|
||||||
.word{
|
|
||||||
padding: 20px 5px;
|
|
||||||
}
|
|
||||||
.zh-update{
|
|
||||||
margin: 0 3%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.am-g{
|
|
||||||
margin: 50px 0 0;
|
|
||||||
}
|
|
||||||
.site-inner-img{
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
.site-inner-img img{
|
|
||||||
width: 450px;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
.site-inner-mywords{
|
|
||||||
margin: 30px auto;
|
|
||||||
}
|
|
||||||
.word{
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 25%;
|
|
||||||
font-size: 21px;
|
|
||||||
line-height: 20px;
|
|
||||||
color: blue;
|
|
||||||
font-family: 华文仿宋;
|
|
||||||
}
|
|
||||||
.zh-update-log-title{
|
|
||||||
margin: 50px 0;
|
|
||||||
}
|
|
||||||
.zh-update-log-title h1{
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #222;
|
|
||||||
text-indent: 1em;
|
|
||||||
}
|
|
||||||
.zh-update-log-title p{
|
|
||||||
text-indent: 1.5em;
|
|
||||||
}
|
|
||||||
.zh-update-log-content{
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.update-log i{
|
|
||||||
color: #999999;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
.update-log h2{
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 1.3em;
|
|
||||||
font-weight: 650;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.update-log-content{
|
|
||||||
margin: 15px 26px;
|
|
||||||
}
|
|
||||||
.update-log-content blockquote{
|
|
||||||
padding: 0 10px 0 20px;
|
|
||||||
border-left: 4px solid #ddd;
|
|
||||||
}
|
|
||||||
.update-log-content p{
|
|
||||||
font-size: 16px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-family: 微软雅黑;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container{
|
|
||||||
padding-left: 1.5rem;
|
|
||||||
padding-right: 1.5rem;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<div id="app">
|
|
||||||
<!--页面主体-->
|
|
||||||
<div id="main">
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="site-inner">
|
|
||||||
|
|
||||||
<div class="site-inner-img">
|
|
||||||
|
|
||||||
<img src="https://zhy-myblog.oss-cn-shenzhen.aliyuncs.com/static/img/sun.jpg" class="am-img-thumbnail">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="site-inner-mywords">
|
|
||||||
<br>
|
|
||||||
<div class="word">
|
|
||||||
过自己喜欢的生活,<br><br>
|
|
||||||
<p>做自己喜欢的人</p><br>
|
|
||||||
<p>不以物喜</p>
|
|
||||||
<p>不以己悲</p>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="zh-update">
|
|
||||||
<div class="zh-update-log">
|
|
||||||
<div class="zh-update-log-title">
|
|
||||||
<h1>更新日志</h1>
|
|
||||||
<p>最后更新于 {{updateService.lastestUpdateTime}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="zh-update-log-content">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="update-log am-animation-slide-bottom" *ngFor="let update of updateService.updateInfoList">
|
|
||||||
<div class="update-log-date">
|
|
||||||
<i nz-icon nzType="star" nzTheme="twotone" nzTwotoneColor="#eb2f96" class="titleTag"></i>
|
|
||||||
<h2>{{update.time}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="update-log-content">
|
|
||||||
<blockquote>
|
|
||||||
<p *ngFor="let item of update.info.split('\n')">{{item}}</p>
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {WebUpdateService} from '../../services/update/web-update.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-update',
|
|
||||||
templateUrl: './update.component.html',
|
|
||||||
styleUrls: ['./update.component.css']
|
|
||||||
})
|
|
||||||
export class UpdateComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public updateService: WebUpdateService,
|
|
||||||
private titleService: Title) {
|
|
||||||
titleService.setTitle('小海博客|更新');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
if (this.updateService.updateInfoList == null) {
|
|
||||||
this.updateService.getUpdateInfo();
|
|
||||||
}
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
if (!this.updateService.lastestUpdateTime) {
|
|
||||||
this.updateService.getLastestUpdateTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import {AfterViewInit, Attribute, Directive, EventEmitter, Input, Output} from '@angular/core';
|
|
||||||
import {EditorConfig} from '../../../class/editor-config';
|
|
||||||
|
|
||||||
declare var editormd: any;
|
|
||||||
declare var $: any;
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[appEditorMd]'
|
|
||||||
})
|
|
||||||
export class EditorMdDirective implements AfterViewInit {
|
|
||||||
@Input() editormdConfig: EditorConfig; // 配置选项
|
|
||||||
@Output() onEditorChange: EventEmitter<string> = new EventEmitter<string>(); // 发射器
|
|
||||||
editor: any; // editormd编辑器
|
|
||||||
|
|
||||||
constructor(@Attribute('id') private id: string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
|
||||||
this.editor = editormd(this.id, this.editormdConfig); // 创建编辑器
|
|
||||||
|
|
||||||
const out = this.onEditorChange;
|
|
||||||
const textarea = $('#' + this.id + ' :first'); // 获取textarea元素
|
|
||||||
|
|
||||||
// 当编辑器内容改变时,触发textarea的change事件
|
|
||||||
// tslint:disable-next-line:only-arrow-functions
|
|
||||||
this.editor.on('change', function() {
|
|
||||||
out.emit(textarea.val());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
/* @import '../../../../../assets/editormd/editor.css';
|
|
||||||
|
|
||||||
.fa {
|
|
||||||
display: none;
|
|
||||||
} */
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center
|
|
||||||
}
|
|
||||||
|
|
||||||
.con {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap
|
|
||||||
}
|
|
||||||
|
|
||||||
#title {
|
|
||||||
/* 85% */
|
|
||||||
flex-grow: 1;
|
|
||||||
margin: 55px 0 5px 3%;
|
|
||||||
height: 35px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
padding-left: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#submit {
|
|
||||||
margin: 55px 3% 5px 20px;
|
|
||||||
width: 100px;
|
|
||||||
height: 35px;
|
|
||||||
background: #D83731;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
|
|
||||||
#md {
|
|
||||||
min-width: 1200px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*发布博客模态框设置*/
|
|
||||||
|
|
||||||
.am-modal-bd {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.article-tag,
|
|
||||||
.article-type,
|
|
||||||
.articleUrlHide {
|
|
||||||
padding: 10px 20px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.publish-tag {
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tags,
|
|
||||||
.type,
|
|
||||||
.tag,
|
|
||||||
.tag-inline,
|
|
||||||
.categories,
|
|
||||||
.grade,
|
|
||||||
.Url,
|
|
||||||
.tabloid {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.singleTag {
|
|
||||||
background: #ececec;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 0 2px;
|
|
||||||
padding: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.taginput {
|
|
||||||
width: 300px;
|
|
||||||
height: 32px;
|
|
||||||
background: #fafafa;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.removeTag {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 1px;
|
|
||||||
font-size: 16px;
|
|
||||||
height: 12px;
|
|
||||||
color: #ddd;
|
|
||||||
transition: color .3s ease-in;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addTagsBtn {
|
|
||||||
margin-left: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0;
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
color: #349edf;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#select-type,
|
|
||||||
#select-categories,
|
|
||||||
#select-grade {
|
|
||||||
width: 138px;
|
|
||||||
height: 32px;
|
|
||||||
background: #fafafa;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.required {
|
|
||||||
margin-left: 2px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #ca0c16;
|
|
||||||
}
|
|
||||||
|
|
||||||
#articleUrl {
|
|
||||||
width: 300px;
|
|
||||||
height: 32px;
|
|
||||||
background: #fafafa;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
<div style="margin-top: -80px;margin-bottom: -130px;z-index: 1000">
|
|
||||||
<div class="con">
|
|
||||||
<input type="text" [(ngModel)]="article.title" id="title">
|
|
||||||
<button id="submit" (click)="articleSubmit()">提交</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="md" appEditorMd [editormdConfig]="conf" (onEditorChange)="syncModel($event)">
|
|
||||||
<textarea style="display: block;" [(ngModel)]="article.mdContent"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="发布博文" (nzOnCancel)="showPupup=false" (nzOnOk)="publishArticle()">
|
|
||||||
<div class="am-modal-bd">
|
|
||||||
<div class="article-setting">
|
|
||||||
|
|
||||||
<div class="article-type row">
|
|
||||||
<label class="publish-tag">文章类型<strong>:</strong></label>
|
|
||||||
<div class="type">
|
|
||||||
<select id="select-type" [(ngModel)]="article.type">
|
|
||||||
<option>请选择</option>
|
|
||||||
<option [ngValue]="true">原创</option>
|
|
||||||
<option [ngValue]="false">转载</option>
|
|
||||||
</select>
|
|
||||||
<span class="required">*</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="article-type row">
|
|
||||||
<label class="publish-tag">博客分类<strong>:</strong></label>
|
|
||||||
<div class="categories">
|
|
||||||
<select id="select-categories" [(ngModel)]="article.category">
|
|
||||||
<option class="categoriesOption" value="">请选择</option>
|
|
||||||
<option class="categoriesOption" *ngFor="let category of categoryService.categories"
|
|
||||||
value={{category.name}}>{{category.name}}</option>
|
|
||||||
</select>
|
|
||||||
<span class="required">*</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="article-tag row">
|
|
||||||
<div class="tags">
|
|
||||||
<div class="tag-inline">
|
|
||||||
<label class="publish-tag">文章标签<strong>:</strong></label>
|
|
||||||
<div class="tag">
|
|
||||||
</div>
|
|
||||||
<input class="taginput" placeholder="每个标签以英文','结束" [(ngModel)]="article.tags"><span
|
|
||||||
class="required">*</span>
|
|
||||||
</div>
|
|
||||||
<span style="display: block;margin-left:67px;" *ngIf="article.tags">
|
|
||||||
<span *ngFor="let tag of article.tags.split(',')" class="singleTag">{{tag}}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="articleUrlHide row" *ngIf="!article.type">
|
|
||||||
<label class="publish-tag" style="display: inline-block">原文链接<strong>:</strong></label>
|
|
||||||
<div class="url" style="display: inline-block">
|
|
||||||
<input type="text" id="articleUrl" [(ngModel)]="article.url" placeholder=" 请输入原文链接">
|
|
||||||
<span class="required">*</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
import {Component, OnInit, Output, Input, EventEmitter} from '@angular/core';
|
|
||||||
import {EditorConfig} from '../../class/editor-config';
|
|
||||||
import {ActivatedRoute} from '@angular/router';
|
|
||||||
import {Router} from '@angular/router';
|
|
||||||
import {Title} from '@angular/platform-browser';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {ArticleService} from '../../services/article/article.service';
|
|
||||||
import {CategoryService} from '../../services/category/category.service';
|
|
||||||
import {ArticleReq} from '../../class/articleReq';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-write',
|
|
||||||
templateUrl: './write.component.html',
|
|
||||||
styleUrls: ['./write.component.css']
|
|
||||||
})
|
|
||||||
export class WriteComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public articleService: ArticleService,
|
|
||||||
private routerinfo: ActivatedRoute,
|
|
||||||
private router: Router,
|
|
||||||
private titleService: Title,
|
|
||||||
private message: NzMessageService,
|
|
||||||
public categoryService: CategoryService,
|
|
||||||
public userService: UserService) {
|
|
||||||
titleService.setTitle('小海博客|创作');
|
|
||||||
}
|
|
||||||
|
|
||||||
public obj: any;
|
|
||||||
show = false;
|
|
||||||
msg: any;
|
|
||||||
conf = new EditorConfig();
|
|
||||||
articleId;
|
|
||||||
isUpdate = false;
|
|
||||||
|
|
||||||
public article: ArticleReq = new ArticleReq();
|
|
||||||
|
|
||||||
showPupup = false;
|
|
||||||
|
|
||||||
// 同步属性内容
|
|
||||||
syncModel(str): void {
|
|
||||||
this.article.mdContent = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.articleId = this.routerinfo.snapshot.queryParams.id;
|
|
||||||
if (this.articleId != null) {
|
|
||||||
this.isUpdate = true;
|
|
||||||
this.getArticle();
|
|
||||||
}
|
|
||||||
if (!this.articleId && localStorage.getItem('tmpArticle')) {
|
|
||||||
this.article = JSON.parse(localStorage.getItem('tmpArticle'));
|
|
||||||
}
|
|
||||||
this.setSuitableHeight();
|
|
||||||
// 用户权限判断
|
|
||||||
if (!this.userService.userInfo) {
|
|
||||||
this.userService.getUserInfo().subscribe(data => {
|
|
||||||
if (!data.result || data.result.role !== 'admin') {
|
|
||||||
this.message.info('你暂时无发布文章的权限,所写文章将暂存在本地');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (this.userService.userInfo.role !== 'admin') {
|
|
||||||
this.message.info('你暂时无发布文章的权限,所写文章将暂存在本地');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置高度
|
|
||||||
*/
|
|
||||||
setSuitableHeight() {
|
|
||||||
this.conf.height = (window.innerHeight - 80 - 50) + '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交按钮的事件
|
|
||||||
articleSubmit() {
|
|
||||||
if (this.article.title === '' || this.article.mdContent === '') {
|
|
||||||
this.message.warning(this.article.title === '' ? '标题不能为空' : '文章不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showPupup = true;
|
|
||||||
if (!this.categoryService.categories) {
|
|
||||||
this.categoryService.getAllCategory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文章数据提交
|
|
||||||
*/
|
|
||||||
publishArticle() {
|
|
||||||
// 去除空值
|
|
||||||
this.article.tags = this.article.tags.split(',').filter(item => item !== '').toString();
|
|
||||||
if (this.article.tags === '') {
|
|
||||||
this.message.warning('文章标签不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.article.type !== (true || false)) {
|
|
||||||
this.message.warning('文章类型不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.article.category === '') {
|
|
||||||
this.message.warning('文章分类不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.article.type) {
|
|
||||||
const regExp = /^http(s|):\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/;
|
|
||||||
if (regExp.test(this.article.url)) {
|
|
||||||
this.message.warning('原文链接不合法');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文章 暂存
|
|
||||||
localStorage.setItem('tmpArticle', JSON.stringify(this.article));
|
|
||||||
|
|
||||||
this.article.url = this.article.type ? null : this.article.url;
|
|
||||||
|
|
||||||
if (!this.isUpdate) {
|
|
||||||
// 非文章更新
|
|
||||||
this.articleService.createArticle(this.article).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
// TODO 成功
|
|
||||||
this.message.success('发布成功,即将转跳');
|
|
||||||
localStorage.removeItem('tmpArticle');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.router.navigateByUrl('article/' + data.result.id);
|
|
||||||
}, 2500);
|
|
||||||
}
|
|
||||||
if (data.code === 301) {
|
|
||||||
// 未登陆
|
|
||||||
this.router.navigateByUrl('login');
|
|
||||||
}
|
|
||||||
if (data.code === 302) {
|
|
||||||
this.message.error('你没有发布文章的权限');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// 文章更新
|
|
||||||
this.articleService.updateArticle(this.article).subscribe(data => {
|
|
||||||
// TODO 未登陆
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('更新成功,即将转跳');
|
|
||||||
localStorage.removeItem('tmpArticle');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.router.navigateByUrl('article/' + data.result.id);
|
|
||||||
}, 2500);
|
|
||||||
} else if (data.code === 301) {
|
|
||||||
this.router.navigateByUrl('login');
|
|
||||||
} else if (data.code === 302) {
|
|
||||||
this.message.error('你没有更新文章的权限');
|
|
||||||
} else {
|
|
||||||
this.message.error('失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文章 for update
|
|
||||||
*/
|
|
||||||
getArticle() {
|
|
||||||
this.articleService.getArticleById(this.articleId, true).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.article.category = data.result.category;
|
|
||||||
this.article.mdContent = data.result.mdContent;
|
|
||||||
this.article.tags = String(data.result.tags);
|
|
||||||
this.article.type = data.result.original;
|
|
||||||
this.article.url = data.result.url;
|
|
||||||
this.article.title = data.result.title;
|
|
||||||
this.article.id = data.result.id;
|
|
||||||
} else if (data.code === 201) {
|
|
||||||
// 文章不存在
|
|
||||||
this.message.error('文章不存在');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ArticleService } from './article.service';
|
|
||||||
|
|
||||||
describe('ArticleService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: ArticleService = TestBed.get(ArticleService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Page} from '../../class/page';
|
|
||||||
import {Article} from '../../class/article';
|
|
||||||
import {Observable} from 'rxjs';
|
|
||||||
import {Data} from '../../class/data';
|
|
||||||
import {ArticleReq} from '../../class/articleReq';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class ArticleService {
|
|
||||||
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 存储所有已经请求过的数据<首页数据>
|
|
||||||
pageList: Page<Article>[] = [];
|
|
||||||
|
|
||||||
// 最后一次请求后的数据集<首页数据>
|
|
||||||
currentPage: Page<Article>;
|
|
||||||
|
|
||||||
// 通过分类获取的article
|
|
||||||
public currentArticleOfCategory: Page<Article>;
|
|
||||||
// 通过分类获取的article
|
|
||||||
public currentArticleOfTag: Page<Article>;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文章
|
|
||||||
* @param pageNum 页码数
|
|
||||||
* @param pageSize 单页数据量
|
|
||||||
*/
|
|
||||||
getArticle(pageNum: number, pageSize: number): object {
|
|
||||||
const articlePage = this.exist(pageNum, pageSize);
|
|
||||||
if (articlePage) {
|
|
||||||
return articlePage;
|
|
||||||
}
|
|
||||||
const observable = this.http.get('/articles?page=' + pageNum + '&count=' + pageSize);
|
|
||||||
observable.subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.currentPage = data.result;
|
|
||||||
this.pageList.push(data.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据分类获取文章
|
|
||||||
* @param name 分类名
|
|
||||||
*/
|
|
||||||
getArticleByCategory(name: string) {
|
|
||||||
return this.http.get('/articles/category/' + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据标签获取文章
|
|
||||||
* @param name 标签名
|
|
||||||
*/
|
|
||||||
getArticleByTag(name: string) {
|
|
||||||
return this.http.get('/articles/tag/' + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getArticleById(id: number, update: boolean = false) {
|
|
||||||
return this.http.get('/article/articleID/' + id + '?update=' + update);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
createArticle(article: ArticleReq) {
|
|
||||||
return this.http.post('/admin/article/create', article, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateArticle(article: ArticleReq) {
|
|
||||||
return this.http.put('/admin/article/update', article);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断并返回数据
|
|
||||||
* @param pageNum 页码数
|
|
||||||
* @param pageSize 单页数据量
|
|
||||||
*/
|
|
||||||
private exist(pageNum: number, pageSize: number): Page<Article> {
|
|
||||||
if (this.currentPage == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// tslint:disable-next-line:prefer-for-of
|
|
||||||
for (let i = 0; i < this.pageList.length; i++) {
|
|
||||||
// tslint:disable-next-line:triple-equals
|
|
||||||
if (this.pageList[i].pageNum == pageNum && this.pageList[i].pageSize == pageSize) {
|
|
||||||
return this.pageList[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { CategoryService } from './category.service';
|
|
||||||
|
|
||||||
describe('CategoryService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: CategoryService = TestBed.get(CategoryService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Category} from '../../class/category';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class CategoryService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
categories: Category[];
|
|
||||||
|
|
||||||
getAllCategory() {
|
|
||||||
const observable = this.http.get('/categories');
|
|
||||||
observable.subscribe((data) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.categories = data.result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { CommentService } from './comment.service';
|
|
||||||
|
|
||||||
describe('CommentService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: CommentService = TestBed.get(CommentService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Page} from '../../class/page';
|
|
||||||
import {LeaveMsg} from '../../class/LeaveMsg';
|
|
||||||
import {CommentReq} from '../../class/commentReq';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class CommentService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 存放
|
|
||||||
leaveMsgPage: Page<LeaveMsg> = new Page();
|
|
||||||
|
|
||||||
commentPage: Page<LeaveMsg> = new Page();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取留言
|
|
||||||
* @param pageNum 页码
|
|
||||||
* @param pageSize 单页数据数量
|
|
||||||
*/
|
|
||||||
getLeaveMsg(pageNum: number, pageSize: number) {
|
|
||||||
const observable = this.http.get('/leaveMsg?count=' + pageSize + '&page=' + pageNum);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.leaveMsgPage = data.result;
|
|
||||||
this.getResponseLeaveMsg();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文章的评论
|
|
||||||
* @param articleId 文章id
|
|
||||||
* @param pageNum 页码
|
|
||||||
* @param pageSize 单页数量
|
|
||||||
*/
|
|
||||||
getPageComment(articleId: number, pageNum: number, pageSize: number) {
|
|
||||||
const observable = this.http.get('/comments?articleId=' + articleId + '&count=' + pageSize + '&page=' + pageNum);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.commentPage = data.result;
|
|
||||||
this.getResponseComment();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取留言的回复
|
|
||||||
*/
|
|
||||||
getResponseLeaveMsg() {
|
|
||||||
if (!this.leaveMsgPage.list) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.leaveMsgPage.list.forEach(leaveMsg => {
|
|
||||||
if (leaveMsg.responseId != null && leaveMsg.responseId !== '') {
|
|
||||||
this.getByPid(leaveMsg.id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
leaveMsg.child = data.result.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取评论的回复
|
|
||||||
*/
|
|
||||||
getResponseComment() {
|
|
||||||
if (!this.commentPage.list) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.commentPage.list.forEach(comment => {
|
|
||||||
if (comment.responseId != null && comment.responseId !== '') {
|
|
||||||
this.getByPid(comment.id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
comment.child = data.result.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过父评论 获取回复
|
|
||||||
* @param pid 父评论id
|
|
||||||
*/
|
|
||||||
getByPid(pid: number) {
|
|
||||||
return this.http.get('/comment/pid/' + pid + '?count=5&page=1');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提交评论/留言 并加入缓存数据中
|
|
||||||
* @param submitBody 请求体
|
|
||||||
*/
|
|
||||||
submitComment(submitBody: CommentReq) {
|
|
||||||
this.http.post('/user/comment/create', submitBody, true).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
if (!submitBody.comment) {
|
|
||||||
this.leaveMsgPage.list.unshift(data.result);
|
|
||||||
} else {
|
|
||||||
this.commentPage.list.unshift(data.result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回复评论/留言
|
|
||||||
* @param responseComment 请求体
|
|
||||||
*/
|
|
||||||
rely(responseComment: CommentReq) {
|
|
||||||
return this.http.post('/user/comment/create', responseComment, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Count} from '../../class/count';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class CountService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
count: Count;
|
|
||||||
|
|
||||||
getCount() {
|
|
||||||
const observable = this.http.get('/counts');
|
|
||||||
observable.subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.count = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { HttpService } from './http.service';
|
|
||||||
|
|
||||||
describe('HttpService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: HttpService = TestBed.get(HttpService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
|
||||||
import {environment} from '../../environments/environment';
|
|
||||||
import {Observable} from 'rxjs';
|
|
||||||
import {Data} from '../class/data';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class HttpService {
|
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
|
||||||
this.host = environment.host;
|
|
||||||
const item = localStorage.getItem('token');
|
|
||||||
this.token = item == null ? '' : item;
|
|
||||||
this.httpOptions = {
|
|
||||||
headers: new HttpHeaders({
|
|
||||||
Accept: '*/*',
|
|
||||||
Authorization: this.token
|
|
||||||
}),
|
|
||||||
withCredentials: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 请求的主机地址
|
|
||||||
public host: string;
|
|
||||||
private token: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* http请求配置
|
|
||||||
*/
|
|
||||||
private httpOptions: object;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get 请求
|
|
||||||
* @param path 路径
|
|
||||||
*/
|
|
||||||
get(path: string): Observable<Data> {
|
|
||||||
return this.http.get<Data>(this.getPath(path), this.httpOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* post请求
|
|
||||||
* @param path 路径
|
|
||||||
* @param reqBody 请求体
|
|
||||||
* @param isJson 请求数据是否是json格式
|
|
||||||
*/
|
|
||||||
post(path: string, reqBody: object, isJson: boolean): Observable<Data> {
|
|
||||||
const Options = {
|
|
||||||
headers: new HttpHeaders({
|
|
||||||
Accept: '*/*',
|
|
||||||
Authorization: this.token,
|
|
||||||
ContentType: isJson ? 'application/json' : 'application/x-www-form-urlencoded'
|
|
||||||
}),
|
|
||||||
withCredentials: true
|
|
||||||
};
|
|
||||||
let submitBody = '';
|
|
||||||
if (!isJson) {
|
|
||||||
for (const key in reqBody) {
|
|
||||||
// 跳过值为null的参数请求
|
|
||||||
if (reqBody[key] == null || reqBody[key] === 'null') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
submitBody = submitBody + '&' + key + '=' + reqBody[key];
|
|
||||||
}
|
|
||||||
submitBody = submitBody.substring(1);
|
|
||||||
}
|
|
||||||
return this.http.post<Data>(this.getPath(path), isJson ? reqBody : submitBody, Options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* put 请求
|
|
||||||
* @param path 请求路径
|
|
||||||
* @param reqBody 请求体
|
|
||||||
*/
|
|
||||||
put(path: string, reqBody: object): Observable<Data> {
|
|
||||||
return this.http.put<Data>(this.getPath(path), reqBody, this.httpOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
visit() {
|
|
||||||
this.post('/visit', null, true).subscribe(data => {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查path 并拼接
|
|
||||||
* @param path 请求路径
|
|
||||||
* @return 拼接后的url
|
|
||||||
*/
|
|
||||||
private getPath(path: string): string {
|
|
||||||
if (path == null || path.length === 0 || path.substr(0, 1) !== '/') {
|
|
||||||
throw new Error('路径不合法');
|
|
||||||
}
|
|
||||||
return this.host + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
setToken(t: string) {
|
|
||||||
if (t == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
localStorage.setItem('token', t);
|
|
||||||
this.token = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeToken() {
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
this.token = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { LinkService } from './link.service';
|
|
||||||
|
|
||||||
describe('LinkService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: LinkService = TestBed.get(LinkService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class LinkService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Links: { id: number, name: string, url: string };
|
|
||||||
|
|
||||||
apply(link: {
|
|
||||||
name: string,
|
|
||||||
url: string
|
|
||||||
}) {
|
|
||||||
return this.http.post('/apply', link, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
getLinks() {
|
|
||||||
this.http.get('/links').subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.Links = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { TagService } from './tag.service';
|
|
||||||
|
|
||||||
describe('TagService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: TagService = TestBed.get(TagService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Tag} from '../../class/tag';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class TagService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
tagCloudList: Tag[];
|
|
||||||
|
|
||||||
getTagCloud() {
|
|
||||||
const observable = this.http.get('/tags/nac');
|
|
||||||
observable.subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.tagCloudList = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { WebUpdateService } from './web-update.service';
|
|
||||||
|
|
||||||
describe('WebUpdateService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: WebUpdateService = TestBed.get(WebUpdateService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {UpdateInfo} from '../../class/updateInfo';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class WebUpdateService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateInfoList: UpdateInfo[];
|
|
||||||
|
|
||||||
public lastestUpdateTime: string;
|
|
||||||
|
|
||||||
// when you fell unhappy,look at the sky, the sun is shining the birds are singing
|
|
||||||
// And you? should be smiling
|
|
||||||
getUpdateInfo() {
|
|
||||||
this.http.get('/webUpdate').subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.updateInfoList = data.result.reverse();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getLastestUpdateTime() {
|
|
||||||
this.http.get('/lastestUpdateTime').subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.lastestUpdateTime = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user