├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── admin
├── .env.development
├── .gitignore
├── README.md
├── package.json
├── pnpm-lock.yaml
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── linkimage
│ │ │ ├── favicon.png
│ │ │ └── zhihu.png
│ │ ├── logo.png
│ │ └── postimage
│ │ │ ├── closure.jpg
│ │ │ ├── english.jpg
│ │ │ ├── git.jpg
│ │ │ ├── learn1.jpg
│ │ │ ├── null.jpg
│ │ │ └── this.jpg
│ ├── components
│ │ ├── HelloWorld.vue
│ │ └── MTopHandle.vue
│ ├── http.js
│ ├── main.js
│ ├── plugins
│ │ └── filters.js
│ ├── router
│ │ └── index.js
│ ├── store
│ │ └── index.js
│ ├── style.css
│ └── views
│ │ ├── About.vue
│ │ ├── AdminUserEdit.vue
│ │ ├── AdminUserList.vue
│ │ ├── ArticleEdit.vue
│ │ ├── ArticleList.vue
│ │ ├── CategoryEdit.vue
│ │ ├── CategoryList.vue
│ │ ├── CommentList.vue
│ │ ├── LinkEdit.vue
│ │ ├── LinkList.vue
│ │ ├── Login.vue
│ │ ├── Main.vue
│ │ ├── MessageList.vue
│ │ └── UserList.vue
└── vue.config.js
├── package.json
├── pnpm-lock.yaml
├── screenshot
├── admin.gif
└── web.gif
├── server
├── .gitignore
├── admin
│ ├── css
│ │ ├── app.b98fe089.css
│ │ ├── article_edit.33f6816a.css
│ │ ├── chunk-vendors.53794358.css
│ │ ├── login.d3cd1897.css
│ │ └── main.b0303dc3.css
│ ├── favicon.ico
│ ├── fonts
│ │ ├── element-icons.535877f5.woff
│ │ ├── element-icons.732389de.ttf
│ │ ├── fontello.068ca2b3.ttf
│ │ ├── fontello.8d4a4e6f.woff2
│ │ ├── fontello.a782baa8.woff
│ │ └── fontello.e73a0647.eot
│ ├── img
│ │ └── fontello.9354499c.svg
│ ├── index.html
│ └── js
│ │ ├── admin_edit.e91fae0c.js
│ │ ├── admin_edit.e91fae0c.js.map
│ │ ├── admin_list.874c83ef.js
│ │ ├── admin_list.874c83ef.js.map
│ │ ├── app.fed95af8.js
│ │ ├── app.fed95af8.js.map
│ │ ├── article_edit.dfcc3957.js
│ │ ├── article_edit.dfcc3957.js.map
│ │ ├── article_list.2a29b43e.js
│ │ ├── article_list.2a29b43e.js.map
│ │ ├── category_edit.3854f8a3.js
│ │ ├── category_edit.3854f8a3.js.map
│ │ ├── category_list.ee7cd4b7.js
│ │ ├── category_list.ee7cd4b7.js.map
│ │ ├── chunk-vendors.64e1808c.js
│ │ ├── chunk-vendors.64e1808c.js.map
│ │ ├── comment_list.554580fc.js
│ │ ├── comment_list.554580fc.js.map
│ │ ├── link_edit.2c0e0f99.js
│ │ ├── link_edit.2c0e0f99.js.map
│ │ ├── link_list.7f84cc17.js
│ │ ├── link_list.7f84cc17.js.map
│ │ ├── login.109891a5.js
│ │ ├── login.109891a5.js.map
│ │ ├── main.ba894f64.js
│ │ ├── main.ba894f64.js.map
│ │ ├── message_list.16168fad.js
│ │ └── message_list.16168fad.js.map
├── index.js
├── middleware
│ ├── auth.js
│ └── resource.js
├── models
│ ├── AdminUser.js
│ ├── Article.js
│ ├── Category.js
│ ├── Comment.js
│ ├── Link.js
│ ├── Message.js
│ └── User.js
├── package.json
├── plugins
│ ├── db.js
│ └── sendEmail.js
├── pnpm-lock.yaml
├── routes
│ ├── admin
│ │ └── index.js
│ └── web
│ │ └── index.js
└── web
│ ├── css
│ ├── about.bb042f05.css
│ ├── about.bb042f05.css.gz
│ ├── app.ffda094d.css
│ ├── app.ffda094d.css.gz
│ ├── archive.55ff8245.css
│ ├── article.9ef0ae68.css
│ ├── home.475a08fb.css
│ ├── home.475a08fb.css.gz
│ ├── link.c7fe52ac.css
│ ├── message.208c449f.css
│ ├── tag.bcfa3e2a.css
│ ├── tag.bcfa3e2a.css.gz
│ ├── vendors~app.3a4b7974.css
│ ├── vendors~app.3a4b7974.css.gz
│ └── vendors~article.1c2c36e5.css
│ ├── favicon.ico
│ ├── fonts
│ ├── element-icons.535877f5.woff
│ └── element-icons.732389de.ttf
│ ├── img
│ └── iconfont.a22d368f.svg
│ ├── index.html
│ └── js
│ ├── about.75b89ddb.js
│ ├── about.75b89ddb.js.gz
│ ├── app.c4457924.js
│ ├── app.c4457924.js.gz
│ ├── archive.845f534c.js
│ ├── archive.845f534c.js.gz
│ ├── article.b4d913a8.js
│ ├── article.b4d913a8.js.gz
│ ├── home.6e81e34d.js
│ ├── home.6e81e34d.js.gz
│ ├── link.2206432e.js
│ ├── link.2206432e.js.gz
│ ├── message.dcf21bf0.js
│ ├── message.dcf21bf0.js.gz
│ ├── tag.4428a61a.js
│ ├── tag.4428a61a.js.gz
│ ├── vendors~app.38cd00d7.js
│ ├── vendors~app.38cd00d7.js.LICENSE.txt
│ ├── vendors~app.38cd00d7.js.gz
│ ├── vendors~article.b06189d7.js
│ ├── vendors~article.b06189d7.js.gz
│ ├── vendors~article~home.db3e17e7.js
│ ├── vendors~article~home.db3e17e7.js.LICENSE.txt
│ └── vendors~article~home.db3e17e7.js.gz
└── web
├── .env.development
├── .gitignore
├── README.md
├── package.json
├── pnpm-lock.yaml
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── assets
│ ├── iconfont
│ │ ├── demo.css
│ │ ├── demo_index.html
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.json
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ ├── images
│ │ ├── bg-blog.png
│ │ ├── git
│ │ │ └── git-1.jpg
│ │ ├── learn1
│ │ │ ├── learn1-0.jpg
│ │ │ ├── learn1-2.jpg
│ │ │ ├── learn1-3.jpg
│ │ │ └── learn1-4.jpg
│ │ ├── logo.png
│ │ └── this
│ │ │ ├── this-1.jpg
│ │ │ └── this-2.png
│ └── scss
│ │ ├── _variables.scss
│ │ └── style.scss
├── commentConfig.js
├── components
│ ├── Footer.vue
│ ├── Header.vue
│ ├── Search.vue
│ ├── commentList.vue
│ ├── commentTextarea.vue
│ ├── formInput.vue
│ ├── linkItem.vue
│ └── snow.vue
├── http.js
├── main.js
├── plugins
│ ├── Toc.js
│ ├── filters.js
│ ├── global.js
│ ├── lineAndCopy.js
│ ├── reg.js
│ └── validate.js
├── router
│ └── index.js
├── store
│ └── index.js
└── views
│ ├── About.vue
│ ├── Archive.vue
│ ├── Article.vue
│ ├── Home.vue
│ ├── Link.vue
│ ├── Main.vue
│ ├── Message.vue
│ ├── Search.vue
│ └── Tag.vue
└── vue.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | .idea
107 |
108 | .idea/
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
5 | "eslintIntegration": true,
6 | "htmlWhitespaceSensitivity": "ignore",
7 | "endOfLine": "auto"
8 | }
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 米淇淋
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### 环境准备
2 |
3 | - Node.js v14.15.5
4 | - MongoDB v4.2.17
5 |
6 | ### 安装MongoDB数据库
7 |
8 | 进入[官网](https://www.mongodb.com/try/download/community)下载,版本是4.2.17,平台是Windows,安装包为msi格式
9 |
10 | ### 项目开发
11 |
12 | #### 1. 克隆项目至本地:
13 |
14 | ```sh
15 | $ git clone git@github.com:miqilin21/vue-blog.git
16 | $ cd vue-blog
17 | $ pnpm i
18 | ```
19 |
20 | #### 2. 安装前后台(admin、web)及后端(server)项目依赖:
21 |
22 | ```sh
23 | $ pnpm install-all
24 | ```
25 |
26 | #### 3. 运行前后台(admin、web)及后端(server)项目:
27 |
28 | ```sh
29 | $ pnpm serve-all
30 | ```
31 |
32 | #### 4. 打开浏览器预览:
33 |
34 | http://localhost:8080 打开前台本地页面;http://localhost:8088 打开后台本地页面。
35 |
36 | 第一次后台admin登陆时请先注册用户,登录后可以将注册按钮隐藏以防登录账户泄露。
37 |
38 | ### 后台管理系统
39 |
40 | - 新增分类
41 | - 分类列表(增删改查)
42 |
43 | - 新增文章
44 | - 文章列表(增删改查)
45 |
46 | - 文章评论列表
47 |
48 | - 新增友链
49 | - 友链列表(增删改查)
50 |
51 | - 留言列表
52 |
53 | - 留言用户列表
54 |
55 | - Markdown 编辑器集成
56 | - 图片上传功能
57 |
58 | - 新增用户
59 | - 用户列表(增删改查)
60 |
61 | - 通用增删改查接口实现(中间件 resourceMiddleware)
62 |
63 | - 登录注册功能
64 | - 登出功能
65 | - 添加 jwt 校验(1. 用户名查找 2. 密码校验 3. 返回 token)
66 | - 添加 http 拦截器(request、response)
67 |
68 | ### 博客系统
69 |
70 | - 博客首页 UI
71 | - 博客首页接口实现
72 | - 博客归档页面 UI
73 | - 博客归档页面接口实现
74 | - 博客标签页面 UI
75 | - 博客标签页面接口实现
76 | - 博客文章页面 UI
77 | - 博客文章页面接口实现
78 | - 博客友链页面 UI
79 | - 博客友链页面接口实现
80 | - 博客留言页面 UI
81 | - 博客留言页面接口实现
82 |
83 | ### 配置注意点
84 |
85 | 1. 评论页面回复他人评论采用的是你的QQ邮箱进行同步通知,需要在 `server/plugins/sendEmail.js` 中进行邮箱配置,如何获取QQ邮箱授权码见下图(在QQ邮箱的设置-账户页面)。
86 |
87 | 
88 |
89 | 2. 评论主账户的配置(主账户用于邮箱回复,所以评论建立的账户邮箱要和上一步QQ邮箱授权码的邮箱为同一个),同时需要在 `web/src/commentConfig.js` 中进行评论账户的设置(注意`topNickName`需要和评论建立的主账号昵称一致,`topParentId`可从后台页面获取),主账户被清除的话要重新进行配置。
90 | 3. 关于后台的图片上传:默认是上传到本地,这种方式的话对于服务器要求比较高,自然前端的加载速度会受影响,可以选择用阿里云的oss进行上传及储存,需要将 `server/routes/admin/index.js` 中关于阿里云oss图片上传的代码注释解除,同时将本地图片上传的代码注释掉,最后将你的阿里云oss配置填入即可。
91 |
92 | ### 项目打包部署
93 |
94 | - web、admin 项目打包(根目录下运行 `pnpm build-all` 命令)
95 | - 域名购买
96 | - 域名解析
97 | - linux 云服务器购买
98 | - git 安装, ssh key 添加
99 | - pm2 进程管理
100 | - ngnix 配置
101 | - mongodb 配置
102 | - mongodb 数据从本地迁移至服务器
103 | - 七牛云 cdn 全站免费加速
104 |
105 | 线上服务器部署可参考这份[指南](https://www.yuque.com/lingqian-ceavu/gxhqpr)。
106 |
107 | ### 博客后台管理系统
108 |
109 | 
110 |
111 | ### 博客系统
112 |
113 | 
114 |
115 | ### 欢迎 Star,Issues
116 |
117 | - 您的 Star,是我不断更新维护的动力!!!
118 | - 若在使用过程中,存在某些问题,欢迎 Issues
119 |
120 | ### To Do List
121 |
122 | - 性能优化,图片需要压缩处理,预加载处理
123 | - 给博文页面加上搜索功能
124 | - 浏览器兼容问题,移动端适配。只用了自己电脑的谷歌 chrome 浏览器开发和手机适配效果,其他种种都没试,不过不建议移动端使用,电脑登陆效果更佳
125 | - 解决 vue 的 seo 问题及刷新渲染页面抖动问题。先暂时做 vue 预渲染,不排除以后会做 vue 服务端渲染或 nuxt.js 服务端渲染
126 | - 整理代码,拆分出组件。让结构更清晰,代码量更少
127 | - 利用 typescript 重构整个项目
128 | - 想到有意思的功能也会慢慢加上,持续开发中...
129 |
--------------------------------------------------------------------------------
/admin/.env.development:
--------------------------------------------------------------------------------
1 | VUE_APP_API_URL = http://localhost:3000/admin/api
--------------------------------------------------------------------------------
/admin/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/admin/README.md:
--------------------------------------------------------------------------------
1 | # admin
2 |
3 | ## Project setup
4 | ```
5 | yarn install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | yarn serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | yarn build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | yarn lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "admin",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "axios": "0.24.0",
12 | "dayjs": "1.10.7",
13 | "element-ui": "2.15.1",
14 | "mavon-editor": "2.10.4",
15 | "vue": "2.6.14",
16 | "vue-router": "3.5.1"
17 | },
18 | "devDependencies": {
19 | "@vue/cli-plugin-eslint": "4.5.13",
20 | "@vue/cli-service": "4.5.13",
21 | "babel-eslint": "10.0.3",
22 | "eslint": "6.7.2",
23 | "eslint-plugin-vue": "6.1.2",
24 | "sass": "1.26.3",
25 | "sass-loader": "8.0.2",
26 | "vue-loader": "17.0.0",
27 | "vue-template-compiler": "2.6.14"
28 | },
29 | "eslintConfig": {
30 | "root": true,
31 | "env": {
32 | "node": true
33 | },
34 | "extends": [
35 | "plugin:vue/essential",
36 | "eslint:recommended"
37 | ],
38 | "parserOptions": {
39 | "parser": "babel-eslint"
40 | },
41 | "rules": {}
42 | },
43 | "browserslist": [
44 | "> 1%",
45 | "last 2 versions"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/admin/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/public/favicon.ico
--------------------------------------------------------------------------------
/admin/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 米淇淋的博客-后台管理
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/admin/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/admin/src/assets/linkimage/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/linkimage/favicon.png
--------------------------------------------------------------------------------
/admin/src/assets/linkimage/zhihu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/linkimage/zhihu.png
--------------------------------------------------------------------------------
/admin/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/logo.png
--------------------------------------------------------------------------------
/admin/src/assets/postimage/closure.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/postimage/closure.jpg
--------------------------------------------------------------------------------
/admin/src/assets/postimage/english.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/postimage/english.jpg
--------------------------------------------------------------------------------
/admin/src/assets/postimage/git.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/postimage/git.jpg
--------------------------------------------------------------------------------
/admin/src/assets/postimage/learn1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/postimage/learn1.jpg
--------------------------------------------------------------------------------
/admin/src/assets/postimage/null.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/postimage/null.jpg
--------------------------------------------------------------------------------
/admin/src/assets/postimage/this.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/admin/src/assets/postimage/this.jpg
--------------------------------------------------------------------------------
/admin/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 |
7 | check out the
8 |
9 | vue-cli documentation
10 |
11 | .
12 |
13 |
Installed CLI Plugins
14 |
34 |
Essential Links
35 |
58 |
Ecosystem
59 |
92 |
93 |
94 |
95 |
103 |
104 |
105 |
121 |
--------------------------------------------------------------------------------
/admin/src/components/MTopHandle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ title }}:
5 |
10 | 搜索
11 |
12 |
13 | {{ content }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
38 |
39 |
48 |
--------------------------------------------------------------------------------
/admin/src/http.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import Vue from 'vue'
3 | import router from './router'
4 |
5 | const http = axios.create({
6 | baseURL: process.env.VUE_APP_API_URL || '/admin/api',
7 | // baseURL: 'http://localhost:3000/admin/api'
8 | })
9 |
10 | http.interceptors.request.use(
11 | function (config) {
12 | // Do something before request is sent
13 | if (localStorage.token) {
14 | config.headers.Authorization = 'Bearer ' + localStorage.token
15 | }
16 | return config
17 | },
18 | function (error) {
19 | // Do something with request error
20 | return Promise.reject(error)
21 | }
22 | )
23 | http.interceptors.response.use(
24 | (res) => {
25 | return res
26 | },
27 | (err) => {
28 | if (err.response.data.message) {
29 | Vue.prototype.$message({
30 | type: 'error',
31 | message: err.response.data.message,
32 | })
33 |
34 | if (err.response.status === 401) {
35 | router.push('/login')
36 | }
37 | }
38 |
39 | return Promise.reject(err)
40 | }
41 | )
42 |
43 | export default http
44 |
--------------------------------------------------------------------------------
/admin/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 | import router from "./router";
4 | import ElementUI from "element-ui";
5 | import "element-ui/lib/theme-chalk/index.css";
6 | import "./style.css";
7 | import './plugins/filters'
8 |
9 | Vue.config.productionTip = false;
10 | Vue.use(ElementUI);
11 |
12 | import http from "./http";
13 | Vue.prototype.$http = http;
14 | import MTopHandle from './components/MTopHandle'
15 | Vue.component('MTopHandle', MTopHandle)
16 | Vue.mixin({
17 | computed: {
18 | uploadUrl() {
19 | return this.$http.defaults.baseURL + "/upload";
20 | }
21 | },
22 | methods: {
23 | getAuthHeaders() {
24 | return {
25 | Authorization: `Bearer ${localStorage.token || ""}`
26 | };
27 | }
28 | }
29 | });
30 |
31 | new Vue({
32 | router,
33 | render: h => h(App),
34 | }).$mount("#app");
35 |
--------------------------------------------------------------------------------
/admin/src/plugins/filters.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import dayjs from 'dayjs'
3 |
4 | Vue.filter('date', (val, type) => {
5 | if (!val) return '';
6 |
7 | return dayjs(val).format(type)
8 | })
--------------------------------------------------------------------------------
/admin/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter from "vue-router";
3 |
4 | Vue.use(VueRouter);
5 |
6 | const router = new VueRouter({
7 | routes: [{
8 | path: "/login",
9 | name: "login",
10 | component: () => import( /* webpackChunkName: "login" */ '../views/Login.vue'),
11 | meta: {
12 | isPublic: true
13 | }
14 | },
15 | {
16 | path: "/",
17 | name: "main",
18 | component: () => import( /* webpackChunkName: "main" */ '../views/Main.vue'),
19 | children: [{
20 | path: "/categories/create",
21 | component: () => import( /* webpackChunkName: "category_edit" */ '../views/CategoryEdit.vue'),
22 | },
23 | {
24 | path: "/categories/edit/:id",
25 | component: () => import( /* webpackChunkName: "category_edit" */ '../views/CategoryEdit.vue'),
26 | props: true
27 | },
28 | {
29 | path: "/categories/list",
30 | component: () => import( /* webpackChunkName: "category_list" */ '../views/CategoryList.vue'),
31 | },
32 | {
33 | path: "/articles/create",
34 | component: () => import( /* webpackChunkName: "article_edit" */ '../views/ArticleEdit.vue'),
35 | },
36 | {
37 | path: "/articles/edit/:id",
38 | component: () => import( /* webpackChunkName: "article_edit" */ '../views/ArticleEdit.vue'),
39 | props: true
40 | },
41 | {
42 | path: "/articles/list",
43 | component: () => import( /* webpackChunkName: "article_list" */ '../views/ArticleList.vue'),
44 | },
45 | {
46 | path: "/comments/list",
47 | component: () => import( /* webpackChunkName: "comment_list" */ '../views/CommentList.vue'),
48 | props: true
49 | },
50 | {
51 | path: "/links/create",
52 | component: () => import( /* webpackChunkName: "link_edit" */ '../views/LinkEdit.vue'),
53 | },
54 | {
55 | path: "/links/edit/:id",
56 | component: () => import( /* webpackChunkName: "link_edit" */ '../views/LinkEdit.vue'),
57 | props: true
58 | },
59 | {
60 | path: "/links/list",
61 | component: () => import( /* webpackChunkName: "link_list" */ '../views/LinkList.vue'),
62 | },
63 | {
64 | path: "/messages/list",
65 | component: () => import( /* webpackChunkName: "message_list" */ '../views/MessageList.vue'),
66 | },
67 | {
68 | path: "/users/list",
69 | component: () => import( /* webpackChunkName: "link_list" */ '../views/UserList.vue'),
70 | },
71 | {
72 | path: "/admin_users/create",
73 | component: () => import( /* webpackChunkName: "admin_edit" */ '../views/AdminUserEdit.vue'),
74 | },
75 | {
76 | path: "/admin_users/edit/:id",
77 | component: () => import( /* webpackChunkName: "admin_edit" */ '../views/AdminUserEdit.vue'),
78 | props: true
79 | },
80 | {
81 | path: "/admin_users/list",
82 | component: () => import( /* webpackChunkName: "admin_list" */ '../views/AdminUserList.vue'),
83 | }
84 | ]
85 | }
86 | ]
87 | });
88 |
89 | router.beforeEach((to, from, next) => {
90 | if (!to.meta.isPublic && !localStorage.token) {
91 | return next('/login')
92 | }
93 | next()
94 | })
95 | export default router;
--------------------------------------------------------------------------------
/admin/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | export default new Vuex.Store({
7 | state: {},
8 | mutations: {},
9 | actions: {},
10 | modules: {}
11 | })
--------------------------------------------------------------------------------
/admin/src/style.css:
--------------------------------------------------------------------------------
1 | .avatar-uploader .el-upload {
2 | border: 1px dashed #d9d9d9;
3 | border-radius: 6px;
4 | cursor: pointer;
5 | position: relative;
6 | overflow: hidden;
7 | }
8 |
9 | .avatar-uploader .el-upload:hover {
10 | border-color: #409eff;
11 | }
12 |
13 | .avatar-uploader-icon {
14 | font-size: 28px;
15 | color: #8c939d;
16 | min-width: 5rem;
17 | min-height: 5rem;
18 | line-height: 5rem !important;
19 | text-align: center;
20 | }
21 |
22 | .avatar {
23 | max-width: 30rem;
24 | max-height: 30rem;
25 | display: block;
26 | }
--------------------------------------------------------------------------------
/admin/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/admin/src/views/AdminUserEdit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ id ? '编辑' : '新建' }}管理员
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 保存
13 |
14 |
15 |
16 |
17 |
18 |
51 |
--------------------------------------------------------------------------------
/admin/src/views/AdminUserList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
管理员列表
4 |
5 |
6 |
7 |
8 |
9 |
15 | 编辑
16 |
17 |
23 | 删除
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
70 |
--------------------------------------------------------------------------------
/admin/src/views/ArticleEdit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ id ? '编辑' : '新建' }}文章
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 | 保存
43 |
44 |
45 |
46 |
47 |
48 |
108 |
--------------------------------------------------------------------------------
/admin/src/views/ArticleList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
文章列表
9 |
10 |
11 |
12 |
13 |
14 | {{ scope.row.createdAt | date('YYYY-MM-DD HH:mm:ss') }}
15 |
16 |
17 |
18 |
19 | {{ scope.row.updatedAt | date('YYYY-MM-DD HH:mm:ss') }}
20 |
21 |
22 |
23 |
24 |
30 | 编辑
31 |
32 |
38 | 删除
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
85 |
--------------------------------------------------------------------------------
/admin/src/views/CategoryEdit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ id ? '编辑' : '新建' }}分类
4 |
5 |
6 |
7 |
8 |
9 | 保存
10 |
11 |
12 |
13 |
14 |
15 |
48 |
--------------------------------------------------------------------------------
/admin/src/views/CategoryList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
分类列表
4 |
5 |
6 |
7 |
8 |
9 |
15 | 编辑
16 |
17 |
23 | 删除
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
70 |
--------------------------------------------------------------------------------
/admin/src/views/CommentList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 回复
18 |
19 | 删除
20 |
21 |
22 |
23 |
24 |
25 |
26 |
66 |
--------------------------------------------------------------------------------
/admin/src/views/LinkEdit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ id ? '编辑' : '新增' }}友链
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
23 |
24 |
25 |
26 |
27 | 保存
28 |
29 |
30 |
31 |
32 |
33 |
67 |
--------------------------------------------------------------------------------
/admin/src/views/LinkList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
友链列表
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 | 编辑
23 |
24 |
30 | 删除
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
77 |
--------------------------------------------------------------------------------
/admin/src/views/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 请先登录
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 登录
18 | 注册
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
57 |
58 |
70 |
--------------------------------------------------------------------------------
/admin/src/views/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 内容管理
9 |
10 |
11 | 分类
12 | 新建分类
13 | 分类列表
14 |
15 |
16 | 文章
17 | 新建文章
18 | 文章列表
19 |
20 |
21 | 文章评论
22 | 评论列表
23 |
24 |
25 | 友链
26 | 新建友链
27 | 友链列表
28 |
29 |
30 | 留言
31 | 留言列表
32 |
33 |
34 | 留言评论用户
35 | 留言评论用户列表
36 |
37 |
38 |
39 |
40 |
41 | 系统设置
42 |
43 |
44 | 管理员
45 | 新建管理员
46 | 管理员列表
47 |
48 |
49 |
50 |
51 |
52 |
53 | {{ username }}
54 |
55 |
56 |
57 |
58 | 退出
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
82 |
83 |
101 |
--------------------------------------------------------------------------------
/admin/src/views/MessageList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 回复
18 |
19 | 删除
20 |
21 |
22 |
23 |
24 |
25 |
26 |
66 |
--------------------------------------------------------------------------------
/admin/src/views/UserList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 推送邮件
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
30 | 编辑
31 |
32 |
33 | 删除
34 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
47 |
48 |
49 |
50 | 提交
51 |
52 |
53 |
54 |
55 |
56 |
131 |
--------------------------------------------------------------------------------
/admin/vue.config.js:
--------------------------------------------------------------------------------
1 | // vue.config.json
2 | module.exports = {
3 | devServer: {
4 | port: 8088,
5 | },
6 | outputDir: __dirname + '/../server/admin',
7 | publicPath: process.env.NODE_ENV === 'production' ?
8 | '/admin/' : '/'
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-node-blog",
3 | "version": "1.0.0",
4 | "description": "- vue-cli v4.5.13\r - Node.js v14.15.5\r - MongoDB v4.2.17",
5 | "scripts": {
6 | "serve-all": "run-p web-serve admin-serve server-serve",
7 | "server-serve": "cd server && pnpm serve",
8 | "web-serve": "cd web && pnpm serve",
9 | "admin-serve": "cd admin && pnpm serve",
10 | "install-all": "run-p web-install admin-install server-install",
11 | "server-install": "cd server && pnpm i",
12 | "web-install": "cd web && pnpm i",
13 | "admin-install": "cd admin && pnpm i",
14 | "build-all": "run-p web-build admin-build",
15 | "web-build": "cd web && pnpm build",
16 | "admin-build": "cd admin && pnpm build"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/zonemeen/vue-node-blog.git"
21 | },
22 | "author": "",
23 | "license": "ISC",
24 | "bugs": {
25 | "url": "https://github.com/zonemeen/vue-node-blog/issues"
26 | },
27 | "homepage": "https://github.com/zonemeen/vue-node-blog#readme",
28 | "devDependencies": {
29 | "npm-run-all": "4.1.5",
30 | "prettier": "2.5.1"
31 | }
32 | }
--------------------------------------------------------------------------------
/screenshot/admin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/screenshot/admin.gif
--------------------------------------------------------------------------------
/screenshot/web.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/screenshot/web.gif
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | uploads
4 | /dist
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
--------------------------------------------------------------------------------
/server/admin/css/app.b98fe089.css:
--------------------------------------------------------------------------------
1 | body,html{margin:0;padding:0}.avatar-uploader .el-upload{border:1px dashed #d9d9d9;border-radius:6px;cursor:pointer;position:relative;overflow:hidden}.avatar-uploader .el-upload:hover{border-color:#409eff}.avatar-uploader-icon{font-size:28px;color:#8c939d;min-width:5rem;min-height:5rem;line-height:5rem!important;text-align:center}.avatar{max-width:30rem;max-height:30rem;display:block}.top-box[data-v-00cf1984]{margin-bottom:30px}.top-box .search-input[data-v-00cf1984]{width:300px;margin-right:10px}
--------------------------------------------------------------------------------
/server/admin/css/article_edit.33f6816a.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:fontello;src:url(../fonts/fontello.e73a0647.eot);src:url(../fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../fonts/fontello.a782baa8.woff) format("woff"),url(../fonts/fontello.068ca2b3.ttf) format("truetype"),url(../img/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}.markdown-body .hljs{overflow:auto}
--------------------------------------------------------------------------------
/server/admin/css/login.d3cd1897.css:
--------------------------------------------------------------------------------
1 | .page-login .card-view[data-v-60cb1fb3]{width:30%;padding:2rem;margin:8% auto}.page-login .card-view .card-body[data-v-60cb1fb3]{margin-top:2rem}
--------------------------------------------------------------------------------
/server/admin/css/main.b0303dc3.css:
--------------------------------------------------------------------------------
1 | .el-header{background-color:#69a8e7;color:#333;line-height:60px}.el-aside{color:#333}
--------------------------------------------------------------------------------
/server/admin/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/favicon.ico
--------------------------------------------------------------------------------
/server/admin/fonts/element-icons.535877f5.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/fonts/element-icons.535877f5.woff
--------------------------------------------------------------------------------
/server/admin/fonts/element-icons.732389de.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/fonts/element-icons.732389de.ttf
--------------------------------------------------------------------------------
/server/admin/fonts/fontello.068ca2b3.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/fonts/fontello.068ca2b3.ttf
--------------------------------------------------------------------------------
/server/admin/fonts/fontello.8d4a4e6f.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/fonts/fontello.8d4a4e6f.woff2
--------------------------------------------------------------------------------
/server/admin/fonts/fontello.a782baa8.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/fonts/fontello.a782baa8.woff
--------------------------------------------------------------------------------
/server/admin/fonts/fontello.e73a0647.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/admin/fonts/fontello.e73a0647.eot
--------------------------------------------------------------------------------
/server/admin/index.html:
--------------------------------------------------------------------------------
1 | 米淇淋的博客-后台管理
--------------------------------------------------------------------------------
/server/admin/js/main.ba894f64.js:
--------------------------------------------------------------------------------
1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["main"],{"22de":function(e,t,l){"use strict";l("8319")},8319:function(e,t,l){},cd56:function(e,t,l){"use strict";l.r(t);var i=function(){var e=this,t=e.$createElement,l=e._self._c||t;return l("el-container",{staticStyle:{height:"100vh",border:"1px solid #eee"}},[l("el-aside",{staticStyle:{"background-color":"rgb(238, 241, 246)"},attrs:{width:"200px"}},[l("el-menu",{attrs:{router:"","default-active":e.$route.path}},[l("el-submenu",{attrs:{index:"1"}},[l("template",{slot:"title"},[l("i",{staticClass:"el-icon-message"}),e._v("内容管理 ")]),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("分类")]),l("el-menu-item",{attrs:{index:"/categories/create"}},[e._v("新建分类")]),l("el-menu-item",{attrs:{index:"/categories/list"}},[e._v("分类列表")])],2),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("文章")]),l("el-menu-item",{attrs:{index:"/articles/create"}},[e._v("新建文章")]),l("el-menu-item",{attrs:{index:"/articles/list"}},[e._v("文章列表")])],2),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("文章评论")]),l("el-menu-item",{attrs:{index:"/comments/list"}},[e._v("评论列表")])],2),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("友链")]),l("el-menu-item",{attrs:{index:"/links/create"}},[e._v("新建友链")]),l("el-menu-item",{attrs:{index:"/links/list"}},[e._v("友链列表")])],2),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("留言")]),l("el-menu-item",{attrs:{index:"/messages/list"}},[e._v("留言列表")])],2),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("留言评论用户")]),l("el-menu-item",{attrs:{index:"/users/list"}},[e._v("留言评论用户列表")])],2)],2),l("el-submenu",{attrs:{index:"2"}},[l("template",{slot:"title"},[l("i",{staticClass:"el-icon-message"}),e._v("系统设置 ")]),l("el-menu-item-group",[l("template",{slot:"title"},[e._v("管理员")]),l("el-menu-item",{attrs:{index:"/admin_users/create"}},[e._v("新建管理员")]),l("el-menu-item",{attrs:{index:"/admin_users/list"}},[e._v("管理员列表")])],2)],2)],1)],1),l("el-container",[l("el-header",{staticStyle:{"text-align":"right","font-size":"12px"}},[l("span",[e._v(e._s(e.username))]),l("el-dropdown",[l("i",{staticClass:"el-icon-setting",staticStyle:{"margin-left":"10px"}}),l("el-dropdown-menu",{attrs:{slot:"dropdown"},slot:"dropdown"},[l("el-dropdown-item",[l("a",{on:{click:e.logout}},[e._v("退出")])])],1)],1)],1),l("el-main",[l("router-view",{key:e.$route.path})],1)],1)],1)},s=[],n={data:function(){return{username:""}},methods:{logout:function(){localStorage.clear(),this.$router.push("/login")}},created:function(){this.username=localStorage.getItem("username")||""}},a=n,r=(l("22de"),l("2877")),o=Object(r["a"])(a,i,s,!1,null,null,null);t["default"]=o.exports}}]);
2 | //# sourceMappingURL=main.ba894f64.js.map
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const cors = require('cors')
3 | const app = express()
4 |
5 | app.set('secret', 'i2u34y12oi3u4y8')
6 |
7 | app.use(cors())
8 | app.use(express.json())
9 | app.use('/uploads', express.static(__dirname + '/uploads'))
10 | app.use('/', express.static(__dirname + '/web'))
11 | app.use('/admin', express.static(__dirname + '/admin'))
12 |
13 | require('./plugins/db')(app)
14 | require('./routes/admin/index.js')(app)
15 | require('./routes/web/index.js')(app)
16 |
17 | app.listen(3000, async (req, res) => {
18 | console.log('http://localhost:3000')
19 | })
20 |
--------------------------------------------------------------------------------
/server/middleware/auth.js:
--------------------------------------------------------------------------------
1 | module.exports = options => {
2 | const assert = require('http-assert')
3 | const jwt = require('jsonwebtoken')
4 | const AdminUser = require('../models/AdminUser')
5 |
6 | return async (req, res, next) => {
7 | const token = String(req.headers.authorization || '').split(' ').pop()
8 | assert(token, 401, '请先登录')
9 | const {
10 | id
11 | } = jwt.verify(token, req.app.get('secret'))
12 | assert(id, 401, '请先登录')
13 | req.user = await AdminUser.findById(id)
14 | assert(req.user, 401, '请先登录')
15 | await next()
16 | }
17 | }
--------------------------------------------------------------------------------
/server/middleware/resource.js:
--------------------------------------------------------------------------------
1 | module.exports = options => {
2 | return async (req, res, next) => {
3 | const modelName = require('inflection').classify(req.params.resource)
4 | req.Model = require(`../models/${modelName}`)
5 | next()
6 | }
7 | }
--------------------------------------------------------------------------------
/server/models/AdminUser.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const bcrypt = require('bcryptjs')
3 |
4 | const schema = new mongoose.Schema({
5 | username: {
6 | type: String,
7 | unique: true
8 | },
9 | password: {
10 | type: String,
11 | select: false,
12 | set(val) {
13 | return bcrypt.hashSync(val, 10);
14 | }
15 | }
16 | });
17 |
18 | module.exports = mongoose.model("AdminUser", schema);
--------------------------------------------------------------------------------
/server/models/Article.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose')
2 |
3 | const schema = new mongoose.Schema({
4 | categories: [{
5 | type: mongoose.SchemaTypes.ObjectId,
6 | ref: 'Category'
7 | }],
8 | title: {
9 | type: String
10 | },
11 | icon: {
12 | type: String
13 | },
14 | body: {
15 | type: String
16 | },
17 | }, {
18 | timestamps: true
19 | })
20 |
21 | module.exports = mongoose.model('Article', schema)
--------------------------------------------------------------------------------
/server/models/Category.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose')
2 |
3 | const schema = new mongoose.Schema({
4 | name: {
5 | type: String
6 | }
7 | })
8 |
9 | // schema.virtual('articlesList', {
10 | // localField: '_id',
11 | // foreignField: 'categories',
12 | // justOne: false,
13 | // ref: 'Article'
14 | // })
15 |
16 | module.exports = mongoose.model('Category', schema)
--------------------------------------------------------------------------------
/server/models/Comment.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose")
2 | const schema = new mongoose.Schema({
3 | nickName: {
4 | type: String
5 | },
6 | avatarImg: {
7 | type: String
8 | },
9 | content: {
10 | type: String
11 | },
12 | userId: {
13 | type: mongoose.SchemaTypes.ObjectId,
14 | ref: 'User'
15 | },
16 | relateBlogId: {
17 | type: mongoose.SchemaTypes.ObjectId,
18 | ref: 'Article'
19 | },
20 | parent: {
21 | type: mongoose.SchemaTypes.ObjectId,
22 | ref: 'Comment'
23 | },
24 | byAiteName: {
25 | type: String
26 | },
27 | }, {
28 | timestamps: true
29 | })
30 | module.exports = mongoose.model('Comment', schema)
--------------------------------------------------------------------------------
/server/models/Link.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose')
2 |
3 | const schema = new mongoose.Schema({
4 | name: {
5 | type: String
6 | },
7 | site: {
8 | type: String
9 | },
10 | description: {
11 | type: String
12 | },
13 | icon: {
14 | type: String
15 | }
16 | })
17 |
18 | module.exports = mongoose.model('Link', schema)
--------------------------------------------------------------------------------
/server/models/Message.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose")
2 | const schema = new mongoose.Schema({
3 | nickName: {
4 | type: String
5 | },
6 | avatarImg: {
7 | type: String
8 | },
9 | content: {
10 | type: String
11 | },
12 | userId: {
13 | type: mongoose.SchemaTypes.ObjectId,
14 | ref: 'User'
15 | },
16 | parent: {
17 | type: mongoose.SchemaTypes.ObjectId,
18 | ref: 'Message'
19 | },
20 | byAiteName: {
21 | type: String
22 | },
23 | }, {
24 | timestamps: true
25 | })
26 | module.exports = mongoose.model('Message', schema)
--------------------------------------------------------------------------------
/server/models/User.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose")
2 | const schema = new mongoose.Schema({
3 | nickName: {
4 | type: String,
5 | },
6 | email: {
7 | type: String
8 | },
9 | url: {
10 | type: String
11 | },
12 | avatarImg: {
13 | type: String
14 | }
15 | }, {
16 | timestamps: true
17 | })
18 | module.exports = mongoose.model('User', schema)
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "serve": "nodemon index.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "bcryptjs": "2.4.3",
14 | "cors": "2.8.5",
15 | "express": "4.17.1",
16 | "http-assert": "1.4.1",
17 | "inflection": "1.12.0",
18 | "jsonwebtoken": "8.5.1",
19 | "mongoose": "5.13.14",
20 | "multer": "1.4.4",
21 | "multer-aliyun-oss": "1.1.1",
22 | "nodemailer": "6.7.2",
23 | "nodemailer-smtp-transport": "2.7.4",
24 | "nodemon": "2.0.15",
25 | "require-all": "3.0.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/server/plugins/db.js:
--------------------------------------------------------------------------------
1 | module.exports = (app) => {
2 | const mongoose = require("mongoose");
3 | mongoose.connect("mongodb://127.0.0.1:27017/blog", {
4 | useNewUrlParser: true,
5 | useFindAndModify: true,
6 | useUnifiedTopology: true,
7 | useCreateIndex: true,
8 | useFindAndModify: true
9 | });
10 | require("require-all")(__dirname + "/../models");
11 | };
12 |
--------------------------------------------------------------------------------
/server/plugins/sendEmail.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @Description 邮件发送
4 | * 调用方法:sendMail('994718917@qq.com','这是测试邮件', 'Hi miqilin,这是一封测试邮件');
5 | * @Author miqilin
6 | * @Created 2020/04/05 15:10
7 | * 技术只是解决问题的选择,而不是解决问题的根本...
8 | *
9 | */
10 |
11 | const nodemailer = require('nodemailer')
12 | const smtpTransport = require('nodemailer-smtp-transport')
13 | const config = {
14 | email: {
15 | service: 'QQ', // 邮箱类别,我固定QQ
16 | user: 'xxxxxxxxxx@qq.com', // 你的QQ邮箱,用来发送回复邮件
17 | pass: 'xxxxxxxxxxxxx', // 你的QQ邮箱授权码,如何操作获取见README.md所述
18 | },
19 | }
20 |
21 | sendSmtpTransport = nodemailer.createTransport(
22 | smtpTransport({
23 | service: config.email.service,
24 | auth: {
25 | user: config.email.user,
26 | pass: config.email.pass,
27 | },
28 | })
29 | )
30 |
31 | /**
32 | * @param {String} recipient 收件人
33 | * @param {String} subject 发送的主题
34 | * @param {String} html 发送的html内容
35 | */
36 | var sendMail = function (replyObj) {
37 | sendSmtpTransport.sendMail(
38 | {
39 | from: config.email.user,
40 | to: replyObj.recipient,
41 | subject: `${replyObj.subject} 你好! 你有新邮件了, 请查收`,
42 | html: replyObj.html,
43 | },
44 | function (error, response) {
45 | if (error) {
46 | console.log(error)
47 | }
48 | console.log('发送成功')
49 | }
50 | )
51 | }
52 |
53 | module.exports = sendMail
54 |
--------------------------------------------------------------------------------
/server/routes/admin/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (app) => {
2 | const express = require('express')
3 | const assert = require('http-assert')
4 | const jwt = require('jsonwebtoken')
5 | const AdminUser = require('../../models/AdminUser')
6 | const sendEmail = require('../../plugins/sendEmail.js')
7 | const router = express.Router({
8 | mergeParams: true,
9 | })
10 | router.post('/', async (req, res) => {
11 | const model = await req.Model.create(req.body)
12 | res.send(model)
13 | })
14 | router.put('/:id', async (req, res) => {
15 | const model = await req.Model.findByIdAndUpdate(req.params.id, req.body)
16 | res.send(model)
17 | })
18 | router.delete('/:id', async (req, res) => {
19 | await req.Model.findByIdAndDelete(req.params.id, req.body)
20 | res.send({
21 | success: true,
22 | })
23 | })
24 | router.get('/', async (req, res) => {
25 | const queryOptions = {}
26 | if (req.Model.modelName === 'Category') {
27 | queryOptions.populate = 'parent'
28 | }
29 | const items = await req.Model.find().setOptions(queryOptions).limit(100)
30 | res.send(items)
31 | })
32 | router.get('/:id', async (req, res) => {
33 | const model = await req.Model.findById(req.params.id)
34 | res.send(model)
35 | })
36 |
37 | //登录校验中间件
38 | const authMiddleware = require('../../middleware/auth')
39 |
40 | //资源中间件
41 | const resourceMiddleware = require('../../middleware/resource')
42 |
43 | //资源路由
44 | app.use(
45 | '/admin/api/rest/:resource',
46 | authMiddleware(),
47 | resourceMiddleware(),
48 | router
49 | )
50 |
51 | /* //用于阿里云oss图片上传
52 | const multer = require('multer')
53 | const MAO = require('multer-aliyun-oss')
54 | const upload = multer({
55 | storage: MAO({
56 | config: {
57 | region: 'your region', // 阿里云oss的所在区域,比如oss-cn-shenzhen
58 | accessKeyId: 'your accessKeyId', // 阿里云oss的accessKeyId,要自己去创建
59 | accessKeySecret: 'your accessKeySecret', // 阿里云oss的accessKeySecret
60 | bucket: 'your bucket name', // 阿里云oss的bucket's name
61 | },
62 | }),
63 | })
64 | app.post(
65 | '/admin/api/upload',
66 | authMiddleware(),
67 | upload.single('file'),
68 | async (req, res) => {
69 | const file = req.file
70 | res.send(file)
71 | }
72 | )*/
73 |
74 | //本地图片上传
75 | const multer = require('multer')
76 | const upload = multer({
77 | dest: __dirname + '/../../uploads',
78 | })
79 | app.post(
80 | '/admin/api/upload',
81 | authMiddleware(),
82 | upload.single('file'),
83 | async (req, res) => {
84 | const file = req.file
85 | file.url = `http://localhost:3000/uploads/${file.filename}`
86 | res.send(file)
87 | }
88 | )
89 |
90 | // 第一次登录把注册注释取消
91 | app.post('/admin/api/register', async (req, res) => {
92 | const user = await AdminUser.create({
93 | username: req.body.username,
94 | password: req.body.password,
95 | })
96 | res.send(user)
97 | })
98 |
99 | //登录
100 | app.post('/admin/api/login', async (req, res) => {
101 | const { username, password } = req.body
102 | const user = await AdminUser.findOne({
103 | username,
104 | }).select('+password')
105 | assert(user, 422, '用户不存在')
106 | const isValid = require('bcryptjs').compareSync(password, user.password)
107 | assert(isValid, 422, '密码错误')
108 | const token = jwt.sign(
109 | {
110 | id: user._id,
111 | },
112 | app.get('secret')
113 | )
114 | res.send({
115 | token,
116 | username,
117 | })
118 | })
119 |
120 | app.post('/admin/api/email', async (req, res) => {
121 | sendEmail(req.body)
122 | res.send({
123 | ok: 'ok',
124 | })
125 | })
126 |
127 | //错误处理函数
128 | app.use(async (err, req, res, next) => {
129 | res.status(err.statusCode || 500).send({
130 | message: err.message,
131 | })
132 | })
133 | }
134 |
--------------------------------------------------------------------------------
/server/routes/web/index.js:
--------------------------------------------------------------------------------
1 | module.exports = app => {
2 | const router = require("express").Router();
3 | const mongoose = require("mongoose");
4 | const sendEmail = require('../../plugins/sendEmail.js');
5 | const Article = mongoose.model("Article");
6 | const Link = mongoose.model("Link");
7 | const Category = mongoose.model("Category");
8 | const Comment = mongoose.model("Comment");
9 | const Message = mongoose.model("Message");
10 | const User = mongoose.model("User");
11 |
12 | // 文章列表
13 | router.get("/articles/list", async (req, res) => {
14 | const data = await Article.find().sort({
15 | 'createdAt': -1
16 | });
17 | res.send(data);
18 | });
19 |
20 | // 最近
21 | router.get("/articles/recent", async (req, res) => {
22 | const data = await Article.find()
23 | .sort({
24 | 'createdAt': -1
25 | }).limit(4);
26 | res.send(data);
27 | });
28 |
29 | // 获取指定页码的文章
30 | router.get('/articles/:pageNum', async (req, res) => {
31 | const currentPage = req.params.pageNum;
32 | const list = await Article.find().sort({
33 | 'createdAt': -1
34 | }).skip((currentPage - 1) * 6).limit(6).populate('categories')
35 | const count = await Article.find().lean().countDocuments()
36 | const totalPage = Math.ceil(count / 6)
37 | res.send({
38 | list,
39 | totalArticles: count,
40 | totalPage,
41 | currentPage
42 | })
43 | })
44 |
45 | // 按照年月进行归类后的数据
46 | router.get('/archive', async (req, res) => {
47 | const data = await Article.aggregate([{
48 | $sort: {
49 | createdAt: -1
50 | }
51 | }, {
52 | $lookup: {
53 | from: 'categories',
54 | localField: 'categories',
55 | foreignField: '_id',
56 | as: 'newList'
57 | }
58 | },
59 | {
60 | $group: {
61 | _id: {
62 | $month: '$createdAt',
63 | },
64 | count: {
65 | $sum: 1
66 | },
67 | list: {
68 | $push: {
69 | _id: '$_id',
70 | title: '$title',
71 | categories: '$newList',
72 | createdAt: '$createdAt',
73 | }
74 | }
75 | }
76 | },
77 | ]).sort({
78 | '_id': -1,
79 | })
80 | res.send(data)
81 | })
82 |
83 | // 标签
84 | router.get('/tags', async (req, res) => {
85 | const data = await Category.aggregate([{
86 | $lookup: {
87 | from: 'articles',
88 | localField: '_id',
89 | foreignField: 'categories',
90 | as: 'tagsList'
91 | }
92 | }]).unwind('$tagsList').sort({
93 | 'tagsList.createdAt': -1
94 | }).group({
95 | _id: "$name",
96 | count: {
97 | $sum: 1
98 | },
99 | list: {
100 | $push: {
101 | _id: '$_id',
102 | title: '$title',
103 | categories: '$tagsList',
104 | createdAt: '$createdAt',
105 | }
106 | }
107 | }).sort({
108 | 'count': -1,
109 | '_id': -1
110 | })
111 | res.send(data)
112 | })
113 |
114 | // 文章详情
115 | router.get("/articles/list/:id", async (req, res) => {
116 | const data = await Article.findById(req.params.id).populate('categories');
117 | res.send(data);
118 | });
119 |
120 | // links
121 | router.get("/links/list", async (req, res) => {
122 | const data = await Link.find();
123 | res.send(data);
124 | });
125 |
126 | // 用户
127 | router.post('/users', async (req, res) => {
128 | const data = await User.create(req.body)
129 | res.send(data)
130 | })
131 | router.get('/users', async (req, res) => {
132 | const data = await Users.find()
133 | res.send(data)
134 | })
135 | router.put('/users/:id', async (req, res) => {
136 | const data = await User.findByIdAndUpdate(req.params.id, req.body)
137 | res.send(data)
138 | })
139 | router.get('/users/:id', async (req, res) => {
140 | const data = await User.findById(req.params.id)
141 | res.send(data)
142 | })
143 |
144 | router.post('/email', async (req, res) => {
145 | sendEmail(req.body)
146 | res.send({
147 | ok: 'ok'
148 | })
149 | })
150 |
151 | // 评论
152 | router.post('/comments', async (req, res) => {
153 | const data = await Comment.create(req.body)
154 | await Article.findByIdAndUpdate(req.body.relateBlogId,
155 | // { msgs: req.body.msgs },
156 | {
157 | $inc: {
158 | msgs: 1
159 | }
160 | }
161 | )
162 | res.send(data)
163 | })
164 | router.get('/comments/:blogsId', async (req, res) => {
165 | const comments = await Comment.find().where({
166 | relateBlogId: req.params.blogsId
167 | })
168 | res.send(comments)
169 | })
170 |
171 | // 留言
172 | router.post('/messages', async (req, res) => {
173 | const data = await Message.create(req.body)
174 | res.send(data)
175 | })
176 | router.get('/messages', async (req, res) => {
177 | // console.log("123",await Blogs.findOne({
178 | // _id: req.params.blogsId}))
179 | const messages = await Message.find()
180 | res.send(messages)
181 | })
182 |
183 | // 获取服务器时间
184 | router.get('/time', async (req, res) => {
185 | let time = new Date().getTime()
186 | res.send({
187 | 'data': time
188 | })
189 | })
190 |
191 | app.use("/web/api", router);
192 | };
--------------------------------------------------------------------------------
/server/web/css/about.bb042f05.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/css/about.bb042f05.css.gz
--------------------------------------------------------------------------------
/server/web/css/app.ffda094d.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/css/app.ffda094d.css.gz
--------------------------------------------------------------------------------
/server/web/css/archive.55ff8245.css:
--------------------------------------------------------------------------------
1 | .main-container[data-v-2d95d8ee]{margin-bottom:180px}.main-container .archive-page .categorys-title[data-v-2d95d8ee]{font-size:20px;position:relative;margin:10px auto;padding:0 32px;color:#bbb}
--------------------------------------------------------------------------------
/server/web/css/article.9ef0ae68.css:
--------------------------------------------------------------------------------
1 | #content[data-v-7900f6df]{line-height:1.8}.page[data-v-7900f6df]{max-width:650px}.post-tags[data-v-7900f6df]{max-width:60px}.post-tags[data-v-7900f6df]:hover{background-color:#f1f3f7;color:#5f5f5f}.left[data-v-7900f6df]{width:25%}.blogs-menu[data-v-7900f6df]{max-width:200px;line-height:1.3;margin-top:205px}.blogs-menu .menu-title[data-v-7900f6df]{padding:6px 0;color:#a7ce94}.blogs-menu .menu-title[data-v-7900f6df]:hover{text-decoration:underline}.toc-sticky[data-v-7900f6df]{position:sticky!important;top:80px}.art-comment[data-v-7900f6df]{max-width:650px;margin:0 auto 40px}.textarea-box[data-v-7900f6df]{padding:15px}@media screen and (max-width:900px){.d-none[data-v-7900f6df]{display:none}.page[data-v-7900f6df]{margin:0 auto}}@media screen and (max-width:768px){.page[data-v-7900f6df]{width:95%;margin:0 auto}.art-comment[data-v-7900f6df]{width:90%;margin:0 auto}}
--------------------------------------------------------------------------------
/server/web/css/home.475a08fb.css:
--------------------------------------------------------------------------------
1 | .bgImg[data-v-686b6344]{background-image:url(https://miqilin-blog.oss-cn-shenzhen.aliyuncs.com/bg-blog.png);width:100%;height:100vh;background-position:50%;background-size:cover;position:relative;overflow:hidden}.bgImg .shouye-text[data-v-686b6344]{font-size:32px;font-family:Roboto,sans-serif;width:13em;white-space:nowrap;-webkit-animation:typing-data-v-686b6344 2.5s steps(13),infinite;animation:typing-data-v-686b6344 2.5s steps(13),infinite;overflow:hidden}.bgImg .line-down[data-v-686b6344]{font-size:32px;font-family:Roboto,sans-serif;-webkit-animation:shine-data-v-686b6344 .5s linear infinite alternate;animation:shine-data-v-686b6344 .5s linear infinite alternate}.bgImg .arrow-down[data-v-686b6344]{position:absolute;bottom:30px;color:#fff;-webkit-animation:arrowDown-data-v-686b6344 .8s linear infinite alternate;animation:arrowDown-data-v-686b6344 .8s linear infinite alternate}.bgImg .arrow-down .icon-down[data-v-686b6344]{cursor:pointer;font-size:45px}@-webkit-keyframes arrowDown-data-v-686b6344{0%{visibility:hidden;opacity:0;-webkit-transform:translatey(-20%)}20%{visibility:visible;opacity:0;-webkit-transform:translatey(10%)}to{visibility:visible;opacity:1;-webkit-transform:translatey(20%)}}@keyframes arrowDown-data-v-686b6344{0%{visibility:hidden;opacity:0;-webkit-transform:translatey(-20%)}20%{visibility:visible;opacity:0;-webkit-transform:translatey(10%)}to{visibility:visible;opacity:1;-webkit-transform:translatey(20%)}}@-webkit-keyframes typing-data-v-686b6344{0%{width:0}to{width:13em}}@keyframes typing-data-v-686b6344{0%{width:0}to{width:13em}}@-webkit-keyframes shine-data-v-686b6344{0%{visibility:hidden;opacity:0}to{visibility:visible;opacity:1}}@keyframes shine-data-v-686b6344{0%{visibility:hidden;opacity:0}to{visibility:visible;opacity:1}}.post-container[data-v-686b6344]{max-width:1024px;margin:0 auto}.post-container .top[data-v-686b6344]{width:270px;height:250px}@media screen and (max-width:768px){.line-down[data-v-686b6344],.shouye-text[data-v-686b6344]{font-size:24px!important}}
--------------------------------------------------------------------------------
/server/web/css/home.475a08fb.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/css/home.475a08fb.css.gz
--------------------------------------------------------------------------------
/server/web/css/link.c7fe52ac.css:
--------------------------------------------------------------------------------
1 | .link-img{width:32px;height:32px;border-radius:50%}.link-item{float:left;width:33.3333%;height:auto;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.content{line-height:1.4!important}@media screen and (max-width:880px){.link{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.link .link-item{width:45%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}}@media screen and (max-width:480px){.link{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.link .link-item{width:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}}.page-link{max-width:650px;margin:90px auto 0}.content{line-height:1.8!important}
--------------------------------------------------------------------------------
/server/web/css/message.208c449f.css:
--------------------------------------------------------------------------------
1 | .textarea-box[data-v-2cc96d00]{width:100%;max-width:650px;padding:5px 15px 15px}.content[data-v-2cc96d00]{line-height:1.8!important}
--------------------------------------------------------------------------------
/server/web/css/tag.bcfa3e2a.css:
--------------------------------------------------------------------------------
1 | .post-tags[data-v-4ae8544e]{margin:0;padding:5px 0 20px;border-bottom:1px solid #767676}.post-tags a[data-v-4ae8544e]{font-size:13px;font-weight:600;display:inline-block;margin:20px 8px 10px 0;padding:5px 15px}.post-tags a[data-v-4ae8544e]:nth-child(1n){color:#fff;border:1px solid #6fa3ef;border-radius:15px;background:#6fa3ef}.post-tags a[data-v-4ae8544e]:nth-child(2n){color:#fff;border:1px solid #ff9800;border-radius:15px;background:#ff9800}.post-tags a[data-v-4ae8544e]:nth-child(3n){color:#fff;border:1px solid #46c47c;border-radius:15px;background:#46c47c}.post-tags a[data-v-4ae8544e]:nth-child(4n){color:#fff;border:1px solid #f9bb3c;border-radius:15px;background:#f9bb3c}.post-tags a[data-v-4ae8544e]:nth-child(5n){color:#fff;border:1px solid #bc99c4;border-radius:15px;background:#bc99c4}.post-tags a[data-v-4ae8544e]:nth-child(6n){color:#fff;border:1px solid #e8583d;border-radius:15px;background:#e8583d}.anchor[data-v-4ae8544e]{margin-top:-80px;padding-top:80px}.anchor .categorys-title[data-v-4ae8544e]{font-size:14px;position:relative;margin:10px auto;padding:0 30px;color:#bbb}
--------------------------------------------------------------------------------
/server/web/css/tag.bcfa3e2a.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/css/tag.bcfa3e2a.css.gz
--------------------------------------------------------------------------------
/server/web/css/vendors~app.3a4b7974.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/css/vendors~app.3a4b7974.css.gz
--------------------------------------------------------------------------------
/server/web/css/vendors~article.1c2c36e5.css:
--------------------------------------------------------------------------------
1 | .hljs-comment,.hljs-quote{color:#999}.hljs-deletion,.hljs-name,.hljs-regexp,.hljs-selector-class,.hljs-selector-id,.hljs-tag,.hljs-template-variable,.hljs-variable{color:#f2777a}.hljs-built_in,.hljs-builtin-name,.hljs-link,.hljs-literal,.hljs-meta,.hljs-number,.hljs-params,.hljs-type{color:#f99157}.hljs-attribute{color:#fc6}.hljs-addition,.hljs-bullet,.hljs-string,.hljs-symbol{color:#9c9}.hljs-section,.hljs-title{color:#69c}.hljs-keyword,.hljs-selector-tag{color:#c9c}.hljs{display:block;overflow-x:auto;background:#2d2d2d;color:#ccc;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
--------------------------------------------------------------------------------
/server/web/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/favicon.ico
--------------------------------------------------------------------------------
/server/web/fonts/element-icons.535877f5.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/fonts/element-icons.535877f5.woff
--------------------------------------------------------------------------------
/server/web/fonts/element-icons.732389de.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/fonts/element-icons.732389de.ttf
--------------------------------------------------------------------------------
/server/web/index.html:
--------------------------------------------------------------------------------
1 | 米淇淋的个人博客
--------------------------------------------------------------------------------
/server/web/js/about.75b89ddb.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["about"],{b062:function(t,s,a){},cc81:function(t,s,a){"use strict";a("b062")},f820:function(t,s,a){"use strict";a.r(s);var e=(a("cc81"),a("2877")),i=Object(e.a)({},(function(){var t=this;t.$createElement;return t._self._c,t._m(0)}),[function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"main-container page-about d-flex flex-column ai-center pt-9 content"},[a("div",{staticClass:"page p-5"},[a("div",{staticClass:"text-green fs-xxxxl"},[t._v("About")]),a("div",{staticClass:"text-grey-2 fs-sm mt-5"},[t._v("Published on March 11th 2020")]),a("div",{staticClass:"mt-5 mb-5"}),a("div",{staticClass:"py-4"},[a("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),a("span",{staticClass:"fs-xxl text-grey-1"},[t._v("关于自己")])]),a("div",{staticClass:"pl-5 text-green-1"},[a("p",[t._v("• 转行前端程序员一枚,目前📍:深圳")]),a("p",[t._v("• 未来希望成为一名优秀的前端程序🐵")]),a("p",[t._v("• 业余爱好比较多,喜欢烹饪、烘焙、音乐制作、踢⚽等等")])]),a("div",{staticClass:"py-4"},[a("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),a("span",{staticClass:"fs-xxl text-grey-1"},[t._v("关于博客")])]),a("div",{staticClass:"pl-5 text-green-1"},[a("p",[t._v(" • 该博客用Vue实现,express提供数据接口,mongoDB储存数据,部署在腾讯云的linux服务器上,搭建博客的初衷是希望把自己平常工作学习生活中值得记录的东西记录下来 ")]),a("p",[t._v("• 如有错误、bug的地方烦请指正")])]),a("div",{staticClass:"py-4 mt-6"},[a("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),a("span",{staticClass:"fs-xxl text-grey-1"},[t._v("Side Project (Coding)")])]),a("div",{staticClass:"pl-5 text-green-1 mb-9"},[a("p",[a("a",{staticClass:"text-green-1 bd-bottom-about",attrs:{href:"https://github.com/miqilin21/myBlog",target:"_blank"}},[t._v("• myBlog(本博客)")]),t._v(" - 基于NodeJs、Vue、MongoDB实现的一款伪全栈博客系统🔥 ")]),a("p",[a("a",{staticClass:"text-green-1 bd-bottom-about",attrs:{href:"https://github.com/miqilin21/iMoney",target:"_blank"}},[t._v("• 蘑菇记账")]),t._v(" - 基于Vue全家桶、TypeScript、Echarts实现的一款极简的本地记账应用🤑 ")]),a("p",[a("a",{staticClass:"text-green-1 bd-bottom-about",attrs:{href:"https://github.com/miqilin21/weapp-mogu-bill",target:"_blank"}},[t._v("• 蘑菇记账(小程序版)")]),t._v(" - 原生小程序实现的一款蘑菇记账应用💰 ")]),a("p",[a("a",{staticClass:"text-green-1 bd-bottom-about",attrs:{href:"https://github.com/miqilin21/wx-todos",target:"_blank"}},[t._v("• TODOS(小程序版)")]),t._v(" - 原生小程序实现的一款TODO应用工具📅 ")]),a("p",[a("a",{staticClass:"text-green-1 bd-bottom-about",attrs:{href:"https://github.com/miqilin21/cv",target:"_blank"}},[t._v("• cv")]),t._v(" - 原生js实现的米淇淋个人简历📄 ")]),a("p",[a("a",{staticClass:"text-green-1 bd-bottom-about",attrs:{href:"https://github.com/miqilin21",target:"_blank"}},[t._v("• 其他项目")]),t._v(" - 持续开发中... ")])])])])}],!1,null,"ed059e92",null);s.default=i.exports}}]);
--------------------------------------------------------------------------------
/server/web/js/about.75b89ddb.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/about.75b89ddb.js.gz
--------------------------------------------------------------------------------
/server/web/js/app.c4457924.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/app.c4457924.js.gz
--------------------------------------------------------------------------------
/server/web/js/archive.845f534c.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["archive"],{"12b6":function(t,e,i){"use strict";i.r(e);var s=i("1da1"),a=(i("96cf"),i("5a0c"),{data:function(){return{model:[]}},methods:{getArchive:function(){var t=this;return Object(s.a)(regeneratorRuntime.mark((function e(){var i;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.$http.get("/archive");case 2:i=e.sent,t.model=i.data;case 4:case"end":return e.stop()}}),e)})))()}},mounted:function(){this.getArchive()}}),n=(i("5e0f"),i("2877")),r=Object(n.a)(a,(function(){var t=this,e=t.$createElement,i=t._self._c||e;return t.model?i("div",{staticClass:"main-container"},[i("div",{staticClass:"main-content archive-page"},t._l(t.model,(function(e){return i("div",{key:e._id,staticClass:"categorys-item mt-6"},[i("div",{staticClass:"categorys-title"},[t._v(t._s(t._f("date")(e.list[0].createdAt,"YYYY"))+"年"+t._s(e._id)+"月")]),i("div",{staticClass:"post-lists"},[i("div",{staticClass:"post-lists-body"},t._l(e.list,(function(e){return i("div",{key:e.createdAt,staticClass:"post-list-item"},[i("div",{staticClass:"post-list-item-container show"},[i("div",[t._v(" "+t._s(e.categories.map((function(t){return t.title})).join("|"))+" ")]),i("div",{staticClass:"item-label bg-postcolor"},[i("div",{staticClass:"item-title pl-4"},[i("router-link",{attrs:{to:"/article/list/"+e._id,title:"访问 "+e.title}},[t._v(t._s(e.title))])],1),i("div",{staticClass:"item-meta"},[i("div",{staticClass:"item-meta-date"},[t._v(" "+t._s(t._f("date")(e.createdAt,"YYYY-MM-DD HH:mm:ss"))+" "),i("router-link",{staticClass:"text-grey-1",attrs:{to:"/tags","data-hover":e.categories.map((function(t){return t.name})).join("|")}},[t._v(" "+t._s(e.categories.map((function(t){return t.name})).join("|"))+" ")])],1)])])])])})),0)])])})),0)]):t._e()}),[],!1,null,"2d95d8ee",null);e.default=r.exports},"5e0f":function(t,e,i){"use strict";i("71bf")},"71bf":function(t,e,i){}}]);
--------------------------------------------------------------------------------
/server/web/js/archive.845f534c.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/archive.845f534c.js.gz
--------------------------------------------------------------------------------
/server/web/js/article.b4d913a8.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["article"],{"3ad6":function(t,e,n){"use strict";n.r(e);var a=n("1da1"),s=(n("4de4"),n("d3b7"),n("159b"),n("96cf"),n("e0c1")),r=n.n(s),o=n("1487"),i=n.n(o),c=(n("803b"),n("ac1f"),n("1276"),n("1157")),d=n.n(c),l=n("2b0e");n("466d"),n("5319"),n("d81d");var m=function(t){var e=[];t=t.replace(/]+)*>([^<]+)/g,(function(t,n,a){var s=function(t){var e=t.match(/^]*data-id=(?:"|')([^"']+)/),n="";return e?n=e[1]:(n=parseInt(1e3*Math.random(),10)+"_"+parseInt(100*Math.random()*100),t=t.replace(/(^").addClass("pre-numbering"),n=d()('').addClass("el-icon-document-copy code-copy");d()(this).parent().addClass("code").append(e).append(n);for(var a=0;a<=t;a++)e.append(d()(""))})),d()("pre.code i.code-copy").click((function(t){var e=d()(t.target).siblings("code").text(),n=d()("");d()("body").append(n),n[0].select(),document.execCommand("Copy"),n.remove(),l.default.prototype.$message.success({message:"代码复制成功"})}))}));case 8:case"end":return e.stop()}}),e)})))()},scrollTo:function(t){var e=document.querySelector('[data-id="'+t+'"]');e&&e.scrollIntoView({behavior:"smooth",block:"center",inline:"nearest"})},getBlogsComments:function(){var t=this;return Object(a.a)(regeneratorRuntime.mark((function e(){var n,a;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.$http.get("/comments/".concat(t.id));case 2:n=e.sent,a=n.data,t.parentComments=a.filter((function(t){return"5ec884e3fe28d35475b43fb3"==t.parent})),t.parentComments.forEach((function(t){return t.children=a.filter((function(e){return e.parent==t._id}))})),t.Comments=n.data;case 7:case"end":return e.stop()}}),e)})))()}},mounted:function(){this.fetch(),this.getBlogsComments()}},f=(n("ca92"),n("2877")),h=Object(f.a)(p,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"main-container"},[t.model?n("div",{staticClass:"page-article d-flex jc-center"},[n("div",{staticClass:"d-none left"}),n("div",{staticClass:"page"},[n("div",{staticClass:"text-green fs-xxxxl mt-11"},[t._v(t._s(t.model.title))]),n("div",{staticClass:"text-grey-2 d-flex fs-sm my-4"},[n("p",{staticClass:"mr-4"},[t._v(t._s(t._f("date")(t.model.createdAt,"YYYY-MM-DD HH:mm:ss")))]),n("p",{staticClass:"mr-4"},[t._v("字数 "+t._s(t.model.body.length))]),n("p",[t._v("评论 "+t._s(t.Comments.length))])]),n("div",[n("router-link",{staticClass:"p-2 bdr post-tags text-border text-center bg-blue fs-sm hand mb-6",attrs:{tag:"div",to:"/tags"}},[n("span",[n("i",{staticClass:"iconfont icon-tag1"})]),t._v(" "),n("span",{},[t._v(t._s(t.model.categories[0].name))])])],1),n("div",{staticClass:"text-grey-2 fs-md mb-9 container"},[n("div",{staticClass:"markdown-body"},[n("div",{attrs:{id:"content"},domProps:{innerHTML:t._s(t.model.body)}})])])]),n("div",{staticClass:"d-none left"},[n("div",{staticClass:"blogs-menu toc-sticky text-grey-1 pl-9"},[n("div",[n("h2",[t._v("目录")]),t._l(t.articleToc,(function(e){return n("div",{key:e.id,staticClass:"menu-title hand text-ellipsis",style:{paddingLeft:e.indent+"em"},attrs:{title:e.text},on:{click:function(n){return t.scrollTo(e.id)}}},[t._v(t._s(e.text))])}))],2)])])]):t._e(),t.model?n("div",{staticClass:"art-comment"},[t._m(0),n("h3",{staticClass:"fs-xxxxl mt-9"},[t._v("评论")]),n("comment-textarea",{staticClass:"textarea-box bg-postcolor bdr",attrs:{model:"comments",type:"parent",blogsId:t.id,placeholder:"输入留言内容"},on:{toResponse:t.getBlogsComments}}),t.parentComments?n("comment-list",{staticClass:"mt-7 mb-10",attrs:{model:"comments",commentsList:t.parentComments,blogsId:t.id},on:{getCommentList:t.getBlogsComments}}):t._e()],1):t._e(),n("div",{staticClass:"w-100 h-100"},[n("el-backtop",{attrs:{bottom:50}})],1)])}),[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"text-grey border-top"},[n("p",[t._v("• 非特殊说明,本博所有文章均为博主原创。")]),n("p",[t._v("• 本博客所有文章均采用 CC BY-SA 3.0协议 。转载请注明出处!")])])}],!1,null,"7900f6df",null);e.default=h.exports},ca92:function(t,e,n){"use strict";n("f04a")},f04a:function(t,e,n){}}]);
--------------------------------------------------------------------------------
/server/web/js/article.b4d913a8.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/article.b4d913a8.js.gz
--------------------------------------------------------------------------------
/server/web/js/home.6e81e34d.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["home"],{"225f":function(t,a,e){},"52a5":function(t,a,e){"use strict";e("225f")},bb51:function(t,a,e){"use strict";e.r(a);var n=e("1da1"),s=(e("96cf"),e("1157")),i=e.n(s),r={data:function(){return{articles:[],pagination:{totalPage:1,currentPage:1}}},methods:{fetchData:function(){var t=this;return Object(n.a)(regeneratorRuntime.mark((function a(){var e;return regeneratorRuntime.wrap((function(a){for(;;)switch(a.prev=a.next){case 0:return a.next=2,t.$http.get("/articles/".concat(t.pagination.currentPage));case 2:e=a.sent,t.articles=e.data.list,t.pagination.totalPage=e.data.totalPage,t.pagination.currentPage=e.data.currentPage;case 6:case"end":return a.stop()}}),a)})))()},goToPage:function(t){var a=this;return Object(n.a)(regeneratorRuntime.mark((function e(){return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:a.pagination.currentPage=t,a.fetchData();case 2:case"end":return e.stop()}}),e)})))()},prev:function(){1!=this.pagination.currentPage&&(this.pagination.currentPage--,this.fetchData())},next:function(){this.pagination.currentPage!=this.pagination.totalPage&&(this.pagination.currentPage++,this.fetchData())},downPage:function(){i()("html,body").animate({scrollTop:i()("#header").outerHeight()-56},500)}},mounted:function(){this.fetchData()}},c=(e("52a5"),e("2877")),o=Object(c.a)(r,(function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"mb-9"},[e("div",{staticClass:"mb-7"},[e("div",{staticClass:"bgImg d-flex jc-center",attrs:{id:"header"}},[t._m(0),e("div",{staticClass:"arrow-down"},[e("i",{staticClass:"iconfont icon-down",on:{click:t.downPage}})])])]),e("div",{staticClass:"post-container d-flex flex-wrap jc-center ai-center"},t._l(t.articles,(function(a,n){return e("div",{key:n},[e("div",{staticClass:"show home-art"},[e("router-link",{staticClass:"top mt-10 mx-8 mb-0 hand",style:{"background-image":"url("+a.icon+")"},attrs:{tag:"div",to:"/article/list/"+a._id}}),e("div",{staticClass:"bg-postcolor pt-8 mx-8 title"},[e("router-link",{staticClass:"fs-xxl jc-center d-flex flex-wrap hand text-grey-1",attrs:{tag:"span",to:"/article/list/"+a._id}},[t._v(t._s(a.title))]),e("div",{staticClass:"d-flex mt-4 p-7 text-grey-1"},[e("i",{staticClass:"iconfont icon-riqi2 pr-2"}),e("span",{staticClass:"fs-sm"},[t._v(t._s(t._f("date")(a.createdAt,"YYYY-MM-DD")))]),e("i",{staticClass:"iconfont icon-sort pl-9"}),e("router-link",{staticClass:"fs-sm pl-2 mr-6 hand",attrs:{tag:"span",to:"/tags"}},[t._v(t._s(a.categories[0].name))]),e("i",{staticClass:"iconfont icon-love text-red hand"})],1)],1)],1)])})),0),t.articles.length>0?e("div",{staticClass:"my-10"},[e("div",{staticClass:"page-navigator d-flex jc-center"},[e("div",{staticClass:"mx-4 hand fs-md",class:{current:1==t.pagination.currentPage}},[e("a",{attrs:{"data-hover":"首页"},on:{click:function(a){return t.goToPage(1)}}},[e("span",{staticClass:"text-grey-1"},[t._v("首页")])])]),e("div",{staticClass:"mx-4 hand fs-md"},[e("a",{on:{click:function(a){return t.prev()}}},[e("span",{staticClass:"text-grey-1"},[t._v("«")])])]),t._l(t.pagination.totalPage,(function(a){return e("div",{key:a,staticClass:"mx-4 hand fs-md",class:{current:a==t.pagination.currentPage}},[e("a",{staticClass:"text-grey-1",attrs:{"data-hover":a},on:{click:function(e){return t.goToPage(a)}}},[t._v(t._s(a))])])})),e("div",{staticClass:"mx-4 hand fs-md"},[e("a",{on:{click:function(a){return t.next()}}},[e("span",{staticClass:"text-grey-1"},[t._v("»")])])]),e("div",{staticClass:"mx-4 hand fs-md",class:{current:t.pagination.totalPage==t.pagination.currentPage}},[e("a",{attrs:{"data-hover":"末页"},on:{click:function(a){return t.goToPage(t.pagination.totalPage)}}},[e("span",{staticClass:"text-grey-1"},[t._v("末页")])])]),e("div",{staticClass:"current mx-4 fs-md"},[e("span",{staticClass:"text-grey-1"},[t._v("第"+t._s(t.pagination.currentPage)+"页 / 共"+t._s(t.pagination.totalPage)+"页")])])],2)]):t._e()])}),[function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"text-white d-flex jc-center ai-center"},[e("span",{staticClass:"shouye-text"},[t._v("亲亲这边建议您要多喝热水哦")]),e("span",{staticClass:"line-down pl-3"},[t._v("_")])])}],!1,null,"686b6344",null);a.default=o.exports}}]);
--------------------------------------------------------------------------------
/server/web/js/home.6e81e34d.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/home.6e81e34d.js.gz
--------------------------------------------------------------------------------
/server/web/js/link.2206432e.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["link"],{"11fa":function(t,s,e){"use strict";e("9ede")},"6e1e":function(t,s,e){},"9ede":function(t,s,e){},ef85:function(t,s,e){"use strict";e.r(s);var n=e("1da1"),a=(e("96cf"),{data:function(){return{model:[]}},methods:{fetchLinks:function(){var t=this;return Object(n.a)(regeneratorRuntime.mark((function s(){var e;return regeneratorRuntime.wrap((function(s){for(;;)switch(s.prev=s.next){case 0:return s.next=2,t.$http.get("links/list");case 2:e=s.sent,t.model=e.data;case 4:case"end":return s.stop()}}),s)})))()}},mounted:function(){this.fetchLinks()}}),i=(e("11fa"),e("2877")),l={components:{linkItem:Object(i.a)(a,(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"link d-flex my-6 content"},t._l(t.model,(function(s){return e("div",{key:s.name,staticClass:"link-item show m-4 p-4 bg-postcolor bdr"},[e("el-tooltip",{attrs:{placement:"right-end",effect:"light","popper-class":"text-grey-2 fs-lg"}},[e("div",{staticClass:"text-green",attrs:{slot:"content"},slot:"content"},[t._v(t._s(s.site))]),e("a",{staticClass:"hand",attrs:{href:s.site,target:"_blank"}},[e("div",{staticClass:"ai-center d-flex"},[e("span",[e("img",{staticClass:"link-img",attrs:{src:s.icon}})]),e("span",{staticClass:"fs-lg text-green pl-5 link-font text-ellipsis"},[t._v(" "+t._s(s.name)+" ")])])])]),e("div",{staticClass:"fs-xs text-grey-1 mt-3 text-ellipsis"},[t._v(t._s(s.description))])],1)})),0)}),[],!1,null,null,null).exports},data:function(){return{}}},c=(e("f8e1"),Object(i.a)(l,(function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"main-container page-link py-9"},[e("div",{staticClass:"p-5"},[t._m(0),e("linkItem"),t._m(1)],1)])}),[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"content"},[e("div",{staticClass:"text-green fs-xxxxl"},[t._v("Links")]),e("div",{staticClass:"text-grey-2 fs-sm mt-5"},[t._v("Published on March 11th 2020")]),e("div",{staticClass:"mt-5 mb-7"}),e("div",[e("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),e("span",{staticClass:"fs-xxl text-grey-1"},[t._v("友情链接")])])])},function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"content"},[e("div",{staticClass:"py-4"},[e("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),e("span",{staticClass:"fs-xxl text-grey-1"},[t._v("链接需知")])]),e("div",{staticClass:"px-5 py-2 text-green-1"},[e("p",[t._v("• 请确定贵站可以稳定运营")]),e("p",[t._v("• 原创博客优先,技术类博客优先,设计、视觉类博客优先")]),e("p",[t._v("• 经常过来访问和评论,眼熟的")])]),e("p",{staticClass:"text-grey-2 my-6"},[t._v("备注:默认申请友情链接均为内页(当前页面)")]),e("div",{staticClass:"py-4 mb-5"},[e("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),e("span",{staticClass:"fs-xxl text-grey-1"},[t._v("基本信息")])]),e("div",{staticClass:"bg-postcolor px-5 py-2 text-green-1 fs-sm bdr"},[e("p",[t._v("• 格式比如:")]),e("p",[t._v("• 网站名称:米淇淋的个人博客")]),e("p",[t._v("• 网站地址:https://amberzqx.com")]),e("p",[t._v("• 描述:我劝你要多喝热水哈哈哈")])]),e("p",{staticClass:"my-9 text-grey-2"},[t._v("暂时先这样,同时欢迎互换友链,到留言页留言即可。 ^_^")])])}],!1,null,null,null));s.default=c.exports},f8e1:function(t,s,e){"use strict";e("6e1e")}}]);
--------------------------------------------------------------------------------
/server/web/js/link.2206432e.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/link.2206432e.js.gz
--------------------------------------------------------------------------------
/server/web/js/message.dcf21bf0.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["message"],{"3bb2":function(t,e,s){},"61b7":function(t,e,s){"use strict";s("3bb2")},"8e2a":function(t,e,s){"use strict";s.r(e);var a=s("1da1"),n=(s("96cf"),s("4de4"),s("d3b7"),s("159b"),{data:function(){return{parentComments:[]}},mounted:function(){this.getMessagesList()},methods:{getMessagesList:function(){var t=this;return Object(a.a)(regeneratorRuntime.mark((function e(){var s,a;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.$http.get("messages");case 2:s=e.sent,a=s.data,t.parentComments=a.filter((function(t){return"5ec884e3fe28d35475b43fb3"==t.parent})),t.parentComments.forEach((function(t){return t.children=a.filter((function(e){return e.parent==t._id}))}));case 6:case"end":return e.stop()}}),e)})))()}}}),r=(s("61b7"),s("2877")),i=Object(r.a)(n,(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"main-container page-message d-flex flex-column ai-center pt-9"},[s("div",{staticClass:"page p-5"},[t._m(0),s("div",[t._m(1),s("div",{class:{"message-box":t.parentComments.length>0}},[s("div",{staticClass:"textarea-box bg-postcolor bdr"},[s("comment-textarea",{attrs:{model:"messages",type:"parent",placeholder:"输入留言内容"},on:{toResponse:t.getMessagesList}})],1),s("div",{staticClass:"my-9",class:{"message-box":t.parentComments.length>0}},[t.parentComments?s("comment-list",{attrs:{model:"messages",commentsList:t.parentComments},on:{getCommentList:t.getMessagesList}}):t._e()],1)])])])])}),[function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"content"},[s("div",{staticClass:"text-green fs-xxxxl"},[t._v("Message")]),s("div",{staticClass:"text-grey-2 fs-sm mt-5"},[t._v("Published on March 11th 2020")]),s("div",{staticClass:"mt-5 mb-5"}),s("div",{staticClass:"py-4"},[s("span",{staticClass:"fs-xxl text-green"},[t._v("#")]),t._v(" "),s("span",{staticClass:"fs-xxl text-grey-1"},[t._v("留言前需知")])]),s("div",{staticClass:"pl-5 text-green-1"},[s("p",[t._v("• 烦请各位留言时务必填写自己真实的邮箱")]),s("p",[t._v("• 留言博主基本都会回复,并会邮件通知留言者")]),s("p",[t._v("• 请不要发广告和带有商业推广链接的无用留言")])]),s("p",{staticClass:"my-8 text-grey-2"},[t._v("希望彼此之间有好的交流。 ^_^")])])},function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"mb-7"},[s("span",{staticClass:"fs-xxxl text-grey-1 text-center ml-5"},[t._v("留言板")])])}],!1,null,"2cc96d00",null);e.default=i.exports}}]);
--------------------------------------------------------------------------------
/server/web/js/message.dcf21bf0.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/message.dcf21bf0.js.gz
--------------------------------------------------------------------------------
/server/web/js/tag.4428a61a.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["tag"],{2722:function(t,e,s){},"295e":function(t,e,s){"use strict";s("2722")},"8ea7":function(t,e,s){"use strict";s.r(e);var a=s("1da1"),i=(s("96cf"),s("5a0c")),r=s.n(i),n={data:function(){return{model:[]}},methods:{fetch:function(){var t=this;return Object(a.a)(regeneratorRuntime.mark((function e(){var s;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t.$http.get("/tags");case 2:s=e.sent,t.model=s.data;case 4:case"end":return e.stop()}}),e)})))()},getDataHover:function(t){return r()(t).format("YYYY-MM-DD HH:mm:ss")}},mounted:function(){this.fetch()}},c=(s("295e"),s("2877")),o=Object(c.a)(n,(function(){var t=this,e=t.$createElement,s=t._self._c||e;return t.model?s("div",{staticClass:"main-container"},[s("div",{staticClass:"main-content archive-page"},[s("div",{staticClass:"post-title text-green fs-xxxxl"},[t._v("标签分类的博文--点击自动查找相应`Tag`")]),s("div",{staticClass:"text-grey-2 fs-sm mt-6"},[t._v("Published on March 11th 2020")]),s("div",[s("div",{staticClass:"post-tags"},t._l(t.model,(function(e){return s("a",{key:e._id,attrs:{href:"#"+e._id}},[t._v(" "+t._s(e._id)+" "),s("span",[t._v("("+t._s(e.count)+")个")])])})),0)])]),s("div",{staticClass:"main-content archive-page"},t._l(t.model,(function(e){return s("div",{key:e._id,staticClass:"post-lists anchor",attrs:{id:""+e._id}},[s("div",[s("div",{staticClass:"categorys-title"},[t._v(t._s(e._id)+" : "+t._s(e.count))]),t._l(e.list,(function(a){return s("div",{key:a.categories._id,staticClass:"post-list-item"},[s("div",{staticClass:"post-list-item-container bg-postcolor show"},[s("div",{staticClass:"item-label"},[s("div",{staticClass:"item-title pl-4"},[s("router-link",{attrs:{"data-hover":""+a.categories.title,to:"/article/list/"+a.categories._id}},[t._v(t._s(a.categories.title))])],1),s("div",{staticClass:"item-meta"},[s("div",{staticClass:"item-meta-date"},[s("router-link",{staticClass:"text-grey-1",attrs:{to:"/archives","data-hover":t.getDataHover(a.categories.createdAt)}},[t._v(t._s(t._f("date")(a.categories.createdAt,"YYYY-MM-DD HH:mm:ss")))]),s("router-link",{staticClass:"text-grey-1",attrs:{"data-hover":""+e._id,to:"/tags"}},[t._v(t._s(e._id))])],1)])])])])}))],2)])})),0)]):t._e()}),[],!1,null,"4ae8544e",null);e.default=o.exports}}]);
--------------------------------------------------------------------------------
/server/web/js/tag.4428a61a.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/tag.4428a61a.js.gz
--------------------------------------------------------------------------------
/server/web/js/vendors~app.38cd00d7.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
2 | * @license MIT */
3 |
4 | /*!
5 | * vue-router v3.5.3
6 | * (c) 2021 Evan You
7 | * @license MIT
8 | */
9 |
10 | /*!
11 | * Vue.js v2.6.14
12 | * (c) 2014-2021 Evan You
13 | * Released under the MIT License.
14 | */
15 |
16 | /*!
17 | * vuex v3.6.2
18 | * (c) 2021 Evan You
19 | * @license MIT
20 | */
21 |
22 | /*! *****************************************************************************
23 | Copyright (c) Microsoft Corporation.
24 |
25 | Permission to use, copy, modify, and/or distribute this software for any
26 | purpose with or without fee is hereby granted.
27 |
28 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
29 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
30 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
31 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
32 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
33 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
34 | PERFORMANCE OF THIS SOFTWARE.
35 | ***************************************************************************** */
36 |
37 | /**
38 | * vue-class-component v7.2.6
39 | * (c) 2015-present Evan You
40 | * @license MIT
41 | */
42 |
43 | /**
44 | * Checks if an event is supported in the current execution environment.
45 | *
46 | * NOTE: This will not work correctly for non-generic events such as `change`,
47 | * `reset`, `load`, `error`, and `select`.
48 | *
49 | * Borrows from Modernizr.
50 | *
51 | * @param {string} eventNameSuffix Event name, e.g. "click".
52 | * @param {?boolean} capture Check if the capture phase is supported.
53 | * @return {boolean} True if the event is supported.
54 | * @internal
55 | * @license Modernizr 3.0.0pre (Custom Build) | MIT
56 | */
57 |
--------------------------------------------------------------------------------
/server/web/js/vendors~app.38cd00d7.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/vendors~app.38cd00d7.js.gz
--------------------------------------------------------------------------------
/server/web/js/vendors~article.b06189d7.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/vendors~article.b06189d7.js.gz
--------------------------------------------------------------------------------
/server/web/js/vendors~article~home.db3e17e7.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | * Sizzle CSS Selector Engine v2.3.6
3 | * https://sizzlejs.com/
4 | *
5 | * Copyright JS Foundation and other contributors
6 | * Released under the MIT license
7 | * https://js.foundation/
8 | *
9 | * Date: 2021-02-16
10 | */
11 |
12 | /*!
13 | * jQuery JavaScript Library v3.6.0
14 | * https://jquery.com/
15 | *
16 | * Includes Sizzle.js
17 | * https://sizzlejs.com/
18 | *
19 | * Copyright OpenJS Foundation and other contributors
20 | * Released under the MIT license
21 | * https://jquery.org/license
22 | *
23 | * Date: 2021-03-02T17:08Z
24 | */
25 |
--------------------------------------------------------------------------------
/server/web/js/vendors~article~home.db3e17e7.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/server/web/js/vendors~article~home.db3e17e7.js.gz
--------------------------------------------------------------------------------
/web/.env.development:
--------------------------------------------------------------------------------
1 | VUE_APP_API_URL = http://localhost:3000/web/api
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/web/README.md:
--------------------------------------------------------------------------------
1 | # web
2 |
3 | ## Project setup
4 | ```
5 | yarn install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | yarn serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | yarn build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | yarn lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "axios": "0.24.0",
12 | "dayjs": "1.10.7",
13 | "element-ui": "2.15.1",
14 | "highlight.js": "10.7.3",
15 | "jquery": "3.4.1",
16 | "marked": "4.0.10",
17 | "nprogress": "0.2.0",
18 | "v-emoji-picker": "2.1.7",
19 | "vue": "2.6.14",
20 | "vue-router": "3.5.1",
21 | "vuex": "3.6.2"
22 | },
23 | "devDependencies": {
24 | "@vue/cli-plugin-eslint": "4.5.13",
25 | "@vue/cli-service": "4.5.13",
26 | "babel-eslint": "10.0.3",
27 | "compression-webpack-plugin": "6.1.1",
28 | "eslint": "6.7.2",
29 | "eslint-plugin-vue": "6.1.2",
30 | "sass": "1.26.3",
31 | "sass-loader": "8.0.2",
32 | "vue-template-compiler": "2.6.14"
33 | },
34 | "eslintConfig": {
35 | "root": false,
36 | "env": {
37 | "node": false
38 | },
39 | "extends": [
40 | "plugin:vue/essential",
41 | "eslint:recommended"
42 | ],
43 | "parserOptions": {
44 | "parser": "babel-eslint"
45 | },
46 | "rules": {}
47 | },
48 | "browserslist": [
49 | "> 1%",
50 | "last 2 versions"
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/web/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/public/favicon.ico
--------------------------------------------------------------------------------
/web/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
15 |
16 |
20 | 米淇淋的个人博客
21 |
22 |
23 |
24 |
25 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/web/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
102 |
--------------------------------------------------------------------------------
/web/src/assets/iconfont/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('iconfont.eot?t=1590638174211'); /* IE9 */
3 | src: url('iconfont.eot?t=1590638174211#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAdwAAsAAAAADsgAAAckAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCENgqPEIwpATYCJAMsCxgABCAFhG0HeBuBDBFVpK+T/UiwcYvrXxdV1CS9yeDfLZuXFyzB14ztilF1uhWoKARqIqHnUDO2xjpy5xUVpKZwKn9HAwQQtN1casamAUSA/IShXbSbe8iO8kNfWZ9xvAwXoQJYAHvf2q+Kty+hYIM0CwVquznRPR6LiiXXkEhEUa80QoVEtFJoGYiozlLTJyyMvHQ+EAAccmEE6dVngA1ysNBUQrnZM6ZNgDwWArbESCAPlObsy4JsgQRy5jPmFoDN7seTn9CKyAEGEgrtQkOm9p4MUyw5doiKCRGjqQixvygAbysBFIARAPumf5kb5AMa+TFTcFVZrAaQCq1SpOp3So8ZYx1jlbG+sSGxsbHdsUOJBKiWtPEIUvW1AA4yyCGBYvQsFlIwb/88KURTYvtpLgfEkk0uJOlQyCBGKOSQjlBIIJVQKCB9oaCQIVAQyFgoWMhuKKSQQ9QAAwDg7X1SAZQDzCCAVkDTB7grsWDBQA4K/lKIAYFEiad8bZpKxRKtXis5RaXTqtUqKqUqlWlJCoXBeWMTIhF7NOoIh4VQaGXonS38XojGHZHYaK4h4AyW8PV+0TfKvovjXDuSk5mGYu7Qvez999vyRx/mpfJU2Mm703ZXrQqFbKHHwmG+lyrRJ/YjJndRWBWxhUID7oU6T7oQcUT5hODygRH97iChzgAXedg465Qh04ZOHjaK8KBc3als7D9dxDeezSMHzixPm9Phscw62yS7Q7DaA65Sm08sE/zuCkfQOb1OkUOnAPH03DjoKrH0GK7yqbu+JMTp4OsPp0zxzxU99k137kxz7HamTt3VwHE74EwW3I17nVUNrro9oqd+hXq+imQdimZLFHZdysoFK+yrpeYrJQcetLM1BDLJ3qDbD4i+QmWs84hNiy6cpv0y8Tp3wmzOlTswjqfL+MZdVGStsF+MkmnhbPBnaXd0sLCzPlg18fT8r6LLa7c7yeyKRJyocDi/Ab0cdousirhs6cXWpUKiMGWnO21aNDqt8azzjOuUeHqCt83k42F3tPPZrN1VDXXJO3Tvhbdsrkh5Q+quqg11e1I8IyIx+wA4TGzo3cqp4PCVI5GEykdfvaKW7HtFpLASt33oORZgMZ4DJGr8WW82nSw/abL/yJkjiyttCso/UxDHLK/53Mmc7JPnzPdOKqVkZf+KSTLtxpEC8v4yNTB/383xpZ16mHciv7DJ7+OSm+de7M87B41cVbCN76/oVblswMNdTb26Twa3MN1OLjNjxNpmdS/VOjVMLVu63Iksg+kVz3ftejb84TMOfI4NT+Pfx9t8//sJxHHidzdF+wHzfU6Jk5rvNSd/hyGr48ya2hpDFszaS7ouqa21d7fX+idxdJ00/vt4vE0cJw3fG04ijmDlZwqgwx852cIvvwhthRkzftVkPqvsgWemsbcWLhROfKx1L5sxo803U4uirDpbaudi7tk5QpTfPFB1vpx2uVNGJ/uFO6PVEGFkD5l9DHrKYBk/zkz6Wci4ccQiI+Zx4y0orE31fsrJuE+9/bx73HPs8c6Y1MJDDzKeUk/SwWRPi3UxxxL/On7Dk/+MLTwlnhZqJbdQbvCXBJLKk6uIGXnRKGz+qKrku5EAd3rt29q+y362Q2eT7M6dmuZrzLTm0aMaS6avobQmTDSvaV6ev2zA24T7f+snzKFDzCc6I2hJYWUYqPiYNRhY5MeCSHIfg7Uzb5xttc42ft3W2qFkvH5iv34TkyaUtreyW7Dd17ONVqtxNo+Ow55YB78ynM7xtsEvDYOtr7Zftuxm/tOly4bZ8Qq9rm5p1Va3aBK1BV4bw8KtBqgVQvZMeR7FBJ9lYkaxhZl+RlUxAk17p+7M+XK43pLacWhf34OBITYriw0JI2hJYXGV9eg5NpG40hlBkWRl68YDQOIYvUYt7jHO0oe0BwDQ3cwsIHGO6hj3kojTzczLnAB9QEfUiTpPTThfozFanreR/kdXPcqsh1YXNqwfp+nyj5x/4pnx5B/HWHeDhMiCigDkt5VYAjym8DU7sb+ixvXRLibXMo7HnttVFgOA03sAjyQJerzoX0+pzT986SkhMJAhByjkKLRkbY2glOC1ASm57sCp8LQWL4mYI1PcNvVvgND6AYbaWaC0fi1Z2z+QSPUPUtrmwLG3PyavONrdCRpFD/YG5LgPRrjuvPKvGMfWSFR0nT5REqVDlZfJ/CfsUfrYIZ1jrRogCHfweLkYti3DIHxCp/lRdTgURcjbMXfcTXZ6EshQ26sHrJtf4rBeGFvtUu//CkWjliElzf74/YREQosHlVxZw/JJ62s1O5eqyVlUUxUVgFlXsA54VFGo1XMYGPLXOkGOyh1bZA0OCtVdqKvl4+vd9b0AgKM9Bx9DKGGJhEiJjMiJgnCEJ0rIPiZyGa+ejfcKWC08X/pFYtGFmlgthb6oXgTq/UZ5vJLp46LlMy7fOmpxMgE=') format('woff2'),
5 | url('iconfont.woff?t=1590638174211') format('woff'),
6 | url('iconfont.ttf?t=1590638174211') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('iconfont.svg?t=1590638174211#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-music-o:before {
19 | content: "\e650";
20 | }
21 |
22 | .icon-Pause1:before {
23 | content: "\e6b4";
24 | }
25 |
26 | .icon-down:before {
27 | content: "\e649";
28 | }
29 |
30 | .icon-sort:before {
31 | content: "\e65e";
32 | }
33 |
34 | .icon-tag1:before {
35 | content: "\e639";
36 | }
37 |
38 | .icon-riqi2:before {
39 | content: "\e697";
40 | }
41 |
42 | .icon-find:before {
43 | content: "\e618";
44 | }
45 |
46 | .icon-touxiang:before {
47 | content: "\e62c";
48 | }
49 |
50 | .icon-love:before {
51 | content: "\e642";
52 | }
53 |
54 | .icon-Smile:before {
55 | content: "\e614";
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/web/src/assets/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/web/src/assets/iconfont/iconfont.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "1845533",
3 | "name": "blog",
4 | "font_family": "iconfont",
5 | "css_prefix_text": "icon-",
6 | "description": "",
7 | "glyphs": [
8 | {
9 | "icon_id": "11132369",
10 | "name": "music-o",
11 | "font_class": "music-o",
12 | "unicode": "e650",
13 | "unicode_decimal": 58960
14 | },
15 | {
16 | "icon_id": "13745135",
17 | "name": "Pause",
18 | "font_class": "Pause1",
19 | "unicode": "e6b4",
20 | "unicode_decimal": 59060
21 | },
22 | {
23 | "icon_id": "1207827",
24 | "name": "down",
25 | "font_class": "down",
26 | "unicode": "e649",
27 | "unicode_decimal": 58953
28 | },
29 | {
30 | "icon_id": "5732293",
31 | "name": "分类",
32 | "font_class": "sort",
33 | "unicode": "e65e",
34 | "unicode_decimal": 58974
35 | },
36 | {
37 | "icon_id": "9512650",
38 | "name": "标签",
39 | "font_class": "tag1",
40 | "unicode": "e639",
41 | "unicode_decimal": 58937
42 | },
43 | {
44 | "icon_id": "766689",
45 | "name": "date",
46 | "font_class": "riqi2",
47 | "unicode": "e697",
48 | "unicode_decimal": 59031
49 | },
50 | {
51 | "icon_id": "902003",
52 | "name": "find",
53 | "font_class": "find",
54 | "unicode": "e618",
55 | "unicode_decimal": 58904
56 | },
57 | {
58 | "icon_id": "10905612",
59 | "name": "头像",
60 | "font_class": "touxiang",
61 | "unicode": "e62c",
62 | "unicode_decimal": 58924
63 | },
64 | {
65 | "icon_id": "11349144",
66 | "name": "love",
67 | "font_class": "love",
68 | "unicode": "e642",
69 | "unicode_decimal": 58946
70 | },
71 | {
72 | "icon_id": "2127147",
73 | "name": "微笑",
74 | "font_class": "Smile",
75 | "unicode": "e614",
76 | "unicode_decimal": 58900
77 | }
78 | ]
79 | }
80 |
--------------------------------------------------------------------------------
/web/src/assets/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/web/src/assets/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/web/src/assets/iconfont/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/iconfont/iconfont.woff2
--------------------------------------------------------------------------------
/web/src/assets/images/bg-blog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/bg-blog.png
--------------------------------------------------------------------------------
/web/src/assets/images/git/git-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/git/git-1.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/learn1/learn1-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/learn1/learn1-0.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/learn1/learn1-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/learn1/learn1-2.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/learn1/learn1-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/learn1/learn1-3.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/learn1/learn1-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/learn1/learn1-4.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/logo.png
--------------------------------------------------------------------------------
/web/src/assets/images/this/this-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/this/this-1.jpg
--------------------------------------------------------------------------------
/web/src/assets/images/this/this-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonemeen/iBlog/2c97326749fcede04f88d28c2b8be8fc3ea4bc9f/web/src/assets/images/this/this-2.png
--------------------------------------------------------------------------------
/web/src/assets/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | // colors
2 | $colors: (
3 | 'blue': #6fa3ef,
4 | 'red': #eb5055,
5 | 'green': #34b686,
6 | 'green-1': #a7ce94,
7 | 'postcolor': #363938,
8 | 'orange': #986801,
9 | 'white': #fff,
10 | 'border': #f1f3f7,
11 | 'bgcolor': #1e2020,
12 | 'navcolor': #363938,
13 | 'codecolor': #9b9999,
14 | 'textcolor': #cccccc,
15 | 'grey-1': #bbbbbb,
16 | 'grey-2': #767676,
17 | 'grey-3': #666666,
18 | 'grey': #5f5f5f,
19 | 'dark': #313131,
20 | 'dark-3': #333333,
21 | 'dark-4': #262626,
22 | 'dark-1': #222222,
23 | 'dark-2': #444444
24 | );
25 | $border-color: map-get($colors, 'dark-2');
26 | // font size
27 | $base-font-size: 1rem;
28 | $font-sizes: (
29 | xs: 0.8571,
30 | //12px
31 | sm: 0.9286,
32 | //13px
33 | md: 1,
34 | //14px
35 | lg: 1.0714,
36 | //15px
37 | xl: 1.1429,
38 | //16px
39 | xxl: 1.2143,
40 | //17px
41 | xxxl: 1.2857,
42 | //18px
43 | xxxxl: 1.5,
44 | //21px
45 | );
46 |
47 | //justify-content 主轴
48 | $flex-jc: (
49 | start: flex-start,
50 | end: flex-end,
51 | center: center,
52 | between: space-between,
53 | around: space-around
54 | );
55 | $flex-ai: (
56 | start: flex-start,
57 | end: flex-end,
58 | center: center,
59 | stretch: stretch
60 | );
61 | // spacing
62 | // 0-5: 0
63 | // .mt-1 => margin top .pb-2
64 | $spacing-types: (
65 | m: margin,
66 | p: padding
67 | );
68 | $spacing-directions: (
69 | t: top,
70 | r: right,
71 | b: bottom,
72 | l: left
73 | );
74 | $spacing-base-size: 1rem;
75 | $spacing-sizes: (
76 | 0: 0,
77 | 1: 0.15,
78 | 2: 0.35,
79 | 3: 0.5,
80 | 4: 0.714,
81 | 5: 1,
82 | 6: 1.5,
83 | 7: 1.8,
84 | 8: 2.14,
85 | 9: 3,
86 | 10: 4.5,
87 | 11: 6
88 | );
89 |
--------------------------------------------------------------------------------
/web/src/commentConfig.js:
--------------------------------------------------------------------------------
1 | const commentConfig = {
2 | topNickName: 'miqilin',
3 | topParentId: '5ec884e3fe28d35475b43fb3',
4 | }
5 |
6 | export default commentConfig
7 |
--------------------------------------------------------------------------------
/web/src/components/Footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
86 |
87 |
88 |
157 |
158 |
165 |
--------------------------------------------------------------------------------
/web/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
25 | {{ item.text }}
26 |
27 |
28 |
34 |
40 |
41 |
49 |
(isShowMenu = v)">
50 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 首页
62 |
63 |
64 | 归档
65 |
66 |
67 | 标签
68 |
69 |
70 | 友链
71 |
72 |
73 | 留言
74 |
75 |
76 | 关于
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
132 |
133 |
212 |
--------------------------------------------------------------------------------
/web/src/components/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
15 |
16 |
25 |
26 |
27 |
34 | {{ blog.title }}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
87 |
88 |
107 |
--------------------------------------------------------------------------------
/web/src/components/formInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
70 |
71 |
72 |
172 |
173 |
214 |
--------------------------------------------------------------------------------
/web/src/components/linkItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
13 | {{ item.site }}
14 |
15 |
16 |
17 |
18 |
19 |
20 | {{ item.name }}
21 |
22 |
23 |
24 |
25 |
26 | {{ item.description }}
27 |
28 |
29 |
30 |
31 |
32 |
50 |
51 |
90 |
--------------------------------------------------------------------------------
/web/src/components/snow.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
203 |
204 |
214 |
--------------------------------------------------------------------------------
/web/src/http.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | import axios from 'axios'
3 |
4 | const http = axios.create({
5 | baseURL: process.env.VUE_APP_API_URL || '/web/api',
6 | timeout: 20 * 1000, // Timeout
7 | })
8 |
9 | export default http;
--------------------------------------------------------------------------------
/web/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 | import ElementUI from 'element-ui'
6 | import 'element-ui/lib/theme-chalk/index.css'
7 | import NProgress from 'nprogress'
8 | import 'nprogress/nprogress.css'
9 | import './assets/scss/style.scss'
10 | import './assets/iconfont/iconfont.css'
11 | import './plugins/filters'
12 | import './plugins/global'
13 | import http from './http'
14 |
15 | Vue.config.productionTip = false
16 | Vue.use(ElementUI)
17 | Vue.prototype.$http = http
18 |
19 | NProgress.configure({
20 | easing: 'ease',
21 | speed: 500,
22 | showSpinner: false,
23 | trickleSpeed: 200,
24 | minimum: 0.3,
25 | })
26 | router.beforeEach((to, from, next) => {
27 | NProgress.start()
28 | next()
29 | })
30 | router.afterEach(() => {
31 | NProgress.done()
32 | })
33 | // axios请求拦截器
34 | http.interceptors.request.use(
35 | (config) => {
36 | NProgress.start()
37 | return config
38 | },
39 | (error) => {
40 | return Promise.reject(error)
41 | }
42 | )
43 | // axios响应拦截器
44 | http.interceptors.response.use(
45 | (response) => {
46 | NProgress.done()
47 | return response.status === 200
48 | ? Promise.resolve(response)
49 | : Promise.reject(response)
50 | },
51 | (error) => {
52 | return Promise.reject(error)
53 | }
54 | )
55 |
56 | new Vue({
57 | router,
58 | store,
59 | render: (h) => h(App),
60 | }).$mount('#app')
61 |
--------------------------------------------------------------------------------
/web/src/plugins/Toc.js:
--------------------------------------------------------------------------------
1 | function prefixID(htmlPart) {
2 | let idMatches = htmlPart.match(/^]*data-id=(?:"|')([^"']+)/)
3 | let id = ''
4 | if (idMatches) {
5 | id = idMatches[1]
6 | } else {
7 | id = parseInt(Math.random() * 1000, 10) + '_' + parseInt(Math.random() * 100 * 100)
8 | htmlPart = htmlPart.replace(/(^]+)*>([^<]+)/g, (htmlPart, indent, text) => {
19 | let prefix = prefixID(htmlPart, indent, text)
20 | toc.push({
21 | indent,
22 | text,
23 | id: prefix.id
24 | })
25 | return prefix.htmlPart
26 | })
27 | // debugger
28 | // article = article.replace(/]+href=['"]([^'"]*)['"]>/g, (htmlPart, indent, text) => {
29 | // let replaceA = htmlPart.replace(/(^ item.indent))
34 | toc.forEach(item => {
35 | item.indent = item.indent - minItendent
36 | })
37 | return {
38 | article,
39 | toc
40 | }
41 | }
42 |
43 | export default Toc
--------------------------------------------------------------------------------
/web/src/plugins/filters.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import dayjs from 'dayjs'
3 |
4 | Vue.filter('date', (val, type) => {
5 | return dayjs(val).format(type)
6 | })
--------------------------------------------------------------------------------
/web/src/plugins/global.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | import commentList from '../components/commentList'
4 | import commentTextarea from '../components/commentTextarea'
5 |
6 | Vue.component('commentList', commentList)
7 | Vue.component('commentTextarea', commentTextarea)
--------------------------------------------------------------------------------
/web/src/plugins/lineAndCopy.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | import Vue from 'vue'
3 | export const addLineAndCopy = () => {
4 | //markdown代码存放在pre code 标签对中
5 | $('pre code').each(function () {
6 | let lines = $(this).text().split('\n').length - 1
7 | //添加有序列表
8 | let $numbering = $('
').addClass('pre-numbering')
9 | //添加复制按钮,此处使用的是element-ui icon 图标
10 | let $copy = $('').addClass('el-icon-document-copy code-copy')
11 | $(this)
12 | .parent()
13 | .addClass('code')
14 | .append($numbering)
15 | .append($copy)
16 | for (let i = 0; i <= lines; i++) {
17 | $numbering.append($(''))
18 | }
19 | })
20 | //监听复制按钮点击事件
21 | $('pre.code i.code-copy').click(e => {
22 | let text = $(e.target).siblings('code').text()
23 | let element = $('')
24 | $('body').append(element)
25 | element[0].select()
26 | document.execCommand('Copy')
27 | element.remove()
28 | //这里是自定义的消息通知组件
29 | Vue.prototype.$message.success({
30 | message: '代码复制成功'
31 | })
32 | })
33 | }
--------------------------------------------------------------------------------
/web/src/plugins/reg.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | export default {
3 | phone: /^(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])\d{8}$/,
4 | tell: /^\d{3,4}\d{7,8}$/, //座机
5 | zh_Name: /^[\u4e00-\u9fa5|a-zA-Z]{2,}$/,
6 | idNumber: /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/,
7 | zhanghu: /^[0-9]*$/,
8 | hanzi: /^[\u2E80-\u9FFF]+$/,
9 | uniformCreditCode: /^[0-9A-Z]{18}$/,
10 | vCode6: /^\d{6}$/, // 6位验证码
11 | email: /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
12 | numberFloatTwo: /^\d+(\.\d{1,2})?$/, //正整数或保留两位小数以内
13 | number: /^\d+$/, //正整数
14 | bankCardNumber: /^[0-9]{10,20}$/, //银行卡号
15 | url: /^((https|http){0,1}(:\/\/){0,1})www\.(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/,
16 | qqEmail: /^\d{5,12}@[q][q]\.(com|cn)$/,
17 | };
18 |
--------------------------------------------------------------------------------
/web/src/plugins/validate.js:
--------------------------------------------------------------------------------
1 | import reg from "./reg";
2 |
3 | //验证手机号码
4 | export const validatePhone = (rule, value, callback) => {
5 | if (!value) {
6 | callback(new Error('请输入手机号码'));
7 | } else if (!reg.phone.test(value)) {
8 | callback(new Error('手机号格式不对'));
9 | } else {
10 | callback();
11 | }
12 | };
13 | export const validateQQEmail = (rule, value, callback) => {
14 | if (!value) {
15 | callback(new Error('请输入QQ邮箱'))
16 | } else if (!reg.qqEmail.test(value)) {
17 | callback(new Error('@qq.com'));
18 | } else {
19 | callback();
20 | }
21 | }
22 | //验证电话号码(座机和手机号)
23 | export const validateTell = (rule, value, callback) => {
24 | if (!value) {
25 | callback(new Error('请输入电话号码'));
26 | } else if (!reg.tell.test(value) && !reg.phone.test(value)) {
27 | callback(new Error('电话号码格式不对'));
28 | } else {
29 | callback();
30 | }
31 | };
32 | //验证验证码
33 | export const validateCode = (rule, value, callback) => {
34 | if (!value) {
35 | callback(new Error('请输入验证码'));
36 | } else {
37 | callback();
38 | }
39 | };
40 | //验证身份证号码
41 | export const validateIdCard = (rule, value, callback) => {
42 | if (!value) {
43 | callback(new Error("请输入身份证号码"));
44 | } else if (!reg.idNumber.test(value)) {
45 | callback(new Error("请输入正确的身份证号码"));
46 | } else {
47 | callback();
48 | }
49 | };
50 | //银行卡号验证
51 | export const validateBankCard = (rule, value, callback) => {
52 | if (!value) {
53 | callback(new Error("请输入账户号码"));
54 | } else if (!reg.bankCardNumber.test(value)) {
55 | callback(new Error("账户号码格式错误"));
56 | } else {
57 | callback();
58 | }
59 | };
60 | //银行卡号验证(非必填)
61 | export const validateBankCardNo = (rule, value, callback) => {
62 | if (value && !reg.bankCardNumber.test(value)) {
63 | callback(new Error('账户号码格式错误'))
64 | } else {
65 | callback()
66 | }
67 | };
68 | //统一信用代码验证
69 | export const validateUniformCreditCode = (rule, value, callback) => {
70 | if (!value) {
71 | callback(new Error("请输入统一信用代码"));
72 | } else if (!reg.uniformCreditCode.test(value)) {
73 | callback(new Error("统一信用代码格式错误"));
74 | } else {
75 | callback();
76 | }
77 | };
78 | //图片上传验证
79 | export const validateUploadImg = (rule, value, callback) => {
80 | if (value.length > 0) {
81 | callback();
82 | } else {
83 | callback(new Error());
84 | }
85 | };
86 | //金额验证
87 | export const validateMoney = (rule, value, callback) => {
88 | if (!value) {
89 | callback(new Error("必填"));
90 | return;
91 | }
92 | if (!reg.numberFloatTwo.test(value)) {
93 | callback(new Error("只能为正数,且最多两位小数"));
94 | return;
95 | }
96 | let str = value.toString();
97 | let strFl = str.substring(0, str.indexOf("."));
98 | if (strFl.length >= 2 && strFl.substring(0, 1) == "0") {
99 | callback(new Error("小数点前二位以上,则首位不能为0"));
100 | return;
101 | }
102 | if (str.length > 12) {
103 | callback(new Error("最多只能输入12位"));
104 | return;
105 | }
106 | callback();
107 | };
108 | //注册资本验证(非必填)
109 | export const validateMoneyNo = (rule, value, callback) => {
110 | if (value) {
111 | if (!reg.numberFloatTwo.test(value)) {
112 | callback(new Error('只能为正数,且最多两位小数'));
113 | return
114 | }
115 | let str = value.toString();
116 | let strFl = str.substring(0, str.indexOf('.'));
117 | if (strFl.length >= 2 && strFl.substring(0, 1) == '0') {
118 | callback(new Error('小数点前二位以上,则首位不能为0'));
119 | return
120 | }
121 | if (str.length > 12) {
122 | callback(new Error('最多只能输入12位'));
123 | return
124 | }
125 | }
126 | callback()
127 | };
128 | //邮箱验证
129 | export const validateEmail = (rule, value, callback) => {
130 | if (!value) {
131 | callback(new Error("请输入邮箱"));
132 | } else if (!reg.email.test(value)) {
133 | callback(new Error("邮箱格式错误"));
134 | } else {
135 | callback();
136 | }
137 | };
138 | export const validateUrl = (rule, value, callback) => {
139 | if (!value) {
140 | callback(new Error("请输入网址"));
141 | } else if (!reg.url.test(value)) {
142 | callback(new Error("以http/https开头的完整正确格式"));
143 | } else {
144 | callback();
145 | }
146 | };
147 | //邮政编码验证(非必填)
148 | export const validateZipCode = (rule, value, callback) => {
149 | if (value && !reg.vCode6.test(value)) {
150 | callback(new Error('邮箱格式错误'))
151 | } else {
152 | callback()
153 | }
154 | };
155 | //供货标签验证
156 | export const validateTagIds = (rule, value, callback) => {
157 | if (value && value.length > 15) {
158 | callback(new Error("最多只能选择15个标签"));
159 | return
160 | }
161 | callback();
162 | };
163 | //公司名称长度验证
164 | export const validateCompanyName = (rule, value, callback) => {
165 | if (!value) {
166 | callback(new Error('请填写公司名称'))
167 | } else if (value.length < 6) {
168 | callback(new Error('公司名称长度需大于6位'))
169 | } else {
170 | callback()
171 | }
172 | };
173 | //姓名长度验证
174 | export const validateName = (rule, value, callback) => {
175 | if (!value) {
176 | callback(new Error('请填写姓名'))
177 | } else if (value && value.length < 2) {
178 | callback(new Error('姓名长度需大于2位'))
179 | } else {
180 | callback()
181 | }
182 | };
183 |
184 | export const validatePassword = (rele, value, callback) => {
185 | if (!value) {
186 | callback(new Error('请输入密码'))
187 | } else if (value.length < 6) {
188 | callback(new Error('请输入6位以上的密码'))
189 | } else {
190 | callback()
191 | }
192 | };
--------------------------------------------------------------------------------
/web/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import Main from '../views/Main.vue'
4 |
5 | Vue.use(VueRouter)
6 |
7 | const routes = [{
8 | path: '/',
9 | component: Main,
10 | children: [{
11 | path: '/',
12 | name: 'Home',
13 | component: () => import( /* webpackChunkName: "home" */ '../views/Home.vue'),
14 | meta: {
15 | title: '首页 - MIQILIN'
16 | }
17 | },
18 | {
19 | path: '/archives',
20 | name: 'Archive',
21 | component: () => import( /* webpackChunkName: "archive" */ '../views/Archive.vue'),
22 | meta: {
23 | title: '归档 - MIQILIN'
24 | }
25 | },
26 | {
27 | path: '/tags',
28 | name: 'Tag',
29 | component: () => import( /* webpackChunkName: "tag" */ '../views/Tag.vue'),
30 | meta: {
31 | title: '标签 - MIQILIN'
32 | }
33 | },
34 | {
35 | path: '/links',
36 | name: 'Link',
37 | component: () => import( /* webpackChunkName: "link" */ '../views/Link.vue'),
38 | meta: {
39 | title: '友链 - MIQILIN'
40 | }
41 | },
42 | {
43 | path: '/message',
44 | name: 'Message',
45 | component: () => import( /* webpackChunkName: "message" */ '../views/Message.vue'),
46 | meta: {
47 | title: '留言 - MIQILIN'
48 | }
49 | },
50 | {
51 | path: '/about',
52 | name: 'About',
53 | component: () => import( /* webpackChunkName: "about" */ '../views/About.vue'),
54 | meta: {
55 | title: '关于 - MIQILIN'
56 | }
57 | },
58 | {
59 | path: '/article/list/:id',
60 | name: 'Article',
61 | component: () => import( /* webpackChunkName: "article" */ '../views/Article.vue'),
62 | props: true,
63 | meta: {
64 | title: '文章详情 - MIQILIN'
65 | }
66 | }
67 | ]
68 | }, {
69 | path: '*',
70 | redirect: '/'
71 | }]
72 |
73 | const router = new VueRouter({
74 | scrollBehavior() {
75 | return {
76 | x: 0,
77 | y: 0
78 | }
79 | },
80 | // base: process.env.BASE_URL,
81 | routes
82 | })
83 | router.beforeEach((to, from, next) => {
84 | // to and from are both route objects
85 | if (to.meta.title) {
86 | document.title = to.meta.title
87 | }
88 | next()
89 | })
90 |
91 | export default router
92 |
--------------------------------------------------------------------------------
/web/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Vuex from "vuex";
3 | Vue.use(Vuex);
4 |
5 | export default new Vuex.Store({
6 | state: {
7 | map_user_info: {},
8 | vuex_skin_obj: {
9 | name: 'miqilin',
10 | chinaName: '米淇淋',
11 | },
12 | },
13 | mutations: {
14 | map_set_user_info(state, data) {
15 | state.userInfo = data
16 | },
17 | vuex_set_skin_obj(state, data) {
18 | state.vuex_skin_obj = data
19 | },
20 | },
21 | actions: {},
22 | modules: {}
23 | });
--------------------------------------------------------------------------------
/web/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
About
7 |
Published on March 11th 2020
8 |
9 |
10 | #
11 |
12 | 关于自己
13 |
14 |
15 |
• 转行半吊子前端一枚,目前📍:杭州
16 |
• 未来希望成为一名优秀的前端程序🐵
17 |
• 业余爱好比较多,喜欢烹饪、烘焙、音乐制作、踢⚽等等
18 |
19 |
20 | #
21 |
22 | 关于博客
23 |
24 |
25 |
26 | •
27 | 该博客用Vue实现,express提供数据接口,mongoDB储存数据,部署在腾讯云或阿里云的linux服务器上,搭建博客的初衷是希望把自己平常工作学习生活中值得记录的东西记录下来
28 |
29 |
• 如有错误、bug的地方烦请指正
30 |
31 |
32 | #
33 |
34 | Side Project (Coding)
35 |
36 |
37 |
38 |
43 | • myBlog(本博客)
44 |
45 | -- 🔥基于NodeJs、Vue、MongoDB实现的一款伪全栈博客系统
46 |
47 |
48 |
53 | • Musicn
54 |
55 | -- 🎵基于NodeJs实现的下载高品质音乐的命令行工具
56 |
57 |
58 |
63 | • react-notion-avatar
64 |
65 | -- ✨用于生成Notion风格头像的 React 库及网址
66 |
67 |
68 |
73 | • 蘑菇记账
74 |
75 | -- 🤑基于Vue全家桶、TypeScript、Echarts实现的一款极简的本地记账应用
76 |
77 |
78 |
83 | • 蘑菇记账(小程序版)
84 |
85 | -- 💰原生小程序实现的一款蘑菇记账应用
86 |
87 |
88 |
93 | • 其他项目
94 |
95 | - 持续开发中...
96 |
97 |
98 |
99 |
100 |
101 |
102 |
115 |
--------------------------------------------------------------------------------
/web/src/views/Archive.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ item.list[0].createdAt | date('YYYY') }}年{{ item._id }}月
7 |
8 |
9 |
10 |
15 |
16 |
17 | {{
18 | article.categories
19 | .map((cat) => {
20 | return cat.title
21 | })
22 | .join('|')
23 | }}
24 |
25 |
26 |
27 |
31 | {{ article.title }}
32 |
33 |
34 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
86 |
87 |
99 |
--------------------------------------------------------------------------------
/web/src/views/Article.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{ model.title }}
7 |
8 |
9 | {{ model.createdAt | date('YYYY-MM-DD HH:mm:ss') }}
10 |
11 |
字数 {{ model.body.length }}
12 |
评论 {{ Comments.length }}
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 | {{ model.categories[0].name }}
25 |
26 |
27 |
32 |
33 |
34 |
49 |
50 |
51 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
164 |
231 |
--------------------------------------------------------------------------------
/web/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
29 | {{ article.title }}
30 |
31 |
32 |
33 |
34 | {{ article.createdAt | date('YYYY-MM-DD') }}
35 |
36 |
37 |
42 | {{ article.categories[0].name }}
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
60 |
65 |
79 |
80 |
85 |
93 |
94 |
95 | 第{{ pagination.currentPage }}页 / 共{{ pagination.totalPage }}页
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
154 |
155 |
242 |
--------------------------------------------------------------------------------
/web/src/views/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Links
6 |
Published on March 11th 2020
7 |
8 |
9 | #
10 |
11 | 友情链接
12 |
13 |
14 |
15 |
16 |
17 | #
18 |
19 | 链接需知
20 |
21 |
22 |
• 请确定贵站可以稳定运营
23 |
• 原创博客优先,技术类博客优先,设计、视觉类博客优先
24 |
• 经常过来访问和评论,眼熟的
25 |
26 |
27 | 备注:默认申请友情链接均为内页(当前页面)
28 |
29 |
30 | #
31 |
32 | 基本信息
33 |
34 |
35 |
• 格式比如:
36 |
• 网站名称:米淇淋的个人博客
37 |
• 网站地址:https://amberzqx.com
38 |
• 描述:我劝你要多喝热水哈哈哈
39 |
40 |
41 | 暂时先这样,同时欢迎互换友链,到留言页留言即可。 ^_^
42 |
43 |
44 |
45 |
46 |
47 |
48 |
60 |
61 |
70 |
--------------------------------------------------------------------------------
/web/src/views/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
26 |
--------------------------------------------------------------------------------
/web/src/views/Message.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Message
6 |
Published on March 11th 2020
7 |
8 |
9 | #
10 |
11 | 留言前需知
12 |
13 |
14 |
• 烦请各位留言时务必填写自己真实的邮箱
15 |
• 留言博主基本都会回复,并会邮件通知留言者
16 |
• 请不要发广告和带有商业推广链接的无用留言
17 |
18 |
希望彼此之间有好的交流。 ^_^
19 |
20 |
21 |
22 | 留言板
23 |
24 |
25 |
26 |
32 |
33 |
37 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
75 |
76 |
86 |
--------------------------------------------------------------------------------
/web/src/views/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

9 |
10 |
11 |
19 |
20 |
21 |
24 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/web/src/views/Tag.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 标签分类的博文--点击自动查找相应`Tag`
6 |
7 |
Published on March 11th 2020
8 |
16 |
17 |
18 |
24 |
25 |
{{ item._id }} : {{ item.count }}
26 |
31 |
32 |
33 |
34 |
38 | {{ tag.categories.title }}
39 |
40 |
41 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
92 |
93 |
154 |
--------------------------------------------------------------------------------
/web/vue.config.js:
--------------------------------------------------------------------------------
1 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
2 | const productionGzipExtensions = ['js', 'css']
3 |
4 | module.exports = {
5 | lintOnSave: false,
6 | outputDir: __dirname + '/../server/web',
7 | // publicPath: process.env.NODE_ENV === 'production' ? '/web' : '/'
8 | productionSourceMap: false,
9 | chainWebpack: (config) => {
10 | //最小化代码
11 | config.optimization.minimize(true)
12 | //分割代码
13 | config.optimization.splitChunks({
14 | chunks: 'all',
15 | })
16 | // // 压缩图片
17 | // config.module
18 | // .rule('images')
19 | // .use('image-webpack-loader')
20 | // .loader('image-webpack-loader')
21 | // .options({
22 | // bypassOnDebug: true,
23 | // })
24 | // .end()
25 | },
26 | configureWebpack: (config) => {
27 | if (process.env.NODE_ENV === 'production') {
28 | // 为生产环境修改配置...
29 | return {
30 | plugins: [
31 | // new PrerenderSPAPlugin({
32 | // staticDir: path.join(__dirname, '/../serve/web'),
33 | // routes: ['/', '/blogs'],
34 | // // renderer: new Renderer({
35 | // // inject: {
36 | // // foo: 'bar'
37 | // // },
38 | // // headless: true,
39 | // // renderAfterDocumentEvent: 'render-event'
40 | // // })
41 | // }),
42 | new CompressionWebpackPlugin({
43 | algorithm: 'gzip',
44 | test: new RegExp(`\\.(${productionGzipExtensions.join('|')})$`),
45 | threshold: 1024,
46 | minRatio: 0.8,
47 | }),
48 | ],
49 | }
50 | } else {
51 | // 为开发环境修改配置...
52 | }
53 | },
54 | }
55 |
--------------------------------------------------------------------------------
• 非特殊说明,本博所有文章均为博主原创。
54 |• 本博客所有文章均采用 CC BY-SA 3.0协议 。转载请注明出处!
55 |评论
57 |