Compare commits
375 Commits
v1.0
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e36ec6058e | ||
|
|
ba80d7bffa | ||
|
|
5fe04e2490 | ||
|
|
77c0a5981f | ||
|
|
4abd43fef0 | ||
|
|
45acb1e697 | ||
|
|
7bca7a0ade | ||
|
|
9515e6cc27 | ||
| e3778e3dd3 | |||
| 95c4178a86 | |||
| 72d16a1996 | |||
| 3dc44b8a34 | |||
| 28f798df9d | |||
| e770b2a7cf | |||
| 516874e9d5 | |||
| 7cba060b9f | |||
| 548a2014d9 | |||
| 716b7ced8b | |||
| c4676fe232 | |||
|
|
af1d07f25b | ||
|
|
d689b9a6ef | ||
|
|
186ed62d18 | ||
| da5900b45a | |||
|
|
323bc86df1 | ||
|
|
0136ee4603 | ||
|
|
35bde50c55 | ||
|
|
d9fa76e9e2 | ||
|
|
28c03b962e | ||
|
|
ae94a50a3e | ||
|
|
840d827c80 | ||
|
|
a909fd650c | ||
|
|
3a0008650e | ||
|
|
6468d0d8d4 | ||
|
|
969fda50f7 | ||
|
|
89d7c98c21 | ||
|
|
1ddb7c093f | ||
|
|
307e0aefa4 | ||
|
|
be312f4d80 | ||
|
|
4bcc35b0b9 | ||
|
|
2e7e835861 | ||
|
|
60a1ed9163 | ||
|
|
6b62c76064 | ||
|
|
3915663838 | ||
|
|
2532f8894e | ||
|
|
defb5042ef | ||
|
|
2ba3d4ca1b | ||
|
|
a2e80e6fdd | ||
|
|
5e29f42115 | ||
|
|
7c08892bac | ||
|
|
080338a824 | ||
|
|
b88132fe60 | ||
|
|
5484e058d7 | ||
|
|
5d7852c54f | ||
|
|
00e10091f3 | ||
|
|
78cd04a88d | ||
|
|
b61b56795e | ||
|
|
6d3abed910 | ||
|
|
b55c03cbd5 | ||
|
|
06d203b65f | ||
|
|
754193d6ab | ||
|
|
03cf88868e | ||
|
|
7f4e4568e5 | ||
|
|
6bfb42e43d | ||
|
|
7ea7f83227 | ||
|
|
2037c95ffd | ||
|
|
33d7bbaf43 | ||
|
|
b65b25c1fa | ||
|
|
c13a7844a6 | ||
|
|
da30c3c51b | ||
|
|
33cc2ae8ec | ||
|
|
51159a49b7 | ||
|
|
dc6bf57587 | ||
|
|
ea83364c12 | ||
|
|
1c5423ebb2 | ||
|
|
02718d23db | ||
|
|
288eb358a3 | ||
|
|
6e5282daef | ||
|
|
8e93e84634 | ||
|
|
4596bbe1d2 | ||
|
|
08e98c5a69 | ||
|
|
5cf648da67 | ||
|
|
7eac8dbdde | ||
|
|
cbf688fb6c | ||
|
|
4d9acbe51b | ||
|
|
19a49f2c69 | ||
|
|
5941fb41e9 | ||
|
|
6a5f1fdefd | ||
|
|
68b380906a | ||
|
|
ad3759afb3 | ||
|
|
a45e558662 | ||
|
|
6d9aa66536 | ||
|
|
27fc65b759 | ||
|
|
75b56c604a | ||
|
|
4b1b44a125 | ||
|
|
53fb39678a | ||
|
|
a5ae7b8465 | ||
|
|
39a8c33be4 | ||
|
|
274fdf0fad | ||
|
|
19fd3e55f7 | ||
|
|
5c274705b0 | ||
|
|
e0d6943c96 | ||
|
|
a96313867e | ||
|
|
ae86991fe8 | ||
|
|
3d0c806fd2 | ||
|
|
2997fed054 | ||
|
|
beb0d27532 | ||
|
|
f05a0cf2b3 | ||
|
|
8917e2fe5a | ||
|
|
8c8cd95c96 | ||
|
|
4472c4bcdc | ||
|
|
6d0fc77ec1 | ||
|
|
845972df71 | ||
|
|
ca9fcddd31 | ||
|
|
425e75cccf | ||
|
|
2fefcb1ce7 | ||
|
|
12a7db276d | ||
|
|
93b9e7e6eb | ||
|
|
4e18c7108b | ||
|
|
a7711a5833 | ||
|
|
f7867cb9d9 | ||
|
|
83d117856c | ||
|
|
f829b269e9 | ||
|
|
ea5e6cd8d7 | ||
|
|
a6a34113c9 | ||
|
|
cf323dfa20 | ||
|
|
0dd3e756b6 | ||
|
|
f389bebf44 | ||
|
|
88f7e8111d | ||
|
|
19d556f2f3 | ||
|
|
152f10b449 | ||
|
|
f2b95c3510 | ||
|
|
a41a7e9eed | ||
|
|
9b656716dc | ||
|
|
9d6af4dc92 | ||
|
|
77d54fa7e0 | ||
|
|
f9a4c8d629 | ||
|
|
23f67e23b2 | ||
|
|
0b81661b76 | ||
|
|
29930ccec0 | ||
|
|
b59b30b32c | ||
|
|
6f1dd5cba5 | ||
|
|
20ec1552a6 | ||
|
|
c388297f12 | ||
|
|
dcbd47332e | ||
|
|
c8323a965c | ||
|
|
086e476da8 | ||
|
|
a4fa38deee | ||
|
|
b63697f717 | ||
|
|
1f2c925b45 | ||
|
|
c67d7b7593 | ||
|
|
7f418c7f95 | ||
|
|
2ce76455a4 | ||
|
|
7d181b71a9 | ||
|
|
91921bda96 | ||
|
|
5b96b66af5 | ||
|
|
4cf1d4130b | ||
|
|
dfd609ded3 | ||
|
|
1d994d16b1 | ||
|
|
23aec69b4f | ||
|
|
322c52ce86 | ||
|
|
410013779e | ||
|
|
b00c6e5a2b | ||
|
|
13c0529def | ||
|
|
d59eb47f03 | ||
|
|
25cf2290b9 | ||
|
|
130e135e03 | ||
|
|
f8e30d8823 | ||
|
|
b42d3b7d33 | ||
|
|
138b93da09 | ||
|
|
072eaa12e8 | ||
|
|
d263cc132d | ||
|
|
f044e9d01b | ||
|
|
c14f495f8e | ||
|
|
ab8a9154ec | ||
|
|
6da84e259e | ||
|
|
e95cd8fe23 | ||
|
|
d8e6e9c5d9 | ||
|
|
990548b8d5 | ||
|
|
449adc4cee | ||
|
|
22480569a2 | ||
|
|
58655bed94 | ||
|
|
32e5c4daf0 | ||
|
|
6ea2f792db | ||
|
|
ab6d056d3a | ||
|
|
670b028384 | ||
|
|
2e1fa1eb6a | ||
|
|
c6aebd8d68 | ||
|
|
1e8acd91c2 | ||
|
|
398716e3ff | ||
|
|
58d11c4fa8 | ||
|
|
5454a747a7 | ||
|
|
953fba5b17 | ||
|
|
fee6f45ea9 | ||
|
|
7803629cd3 | ||
|
|
a81f41e15c | ||
|
|
86378a46f2 | ||
|
|
53ddfe6e4c | ||
|
|
44f251135c | ||
|
|
6fb62adb91 | ||
|
|
01c21f5732 | ||
|
|
66d523e69c | ||
|
|
3ff80e5b54 | ||
|
|
8fb268f4cf | ||
|
|
34ff380731 | ||
|
|
392c7f3996 | ||
|
|
0c8eed9243 | ||
|
|
7e0b2b0e78 | ||
|
|
6b63e7b02b | ||
|
|
5d3b55b8b7 | ||
|
|
a6c3f16ddf | ||
|
|
c75b17fa05 | ||
|
|
bf2b0f0c64 | ||
|
|
bc4cce8ec3 | ||
|
|
4479d1536f | ||
|
|
fa2eed47ab | ||
|
|
414497ac70 | ||
|
|
6fce3f646b | ||
|
|
f42beeb5bb | ||
|
|
2008f43522 | ||
|
|
c7e364f6bd | ||
|
|
38e24fdd2c | ||
|
|
0b810a8ef5 | ||
|
|
f87b8041e8 | ||
|
|
d5d592fee5 | ||
|
|
89ec668b39 | ||
|
|
36db5289a4 | ||
|
|
cc8853e081 | ||
|
|
30a2fbdecc | ||
|
|
54b3b643c9 | ||
|
|
5524b8a80b | ||
|
|
eb4b9ea440 | ||
|
|
8a8302eb51 | ||
|
|
06d1d2e48c | ||
|
|
3a4e0ec815 | ||
|
|
d800fa479b | ||
|
|
efa1f0bee2 | ||
|
|
c8fe9c3658 | ||
|
|
8bd8986bdd | ||
|
|
551dbc10e5 | ||
|
|
5814a484c6 | ||
|
|
94ba2c2281 | ||
|
|
03018d402f | ||
|
|
d9a7b68a2b | ||
|
|
1e3472244e | ||
|
|
e1efc88103 | ||
|
|
7da74fcba1 | ||
|
|
c96b4d90da | ||
|
|
3330d0a090 | ||
|
|
7ce46ab634 | ||
|
|
9dca081c7a | ||
|
|
1d46241a06 | ||
|
|
7be9dc3f8a | ||
|
|
550b95ef8e | ||
|
|
845752b432 | ||
|
|
6bd15f3cc0 | ||
|
|
8cc8f8e8d5 | ||
|
|
014a9eebe4 | ||
|
|
7a788dc559 | ||
|
|
5e2dfe056b | ||
|
|
c265ff68fc | ||
|
|
3dce668594 | ||
|
|
718a7516af | ||
|
|
e3a4862e13 | ||
|
|
781513d8c9 | ||
|
|
c271b1a8cf | ||
|
|
b0b7e5d1f8 | ||
|
|
b60688cfd7 | ||
|
|
9cf543a0ab | ||
|
|
e66d3bbf62 | ||
|
|
dba21730ca | ||
|
|
e51725bc21 | ||
|
|
deb8646bda | ||
|
|
dba14fe5eb | ||
|
|
ffe4b36f3e | ||
|
|
f8d3494626 | ||
|
|
7b6a63cd84 | ||
|
|
00f69509c3 | ||
|
|
f21438f968 | ||
|
|
728f8c4a03 | ||
|
|
8a0f5726da | ||
|
|
c0002d5310 | ||
|
|
cdc4f3ea0f | ||
|
|
e291a69e43 | ||
|
|
d3a122065e | ||
|
|
7987da4d4a | ||
|
|
e3dc949245 | ||
|
|
955f537d59 | ||
|
|
565fc9f673 | ||
|
|
67c509a245 | ||
|
|
3e5524397b | ||
|
|
42177a7721 | ||
|
|
abc792a561 | ||
|
|
446d7e06e4 | ||
|
|
1c7f189d11 | ||
|
|
b45f3f16e3 | ||
|
|
dc17bba056 | ||
|
|
5371a9a5c5 | ||
|
|
e61e59fa5f | ||
|
|
7faebe83d5 | ||
|
|
ae62cbc58f | ||
|
|
992f0919cf | ||
|
|
adaa54b7ec | ||
|
|
92e17f58ea | ||
|
|
4537f78015 | ||
|
|
bc55aa48ff | ||
|
|
05143da5e2 | ||
|
|
4571d52e5d | ||
|
|
1930fe2f76 | ||
|
|
61d9d8949c | ||
|
|
441b5c9d10 | ||
|
|
035966e5e7 | ||
|
|
bc512d17b0 | ||
|
|
ea8be85015 | ||
|
|
dbc69956d4 | ||
|
|
6f540acebc | ||
|
|
dd6f85dc62 | ||
|
|
b266340ef1 | ||
|
|
e54726b4e8 | ||
|
|
a5dcdea130 | ||
|
|
eb7b3f6022 | ||
|
|
6a4775f503 | ||
|
|
d7a0adacb2 | ||
|
|
c18c32de98 | ||
|
|
349431c1d8 | ||
|
|
52f51138cb | ||
|
|
ce251b1217 | ||
|
|
dd38eaac54 | ||
|
|
76a9f590b8 | ||
|
|
62e538ac3c | ||
|
|
45efb7eff4 | ||
|
|
c40837b1b2 | ||
|
|
b2709cffd8 | ||
|
|
f74aca491b | ||
|
|
bd5d10c8b7 | ||
|
|
adb8f889c6 | ||
|
|
94e2c27f8b | ||
|
|
d4f5b3536f | ||
|
|
612b626ca0 | ||
|
|
e96e2c2f0d | ||
|
|
e397131473 | ||
|
|
94b7c7e7ba | ||
|
|
35736ab3e1 | ||
|
|
042c4d4fda | ||
|
|
757cdf31df | ||
|
|
f36287fc43 | ||
|
|
5d9c385d46 | ||
|
|
6f9eb718ce | ||
|
|
2bcca393e1 | ||
|
|
caad40170a | ||
|
|
9ed77d83dd | ||
|
|
2aa5d91857 | ||
|
|
d3e55152b0 | ||
|
|
b333f554b9 | ||
|
|
3cd3ca7afc | ||
|
|
1f4b447a74 | ||
|
|
d67f2ed7ca | ||
|
|
7aada7801f | ||
|
|
3ca8d6a4ff | ||
|
|
71669bacf3 | ||
|
|
ca190ced8a | ||
|
|
102908a864 | ||
|
|
0a9608b697 | ||
|
|
d54b508236 | ||
|
|
6b84118d16 | ||
|
|
f85973f4c8 | ||
|
|
c569f7a63f | ||
|
|
a30ee898ba | ||
|
|
9b511e7fe5 | ||
|
|
cb880e1ac1 | ||
|
|
8d1169ccd0 | ||
|
|
5cf4571e65 | ||
|
|
3ea8f63abc | ||
|
|
f2791ee150 | ||
|
|
df944335da | ||
|
|
d8eaa0d471 |
87
.eslintrc.json
Normal file
87
.eslintrc.json
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"ignorePatterns": [
|
||||||
|
"projects/**/*"
|
||||||
|
],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"*.ts"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"project": [
|
||||||
|
"tsconfig.json",
|
||||||
|
"e2e/tsconfig.json"
|
||||||
|
],
|
||||||
|
"createDefaultProgram": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:@angular-eslint/ng-cli-compat",
|
||||||
|
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
|
||||||
|
"plugin:@angular-eslint/template/process-inline-templates"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"prefer-arrow/prefer-arrow-functions": [
|
||||||
|
"off"
|
||||||
|
],
|
||||||
|
"@typescript-eslint/ban-types": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"types": {
|
||||||
|
"Object": {
|
||||||
|
"message": "Use {} instead",
|
||||||
|
"fixWith": "{}"
|
||||||
|
},
|
||||||
|
"{}": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@angular-eslint/component-selector": [
|
||||||
|
"off",
|
||||||
|
{
|
||||||
|
"type": "element",
|
||||||
|
"prefix": "app",
|
||||||
|
"style": "kebab-case"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@angular-eslint/directive-selector": [
|
||||||
|
"off",
|
||||||
|
{
|
||||||
|
"type": "attribute",
|
||||||
|
"prefix": "app",
|
||||||
|
"style": "camelCase"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"@typescript-eslint/explicit-member-accessibility": [
|
||||||
|
"off",
|
||||||
|
{
|
||||||
|
"accessibility": "explicit"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@typescript-eslint/no-inferrable-types": [
|
||||||
|
"off",
|
||||||
|
{
|
||||||
|
"ignoreParameters": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"arrow-parens": [
|
||||||
|
"off",
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"import/order": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"*.html"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"plugin:@angular-eslint/template/recommended"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"@angular-eslint/template/eqeqeq": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "npm" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
open-pull-requests-limit: 15
|
||||||
56
.github/workflows/build.yml
vendored
Normal file
56
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '.md')" # 如果 commit 信息包含以下关键字则跳过该任务
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Sync to Gitee
|
||||||
|
uses: x-dr/sync-repo-to-gitee@master
|
||||||
|
env:
|
||||||
|
# 在 Settings->Secrets 配置 GITEE_KEY
|
||||||
|
SSH_KEY: ${{ secrets.GITEE_KEY }}
|
||||||
|
with:
|
||||||
|
# 注意替换为你的 GitHub 源仓库地址
|
||||||
|
github-repo: "git@github.com:xiaohai2271/blog-frontEnd.git"
|
||||||
|
# 注意替换为你的 Gitee 目标仓库地址
|
||||||
|
gitee-repo: "git@gitee.com:xiaohai2271/blog-frontEnd.git"
|
||||||
|
|
||||||
|
- name: Use Node.js 16.x
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run lint && npm run build
|
||||||
|
- run: cd dist/index/ && tar -cf index.tar ./* && mv index.tar ../../
|
||||||
|
|
||||||
|
- name: Upload a Build Artifact
|
||||||
|
uses: actions/upload-artifact@v2.1.4
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: ./dist/index/*
|
||||||
|
|
||||||
|
# - name: SCP
|
||||||
|
# uses: appleboy/scp-action@master
|
||||||
|
# with:
|
||||||
|
# host: ${{ secrets.SSH_HOST }}
|
||||||
|
# username: ${{ secrets.SSH_USERNAME }}
|
||||||
|
# password: ${{ secrets.SSH_PASSWORD }}
|
||||||
|
# port: ${{ secrets.SSH_PORT }}
|
||||||
|
# source: "index.tar"
|
||||||
|
# target: "/www/wwwroot/www.celess.cn"
|
||||||
|
|
||||||
|
# - name: Run SSH command
|
||||||
|
# uses: garygrossgarten/github-action-ssh@v0.5.0
|
||||||
|
# with:
|
||||||
|
# command: cd /www/wwwroot/www.celess.cn && bash deploy.sh
|
||||||
|
# host: ${{ secrets.SSH_HOST }}
|
||||||
|
# username: ${{ secrets.SSH_USERNAME }}
|
||||||
|
# password: ${{ secrets.SSH_PASSWORD }}
|
||||||
|
# port: ${{ secrets.SSH_PORT }}
|
||||||
19
.github/workflows/test.yml
vendored
Normal file
19
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '.md')" # 如果 commit 信息包含以下关键字则跳过该任务
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js 16.x
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '16.x'
|
||||||
|
- run: npm install
|
||||||
|
- run: npm run lint && npm run build
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
|||||||
|
/.angular/cache
|
||||||
dist
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
|
.idea
|
||||||
.editorconfig
|
.editorconfig
|
||||||
|
package-lock.json
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
Copyright (C) 2014 by Marijn Haverbeke <marijnh@gmail.com> and others
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 禾几海
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -7,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in all
|
||||||
all copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
THE SOFTWARE.
|
SOFTWARE.
|
||||||
49
README.md
49
README.md
@@ -1,4 +1,5 @@
|
|||||||
# 小海博客前端页面
|
# 小海博客前端页面
|
||||||
|

|
||||||
|
|
||||||
基于angular的前端展示页面
|
基于angular的前端展示页面
|
||||||
|
|
||||||
@@ -31,12 +32,17 @@
|
|||||||
|
|
||||||
> 普通用户后台
|
> 普通用户后台
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
> 写作页面
|
> 写作页面
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
> 登录页面
|
||||||
|
|
||||||
|

|
||||||
|
> 登录页面的背景图采用bing的图片,每日一更哦。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -45,53 +51,28 @@
|
|||||||
|
|
||||||
##### 构建
|
##### 构建
|
||||||
|
|
||||||
> - index
|
> >
|
||||||
>
|
> > 1. npm install
|
||||||
> > 1. 进入index目录
|
> > 2. 修改环境数据中的host
|
||||||
> > 2. npm install
|
|
||||||
> > 3. 修改环境数据中的host
|
|
||||||
> >
|
> >
|
||||||
> > - ` /src/environments/environment.ts` (本地开发环境)
|
> > - ` /src/environments/environment.ts` (本地开发环境)
|
||||||
> > - `/src/environments/environment-prod.ts`(线上发布环境)
|
> > - `/src/environments/environment-prod.ts`(线上发布环境)
|
||||||
> > 4. ng build --prod
|
> > 3. ng build --prod
|
||||||
>
|
>
|
||||||
> - admin
|
|
||||||
>
|
>
|
||||||
> > 1. cd admin
|
>可使用项目根目录的`build.sh` 脚本进行构建,但是 两个项目中的环境里面的变量仍需自己修改
|
||||||
> > 2. npm install
|
|
||||||
> > 3. 修改环境数据中的host
|
|
||||||
> > - ` /src/environments/environment.ts` (本地开发环境)
|
|
||||||
> > - `/src/environments/environment-prod.ts`(线上发布环境)
|
|
||||||
> > 4. ng build --prod
|
|
||||||
> > 5. 修改index.html将` <base href="/">`改为 ` <base href="/admin/">`
|
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
|
|
||||||
##### 发布
|
##### 发布
|
||||||
|
|
||||||
- 将`index/dist/index`下的全部文件上传到网站根目录
|
- 将`dist/index`下的全部文件上传到网站根目录
|
||||||
|
|
||||||
- 将`admin/dist/admin`文件夹上传到根目录
|
|
||||||
|
|
||||||
- 目录结构如下:
|
- 目录结构如下:
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- 修改nginx的location配置
|
- 修改nginx的location配置
|
||||||
```nginx
|
```nginx
|
||||||
location ~ /admin/* {
|
location / {
|
||||||
try_files $uri $uri /admin/index.html;
|
|
||||||
}
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 📝TODO
|
|
||||||
|
|
||||||
|
|
||||||
#### 📌FIXME
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
# Admin
|
|
||||||
|
|
||||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.4.
|
|
||||||
|
|
||||||
## 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).
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
||||||
"version": 1,
|
|
||||||
"newProjectRoot": "projects",
|
|
||||||
"projects": {
|
|
||||||
"admin": {
|
|
||||||
"projectType": "application",
|
|
||||||
"schematics": {},
|
|
||||||
"root": "",
|
|
||||||
"sourceRoot": "src",
|
|
||||||
"prefix": "app",
|
|
||||||
"architect": {
|
|
||||||
"build": {
|
|
||||||
"builder": "@angular-devkit/build-angular:browser",
|
|
||||||
"options": {
|
|
||||||
"outputPath": "dist/admin/",
|
|
||||||
"index": "src/index.html",
|
|
||||||
"main": "src/main.ts",
|
|
||||||
"polyfills": "src/polyfills.ts",
|
|
||||||
"tsConfig": "tsconfig.app.json",
|
|
||||||
"aot": false,
|
|
||||||
"assets": [
|
|
||||||
"src/favicon.ico",
|
|
||||||
"src/assets",
|
|
||||||
{
|
|
||||||
"glob": "**/*",
|
|
||||||
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
|
|
||||||
"output": "/assets/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"styles": [
|
|
||||||
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
|
|
||||||
"src/styles.css"
|
|
||||||
],
|
|
||||||
"scripts": []
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"fileReplacements": [
|
|
||||||
{
|
|
||||||
"replace": "src/environments/environment.ts",
|
|
||||||
"with": "src/environments/environment.prod.ts"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"optimization": true,
|
|
||||||
"outputHashing": "all",
|
|
||||||
"sourceMap": false,
|
|
||||||
"extractCss": true,
|
|
||||||
"namedChunks": false,
|
|
||||||
"aot": true,
|
|
||||||
"extractLicenses": true,
|
|
||||||
"vendorChunk": false,
|
|
||||||
"buildOptimizer": true,
|
|
||||||
"budgets": [
|
|
||||||
{
|
|
||||||
"type": "initial",
|
|
||||||
"maximumWarning": "2mb",
|
|
||||||
"maximumError": "5mb"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"serve": {
|
|
||||||
"builder": "@angular-devkit/build-angular:dev-server",
|
|
||||||
"options": {
|
|
||||||
"browserTarget": "admin:build"
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"browserTarget": "admin:build:production"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extract-i18n": {
|
|
||||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
|
||||||
"options": {
|
|
||||||
"browserTarget": "admin:build"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
|
||||||
"options": {
|
|
||||||
"main": "src/test.ts",
|
|
||||||
"polyfills": "src/polyfills.ts",
|
|
||||||
"tsConfig": "tsconfig.spec.json",
|
|
||||||
"karmaConfig": "karma.conf.js",
|
|
||||||
"assets": [
|
|
||||||
"src/favicon.ico",
|
|
||||||
"src/assets"
|
|
||||||
],
|
|
||||||
"styles": [
|
|
||||||
"./node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
|
|
||||||
"src/styles.css"
|
|
||||||
],
|
|
||||||
"scripts": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
|
||||||
"options": {
|
|
||||||
"tsConfig": [
|
|
||||||
"tsconfig.app.json",
|
|
||||||
"tsconfig.spec.json",
|
|
||||||
"e2e/tsconfig.json"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"**/node_modules/**"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"e2e": {
|
|
||||||
"builder": "@angular-devkit/build-angular:protractor",
|
|
||||||
"options": {
|
|
||||||
"protractorConfig": "e2e/protractor.conf.js",
|
|
||||||
"devServerTarget": "admin:serve"
|
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"production": {
|
|
||||||
"devServerTarget": "admin:serve:production"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultProject": "admin"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
|
||||||
# For additional information regarding the format and rule options, please see:
|
|
||||||
# https://github.com/browserslist/browserslist#queries
|
|
||||||
|
|
||||||
# You can see what browsers were selected by your queries by running:
|
|
||||||
# npx browserslist
|
|
||||||
|
|
||||||
> 0.5%
|
|
||||||
last 2 versions
|
|
||||||
Firefox ESR
|
|
||||||
not dead
|
|
||||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
// Protractor configuration file, see link for more information
|
|
||||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
|
||||||
|
|
||||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type { import("protractor").Config }
|
|
||||||
*/
|
|
||||||
exports.config = {
|
|
||||||
allScriptsTimeout: 11000,
|
|
||||||
specs: [
|
|
||||||
'./src/**/*.e2e-spec.ts'
|
|
||||||
],
|
|
||||||
capabilities: {
|
|
||||||
'browserName': 'chrome'
|
|
||||||
},
|
|
||||||
directConnect: true,
|
|
||||||
baseUrl: 'http://localhost:4200/',
|
|
||||||
framework: 'jasmine',
|
|
||||||
jasmineNodeOpts: {
|
|
||||||
showColors: true,
|
|
||||||
defaultTimeoutInterval: 30000,
|
|
||||||
print: function() {}
|
|
||||||
},
|
|
||||||
onPrepare() {
|
|
||||||
require('ts-node').register({
|
|
||||||
project: require('path').join(__dirname, './tsconfig.json')
|
|
||||||
});
|
|
||||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { AppPage } from './app.po';
|
|
||||||
import { browser, logging } from 'protractor';
|
|
||||||
|
|
||||||
describe('workspace-project App', () => {
|
|
||||||
let page: AppPage;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
page = new AppPage();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
|
||||||
page.navigateTo();
|
|
||||||
expect(page.getTitleText()).toEqual('Welcome to admin!');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
// Assert that there are no errors emitted from the browser
|
|
||||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
|
||||||
expect(logs).not.toContain(jasmine.objectContaining({
|
|
||||||
level: logging.Level.SEVERE,
|
|
||||||
} as logging.Entry));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { browser, by, element } from 'protractor';
|
|
||||||
|
|
||||||
export class AppPage {
|
|
||||||
navigateTo() {
|
|
||||||
return browser.get(browser.baseUrl) as Promise<any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTitleText() {
|
|
||||||
return element(by.css('app-root h1')).getText() as Promise<string>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../out-tsc/e2e",
|
|
||||||
"module": "commonjs",
|
|
||||||
"target": "es5",
|
|
||||||
"types": [
|
|
||||||
"jasmine",
|
|
||||||
"jasminewd2",
|
|
||||||
"node"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// Karma configuration file, see link for more information
|
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|
||||||
|
|
||||||
module.exports = function (config) {
|
|
||||||
config.set({
|
|
||||||
basePath: '',
|
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
||||||
plugins: [
|
|
||||||
require('karma-jasmine'),
|
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, './coverage/admin'),
|
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: false,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
|
||||||
};
|
|
||||||
9678
admin/package-lock.json
generated
9678
admin/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "admin",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"scripts": {
|
|
||||||
"ng": "ng",
|
|
||||||
"start": "ng serve",
|
|
||||||
"build": "ng build",
|
|
||||||
"test": "ng test",
|
|
||||||
"lint": "ng lint",
|
|
||||||
"e2e": "ng e2e"
|
|
||||||
},
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@angular/animations": "~8.0.1",
|
|
||||||
"@angular/common": "~8.0.1",
|
|
||||||
"@angular/compiler": "~8.0.1",
|
|
||||||
"@angular/core": "~8.0.1",
|
|
||||||
"@angular/forms": "~8.0.1",
|
|
||||||
"@angular/platform-browser": "~8.0.1",
|
|
||||||
"@angular/platform-browser-dynamic": "~8.0.1",
|
|
||||||
"@angular/router": "~8.0.1",
|
|
||||||
"ng-zorro-antd": "^8.1.0",
|
|
||||||
"rxjs": "~6.4.0",
|
|
||||||
"tslib": "^1.9.0",
|
|
||||||
"zone.js": "~0.9.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@angular-devkit/build-angular": "~0.800.0",
|
|
||||||
"@angular/cli": "~8.0.4",
|
|
||||||
"@angular/compiler-cli": "~8.0.1",
|
|
||||||
"@angular/language-service": "~8.0.1",
|
|
||||||
"@types/node": "~8.9.4",
|
|
||||||
"@types/jasmine": "~3.3.8",
|
|
||||||
"@types/jasminewd2": "~2.0.3",
|
|
||||||
"codelyzer": "^5.0.0",
|
|
||||||
"jasmine-core": "~3.4.0",
|
|
||||||
"jasmine-spec-reporter": "~4.2.1",
|
|
||||||
"karma": "~4.1.0",
|
|
||||||
"karma-chrome-launcher": "~2.2.0",
|
|
||||||
"karma-coverage-istanbul-reporter": "~2.0.1",
|
|
||||||
"karma-jasmine": "~2.0.1",
|
|
||||||
"karma-jasmine-html-reporter": "^1.4.0",
|
|
||||||
"protractor": "~5.4.0",
|
|
||||||
"ts-node": "~7.0.0",
|
|
||||||
"tslint": "~5.15.0",
|
|
||||||
"typescript": "~3.4.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import {NgModule} from '@angular/core';
|
|
||||||
import {NavigationStart, Router, RouterModule, Routes} from '@angular/router';
|
|
||||||
import {filter} from 'rxjs/operators';
|
|
||||||
import {UserService} from './services/user/user.service';
|
|
||||||
|
|
||||||
import {AIndexComponent} from './pages/a-index/a-index.component';
|
|
||||||
import {ArticleManagerComponent} from './pages/article-manager/article-manager.component';
|
|
||||||
import {CommentManagerComponent} from './pages/comment-manager/comment-manager.component';
|
|
||||||
import {TagManagerComponent} from './pages/tag-manager/tag-manager.component';
|
|
||||||
import {UserInfoComponent} from './pages/user-info/user-info.component';
|
|
||||||
import {CategoryManagerComponent} from './pages/category-manager/category-manager.component';
|
|
||||||
import {LinksManagerComponent} from './pages/links-manager/links.component';
|
|
||||||
import {VisitorManagerComponent} from './pages/visitor-manager/visitor-manager.component';
|
|
||||||
import {UpdateManagerComponent} from './pages/update-manager/update.component';
|
|
||||||
import {UserManagerComponent} from './pages/user-manager/user-manager.component';
|
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [
|
|
||||||
{path: '', component: AIndexComponent},
|
|
||||||
{path: 'articles', component: ArticleManagerComponent},
|
|
||||||
{path: 'comments', component: CommentManagerComponent},
|
|
||||||
{path: 'tags', component: TagManagerComponent},
|
|
||||||
{path: 'userInfo', component: UserInfoComponent},
|
|
||||||
{path: 'categories', component: CategoryManagerComponent},
|
|
||||||
{path: 'links', component: LinksManagerComponent},
|
|
||||||
{path: 'visitors', component: VisitorManagerComponent},
|
|
||||||
{path: 'update', component: UpdateManagerComponent},
|
|
||||||
{path: 'users', component: UserManagerComponent},
|
|
||||||
{path: '**', component: AIndexComponent}
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forRoot(routes)],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class AppRoutingModule {
|
|
||||||
|
|
||||||
// todo : 换用路由守卫
|
|
||||||
constructor(private router: Router, private userService: UserService) {
|
|
||||||
this.router.events.pipe(filter((event) => event instanceof NavigationStart)
|
|
||||||
).subscribe((event: NavigationStart) => {
|
|
||||||
if (!this.userService.userInfo) {
|
|
||||||
this.userService.getUserInfo().subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.checkPermission(event);
|
|
||||||
} else if (data.code === 301) {
|
|
||||||
window.location.href = '/login';
|
|
||||||
} else {
|
|
||||||
window.location.href = '/';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.checkPermission(event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private checkPermission(event) {
|
|
||||||
if (this.userService.userInfo.role === 'user') {
|
|
||||||
switch (event.url) {
|
|
||||||
case '/':
|
|
||||||
case '/comments':
|
|
||||||
case '/userInfo':
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
this.router.navigateByUrl('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
.menu {
|
|
||||||
position: fixed;
|
|
||||||
max-width: 240px;
|
|
||||||
top: 50px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.myCard {
|
|
||||||
width: 180px;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
position: absolute;
|
|
||||||
top: 50px;
|
|
||||||
right: 0;
|
|
||||||
left: 240px;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
nz-content {
|
|
||||||
margin-left: 30px;
|
|
||||||
margin-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content {
|
|
||||||
padding: 15px;
|
|
||||||
background: #fff;
|
|
||||||
min-height: 560px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nz-footer {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
|
||||||
nz-content {
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
<app-header></app-header>
|
|
||||||
<div style="height: 60px;"></div>
|
|
||||||
|
|
||||||
<nz-layout class="layout">
|
|
||||||
|
|
||||||
<nz-sider nzCollapsible
|
|
||||||
[(nzCollapsed)]="isCollapsed"
|
|
||||||
[nzBreakpoint]="'lg'"
|
|
||||||
[nzCollapsedWidth]="0"
|
|
||||||
[nzZeroTrigger]="zeroTrigger"
|
|
||||||
nzTheme="light"
|
|
||||||
*ngIf="userService.userInfo">
|
|
||||||
<ul nz-menu nzTheme="light" nzMode="inline" [nzInlineCollapsed]="isCollapsed">
|
|
||||||
<li nz-menu-item routerLink="/">
|
|
||||||
<i nz-icon nzType="desktop" nzTheme="outline"></i>
|
|
||||||
<span>后台首页</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-submenu nzTitle="文章管理" nzIcon="file" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<ul>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a href="../write">
|
|
||||||
<i nz-icon nzType="form" nzTheme="outline"></i>
|
|
||||||
<span>新增文章</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li nz-menu-item routerLink="/articles">
|
|
||||||
<i nz-icon nzType="ordered-list" nzTheme="outline"></i>
|
|
||||||
<span>文章列表</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="comments">
|
|
||||||
<i nz-icon nzType="message" nzTheme="outline"></i>
|
|
||||||
<span>评论管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="tags" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<i nz-icon nzType="tags" nzTheme="outline"></i>
|
|
||||||
<span>标签管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="categories" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<i nz-icon nzType="appstore" nzTheme="outline"></i>
|
|
||||||
<span>分类管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="userInfo">
|
|
||||||
<i nz-icon nzType="idcard" nzTheme="outline"></i>
|
|
||||||
<span>修改信息</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="users" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<i nz-icon nzType="user" nzTheme="outline"></i>
|
|
||||||
<span>用户管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="links" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<i nz-icon nzType="link" nzTheme="outline"></i>
|
|
||||||
<span>友链管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="visitors" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<i nz-icon nzType="chrome" nzTheme="outline"></i>
|
|
||||||
<span>访问管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li nz-menu-item routerLink="update" *ngIf="userService.userInfo.role=='admin'">
|
|
||||||
<i nz-icon nzType="arrow-up" nzTheme="outline"></i>
|
|
||||||
<span>更新管理</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<!--TODO : do something here ..... -->
|
|
||||||
<nz-card class="myCard" *ngIf="!isCollapsed&&userService.userInfo.role=='admin'">
|
|
||||||
<p>别管别人言语</p>
|
|
||||||
<p>做最好的自己</p>
|
|
||||||
</nz-card>
|
|
||||||
<nz-card class="myCard" *ngIf="!isCollapsed&&userService.userInfo.role=='user'">
|
|
||||||
<p>欢迎来访小海博客</p>
|
|
||||||
</nz-card>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</nz-sider>
|
|
||||||
<nz-layout>
|
|
||||||
<nz-content>
|
|
||||||
<div class="inner-content">
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
</div>
|
|
||||||
</nz-content>
|
|
||||||
<nz-footer>© <a href="https://www.celess.cn">小海博客</a> - Design by 小海</nz-footer>
|
|
||||||
</nz-layout>
|
|
||||||
</nz-layout>
|
|
||||||
<ng-template #zeroTrigger>
|
|
||||||
<i nz-icon nzType="menu-fold" nzTheme=outline></i>
|
|
||||||
</ng-template>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { TestBed, async } from '@angular/core/testing';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [
|
|
||||||
RouterTestingModule
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
AppComponent
|
|
||||||
],
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should create the app', () => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.debugElement.componentInstance;
|
|
||||||
expect(app).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should have as title 'admin'`, () => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.debugElement.componentInstance;
|
|
||||||
expect(app.title).toEqual('admin');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render title in a h1 tag', () => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
const compiled = fixture.debugElement.nativeElement;
|
|
||||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to admin!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {UserService} from './services/user/user.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-root',
|
|
||||||
templateUrl: './app.component.html',
|
|
||||||
styleUrls: ['./app.component.css']
|
|
||||||
})
|
|
||||||
export class AppComponent implements OnInit {
|
|
||||||
|
|
||||||
isCollapsed: boolean = false;
|
|
||||||
|
|
||||||
constructor(public userService: UserService) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import {BrowserModule} from '@angular/platform-browser';
|
|
||||||
import {NgModule} from '@angular/core';
|
|
||||||
import {NgZorroAntdModule, NZ_I18N, zh_CN} from 'ng-zorro-antd';
|
|
||||||
import {FormsModule} from '@angular/forms';
|
|
||||||
import {HttpClientModule} from '@angular/common/http';
|
|
||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
|
||||||
import {registerLocaleData} from '@angular/common';
|
|
||||||
import zh from '@angular/common/locales/zh';
|
|
||||||
import {AppRoutingModule} from './app-routing.module';
|
|
||||||
import {AppComponent} from './app.component';
|
|
||||||
|
|
||||||
|
|
||||||
// components
|
|
||||||
import {HeaderComponent} from './components/header/header.component';
|
|
||||||
// pages
|
|
||||||
import {AIndexComponent} from './pages/a-index/a-index.component';
|
|
||||||
import {ArticleManagerComponent} from './pages/article-manager/article-manager.component';
|
|
||||||
import {CommentManagerComponent} from './pages/comment-manager/comment-manager.component';
|
|
||||||
import {TagManagerComponent} from './pages/tag-manager/tag-manager.component';
|
|
||||||
import {UserInfoComponent} from './pages/user-info/user-info.component';
|
|
||||||
import {CategoryManagerComponent} from './pages/category-manager/category-manager.component';
|
|
||||||
import {LinksManagerComponent} from './pages/links-manager/links.component';
|
|
||||||
import {VisitorManagerComponent} from './pages/visitor-manager/visitor-manager.component';
|
|
||||||
import {UpdateManagerComponent} from './pages/update-manager/update.component';
|
|
||||||
import {UserManagerComponent} from './pages/user-manager/user-manager.component';
|
|
||||||
// services
|
|
||||||
import {HttpService} from './services/http.service';
|
|
||||||
|
|
||||||
|
|
||||||
registerLocaleData(zh);
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [
|
|
||||||
AppComponent,
|
|
||||||
|
|
||||||
HeaderComponent,
|
|
||||||
AIndexComponent,
|
|
||||||
ArticleManagerComponent,
|
|
||||||
CommentManagerComponent,
|
|
||||||
TagManagerComponent,
|
|
||||||
UserInfoComponent,
|
|
||||||
CategoryManagerComponent,
|
|
||||||
LinksManagerComponent,
|
|
||||||
VisitorManagerComponent,
|
|
||||||
UpdateManagerComponent,
|
|
||||||
UserManagerComponent
|
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
AppRoutingModule,
|
|
||||||
NgZorroAntdModule,
|
|
||||||
FormsModule,
|
|
||||||
HttpClientModule,
|
|
||||||
BrowserAnimationsModule
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{provide: NZ_I18N, useValue: zh_CN},
|
|
||||||
HttpService
|
|
||||||
],
|
|
||||||
bootstrap: [AppComponent]
|
|
||||||
})
|
|
||||||
export class AppModule {
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export class Article {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
summary: string;
|
|
||||||
mdContent?: string;
|
|
||||||
original?: boolean;
|
|
||||||
url?: string;
|
|
||||||
publishDateFormat?: string;
|
|
||||||
updateDateFormat?: string;
|
|
||||||
category?: string;
|
|
||||||
tags?: string[];
|
|
||||||
authorName?: string;
|
|
||||||
preArticleId?: number;
|
|
||||||
nextArticleId?: number;
|
|
||||||
preArticleTitle?: string;
|
|
||||||
nextArticleTitle?: string;
|
|
||||||
readingNumber?: number;
|
|
||||||
open?: string;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export class Category {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
articles: string;
|
|
||||||
size?: number;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export class Comment {
|
|
||||||
id: number;
|
|
||||||
type: number;
|
|
||||||
authorName: string;
|
|
||||||
authorAvatarImgUrl: string;
|
|
||||||
content: string;
|
|
||||||
date: string;
|
|
||||||
pid: number;
|
|
||||||
responseId: string;
|
|
||||||
articleID: number;
|
|
||||||
articleTitle: string;
|
|
||||||
child: Comment[];
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export class CommentReq {
|
|
||||||
articleID: number;
|
|
||||||
comment: boolean;
|
|
||||||
content: string;
|
|
||||||
id: number;
|
|
||||||
pid: number;
|
|
||||||
responseId: string;
|
|
||||||
|
|
||||||
constructor(comment: boolean) {
|
|
||||||
this.comment = comment;
|
|
||||||
this.responseId = '';
|
|
||||||
if (!comment) {
|
|
||||||
this.articleID = -1;
|
|
||||||
}
|
|
||||||
this.pid = -1;
|
|
||||||
this.id = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export class Data {
|
|
||||||
code: number;
|
|
||||||
msg: string;
|
|
||||||
result: any;
|
|
||||||
date: number;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export class Link {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
open: boolean;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export class Tag {
|
|
||||||
id?: number;
|
|
||||||
name: string;
|
|
||||||
articles?: string;
|
|
||||||
size: number;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
export class User {
|
|
||||||
id: number;
|
|
||||||
email: string;
|
|
||||||
displayName: string;
|
|
||||||
emailStatus: boolean;
|
|
||||||
avatarImgUrl: string;
|
|
||||||
recentlyLandedDate: string;
|
|
||||||
desc: string;
|
|
||||||
role: string;
|
|
||||||
pwd?: string;
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
header {
|
|
||||||
height: 50px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
opacity: 0.8;
|
|
||||||
position: fixed;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 768px) {
|
|
||||||
/**导航栏*/
|
|
||||||
.nav-desktop {
|
|
||||||
position: fixed;
|
|
||||||
width: auto;
|
|
||||||
left: 50%;
|
|
||||||
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: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<header>
|
|
||||||
<a href="/">
|
|
||||||
<div>
|
|
||||||
<img src="https://56462271.oss-cn-beijing.aliyuncs.com/web/logo.png"/>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<div>
|
|
||||||
<a href="/" id="blogTitle"><span>小海博客</span></a>
|
|
||||||
<span id="desc">记录学习成长历程</span>
|
|
||||||
</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="../">博客首页</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">
|
|
||||||
<div class="login">
|
|
||||||
<a class="headerButton" style="border-radius: 8px;color: white"
|
|
||||||
id="index-topbar-forLogin" (click)="toPage('login')">登录</a>
|
|
||||||
</div>
|
|
||||||
<div class="registration">
|
|
||||||
<a class="headerButton" style="border-radius: 8px;color: white" (click)="toPage('registration')">注册</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { HeaderComponent } from './header.component';
|
|
||||||
|
|
||||||
describe('HeaderComponent', () => {
|
|
||||||
let component: HeaderComponent;
|
|
||||||
let fixture: ComponentFixture<HeaderComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ HeaderComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(HeaderComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {environment} from '../../../environments/environment';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-header',
|
|
||||||
templateUrl: './header.component.html',
|
|
||||||
styleUrls: ['./header.component.css']
|
|
||||||
})
|
|
||||||
export class HeaderComponent implements OnInit {
|
|
||||||
|
|
||||||
|
|
||||||
constructor(public userService: UserService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 菜单是否可见
|
|
||||||
public visible: boolean = false;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
}
|
|
||||||
|
|
||||||
logout() {
|
|
||||||
this.userService.logout();
|
|
||||||
window.location.href = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
toPage(path: string) {
|
|
||||||
window.location.href = path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
.dashboardUl {
|
|
||||||
width: 100%;
|
|
||||||
padding: 1.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboardUl i {
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboardUl li {
|
|
||||||
float: left;
|
|
||||||
border-right: 1px solid #ececec;
|
|
||||||
width: 25%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboardUl li:last-child {
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle {
|
|
||||||
border-radius: 50%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log {
|
|
||||||
margin-top: 20px;
|
|
||||||
max-height: 500px;
|
|
||||||
padding: 10px;
|
|
||||||
background: #F8F8F8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reloadLog {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
top: 10px;
|
|
||||||
z-index: 990;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card i {
|
|
||||||
font-size: 40px;
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<!-- content start -->
|
|
||||||
<div class="admin-content" id="index">
|
|
||||||
<div class="admin-content-body" *ngIf="userService.userInfo&&userService.userInfo.role=='user'">
|
|
||||||
<div>
|
|
||||||
<div><strong class="part-title">首页</strong></div>
|
|
||||||
</div>
|
|
||||||
<h2 style="text-align: center;">
|
|
||||||
Welcome {{userService.userInfo.displayName}}!
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<nz-card class="card">
|
|
||||||
<ul class="dashboardUl">
|
|
||||||
<li style="width: 50%">
|
|
||||||
<div><i nz-icon nzType="login" nzTheme="outline"></i></div>
|
|
||||||
<p>上次登录</p>
|
|
||||||
<p>{{userService.userInfo.recentlyLandedDate}}</p>
|
|
||||||
</li>
|
|
||||||
<li style="width: 50%">
|
|
||||||
<div><i nz-icon nzType="environment" nzTheme="outline"></i></div>
|
|
||||||
<p>您的ip和位置</p>
|
|
||||||
<p>
|
|
||||||
ip:{{ip}}
|
|
||||||
<br>
|
|
||||||
位置:{{location}}
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- administrator page -->
|
|
||||||
<div *ngIf="userService.userInfo&&userService.userInfo.role=='admin'">
|
|
||||||
<nz-card>
|
|
||||||
<ul class="dashboardUl">
|
|
||||||
<li>
|
|
||||||
<div><i nz-icon nzType="ie" nzTheme="outline"></i></div>
|
|
||||||
<p>总访问量</p>
|
|
||||||
<p>{{visitorService.totalVisitCount}}</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div><i nz-icon nzType="chrome" nzTheme="outline"></i></div>
|
|
||||||
<p>今日访问量</p>
|
|
||||||
<p>{{visitorService.dayVisit}}</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div><i nz-icon nzType="login" nzTheme="outline"></i></div>
|
|
||||||
<p>上次登录</p>
|
|
||||||
<p>{{userService.userInfo.recentlyLandedDate}}</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<div><i nz-icon nzType="arrow-up" nzTheme="outline"></i></div>
|
|
||||||
<p>上次更新</p>
|
|
||||||
<p>{{webUpdateService.lastestUpdateTime}}</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-card>
|
|
||||||
|
|
||||||
<div style="position: relative">
|
|
||||||
<button nz-button nzType="danger" nzShape="circle" class="reloadLog" (click)="readLog()">
|
|
||||||
<i nz-icon nzType="reload" nzTheme="outline"></i>
|
|
||||||
</button>
|
|
||||||
<nz-spin [nzSpinning]="Loading">
|
|
||||||
<pre class="log">
|
|
||||||
{{this.logService.logText}}
|
|
||||||
</pre>
|
|
||||||
</nz-spin>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- content end -->
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { AIndexComponent } from './a-index.component';
|
|
||||||
|
|
||||||
describe('AIndexComponent', () => {
|
|
||||||
let component: AIndexComponent;
|
|
||||||
let fixture: ComponentFixture<AIndexComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ AIndexComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(AIndexComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {VisitorService} from '../../services/visitor/visitor.service';
|
|
||||||
import {WebUpdateService} from '../../services/update/web-update.service';
|
|
||||||
import {LogService} from '../../services/log/log.service';
|
|
||||||
import {Observable} from 'rxjs';
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-a-index',
|
|
||||||
templateUrl: './a-index.component.html',
|
|
||||||
styleUrls: ['./a-index.component.css']
|
|
||||||
})
|
|
||||||
export class AIndexComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public userService: UserService,
|
|
||||||
public visitorService: VisitorService,
|
|
||||||
public webUpdateService: WebUpdateService,
|
|
||||||
public logService: LogService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading: boolean = false;
|
|
||||||
ip: string;
|
|
||||||
location: string;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
if (this.userService.userInfo) {
|
|
||||||
if (this.userService.userInfo.role === 'admin') {
|
|
||||||
this.admin();
|
|
||||||
} else {
|
|
||||||
this.user();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.userService.getUserInfo().subscribe(data => {
|
|
||||||
if (data.result.role === 'admin') {
|
|
||||||
this.admin();
|
|
||||||
} else {
|
|
||||||
this.user();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
admin() {
|
|
||||||
if (!this.visitorService.dayVisit) {
|
|
||||||
this.visitorService.getDayVisitor();
|
|
||||||
}
|
|
||||||
this.visitorService.getTotalVisitorCount();
|
|
||||||
if (!this.webUpdateService.lastestUpdateTime) {
|
|
||||||
this.webUpdateService.getLastestUpdateTime();
|
|
||||||
}
|
|
||||||
this.readLog();
|
|
||||||
}
|
|
||||||
|
|
||||||
user() {
|
|
||||||
this.visitorService.getLocalIp().subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.ip = data.result;
|
|
||||||
const getip = this.visitorService.getIp(this.ip);
|
|
||||||
if (getip instanceof Observable) {
|
|
||||||
getip.subscribe(ipOb => {
|
|
||||||
this.location = ipOb.result;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.location = getip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
readLog() {
|
|
||||||
this.Loading = true;
|
|
||||||
this.logService.getLog().subscribe(date => {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.Loading = false;
|
|
||||||
}, 100);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
|
|
||||||
.popup-content {
|
|
||||||
text-align: center;
|
|
||||||
height: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<!--文章管理-->
|
|
||||||
|
|
||||||
<div class="admin-content" id="article-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<div><strong class="part-title">文章管理</strong></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="scrollable-horizontal" *ngIf="articleService.currentPage">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>标题</th>
|
|
||||||
<th>发布日期</th>
|
|
||||||
<th>更新日期</th>
|
|
||||||
<th>阅读量</th>
|
|
||||||
<th title="(可见/不可见)勾选则可见,否则不可见">文章状态</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let article of articleService.currentPage.list">
|
|
||||||
<td>{{article.id}}</td>
|
|
||||||
<td><a [routerLink]="[ '/article']" [queryParams]="{'id':article.id}">{{article.title}}</a>
|
|
||||||
</td>
|
|
||||||
<td>{{article.publishDateFormat}}</td>
|
|
||||||
<td>{{article.updateDateFormat}}</td>
|
|
||||||
<td><span class="badge badge-success">{{article.readingNumber}}</span></td>
|
|
||||||
<td style="text-align: center">
|
|
||||||
<input type="checkbox" class="disabled" disabled [checked]="article.open"
|
|
||||||
[title]="article.open?'可见':'不可见'">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a [href]="'../write?id='+article.id">
|
|
||||||
<i nz-icon nzType="edit" nzTheme="twotone" nzTwotoneColor="#52c41a"></i> 编辑
|
|
||||||
</a>
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzPlacement="bottomLeft" nzTrigger="click">
|
|
||||||
更多 <i nz-icon nzType="down" nzTheme="outline"></i>
|
|
||||||
</a>
|
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
|
||||||
|
|
||||||
|
|
||||||
<ul nz-menu nzSelectable>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a [href]="'../article/'+article.id">
|
|
||||||
<i nz-icon nzType="file" nzTheme="twotone" nzTwotoneColor="#3F66FF"></i> 查看
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a nz-popconfirm [nzTitle]="'是否要删除'+article.title+'?'"
|
|
||||||
(nzOnConfirm)="doDel(article.id)">
|
|
||||||
<i nz-icon nzType="delete" nzTheme="twotone" nzTwotoneColor="#eb2f96"></i> 删除
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<nz-pagination align="center" [nzHideOnSinglePage]="true" [nzPageIndex]="pageNum" [nzPageSize]="pageSize"
|
|
||||||
[nzTotal]="articleService.currentPage.total"
|
|
||||||
(nzPageIndexChange)="toPage($event)">
|
|
||||||
</nz-pagination>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ArticleManagerComponent } from './article-manager.component';
|
|
||||||
|
|
||||||
describe('ArticleManagerComponent', () => {
|
|
||||||
let component: ArticleManagerComponent;
|
|
||||||
let fixture: ComponentFixture<ArticleManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ ArticleManagerComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(ArticleManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {ArticleService} from '../../services/article/article.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-article-manager',
|
|
||||||
templateUrl: './article-manager.component.html',
|
|
||||||
styleUrls: ['./article-manager.component.css']
|
|
||||||
})
|
|
||||||
export class ArticleManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(private message: NzMessageService,
|
|
||||||
public articleService: ArticleService) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public pageNum = 1;
|
|
||||||
|
|
||||||
public pageSize = 10;
|
|
||||||
|
|
||||||
showPupup = false;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
this.articleService.getArticle(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
doDel(id) {
|
|
||||||
this.showPupup = false;
|
|
||||||
this.articleService.deleteArticle(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('删除成功');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toPage(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
a{
|
|
||||||
padding: 10px 0;
|
|
||||||
z-index: 5;
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
<!--分类-->
|
|
||||||
<div class="admin-content" id="category-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<strong class="part-title">分类管理</strong>
|
|
||||||
<button nz-button nzGhost="true" nzType="primary" style="margin-left: 30px" (click)="addNewOne()">新增分类
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="scrollable-horizontal" *ngIf="categoryService.categories">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>分类名称</th>
|
|
||||||
<th>分类文章</th>
|
|
||||||
<th>文章数目</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let category of categoryService.categories">
|
|
||||||
<td>{{category.id}}</td>
|
|
||||||
<td class="text-truncate" style="max-width: 150px">{{category.name}}</td>
|
|
||||||
<td>{{category.articles}}</td>
|
|
||||||
<td><span class="badge badge-success">{{category.articles.split(",").length - 1}}</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<a [href]="'../category?name='+category.name">
|
|
||||||
<i nz-icon nzType="book" nzTheme="twotone"></i> 查看
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzPlacement="bottomLeft" nzTrigger="click">
|
|
||||||
更多 <i nz-icon nzType="down" nzTheme="outline"></i>
|
|
||||||
</a>
|
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
|
||||||
<ul nz-menu nzSelectable>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a class="btn btn-secondary " (click)="edit(category.id,category.name)">编辑</a>
|
|
||||||
</li>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这个分类?" (nzOnConfirm)="doDel(category.id)">删除
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="编辑" (nzOnCancel)="cancel()" (nzOnOk)="submit()">
|
|
||||||
<input nz-input style="width: 80%;margin-left: 10%" [(ngModel)]="updateReqBody.name">
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { CategoryManagerComponent } from './category-manager.component';
|
|
||||||
|
|
||||||
describe('CategoryManagerComponent', () => {
|
|
||||||
let component: CategoryManagerComponent;
|
|
||||||
let fixture: ComponentFixture<CategoryManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ CategoryManagerComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(CategoryManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {CategoryService} from '../../services/category/category.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-category-manager',
|
|
||||||
templateUrl: './category-manager.component.html',
|
|
||||||
styleUrls: ['./category-manager.component.css']
|
|
||||||
})
|
|
||||||
export class CategoryManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public categoryService: CategoryService, private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
showPupup = false;
|
|
||||||
|
|
||||||
updateReqBody = {
|
|
||||||
id: null,
|
|
||||||
name: null
|
|
||||||
};
|
|
||||||
isAddNowOne = false; // 是否是新增分类的标识
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
if (this.categoryService.categories) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.categoryService.getAllCategory();
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(id, name) {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.updateReqBody.id = id;
|
|
||||||
this.updateReqBody.name = name;
|
|
||||||
this.isAddNowOne = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
|
||||||
if (this.updateReqBody.name === '') {
|
|
||||||
alert('不能修改为空值!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showPupup = false;
|
|
||||||
if (!this.isAddNowOne) {
|
|
||||||
// 更新
|
|
||||||
this.categoryService.update(this.updateReqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('修改成功');
|
|
||||||
for (let i = 0; i < this.categoryService.categories.length; i++) {
|
|
||||||
if ( this.categoryService.categories[i].id === this.updateReqBody.id) {
|
|
||||||
this.categoryService.categories[i].name = this.updateReqBody.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.message.error('修改失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 新建
|
|
||||||
this.categoryService.create(this.updateReqBody.name).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('新增成功');
|
|
||||||
} else {
|
|
||||||
this.message.error('新增失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
doDel(id) {
|
|
||||||
|
|
||||||
this.categoryService.delete(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('删除成功');
|
|
||||||
} else {
|
|
||||||
this.message.error('删除失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addNewOne() {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.updateReqBody.name = name;
|
|
||||||
this.isAddNowOne = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.showPupup = !this.showPupup;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
.modal-mask {
|
|
||||||
background: black;
|
|
||||||
opacity: 0.4;
|
|
||||||
position: absolute;
|
|
||||||
overflow: hidden;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment {
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
<!--评论管理-->
|
|
||||||
<div class="admin-content" id="comment-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
|
|
||||||
<div><strong class="part-title">评论管理</strong>
|
|
||||||
<select class="select" [(ngModel)]="commentType" (change)="doInquire()">
|
|
||||||
<option class="option" selected value="1">评论</option>
|
|
||||||
<option class="option" value="0">留言</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 评论 -->
|
|
||||||
<div *ngIf="commentType==1&&commentService.currentComment">
|
|
||||||
<div class="scrollable-horizontal">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>文章标题</th>
|
|
||||||
<th>评论内容</th>
|
|
||||||
<th>评论日期</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let comment of commentService.currentComment.list">
|
|
||||||
<td>{{comment.id}}</td>
|
|
||||||
<td class="text-truncate" [title]="comment.articleID+'.'+comment.articleTitle">
|
|
||||||
<a [routerLink]="[ '/article']"
|
|
||||||
[queryParams]="{'id':comment.articleID}">{{comment.articleTitle}}</a>
|
|
||||||
</td>
|
|
||||||
<td [title]="comment.content">
|
|
||||||
<span>{{comment.content.length > 40 ? (comment.content.substr(0, 40) + '...') : comment.content}}</span>
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a style="float: right;clear: both" (click)="prepareComment(comment)">查看</a>
|
|
||||||
</td>
|
|
||||||
<td>{{comment.date}}</td>
|
|
||||||
<td>
|
|
||||||
<a (click)="edit(0,comment.id,comment.content)">
|
|
||||||
<i nz-icon nzType="edit" nzTheme="twotone" nzTwotoneColor="#52c41a"></i> 编辑
|
|
||||||
</a>
|
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzPlacement="bottomLeft" nzTrigger="click">
|
|
||||||
更多 <i nz-icon nzType="down" nzTheme="outline"></i>
|
|
||||||
</a>
|
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
|
||||||
<ul nz-menu nzSelectable>
|
|
||||||
<!-- <li nz-menu-item>-->
|
|
||||||
<!-- <a disabled="true">回复</a>-->
|
|
||||||
<!-- </li>-->
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这条评论?"
|
|
||||||
(nzOnConfirm)="doDel(comment.id)">删除
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<nz-pagination align="center" [nzHideOnSinglePage]="true" [nzPageIndex]="pageNum"
|
|
||||||
[nzTotal]="commentService.currentComment.total"
|
|
||||||
[nzPageSize]="pageSize" (nzPageIndexChange)="toPage($event)">
|
|
||||||
</nz-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 留言 -->
|
|
||||||
<div *ngIf="commentType==0&&commentService.currentLeaveMsg">
|
|
||||||
<div class=" scrollable-horizontal">
|
|
||||||
<table class="table ">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>留言者</th>
|
|
||||||
<th>留言内容</th>
|
|
||||||
<th>留言日期</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let leaveMsg of commentService.currentLeaveMsg.list">
|
|
||||||
<td>{{leaveMsg.id}}</td>
|
|
||||||
<td>{{leaveMsg.authorName}}</td>
|
|
||||||
<td [title]="leaveMsg.content">
|
|
||||||
<span>{{leaveMsg.content.length > 40 ? (leaveMsg.content.substr(0, 40) + '...') : leaveMsg.content}}</span>
|
|
||||||
<a style="float: right;clear: both" (click)="prepareComment(leaveMsg)">查看</a>
|
|
||||||
</td>
|
|
||||||
<td>{{leaveMsg.date}}</td>
|
|
||||||
<td>
|
|
||||||
<a (click)="edit(1,leaveMsg.id,leaveMsg.content)">
|
|
||||||
<i nz-icon nzType="edit" nzTheme="twotone" nzTwotoneColor="#52c41a"></i> 编辑
|
|
||||||
</a>
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzPlacement="bottomLeft" nzTrigger="click">
|
|
||||||
更多 <i nz-icon nzType="down" nzTheme="outline"></i>
|
|
||||||
</a>
|
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
|
||||||
<ul nz-menu nzSelectable>
|
|
||||||
<!-- <li nz-menu-item>-->
|
|
||||||
<!-- <a disabled="true">回复</a>-->
|
|
||||||
<!-- </li>-->
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这条留言?"
|
|
||||||
(nzOnConfirm)="doDel(leaveMsg.id)">删除
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<nz-pagination align="center" [nzHideOnSinglePage]="true" [nzPageIndex]="pageNum"
|
|
||||||
[nzTotal]="commentService.currentLeaveMsg.total"
|
|
||||||
[nzPageSize]="pageSize" (nzPageIndexChange)="toPage($event)">
|
|
||||||
</nz-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 带输入框的弹出层 -->
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="编辑" (nzOnCancel)="showPupup=!showPupup" (nzOnOk)="update()">
|
|
||||||
|
|
||||||
<textarea nz-input [(ngModel)]="updateReqBody.content"
|
|
||||||
[nzAutosize]="{ minRows: 2, maxRows: 6 }"></textarea>
|
|
||||||
|
|
||||||
</nz-modal>
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showCommentDetail" (nzOnCancel)="showCommentDetail=!showCommentDetail"
|
|
||||||
(nzOnOk)="showCommentDetail=!showCommentDetail">
|
|
||||||
<nz-comment [nzAuthor]="commentDetail.authorName"
|
|
||||||
[nzDatetime]="commentDetail.date">
|
|
||||||
<nz-avatar nz-comment-avatar nzIcon="user" [nzSrc]="commentDetail.authorAvatarImgUrl"></nz-avatar>
|
|
||||||
<nz-comment-content class="comment">
|
|
||||||
<p>{{commentDetail.content}}</p>
|
|
||||||
</nz-comment-content>
|
|
||||||
|
|
||||||
<ng-container *ngIf="commentDetail.child && commentDetail.child.length">
|
|
||||||
<nz-comment *ngFor="let secLeaveMsg of commentDetail.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>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<nz-comment>
|
|
||||||
<nz-comment-content>
|
|
||||||
<nz-form-item>
|
|
||||||
<textarea [(ngModel)]="responseComment.content" nz-input
|
|
||||||
[nzAutosize]="{ minRows: 2, maxRows: 6 }"></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-modal>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { CommentManagerComponent } from './comment-manager.component';
|
|
||||||
|
|
||||||
describe('CommentManagerComponent', () => {
|
|
||||||
let component: CommentManagerComponent;
|
|
||||||
let fixture: ComponentFixture<CommentManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ CommentManagerComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(CommentManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {CommentService} from '../../services/comment/comment.service';
|
|
||||||
import {Comment} from '../../classes/comment';
|
|
||||||
import {CommentReq} from '../../classes/commentReq';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-comment-manager',
|
|
||||||
templateUrl: './comment-manager.component.html',
|
|
||||||
styleUrls: ['./comment-manager.component.css']
|
|
||||||
})
|
|
||||||
export class CommentManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public userService: UserService,
|
|
||||||
public commentService: CommentService,
|
|
||||||
private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
pageSize: number = 10;
|
|
||||||
|
|
||||||
commentType: number = 0;
|
|
||||||
|
|
||||||
showPupup = false;
|
|
||||||
|
|
||||||
updateReqBody = {
|
|
||||||
id: null,
|
|
||||||
type: null,
|
|
||||||
content: null
|
|
||||||
};
|
|
||||||
showCommentDetail: boolean = false;
|
|
||||||
commentDetail: Comment = new Comment();
|
|
||||||
|
|
||||||
responseComment: CommentReq = new CommentReq(true);
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
if (!this.userService.userInfo) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.doInquire();
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
this.doInquire();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doInquire() {
|
|
||||||
const isAdmin: boolean = this.userService.userInfo.role === 'admin';
|
|
||||||
if (this.commentType) {
|
|
||||||
this.commentService.getComments(this.pageNum, this.pageSize, isAdmin);
|
|
||||||
} else {
|
|
||||||
this.commentService.getLeaveMsg(this.pageNum, this.pageSize, isAdmin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toPage(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.doInquire();
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareComment(comment: Comment) {
|
|
||||||
this.showCommentDetail = true;
|
|
||||||
this.commentDetail = comment;
|
|
||||||
this.commentService.getByPid(comment.id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.commentDetail.child = data.result.list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// tslint:disable-next-line:triple-equals
|
|
||||||
this.responseComment.comment = this.commentType == 1;
|
|
||||||
// 若展示的是顶级评论 则pid为顶级评论的id 否则为该二级评论的pid
|
|
||||||
this.responseComment.pid = this.commentDetail.pid === -1 ? this.commentDetail.id : this.commentDetail.pid;
|
|
||||||
this.responseComment.articleID = this.commentDetail.articleID;
|
|
||||||
console.log(`${this.commentType.valueOf() == 1} and type is ${this.commentType}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(type, id, content) {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.updateReqBody.id = id;
|
|
||||||
this.updateReqBody.type = type;
|
|
||||||
this.updateReqBody.content = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
if (this.updateReqBody.content === '') {
|
|
||||||
this.message.warning('不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showPupup = false;
|
|
||||||
this.commentService.update(this.updateReqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('修改成功!');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
doDel(id) {
|
|
||||||
this.commentService.delete(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('删除成功');
|
|
||||||
} else {
|
|
||||||
this.message.error('删除失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
reply() {
|
|
||||||
if (this.responseComment.content == null || this.responseComment.content === '') {
|
|
||||||
this.message.info('内容不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.responseComment.content = `@${this.commentDetail.authorName} ${this.responseComment.content}`
|
|
||||||
this.commentService.rely(this.responseComment).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.commentDetail.child.push(data.result);
|
|
||||||
this.message.success('回复成功');
|
|
||||||
this.responseComment = new CommentReq(true);
|
|
||||||
// tslint:disable-next-line:triple-equals
|
|
||||||
if (this.commentType == 1) {
|
|
||||||
this.commentService.currentComment.list.push(data.result);
|
|
||||||
} else {
|
|
||||||
this.commentService.currentLeaveMsg.list.push(data.result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<div class="admin-content" id="links-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<strong class="part-title">友链管理</strong>
|
|
||||||
<button nz-button nzType="primary" nzGhost="true" style="margin-left: 30px;" (click)="add()">新增</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class=" scrollable-horizontal" *ngIf="linkService.currentPage">
|
|
||||||
<table class="table ">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>友链名称</th>
|
|
||||||
<th>友链链接</th>
|
|
||||||
<th>状态</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let link of linkService.currentPage.list">
|
|
||||||
<td>{{link.id}}</td>
|
|
||||||
<td class="text-truncate" style="max-width: 150px" [title]="link.name">{{link.name}}</td>
|
|
||||||
<td><a [href]="link.url" target="_blank">{{link.url}}</a></td>
|
|
||||||
<td><input type="checkbox" [checked]="link.open" disabled="disabled"></td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a (click)="edit(link)">编辑</a>
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这条友链?" (nzOnConfirm)="doDel(link.id)">删除</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
<nz-pagination align="center" [nzPageIndex]="pageNum" [nzHideOnSinglePage]="true"
|
|
||||||
[nzTotal]="linkService.currentPage.total" [nzPageSize]="pageSize"
|
|
||||||
(nzPageIndexChange)="toPage($event)"></nz-pagination>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 带输入框的弹出层 -->
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="友链编辑" (nzOnCancel)="showPupup=!showPupup" (nzOnOk)="update()">
|
|
||||||
<label style="margin-left: 10%;">网站名称:</label>
|
|
||||||
<input nz-input style="width: 80%;margin-left: 10%" [(ngModel)]="updateReqBody.name">
|
|
||||||
<label style="margin-left: 10%;">网站链接:</label>
|
|
||||||
<input nz-input style="width: 80%;margin-left: 10%" [(ngModel)]="updateReqBody.url">
|
|
||||||
<label style="margin-left: 10%;">是否公开显示:</label>
|
|
||||||
<select [(ngModel)]="updateReqBody.open">
|
|
||||||
<option value="">请选择</option>
|
|
||||||
<option value="true">显示</option>
|
|
||||||
<option value="false">不显示</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { LinksManagerComponent } from './links.component';
|
|
||||||
|
|
||||||
describe('LinksComponent', () => {
|
|
||||||
let component: LinksManagerComponent;
|
|
||||||
let fixture: ComponentFixture<LinksManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [LinksManagerComponent]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(LinksManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {LinkService} from '../../services/link/link.service';
|
|
||||||
import {Link} from '../../classes/link';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-links',
|
|
||||||
templateUrl: './links.component.html',
|
|
||||||
styleUrls: ['./links.component.css']
|
|
||||||
})
|
|
||||||
export class LinksManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public linkService: LinkService, private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
pageSize: number = 10;
|
|
||||||
|
|
||||||
showPupup = false;
|
|
||||||
|
|
||||||
updateReqBody = new Link();
|
|
||||||
|
|
||||||
isUpdate;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
this.linkService.getLinks(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
toPage(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(link) {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.updateReqBody = link;
|
|
||||||
this.isUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
if (this.updateReqBody.name === '') {
|
|
||||||
this.message.warning('友链名称不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.updateReqBody.url === '') {
|
|
||||||
this.message.warning('友链链接不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
// tslint:disable-next-line:triple-equals
|
|
||||||
if (this.updateReqBody.open == '') {
|
|
||||||
this.message.warning('友链状态不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showPupup = false;
|
|
||||||
if (this.isUpdate) {
|
|
||||||
this.linkService.update(this.updateReqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('更新成功');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('更新失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
this.updateReqBody.name = null;
|
|
||||||
this.updateReqBody.url = null;
|
|
||||||
this.updateReqBody.open = null;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.linkService.create(this.updateReqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('新增成功');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('新增失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
this.updateReqBody.name = null;
|
|
||||||
this.updateReqBody.url = null;
|
|
||||||
this.updateReqBody.open = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add() {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.isUpdate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
doDel(id) {
|
|
||||||
this.linkService.delete(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('删除成功!');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('删除失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
#publishArticle{
|
|
||||||
width: 100%;
|
|
||||||
height: 32px;
|
|
||||||
border-bottom-left-radius: 10px;
|
|
||||||
border-bottom-right-radius: 10px;
|
|
||||||
border: none;
|
|
||||||
background: turquoise;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
<!--标签-->
|
|
||||||
<div class="admin-content" id="tag-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<div><strong class="part-title">标签管理</strong></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="g">
|
|
||||||
<div class="scrollable-horizontal" *ngIf="tagService.currentTagPage">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>标签名称</th>
|
|
||||||
<th>标签文章</th>
|
|
||||||
<th>文章数目</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let tag of tagService.currentTagPage.list">
|
|
||||||
<td>{{tag.id}}</td>
|
|
||||||
<td class="text-truncate" style="max-width: 150px" [title]="tag.name">{{tag.name}}</td>
|
|
||||||
<td>{{tag.articles}}</td>
|
|
||||||
<td><span class="badge badge-success">{{tag.articles.split(',').length - 1}}</span></td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
<a [href]="'../tag?name='+tag.name">
|
|
||||||
<i nz-icon nzType="tag" nzTheme="twotone"></i> 查看
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-dropdown [nzDropdownMenu]="menu" nzPlacement="bottomLeft" nzTrigger="click">
|
|
||||||
更多 <i nz-icon nzType="down" nzTheme="outline"></i>
|
|
||||||
</a>
|
|
||||||
<nz-dropdown-menu #menu="nzDropdownMenu">
|
|
||||||
<ul nz-menu nzSelectable>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a (click)="edit(tag.id,tag.name)">编辑</a>
|
|
||||||
</li>
|
|
||||||
<li nz-menu-item>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这条标签?" (nzOnConfirm)="doDel(tag.id)">删除</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nz-dropdown-menu>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<nz-pagination align="center" [nzPageIndex]="pageNum" [nzHideOnSinglePage]="true"
|
|
||||||
[nzTotal]="tagService.currentTagPage.total" [nzPageSize]="pageSize"
|
|
||||||
(nzPageIndexChange)="toPage($event)"></nz-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 带输入框的弹出层 -->
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="编辑" (nzOnCancel)="showPupup=!showPupup" (nzOnOk)="update()">
|
|
||||||
<input class="select" style="width: 80%;margin-left: 10%" [(ngModel)]="updateReqBody.name">
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {TagService} from '../../services/tag/tag.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-tag-manager',
|
|
||||||
templateUrl: './tag-manager.component.html',
|
|
||||||
styleUrls: ['./tag-manager.component.css']
|
|
||||||
})
|
|
||||||
export class TagManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public tagService: TagService, private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
|
|
||||||
pageSize: number = 10;
|
|
||||||
|
|
||||||
showPupup: boolean = false;
|
|
||||||
|
|
||||||
updateReqBody = {
|
|
||||||
id: null,
|
|
||||||
name: null
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
this.tagService.getTags(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
toPage(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
edit(id, name) {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.updateReqBody.id = id;
|
|
||||||
this.updateReqBody.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
if (this.updateReqBody.name === '') {
|
|
||||||
this.message.warning('不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.showPupup = false;
|
|
||||||
this.tagService.update(this.updateReqBody.id, this.updateReqBody.name).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('修改成功!');
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
doDel(id) {
|
|
||||||
this.tagService.delete(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('删除成功');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error(`删除失败,原因:${data.msg}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<div class="admin-content" id="tag-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<strong class="part-title">更新管理</strong>
|
|
||||||
<button nz-button nzType="primary" nzGhost="true" style="margin-left: 30px;" (click)="add()">新增</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class=" scrollable-horizontal" *ngIf="updateService.updateInfoList">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>更新内容</th>
|
|
||||||
<th>更新日期</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let update of updateService.updateInfoList.list">
|
|
||||||
<td>{{update.id}}</td>
|
|
||||||
<td style="max-width: 150px" nz-tooltip [nzTitle]="update.info">
|
|
||||||
{{update.info.length > 20 ? update.info.substr(0, 20) + '...' : update.info}}
|
|
||||||
</td>
|
|
||||||
<td>{{update.time}}</td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<a (click)="edit(update)">编辑</a>
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这条更新?" (nzOnConfirm)="doDel(update.id)">删除</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<nz-pagination align="center" [nzPageIndex]="pageNum" [nzHideOnSinglePage]="true"
|
|
||||||
[nzTotal]="updateService.updateInfoList.total"
|
|
||||||
[nzPageSize]="pageSize" (nzPageIndexChange)="toPage($event)"></nz-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 带输入框的弹出层 -->
|
|
||||||
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="编辑" (nzOnCancel)="showPupup=!showPupup" (nzOnOk)="submit()">
|
|
||||||
<label style="margin-left: 10%;margin-bottom: 10px">更新内容:</label>
|
|
||||||
<textarea nz-input style="width: 80%;margin-left: 10%; height: 100px;"
|
|
||||||
[(ngModel)]="updateReqBody.info" placeholder="更新内容"
|
|
||||||
[nzAutosize]="{ minRows: 2, maxRows: 6 }"></textarea>
|
|
||||||
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { UpdateManagerComponent } from './update.component';
|
|
||||||
|
|
||||||
describe('UpdateComponent', () => {
|
|
||||||
let component: UpdateManagerComponent;
|
|
||||||
let fixture: ComponentFixture<UpdateManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [UpdateManagerComponent]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(UpdateManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {WebUpdateService} from '../../services/update/web-update.service';
|
|
||||||
import {UpdateInfo} from "../../classes/updateInfo";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-update',
|
|
||||||
templateUrl: './update.component.html',
|
|
||||||
styleUrls: ['./update.component.css']
|
|
||||||
})
|
|
||||||
export class UpdateManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public updateService: WebUpdateService, private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
isUpdate = false;
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
pageSize: number = 10;
|
|
||||||
|
|
||||||
showPupup = false;
|
|
||||||
|
|
||||||
updateReqBody = new UpdateInfo();
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
getData() {
|
|
||||||
this.updateService.getUpdateInfo(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
toPage(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(link) {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.updateReqBody = link;
|
|
||||||
this.isUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
submit() {
|
|
||||||
if (this.updateReqBody.info === '') {
|
|
||||||
this.message.warning('更新内容不能为空');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showPupup = false;
|
|
||||||
if (this.isUpdate) {
|
|
||||||
this.updateService.update(this.updateReqBody).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('更新成功');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('更新失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.updateReqBody.id = null;
|
|
||||||
this.updateService.create(this.updateReqBody.info).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('新增成功');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('新增失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.updateReqBody.id = null;
|
|
||||||
this.updateReqBody.info = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
add() {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.isUpdate = false;
|
|
||||||
this.updateReqBody.id = null;
|
|
||||||
this.updateReqBody.info = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
doDel(id: number) {
|
|
||||||
this.updateService.delete(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('删除成功!');
|
|
||||||
this.getData();
|
|
||||||
} else {
|
|
||||||
this.message.error('删除失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
.label {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.4em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: 200px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
background: #eeeeee;
|
|
||||||
height: 30px;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#user-gender input {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit {
|
|
||||||
width: 80%;
|
|
||||||
margin-left: 10%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#avatar {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
top: 30%;
|
|
||||||
border: 1px solid #999999;
|
|
||||||
border-radius: 1px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#avatarimg {
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#info {
|
|
||||||
width: 350px;
|
|
||||||
position: relative;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
#info i {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#info .sendEmail {
|
|
||||||
position: absolute;
|
|
||||||
margin-top: 3px;
|
|
||||||
top: 0;
|
|
||||||
right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#info input {
|
|
||||||
width: 90%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<!--修改信息-->
|
|
||||||
<div class="admin-content" id="user-info">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<div><strong class="part-title">个人资料</strong> /
|
|
||||||
<small>Personal information</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
|
|
||||||
<div id="info">
|
|
||||||
<i nz-icon nzType="mail" nzTheme="twotone"></i>
|
|
||||||
<input nz-input [(ngModel)]="user.email" style="display: inline" [disabled]="true"/>
|
|
||||||
<button *ngIf="!user.emailStatus" nz-button nzType="primary" class="sendEmail" (click)="sendEmail()"
|
|
||||||
[title]="'发生邮件到'+user.email+'中'" [disabled]="!clickable">
|
|
||||||
发送激活邮件
|
|
||||||
</button>
|
|
||||||
<br>
|
|
||||||
<i nz-icon nzType="info-circle" nzTheme="twotone"></i>
|
|
||||||
<input nz-input type="text" placeholder="用一句话来描述自己吧" name="desc" id="desc" [(ngModel)]="user.desc">
|
|
||||||
<br>
|
|
||||||
<i nz-icon nzType="crown" nzTheme="twotone"></i>
|
|
||||||
<input nz-input type="text" placeholder="昵称" name="displayName" id="displayName"
|
|
||||||
[(ngModel)]="user.displayName">
|
|
||||||
<br>
|
|
||||||
<button nz-button nzType="primary" nzGhost="true" [nzBlock]="true" (click)="userInfoSubmit()">提交</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="avatar">
|
|
||||||
<h3><strong>头像</strong></h3>
|
|
||||||
<div>
|
|
||||||
<img id="avatarimg" [src]="user.avatarImgUrl" alt="avatar">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<nz-upload [nzAction]="host+'/user/imgUpload'" nzWithCredentials="true" nzLimit="1" nzSize="2048"
|
|
||||||
(nzChange)="avatarUpload($event)">
|
|
||||||
<button nz-button><i nz-icon nzType="upload"></i><span>选择图片上传</span></button>
|
|
||||||
</nz-upload>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { UserInfoComponent } from './user-info.component';
|
|
||||||
|
|
||||||
describe('UserInfoComponent', () => {
|
|
||||||
let component: UserInfoComponent;
|
|
||||||
let fixture: ComponentFixture<UserInfoComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ UserInfoComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(UserInfoComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {User} from '../../classes/user';
|
|
||||||
import {environment} from '../../../environments/environment';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-user-info',
|
|
||||||
templateUrl: './user-info.component.html',
|
|
||||||
styleUrls: ['./user-info.component.css']
|
|
||||||
})
|
|
||||||
export class UserInfoComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public userService: UserService,
|
|
||||||
private message: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
host: string;
|
|
||||||
|
|
||||||
user: User = new User();
|
|
||||||
|
|
||||||
clickable: boolean = true;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
if (!this.userService.userInfo) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.user = this.userService.userInfo;
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
this.user = this.userService.userInfo;
|
|
||||||
}
|
|
||||||
this.host = environment.host;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
userInfoSubmit() {
|
|
||||||
const info = {
|
|
||||||
desc: this.user.desc,
|
|
||||||
displayName: this.user.displayName
|
|
||||||
};
|
|
||||||
this.userService.updateInfo(info).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('修改成功');
|
|
||||||
} else if (data.code === 301) {
|
|
||||||
window.location.href = '/login';
|
|
||||||
} else {
|
|
||||||
this.message.error('修改信息失败,原因:' + data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sendEmail() {
|
|
||||||
this.clickable = false;
|
|
||||||
if (!this.userService.userInfo) {
|
|
||||||
window.location.href = '/login';
|
|
||||||
}
|
|
||||||
this.userService.sendEmail().subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.message.success('发送成功!请前往邮箱进行激活');
|
|
||||||
} else {
|
|
||||||
this.message.error(data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
avatarUpload(info: any) {
|
|
||||||
if (info.type === 'success' && info.file.response.code === 0) {
|
|
||||||
const time = new Date().valueOf();
|
|
||||||
this.userService.userInfo.avatarImgUrl = this.userService.avatarHost + '/' + info.file.response.result;
|
|
||||||
// 加上时间戳 让图片自动预览,避免读取本地缓存而不显示新头像
|
|
||||||
this.user.avatarImgUrl = this.userService.avatarHost + '/' + info.file.response.result + '?time=' + time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
.error {
|
|
||||||
padding-left: 20px;
|
|
||||||
color: red;
|
|
||||||
border: 1px solid #eb2f96;
|
|
||||||
border-radius: 2px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
<!--标签-->
|
|
||||||
<div class="admin-content" id="tag-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<div><strong class="part-title">用户管理</strong></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="g">
|
|
||||||
<div class="scrollable-horizontal" *ngIf="userService.currentUserPage">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>用户邮箱</th>
|
|
||||||
<th>用户昵称</th>
|
|
||||||
<th>用户角色</th>
|
|
||||||
<th>管理</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let user of userService.currentUserPage.list">
|
|
||||||
<td align="center">{{user.id}}</td>
|
|
||||||
<td align="center" class="text-truncate">{{user.email}}</td>
|
|
||||||
<td align="center">{{user.displayName}}</td>
|
|
||||||
<td align="center"><span class="badge badge-success">{{user.role}}</span></td>
|
|
||||||
<td>
|
|
||||||
<a (click)="edit(user)"><i nz-icon nzType="tag" nzTheme="twotone"></i> 编辑</a>
|
|
||||||
<nz-divider nzType="vertical"></nz-divider>
|
|
||||||
<a nz-popconfirm nzTitle="是否要删除这名用户?" (nzOnConfirm)="delete(user.id)">
|
|
||||||
<i nz-icon nzType="delete" nzTheme="twotone" nzTwotoneColor="#eb2f96"></i> 删除</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<nz-pagination align="center" [nzPageIndex]="pageNum" [nzHideOnSinglePage]="true"
|
|
||||||
[nzTotal]="userService.currentUserPage.total" [nzPageSize]="pageSize"
|
|
||||||
(nzPageIndexChange)="toPage($event)"></nz-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!--用户编辑-->
|
|
||||||
<nz-modal [(nzVisible)]="showPupup" nzTitle="编辑" (nzOnCancel)="showPupup=!showPupup" (nzOnOk)="update()">
|
|
||||||
<form action="#">
|
|
||||||
<label for="email">邮箱:</label>
|
|
||||||
<input nz-input type="email" id="email" name="email" [(ngModel)]="editUser.email" (blur)="getEmailStatus()">
|
|
||||||
<ng-template [ngIf]="showError">
|
|
||||||
<span class="error">
|
|
||||||
<i nz-icon nzType="exclamation-circle" nzTheme="twotone" nzTwotoneColor="#eb2f96"></i>
|
|
||||||
邮箱已被占用!
|
|
||||||
</span>
|
|
||||||
</ng-template>
|
|
||||||
<label for="display-name">昵称:</label>
|
|
||||||
<input nz-input type="text" id="display-name" name="display-name" [(ngModel)]="editUser.displayName">
|
|
||||||
<label for="pwd">密码:<span style="font-weight: lighter;font-size: smaller">留空则不重设密码,反之则设置为输入的密码</span></label>
|
|
||||||
<input nz-input type="password" id="pwd" name="pwd" [(ngModel)]="editUser.pwd" placeholder="******">
|
|
||||||
<label for="user-role">角色:</label>
|
|
||||||
<nz-select name="user-role" style="width: 100%" id="user-role"
|
|
||||||
[nzDisabled]="editUser.id==userService.userInfo.id" [(ngModel)]="editUser.role">
|
|
||||||
<nz-option nzValue="user" nzLabel="user"></nz-option>
|
|
||||||
<nz-option nzValue="admin" nzLabel="admin"></nz-option>
|
|
||||||
</nz-select>
|
|
||||||
<label for="email-status">邮箱验证状态:</label>
|
|
||||||
<br>
|
|
||||||
<nz-radio-group name="email-status" id="email-status" [(ngModel)]="editUser.emailStatus">
|
|
||||||
<label nz-radio [nzValue]="true">已验证</label>
|
|
||||||
<label nz-radio [nzValue]="false">未验证</label>
|
|
||||||
</nz-radio-group>
|
|
||||||
<br>
|
|
||||||
<label for="desc">描述:</label>
|
|
||||||
<textarea rows="4" id="desc" name="desc" nz-input [(ngModel)]="editUser.desc"></textarea>
|
|
||||||
</form>
|
|
||||||
</nz-modal>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { UserManagerComponent } from './user-manager.component';
|
|
||||||
|
|
||||||
describe('UserManagerComponent', () => {
|
|
||||||
let component: UserManagerComponent;
|
|
||||||
let fixture: ComponentFixture<UserManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ UserManagerComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(UserManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {UserService} from '../../services/user/user.service';
|
|
||||||
import {User} from '../../classes/user';
|
|
||||||
import {NzMessageService} from 'ng-zorro-antd';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-user-manager',
|
|
||||||
templateUrl: './user-manager.component.html',
|
|
||||||
styleUrls: ['./user-manager.component.css']
|
|
||||||
})
|
|
||||||
export class UserManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public userService: UserService,
|
|
||||||
private messageService: NzMessageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
pageSize: number = 10;
|
|
||||||
showPupup: boolean = false;
|
|
||||||
editUser: User = new User();
|
|
||||||
showError: boolean = false;
|
|
||||||
formerEmail: string;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.userService.getPageUser(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
toPage(e: number) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.userService.getPageUser(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(user: User) {
|
|
||||||
this.showPupup = true;
|
|
||||||
this.showError = false;
|
|
||||||
// 避免引用赋值,采用json进行浅拷贝!!
|
|
||||||
this.editUser = JSON.parse(JSON.stringify(user));
|
|
||||||
this.formerEmail = this.editUser.email;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number) {
|
|
||||||
this.userService.delete(id).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
if (data.result[0].status) {
|
|
||||||
this.messageService.success('删除成功!');
|
|
||||||
this.userService.getPageUser(this.pageNum, this.pageSize);
|
|
||||||
} else {
|
|
||||||
this.messageService.error(`删除失败,原因:${data.result[0].msg}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.messageService.error(`请求失败,原因:${data.msg}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
update() {
|
|
||||||
this.editUser.recentlyLandedDate = null;
|
|
||||||
this.editUser.avatarImgUrl = null;
|
|
||||||
if (this.showError) {
|
|
||||||
this.showPupup = false;
|
|
||||||
this.messageService.warning('邮箱不可用,请修改!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.userService.update(this.editUser).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.messageService.success('修改成功!');
|
|
||||||
if (this.userService.userInfo.id === this.editUser.id) {
|
|
||||||
this.userService.userInfo = this.editUser;
|
|
||||||
}
|
|
||||||
this.userService.getPageUser(this.pageNum, this.pageSize, true);
|
|
||||||
} else {
|
|
||||||
this.messageService.error('修改失败!');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.showPupup = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getEmailStatus() {
|
|
||||||
if (this.editUser.email === this.formerEmail) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.userService.getExistOfEmail(this.editUser.email).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.showError = data.result;
|
|
||||||
} else {
|
|
||||||
this.messageService.error(data.msg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
<!--访问量-->
|
|
||||||
<div class="admin-content" id="visitor-manager">
|
|
||||||
<div class="admin-content-body">
|
|
||||||
<div>
|
|
||||||
<div><strong class="part-title">访问管理</strong>
|
|
||||||
<span>---当日访问量{{visitorService.dayVisit}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="g">
|
|
||||||
<div class="scrollable-horizontal" *ngIf="visitorService.currentPage">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>ip地址</th>
|
|
||||||
<th>访问日期</th>
|
|
||||||
<th>浏览器类型</th>
|
|
||||||
<th>系统</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let visitor of visitorService.currentPage.list">
|
|
||||||
<td>{{visitor.id}}</td>
|
|
||||||
<td>
|
|
||||||
<span (mouseenter)="getIp(visitor.ip)" [title]="location">{{visitor.ip}}</span>
|
|
||||||
<i nz-icon nzType="smile" nzTheme="twotone" nzTwotoneColor="#00DC25"
|
|
||||||
*ngIf="visitor.ip==localIp" style="float: right;clear: both" title="您的访问记录"></i>
|
|
||||||
</td>
|
|
||||||
<td>{{visitor.date}}</td>
|
|
||||||
<td style="text-align: center" [title]="visitor.browserVersion">
|
|
||||||
<span *ngIf="visitor.browserName!='Unknown'"> {{visitor.browserName}}</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span *ngIf="visitor.osname!='Unknown' "> {{visitor.osname}}</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<nz-pagination align="center " [nzPageIndex]="pageNum " [nzHideOnSinglePage]="true "
|
|
||||||
[nzTotal]="visitorService.currentPage.total " [nzPageSize]="pageSize "
|
|
||||||
(nzPageIndexChange)="toPage($event) "></nz-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { VisitorManagerComponent } from './visitor-manager.component';
|
|
||||||
|
|
||||||
describe('VisitorManagerComponent', () => {
|
|
||||||
let component: VisitorManagerComponent;
|
|
||||||
let fixture: ComponentFixture<VisitorManagerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ VisitorManagerComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(VisitorManagerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
import {VisitorService} from '../../services/visitor/visitor.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-visitor-manager',
|
|
||||||
templateUrl: './visitor-manager.component.html',
|
|
||||||
styleUrls: ['./visitor-manager.component.css']
|
|
||||||
})
|
|
||||||
export class VisitorManagerComponent implements OnInit {
|
|
||||||
|
|
||||||
constructor(public visitorService: VisitorService) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pageNum: number = 1;
|
|
||||||
pageSize: number = 10;
|
|
||||||
|
|
||||||
|
|
||||||
localIp = '';
|
|
||||||
|
|
||||||
location: string;
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.getPageData();
|
|
||||||
this.visitorService.getDayVisitor();
|
|
||||||
this.visitorService.getLocalIp().subscribe(data => {
|
|
||||||
this.localIp = data.result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getIp(ip) {
|
|
||||||
const result = this.visitorService.getIp(ip);
|
|
||||||
if (typeof result === 'string') {
|
|
||||||
this.location = result;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
result.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.location = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getPageData() {
|
|
||||||
this.visitorService.getVisitor(this.pageNum, this.pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
toPage(e) {
|
|
||||||
this.pageNum = e;
|
|
||||||
this.getPageData();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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,49 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
import {Article} from '../../classes/article';
|
|
||||||
import {Observable, of} from 'rxjs';
|
|
||||||
import {exist} from '../../utils/dataUtil';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class ArticleService {
|
|
||||||
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 存储所有已经请求过的数据<首页数据>
|
|
||||||
pageList: Page<Article>[] = [];
|
|
||||||
|
|
||||||
currentPage: Page<Article>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文章
|
|
||||||
* @param pageNum 页码数
|
|
||||||
* @param pageSize 单页数据量
|
|
||||||
*/
|
|
||||||
getArticle(pageNum: number, pageSize: number): object {
|
|
||||||
const articlePage = exist<Article>(pageNum, pageSize, this.pageList);
|
|
||||||
if (articlePage) {
|
|
||||||
articlePage.subscribe(data => {
|
|
||||||
this.currentPage = data;
|
|
||||||
});
|
|
||||||
return articlePage;
|
|
||||||
}
|
|
||||||
const observable = this.http.get('/admin/articles?page=' + pageNum + '&count=' + pageSize);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.currentPage = data.result;
|
|
||||||
this.pageList.push(data.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteArticle(id) {
|
|
||||||
return this.http.delete('/admin/article/del?articleID=' + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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,56 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Category} from '../../classes/category';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class CategoryService {
|
|
||||||
|
|
||||||
// FIXME : !!!!!!!!!!!!!!!!!!数据处理全部放到一个模块中!!!!!!!!!!!!!!!!!!
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(submitBody: { id: number, name: string }) {
|
|
||||||
return this.http.put('/admin/category/update', submitBody, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
create(nameStr: string) {
|
|
||||||
const observable = this.http.post('/admin/category/create', {name: nameStr}, false);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.categories.push(data.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number) {
|
|
||||||
const observable = this.http.delete(`/admin/category/del?id=${id}`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
// tslint:disable-next-line:prefer-for-of
|
|
||||||
for (let i = 0; i < this.categories.length; i++) {
|
|
||||||
if (this.categories[i].id === id) {
|
|
||||||
this.categories.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
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,98 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
import {Comment} from '../../classes/comment';
|
|
||||||
import {exist} from '../../utils/dataUtil';
|
|
||||||
import {CommentReq} from "../../classes/commentReq";
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class CommentService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 存放
|
|
||||||
leaveMsgPage: Page<Comment>[] = [];
|
|
||||||
|
|
||||||
commentPage: Page<Comment>[] = [];
|
|
||||||
|
|
||||||
currentComment: Page<Comment>;
|
|
||||||
|
|
||||||
currentLeaveMsg: Page<Comment>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 评论
|
|
||||||
* @param pageNum 页码
|
|
||||||
* @param pageSize 单页数据数量
|
|
||||||
* @param isAdmin 是否是管理员
|
|
||||||
*/
|
|
||||||
getComments(pageNum: number, pageSize: number, isAdmin: boolean) {
|
|
||||||
const exist1 = exist<Comment>(pageNum, pageSize, this.commentPage);
|
|
||||||
if (exist1) {
|
|
||||||
exist1.subscribe(data => {
|
|
||||||
this.currentComment = data;
|
|
||||||
});
|
|
||||||
return exist1;
|
|
||||||
}
|
|
||||||
const observable = this.http.get(`/${isAdmin ? 'admin' : 'user'}/comment/type/1?count=${pageSize}&page=${pageNum}`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.commentPage.unshift(data.result);
|
|
||||||
this.currentComment = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 留言
|
|
||||||
* @param pageNum 页码
|
|
||||||
* @param pageSize 单页数据数量
|
|
||||||
* @param isAdmin 是否是管理员
|
|
||||||
*/
|
|
||||||
getLeaveMsg(pageNum: number, pageSize: number, isAdmin: boolean) {
|
|
||||||
const exist1 = exist<Comment>(pageNum, pageSize, this.leaveMsgPage);
|
|
||||||
if (exist1) {
|
|
||||||
exist1.subscribe(data => {
|
|
||||||
this.currentLeaveMsg = data;
|
|
||||||
});
|
|
||||||
return exist1;
|
|
||||||
}
|
|
||||||
const observable = this.http.get(`/${isAdmin ? 'admin' : 'user'}/comment/type/0?count=${pageSize}&page=${pageNum}`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.leaveMsgPage.unshift(data.result);
|
|
||||||
this.currentLeaveMsg = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回复评论/留言
|
|
||||||
* @param responseComment 请求体
|
|
||||||
*/
|
|
||||||
rely(responseComment: CommentReq) {
|
|
||||||
return this.http.post('/user/comment/create', responseComment, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过父评论 获取回复
|
|
||||||
* @param pid 父评论id
|
|
||||||
*/
|
|
||||||
getByPid(pid: number) {
|
|
||||||
return this.http.get('/comment/pid/' + pid + '?count=5&page=1');
|
|
||||||
}
|
|
||||||
|
|
||||||
update(subComment) {
|
|
||||||
return this.http.put('/user/comment/update', subComment);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number) {
|
|
||||||
return this.http.delete('/user/comment/del?id=' + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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,103 +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 '../classes/data';
|
|
||||||
import {reqBody2Str} from '../utils/dataUtil';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class HttpService {
|
|
||||||
|
|
||||||
constructor(public httpClient: 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.httpClient.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,
|
|
||||||
'Content-Type': isJson ? 'application/json' : 'application/x-www-form-urlencoded'
|
|
||||||
}),
|
|
||||||
withCredentials: true
|
|
||||||
};
|
|
||||||
return this.httpClient.post<Data>(this.getPath(path), isJson ? reqBody : reqBody2Str(reqBody), Options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* put 请求
|
|
||||||
* @param path 请求路径
|
|
||||||
* @param reqBody 请求体
|
|
||||||
* @param isJson 是否发生json格式数据到服务器
|
|
||||||
*/
|
|
||||||
put(path: string, reqBody: object, isJson: boolean = false): Observable<Data> {
|
|
||||||
const Options = {
|
|
||||||
headers: new HttpHeaders({
|
|
||||||
Accept: '*/*',
|
|
||||||
Authorization: this.token,
|
|
||||||
'Content-Type': isJson ? 'application/json' : 'application/x-www-form-urlencoded'
|
|
||||||
}),
|
|
||||||
withCredentials: true
|
|
||||||
};
|
|
||||||
return this.httpClient.put<Data>(this.getPath(path), isJson ? reqBody : reqBody2Str(reqBody), Options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* delete 请求
|
|
||||||
* @param path 请求路径
|
|
||||||
*/
|
|
||||||
delete(path: string): Observable<Data> {
|
|
||||||
return this.httpClient.delete<Data>(this.getPath(path), this.httpOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查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;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeToken() {
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
this.token = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,39 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Link} from '../../classes/link';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class LinkService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不采取存储page[] :: 数据量较少
|
|
||||||
public currentPage: Page<Link>;
|
|
||||||
|
|
||||||
getLinks(pageNum: number, pageSize: number) {
|
|
||||||
const observable = this.http.get(`/admin/links?page=${pageNum}&count=${pageSize}`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.currentPage = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(submitBody: Link) {
|
|
||||||
return this.http.put('/admin/links/update', submitBody, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
create(submitBody: Link) {
|
|
||||||
submitBody.id = null;
|
|
||||||
return this.http.post('/admin/links/create', submitBody, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id) {
|
|
||||||
return this.http.delete(`/admin/links/del/${id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { LogService } from './log.service';
|
|
||||||
|
|
||||||
describe('LogService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: LogService = TestBed.get(LogService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class LogService {
|
|
||||||
|
|
||||||
constructor(private http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
logText: string;
|
|
||||||
|
|
||||||
getLog() {
|
|
||||||
// @ts-ignore
|
|
||||||
const observable = this.http.httpClient.get<string>('https://api.celess.cn/blog.log', {responseType: 'text'});
|
|
||||||
observable.subscribe(data => {
|
|
||||||
this.logText = data;
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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,43 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Tag} from '../../classes/tag';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
import {exist} from '../../utils/dataUtil';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class TagService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
tagPages: Page<Tag>[] = [];
|
|
||||||
currentTagPage: Page<Tag>;
|
|
||||||
|
|
||||||
getTags(pageNum: number, pageSize: number) {
|
|
||||||
const exist1 = exist<Tag>(pageNum, pageSize, this.tagPages);
|
|
||||||
if (exist1) {
|
|
||||||
exist1.subscribe(data => {
|
|
||||||
this.currentTagPage = data;
|
|
||||||
});
|
|
||||||
return exist1;
|
|
||||||
}
|
|
||||||
const observable = this.http.get(`/tags?count=${pageSize}&page=${pageNum}`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.currentTagPage = data.result;
|
|
||||||
this.tagPages.unshift(data.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: number, name: string) {
|
|
||||||
return this.http.put(`/admin/tag/update?id=${id}&name=${name}`, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number) {
|
|
||||||
return this.http.delete(`/admin/tag/del?id=${id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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,48 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {UpdateInfo} from '../../classes/updateInfo';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class WebUpdateService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateInfoList: Page<UpdateInfo>;
|
|
||||||
|
|
||||||
public lastestUpdateTime: string;
|
|
||||||
|
|
||||||
getUpdateInfo(pageNum: number, pageSize: number) {
|
|
||||||
const observable = this.http.get(`/webUpdate/pages?page=${pageNum}&count=${pageSize}`);
|
|
||||||
observable.subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.updateInfoList = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLastestUpdateTime() {
|
|
||||||
this.http.get('/lastestUpdateTime').subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.lastestUpdateTime = data.result;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
update(submitBody: { id: number, info: string }) {
|
|
||||||
return this.http.put('/admin/webUpdate/update', submitBody, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
create(infoStr: string) {
|
|
||||||
return this.http.post('/admin/webUpdate/create', {info: infoStr}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number) {
|
|
||||||
return this.http.delete(`/admin/webUpdate/del/${id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { UserService } from './user.service';
|
|
||||||
|
|
||||||
describe('UserService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: UserService = TestBed.get(UserService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {User} from '../../classes/user';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
import {exist} from '../../utils/dataUtil';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class UserService {
|
|
||||||
|
|
||||||
userInfo: User;
|
|
||||||
|
|
||||||
avatarHost: string = 'http://cdn.celess.cn';
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
this.getUserInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
userPage: Page<User>[] = [];
|
|
||||||
currentUserPage: Page<User>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户信息
|
|
||||||
*/
|
|
||||||
getUserInfo() {
|
|
||||||
const observable = this.http.get('/user/userInfo');
|
|
||||||
observable.subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.userInfo = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注销登录
|
|
||||||
*/
|
|
||||||
logout() {
|
|
||||||
this.http.get('/logout').subscribe((data: any) => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.userInfo = null;
|
|
||||||
this.http.removeToken();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
updateInfo(submitBody: { desc: string, displayName: string }) {
|
|
||||||
const observable = this.http.put('/user/userInfo/update', submitBody, false);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.userInfo.desc = submitBody.desc;
|
|
||||||
this.userInfo.displayName = submitBody.displayName;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sendEmail() {
|
|
||||||
return this.http.post('/sendVerifyEmail', {email: this.userInfo.email}, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取分页数据
|
|
||||||
* @param pageNum 页码
|
|
||||||
* @param pageSize 单页数据量
|
|
||||||
* @param refresh 是否强制刷新
|
|
||||||
*/
|
|
||||||
getPageUser(pageNum: number, pageSize: number, refresh: boolean = false) {
|
|
||||||
const existData = exist<User>(pageNum, pageSize, this.userPage);
|
|
||||||
if (existData && !refresh) {
|
|
||||||
existData.subscribe(data => {
|
|
||||||
this.currentUserPage = data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.http.get(`/admin/users?page=${pageNum}&count=${pageSize}`).subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.currentUserPage = data.result;
|
|
||||||
this.userPage.unshift(data.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: number) {
|
|
||||||
return this.http.delete(`/admin/user/delete/${id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(user: User) {
|
|
||||||
return this.http.put('/admin/user', user, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
getExistOfEmail(email: string) {
|
|
||||||
return this.http.get(`/emailStatus/${email}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { VisitorService } from './visitor.service';
|
|
||||||
|
|
||||||
describe('VisitorService', () => {
|
|
||||||
beforeEach(() => TestBed.configureTestingModule({}));
|
|
||||||
|
|
||||||
it('should be created', () => {
|
|
||||||
const service: VisitorService = TestBed.get(VisitorService);
|
|
||||||
expect(service).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import {Injectable} from '@angular/core';
|
|
||||||
import {HttpService} from '../http.service';
|
|
||||||
import {Page} from '../../classes/page';
|
|
||||||
import {Visitor} from '../../classes/visitor';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root'
|
|
||||||
})
|
|
||||||
export class VisitorService {
|
|
||||||
|
|
||||||
constructor(public http: HttpService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public pageList: Page<Visitor>[] = [];
|
|
||||||
public currentPage: Page<Visitor>;
|
|
||||||
|
|
||||||
public dayVisit: number;
|
|
||||||
public totalVisitCount: number;
|
|
||||||
|
|
||||||
private ipLocationList: { ip: string, location: string }[] = [];
|
|
||||||
|
|
||||||
getVisitor(pageNum: number, pageSize: number) {
|
|
||||||
const observable = this.http.get(`/admin/visitor/page?count=${pageSize}&page=${pageNum}&showLocation=false`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.pageList.unshift(data.result);
|
|
||||||
this.currentPage = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getDayVisitor() {
|
|
||||||
this.http.get('/dayVisitCount').subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.dayVisit = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTotalVisitorCount() {
|
|
||||||
this.http.get('/visitor/count').subscribe(data => {
|
|
||||||
this.totalVisitCount = data.result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getIp(ip: string) {
|
|
||||||
const location = this.exist(ip);
|
|
||||||
if (location) {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
const observable = this.http.get(`/ip/${ip}`);
|
|
||||||
observable.subscribe(data => {
|
|
||||||
if (data.code === 0) {
|
|
||||||
this.ipLocationList.unshift(data.result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return observable;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLocalIp() {
|
|
||||||
return this.http.get('/ip');
|
|
||||||
}
|
|
||||||
|
|
||||||
private exist(ip): string {
|
|
||||||
if (this.ipLocationList.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// tslint:disable-next-line:prefer-for-of
|
|
||||||
for (let i = 0; i < this.ipLocationList.length; i++) {
|
|
||||||
if (this.ipLocationList[i].ip === ip) {
|
|
||||||
return this.ipLocationList[i].location;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import {Page} from '../classes/page';
|
|
||||||
import {Observable, of} from 'rxjs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断 一个Page<any>[] 中是否存在一条已查询的数据
|
|
||||||
* @param pageNum 页码
|
|
||||||
* @param pageSize 单页数量
|
|
||||||
* @param pageList 源数据
|
|
||||||
* @return 未查到:null 查到:该条数据
|
|
||||||
*/
|
|
||||||
export function exist<T>(pageNum: number, pageSize: number, pageList: Page<any>[]): Observable<Page<T>> {
|
|
||||||
if (pageList === undefined || pageList == null || pageList.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// tslint:disable-next-line:prefer-for-of
|
|
||||||
for (let i = 0; i < pageList.length; i++) {
|
|
||||||
// tslint:disable-next-line:triple-equals
|
|
||||||
if (pageList[i].pageNum == pageNum && pageList[i].pageSize == pageSize) {
|
|
||||||
return of<Page<T>>(pageList[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将reqBody对象 转化为拼接到url上面的字符串
|
|
||||||
* @param reqBody 请求体 from {a:xx,b:xxx}
|
|
||||||
* @return 字符串 to ==> a=xx&b=xxx
|
|
||||||
*/
|
|
||||||
export function reqBody2Str(reqBody: object): string {
|
|
||||||
let submitBody = '';
|
|
||||||
for (const key in reqBody) {
|
|
||||||
// 跳过值为null的参数请求
|
|
||||||
if (reqBody[key] == null || reqBody[key] === 'null') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
submitBody = submitBody + '&' + key + '=' + reqBody[key];
|
|
||||||
}
|
|
||||||
return submitBody.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="zh">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>小海博客|后台管理</title>
|
|
||||||
<base href="/">
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="icon" type="image/x-icon" href="https://56462271.oss-cn-beijing.aliyuncs.com/web/logo.png">
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<app-root></app-root>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { enableProdMode } from '@angular/core';
|
|
||||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
||||||
|
|
||||||
import { AppModule } from './app/app.module';
|
|
||||||
import { environment } from './environments/environment';
|
|
||||||
|
|
||||||
if (environment.production) {
|
|
||||||
enableProdMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
|
||||||
* {
|
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background: #F0F1F5;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #797979;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 水平滚动 */
|
|
||||||
.scrollable-horizontal {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表格 */
|
|
||||||
table {
|
|
||||||
margin: 10px 0;
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:nth-child(2n) {
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr:hover {
|
|
||||||
background: #E3F6FF;
|
|
||||||
}
|
|
||||||
tr td:last-child{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
background: #EFF3F5;
|
|
||||||
padding: 8px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 10px 8px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
height: 32px;
|
|
||||||
background: #fafafa;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
margin: 5px 10px;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./out-tsc/spec",
|
|
||||||
"types": [
|
|
||||||
"jasmine",
|
|
||||||
"node"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/test.ts",
|
|
||||||
"src/polyfills.ts"
|
|
||||||
],
|
|
||||||
"include": [
|
|
||||||
"src/**/*.spec.ts",
|
|
||||||
"src/**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "tslint:recommended",
|
|
||||||
"rules": {
|
|
||||||
"array-type": false,
|
|
||||||
"arrow-parens": false,
|
|
||||||
"deprecation": {
|
|
||||||
"severity": "warn"
|
|
||||||
},
|
|
||||||
"component-class-suffix": true,
|
|
||||||
"contextual-lifecycle": true,
|
|
||||||
"directive-class-suffix": true,
|
|
||||||
"directive-selector": [
|
|
||||||
true,
|
|
||||||
"attribute",
|
|
||||||
"app",
|
|
||||||
"camelCase"
|
|
||||||
],
|
|
||||||
"component-selector": [
|
|
||||||
true,
|
|
||||||
"element",
|
|
||||||
"app",
|
|
||||||
"kebab-case"
|
|
||||||
],
|
|
||||||
"import-blacklist": [
|
|
||||||
true,
|
|
||||||
"rxjs/Rx"
|
|
||||||
],
|
|
||||||
"interface-name": false,
|
|
||||||
"max-classes-per-file": false,
|
|
||||||
"max-line-length": [
|
|
||||||
true,
|
|
||||||
140
|
|
||||||
],
|
|
||||||
"member-access": false,
|
|
||||||
"member-ordering": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"order": [
|
|
||||||
"static-field",
|
|
||||||
"instance-field",
|
|
||||||
"static-method",
|
|
||||||
"instance-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-consecutive-blank-lines": false,
|
|
||||||
"no-console": [
|
|
||||||
true,
|
|
||||||
"debug",
|
|
||||||
"info",
|
|
||||||
"time",
|
|
||||||
"timeEnd",
|
|
||||||
"trace"
|
|
||||||
],
|
|
||||||
"no-empty": false,
|
|
||||||
"no-inferrable-types": [
|
|
||||||
false,
|
|
||||||
"ignore-params"
|
|
||||||
],
|
|
||||||
"no-non-null-assertion": true,
|
|
||||||
"no-redundant-jsdoc": true,
|
|
||||||
"no-switch-case-fall-through": true,
|
|
||||||
"no-use-before-declare": true,
|
|
||||||
"no-var-requires": false,
|
|
||||||
"object-literal-key-quotes": [
|
|
||||||
true,
|
|
||||||
"as-needed"
|
|
||||||
],
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"ordered-imports": false,
|
|
||||||
"quotemark": [
|
|
||||||
true,
|
|
||||||
"single"
|
|
||||||
],
|
|
||||||
"trailing-comma": false,
|
|
||||||
"no-conflicting-lifecycle": true,
|
|
||||||
"no-host-metadata-property": true,
|
|
||||||
"no-input-rename": true,
|
|
||||||
"no-inputs-metadata-property": true,
|
|
||||||
"no-output-native": true,
|
|
||||||
"no-output-on-prefix": true,
|
|
||||||
"no-output-rename": true,
|
|
||||||
"no-outputs-metadata-property": true,
|
|
||||||
"template-banana-in-box": true,
|
|
||||||
"template-no-negated-async": true,
|
|
||||||
"use-lifecycle-interface": true,
|
|
||||||
"use-pipe-transform-interface": true
|
|
||||||
},
|
|
||||||
"rulesDirectory": [
|
|
||||||
"codelyzer"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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",
|
||||||
@@ -18,7 +22,7 @@
|
|||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"polyfills": "src/polyfills.ts",
|
"polyfills": "src/polyfills.ts",
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
"aot": false,
|
"aot": true,
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/favicon.ico",
|
"src/favicon.ico",
|
||||||
"src/assets",
|
"src/assets",
|
||||||
@@ -26,22 +30,15 @@
|
|||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
|
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
|
||||||
"output": "/assets/"
|
"output": "/assets/"
|
||||||
}
|
},
|
||||||
|
"src/manifest.webmanifest"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/assets/editor.md/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.md/lib/raphael.min.js",
|
|
||||||
"src/assets/editor.md/lib/underscore.min.js",
|
|
||||||
"src/assets/editor.md/lib/sequence-diagram.min.js",
|
|
||||||
"src/assets/editor.md/lib/flowchart.min.js",
|
|
||||||
"src/assets/editor.md/lib/jquery.flowchart.min.js",
|
|
||||||
"src/assets/editor.md/editormd.min.js"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
@@ -55,7 +52,6 @@
|
|||||||
"optimization": true,
|
"optimization": true,
|
||||||
"outputHashing": "all",
|
"outputHashing": "all",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"extractCss": true,
|
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"aot": true,
|
"aot": true,
|
||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
@@ -66,8 +62,15 @@
|
|||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "2mb",
|
"maximumWarning": "2mb",
|
||||||
"maximumError": "5mb"
|
"maximumError": "5mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "6kb",
|
||||||
|
"maximumError": "10kb"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"serviceWorker": true,
|
||||||
|
"ngswConfigPath": "ngsw-config.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -97,25 +100,22 @@
|
|||||||
"karmaConfig": "karma.conf.js",
|
"karmaConfig": "karma.conf.js",
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/favicon.ico",
|
"src/favicon.ico",
|
||||||
"src/assets"
|
"src/assets",
|
||||||
|
"src/manifest.webmanifest"
|
||||||
],
|
],
|
||||||
"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": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
"builder": "@angular-eslint/builder:lint",
|
||||||
"options": {
|
"options": {
|
||||||
"tsConfig": [
|
"lintFilePatterns": [
|
||||||
"tsconfig.app.json",
|
"src/**/*.ts",
|
||||||
"tsconfig.spec.json",
|
"src/**/*.html"
|
||||||
"e2e/tsconfig.json"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"**/node_modules/**"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -134,5 +134,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultProject": "index"
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user