├── .gitignore ├── MongodbData ├── routes.json ├── timeclues.json └── users.json ├── MyBlogAdmin ├── .browserslistrc ├── .eslintrc.js ├── babel.config.js ├── jsconfig.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── api.js │ │ └── request.js │ ├── assets │ │ ├── bg.jpg │ │ ├── conmon.css │ │ └── prefixfree.js │ ├── components │ │ ├── Foot.vue │ │ ├── Head.vue │ │ └── Nav.vue │ ├── main.js │ ├── router │ │ ├── index.js │ │ └── router.js │ ├── store │ │ ├── blogs.js │ │ ├── classify.js │ │ ├── index.js │ │ ├── jotting.js │ │ ├── route.js │ │ ├── tags.js │ │ └── user.js │ ├── util │ │ ├── directive.js │ │ └── index.js │ └── views │ │ ├── 404.vue │ │ ├── Admin.vue │ │ ├── Article.vue │ │ ├── DataBoard.vue │ │ ├── Log.vue │ │ ├── LoginOrRegister.vue │ │ ├── Markdown.vue │ │ ├── Photo.vue │ │ ├── Result.vue │ │ ├── Route.vue │ │ ├── Self.vue │ │ ├── Timeclue.vue │ │ └── User.vue ├── vue.config.js └── yarn.lock ├── MyBlogFront ├── .browserslistrc ├── .eslintrc.js ├── babel.config.js ├── jsconfig.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.css │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── api.js │ │ ├── index.js │ │ └── request.js │ ├── assets │ │ ├── common.css │ │ ├── icons │ │ │ ├── iconfont.css │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ ├── img │ │ │ ├── avatar.png │ │ │ ├── infoBg.jpg │ │ │ ├── lightBg.png │ │ │ ├── nightBg.jpg │ │ │ └── slideBg │ │ │ │ ├── slidebg1.jpg │ │ │ │ ├── slidebg2.jpg │ │ │ │ └── slidebg3.jpg │ │ └── logo.png │ ├── components │ │ ├── Comment.vue │ │ ├── Footer.vue │ │ ├── Header.vue │ │ ├── Loading │ │ │ ├── Loading.vue │ │ │ └── index.js │ │ ├── Nav.vue │ │ ├── SiderInfo.vue │ │ ├── Slideshow.vue │ │ └── Switch.vue │ ├── main.js │ ├── router │ │ └── index.js │ ├── store │ │ ├── index.js │ │ ├── synthesis.js │ │ └── theme.js │ ├── util │ │ ├── bgSpecialEffect.js │ │ ├── clickSpecialEffect.js │ │ └── index.js │ └── views │ │ ├── About.vue │ │ ├── Article.vue │ │ ├── List.vue │ │ ├── MessageBoard.vue │ │ ├── PhotoWall.vue │ │ └── TimeClue.vue ├── vue.config.js └── yarn.lock ├── MyBlogServe ├── app.js ├── bin │ └── www ├── controllers │ ├── blogs.js │ ├── classifies.js │ ├── comments.js │ ├── jottings.js │ ├── murmur.js │ ├── photo.js │ ├── routes.js │ ├── synthesis.js │ ├── timeclue.js │ └── users.js ├── db │ └── connect.js ├── keys │ ├── rsa_private_key.pem │ └── rsa_public_key.pem ├── model │ ├── blogs.js │ ├── classifies.js │ ├── comments.js │ ├── jottings.js │ ├── murmurs.js │ ├── photo.js │ ├── routes.js │ ├── tag.js │ ├── timeclue.js │ └── users.js ├── package.json ├── public │ ├── avatars │ │ ├── 1661779453078 │ │ └── 1662256970035 │ ├── photos │ │ ├── 1662046452834 │ │ ├── 1662046521921 │ │ ├── 1662046564119 │ │ ├── 1662046595682 │ │ ├── 1662047030636 │ │ ├── 1662047054759 │ │ ├── 1662047189170 │ │ ├── 1662049020699 │ │ ├── 1662049188808 │ │ ├── 1662049270170 │ │ ├── 1662049353519 │ │ ├── 1662049446197 │ │ ├── 1662049505602 │ │ ├── 1662049548427 │ │ ├── 1662049654510 │ │ ├── 1662049758833 │ │ ├── 1662049791176 │ │ ├── 1662049883085 │ │ ├── 1662050480857 │ │ └── 1662050583435 │ └── stylesheets │ │ └── style.css ├── routes │ ├── blogs.js │ ├── classifies.js │ ├── comments.js │ ├── jottings.js │ ├── murmur.js │ ├── photo.js │ ├── routes.js │ ├── synthesis.js │ ├── timeclue.js │ └── users.js ├── utils │ └── index.js ├── views │ ├── error.jade │ ├── index.jade │ └── layout.jade └── yarn.lock ├── README.md ├── ReadmeImg ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png └── default.conf /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist 4 | .gitignore 5 | 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | node_modules 26 | -------------------------------------------------------------------------------- /MongodbData/routes.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "_id": { 3 | "$oid": "6314288d53aa7200deac6936" 4 | }, 5 | "path": "article", 6 | "name": "文章管理", 7 | "component": "Article.vue", 8 | "limits": [ 9 | "管理员", 10 | "普通用户" 11 | ], 12 | "meta": { 13 | "icon": "el-icon-document" 14 | } 15 | },{ 16 | "_id": { 17 | "$oid": "6314288d53aa7200deac6939" 18 | }, 19 | "path": "photo", 20 | "name": "照片管理", 21 | "component": "Photo.vue", 22 | "limits": [ 23 | "管理员", 24 | "普通用户" 25 | ], 26 | "meta": { 27 | "icon": "el-icon-menu" 28 | } 29 | },{ 30 | "_id": { 31 | "$oid": "6314288d53aa7200deac693c" 32 | }, 33 | "path": "markdown", 34 | "name": "编辑文章", 35 | "component": "Markdown.vue", 36 | "limits": [ 37 | "管理员", 38 | "普通用户" 39 | ], 40 | "meta": { 41 | "icon": "el-icon-edit" 42 | } 43 | },{ 44 | "_id": { 45 | "$oid": "6314288d53aa7200deac693f" 46 | }, 47 | "path": "timeclue", 48 | "name": "时间节点管理", 49 | "component": "Timeclue.vue", 50 | "limits": [ 51 | "管理员", 52 | "普通用户" 53 | ], 54 | "meta": { 55 | "icon": "el-icon-notebook-1" 56 | } 57 | },{ 58 | "_id": { 59 | "$oid": "6314288d53aa7200deac6942" 60 | }, 61 | "path": "routingmanage", 62 | "name": "路由管理", 63 | "component": "Route.vue", 64 | "limits": [ 65 | "管理员" 66 | ], 67 | "meta": { 68 | "icon": "el-icon-rank" 69 | } 70 | },{ 71 | "_id": { 72 | "$oid": "6314288d53aa7200deac6945" 73 | }, 74 | "path": "user", 75 | "name": "用户管理", 76 | "component": "User.vue", 77 | "limits": [ 78 | "管理员" 79 | ], 80 | "meta": { 81 | "icon": "el-icon-s-custom" 82 | } 83 | },{ 84 | "_id": { 85 | "$oid": "6314288d53aa7200deac6948" 86 | }, 87 | "path": "logs", 88 | "name": "日志", 89 | "component": "Log.vue", 90 | "limits": [ 91 | "管理员" 92 | ], 93 | "meta": { 94 | "icon": "el-icon-setting" 95 | } 96 | },{ 97 | "_id": { 98 | "$oid": "6315efa453aa7200deac7a78" 99 | }, 100 | "path": "result", 101 | "name": "结果页", 102 | "component": "Result.vue", 103 | "limits": [ 104 | "管理员", 105 | "普通用户" 106 | ], 107 | "meta": { 108 | "NotShow": true 109 | } 110 | },{ 111 | "_id": { 112 | "$oid": "6315f83453aa7200deac7d30" 113 | }, 114 | "path": "self", 115 | "name": "个人中心", 116 | "component": "Self.vue", 117 | "limits": [ 118 | "管理员", 119 | "普通用户" 120 | ], 121 | "meta": { 122 | "icon": "el-icon-s-check" 123 | } 124 | }] -------------------------------------------------------------------------------- /MongodbData/timeclues.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "_id": { 3 | "$oid": "630f625353aa7200deabcd45" 4 | }, 5 | "title": "持续开发中, 敬请期待...", 6 | "state": false, 7 | "date": "2022-09-07", 8 | "digest": "持续开发中, 敬请期待..." 9 | },{ 10 | "_id": { 11 | "$oid": "630f626453aa7200deabcd4f" 12 | }, 13 | "date": "2022-07-31", 14 | "state": true, 15 | "title": "前后端联调,完善系统,开发新功能", 16 | "digest": "规范了前后端代码,完善了部分代码,新增了功能:注册、后台管理系统:权限管理、路由管理、图片上传;前端展示部分:评论、留言板、关于、小站时间线、优化了切换效果,。" 17 | },{ 18 | "_id": { 19 | "$oid": "630f626f53aa7200deabcd56" 20 | }, 21 | "date": "2022-07-25", 22 | "state": true, 23 | "title": "前端部分基础功能完成", 24 | "digest": "完成了前端的基础功能,管理系统:登录、用户管理、博客管理、随笔管理、使用markdown语法新增博客随笔;展示部分:博客展示、随笔展示。" 25 | },{ 26 | "_id": { 27 | "$oid": "630f627a53aa7200deabcd5d" 28 | }, 29 | "date": "2022-07-14", 30 | "state": true, 31 | "title": "后端基础功能完成", 32 | "digest": "完成了后端基础工功能的接口设计与实现" 33 | },{ 34 | "_id": { 35 | "$oid": "630f628453aa7200deabcd64" 36 | }, 37 | "date": "2022-06-25", 38 | "state": true, 39 | "title": "项目搭建完成", 40 | "digest": "完成项目环境的搭建、静态页面的编写和一些必要组件、方法的封装" 41 | },{ 42 | "_id": { 43 | "$oid": "630f628d53aa7200deabcd69" 44 | }, 45 | "date": "2022-06-25", 46 | "state": true, 47 | "title": "前期准备工作", 48 | "digest": "在网上查找个人博客相关资料,查看优秀的个人博客作品,分析自己的需求,确定使用什么技术,完成数据库的设计。" 49 | },{ 50 | "_id": { 51 | "$oid": "630f629653aa7200deabcd6e" 52 | }, 53 | "date": "2022-06-20", 54 | "state": true, 55 | "title": "确定博客项目", 56 | "digest": "大发大" 57 | },{ 58 | "_id": { 59 | "$oid": "63189d281ac7353c8b30acad" 60 | }, 61 | "date": "2022-08-20T00:00:00.000Z", 62 | "title": "小站第一次上线", 63 | "digest": "所有功能基本完善,尝试第一次上线。", 64 | "__v": 0, 65 | "state": true 66 | }] -------------------------------------------------------------------------------- /MongodbData/users.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "_id": { 3 | "$oid": "6313fb41c2377786e8339d70" 4 | }, 5 | "username": "管理员", 6 | "password": "$2b$10$LcM347ZIT4upIpm70zBHEOFXM6pXe2fXgfmPXUGzdLiThjkTbNyCW", 7 | "email": "123@qq.com", 8 | "date": { 9 | "$date": { 10 | "$numberLong": "1662253889206" 11 | } 12 | }, 13 | "role": "管理员", 14 | "__v": 0 15 | },{ 16 | "_id": { 17 | "$oid": "6319fd5eccef1193b5e48760" 18 | }, 19 | "username": "普通用户", 20 | "password": "$2b$10$G0H7p87B.vTw90ppA.c9q.AlcRDPEVBUK731gnUO1mknQVC0DmlQC", 21 | "email": "234@qq.com", 22 | "date": { 23 | "$date": { 24 | "$numberLong": "1662647646590" 25 | } 26 | }, 27 | "role": "普通用户", 28 | "__v": 0 29 | }] -------------------------------------------------------------------------------- /MyBlogAdmin/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /MyBlogAdmin/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | parserOptions: { 11 | parser: '@babel/eslint-parser' 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MyBlogAdmin/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ], 5 | plugins: [ 6 | [ 7 | "component", 8 | { 9 | "libraryName": "element-ui", 10 | "styleLibraryName": "theme-chalk" 11 | } 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /MyBlogAdmin/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MyBlogAdmin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myblogadmin", 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.26.1", 12 | "core-js": "^3.8.3", 13 | "echarts": "^5.3.3", 14 | "element-ui": "^2.15.6", 15 | "mavon-editor": "^2.10.4", 16 | "nprogress": "^0.2.0", 17 | "vue": "^2.6.14", 18 | "vue-router": "^3.5.1", 19 | "vuex": "^3.6.2" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "^7.12.16", 23 | "@babel/eslint-parser": "^7.12.16", 24 | "@vue/cli-plugin-babel": "~5.0.0", 25 | "@vue/cli-plugin-eslint": "~5.0.0", 26 | "@vue/cli-plugin-router": "~5.0.0", 27 | "@vue/cli-plugin-vuex": "~5.0.0", 28 | "@vue/cli-service": "~5.0.0", 29 | "babel-plugin-component": "^1.1.1", 30 | "compression-webpack-plugin": "^10.0.0", 31 | "eslint": "^7.32.0", 32 | "eslint-plugin-vue": "^8.0.3", 33 | "less": "^4.0.0", 34 | "less-loader": "^8.0.0", 35 | "vue-template-compiler": "^2.6.14" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MyBlogAdmin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogAdmin/public/favicon.ico -------------------------------------------------------------------------------- /MyBlogAdmin/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 孤城浪人的博客(后台管理) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 |
23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/api/api.js: -------------------------------------------------------------------------------- 1 | // 统一管理所有接口 2 | import requests from "./request"; 3 | // 获取文章列表 4 | export const getBlogs = () => requests.get("/blogs/getblogs"); 5 | // 更新文章 6 | export const updateBlog = data => requests.post("/blogs/updateblog", data); 7 | // 删除文章 8 | export const deleteBlog = (params = {}) => requests.delete("/blogs/deleteblog", { params }); 9 | // 修改文章状态 10 | export const changeBlogState = params => requests.get("/blogs/changeblogstate", { params }); 11 | // 增加文章 12 | export const addBlog = data => requests.post("/blogs/addblog", data); 13 | // 获取某一文章 14 | export const getBlog = params => requests.get("/blogs/getblog", { params }); 15 | 16 | // 登录 17 | export const login = data => requests.post("/users/login", data); 18 | // 获取用户信息 19 | export const getUsers = () => requests.get("/users/getusers"); 20 | // 删除用户 21 | export const deleteUser = params => requests.delete("/users/deleteuser", { params }); 22 | // 注册用户 23 | export const register = data => requests.post("/users/register", data); 24 | // 修改用户信息 25 | export const updateUserInfo = data => requests.post("/users/updateuserinfo", data); 26 | // 修改密码 27 | export const updatePassword = data => requests.post("/users/updatepassword", data); 28 | // 退出 29 | export const logout = () => requests.get("/users/logout"); 30 | // 获取某个用户信息 31 | export const getUser = params => requests.get("/users/getuser", { params }); 32 | 33 | // 获取专栏列表 34 | export const getClassifies = () => requests.get("/classifies/getclassifies"); 35 | // 删除专栏 36 | export const deleteClassify = params => requests.delete("/classifies/deleteclassify", { params }); 37 | // 编辑专栏 38 | export const updateClassifyTitle = data => requests.post("/classifies/updateclassifytitle", data); 39 | // 新增专栏 40 | export const addClassify = data => requests.post("/classifies/addclassify", data); 41 | 42 | // 获取随笔列表 43 | export const getJottings = () => requests.get("/jottings/getjottings"); 44 | // 修改状态 45 | export const changeJottingState = params => requests.get("/jottings/changestate", { params }); 46 | // 删除随笔 47 | export const deleteJotting = params => requests.delete("/jottings/deletejotting", { params }); 48 | // 添加随笔 49 | export const addJotting = data => requests.post("/jottings/addjotting", data); 50 | // 获取某一随笔 51 | export const getJotting = params => requests.get("/jottings/getjotting", { params }); 52 | // 添加图片 53 | export const uploadImg = data => requests.post("/synthesis/uploadartimg", data, { headers: { "content-type": "multipart/form-data" } }); 54 | // 添加随笔 55 | export const updateJotting = data => requests.post("/jottings/updatejotting", data); 56 | 57 | // 添加一级路由 58 | export const addFirstRoute = data => requests.post("/routes/addfirstroute", data); 59 | // 添加二级路由 60 | export const addSecondRoute = data => requests.post("/routes/addsecondroute", data); 61 | // 修改路由 62 | export const updateRoute = data => requests.post("/routes/updatroute", data); 63 | // 删除路由 64 | export const deleteRoute = params => requests.delete("/routes/deleteroute", { params }); 65 | // 获取路由 66 | export const getRoutes = params => requests.get("/routes/getroutes", { params }); 67 | // 获取所有路由 68 | export const getRouteList = () => requests.get("/routes/getroutelist"); 69 | 70 | // 添加书签 71 | export const addTag = data => requests.post("/synthesis/addtag", data); 72 | // 获取书签 73 | export const getTags = () => requests.get("/synthesis/gettags"); 74 | // 修改书签 75 | export const updateTag = data => requests.post("/synthesis/updatetag", data); 76 | // 删除书签 77 | export const deleteTag = params => requests.delete("/synthesis/deletetag", { params }); 78 | 79 | // 修改游客信息 80 | export const getMurmurInfos = () => requests.get("/murmur/getmurmurinfos"); 81 | // 删除游客信息 82 | export const deleteMurmurInfo = params => requests.delete("/murmur/deletemurmurinfo", { params }); 83 | 84 | // 获取所有照片信息 85 | export const getPhotos = () => requests.get("/photo/getphotos"); 86 | // 修改照片信息 87 | export const updatePhotos = data => requests.post("/photo/updatephotodigest", data); 88 | // 删除照片信息 89 | export const deletePhoto = params => requests.delete("/photo/deletephoto", { params }); 90 | // 新增照片信息 91 | export const addPhoto = data => requests.post("/photo/addphoto", data); 92 | 93 | // 获取所有评论 94 | export const getComments = () => requests.get("/comments/getcomments"); 95 | // 删除一级评论 96 | export const deleteFirstComment = params => requests.delete("/comments/deletefirstcomment", { params }); 97 | // 删除二级评论 98 | export const deleteSecondComment = params => requests.delete("/comments/deletesecondcomment", { params }); 99 | 100 | // 获取所有时间节点 101 | export const getTimeclues = () => requests.get("/timeclues/gettimeclues"); 102 | // 删除时间节点 103 | export const deleteTimeclue = params => requests.delete("/timeclues/deletetimeclue", { params }); 104 | // 修改时间节点 105 | export const updateTimeclue = data => requests.post("/timeclues/updatetimeclue", data); 106 | // 新增时间节点 107 | export const addTimeclue = data => requests.post("/timeclues/addtimeclue", data); 108 | // 改变时间节点状态 109 | export const changeTimeNodeState = params => requests.get("/timeclues/changetimenodestate", { params }); 110 | // 改变时间节点状态 111 | export const getDataForDataBoard = () => requests.get("/synthesis/getdatafordataboard"); 112 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/api/request.js: -------------------------------------------------------------------------------- 1 | // 引入axios进行二次封装 2 | // import axios from "axios"; 3 | // 进度条 4 | import nprogress from "nprogress"; 5 | // 引入进度条样式 6 | import "nprogress/nprogress.css"; 7 | import store from "@/store"; 8 | const requests = axios.create({ 9 | // 配置对象 10 | // 基础路径 11 | baseURL: "/api", 12 | // 请求超时的时间限 制 13 | timeout: 5000, 14 | }); 15 | // 请求拦截器:在请求发出去之前做处理 16 | requests.interceptors.request.use( 17 | config => { 18 | // config:配置对象,对象信息里边有一个重要信息,请求头headers 19 | nprogress.start(); 20 | // // 需要携带token带给服务器 21 | if (store.state.user.token || localStorage.getItem("TOKEN")) { 22 | config.headers.token = store.state.user.token; 23 | } 24 | return config; 25 | }, 26 | error => { 27 | //请求错误时 28 | console.log("request:", error); 29 | // 1.判断请求超时 30 | if (error.code === "ECONNABORTED" && error.message.indexOf("timeout") !== -1) { 31 | console.log("timeout请求超时"); 32 | return service.request(originalRequest); // 再重复请求一次 33 | } 34 | return Promise.reject(error); 35 | } 36 | ); 37 | // 响应拦截器 38 | requests.interceptors.response.use( 39 | res => { 40 | // 进度条结束 41 | nprogress.done(); 42 | return res.data; 43 | }, 44 | err => { 45 | nprogress.done(); 46 | //console.log('response:',err) 47 | // 1.判断请求超时 48 | if (err.code === "ECONNABORTED" && err.message.indexOf("timeout") !== -1) { 49 | return Promise.reject("timeout请求超时"); 50 | // return service.request(originalRequest);// 再重复请求一次 51 | } 52 | if (err.message.indexOf("Network") !== -1) { 53 | return Promise.reject("网络异常"); 54 | } 55 | if (err.response && err.response.status === 404) { 56 | return Promise.reject("请求的资源无法找到"); 57 | } else if (err.response && err.response.status === 500) { 58 | return Promise.reject("服务器繁忙"); 59 | } 60 | console.log(err.response.status); 61 | return Promise.reject(err); 62 | } 63 | ); 64 | 65 | export default requests; 66 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogAdmin/src/assets/bg.jpg -------------------------------------------------------------------------------- /MyBlogAdmin/src/assets/conmon.css: -------------------------------------------------------------------------------- 1 | /* el-table和el-dialog样式 */ 2 | .el-table__cell, 3 | .el-dialog, 4 | .el-table tr { 5 | background-color: #323232 !important; 6 | } 7 | .el-table { 8 | background-color: transparent; 9 | color: #ddd; 10 | } 11 | .el-tabs__content { 12 | height: calc(100% - 55px); 13 | } 14 | 15 | .is-active { 16 | color: #409eff; 17 | box-shadow: none !important; 18 | } 19 | .el-dialog{ 20 | position: absolute; 21 | left: 50%; 22 | top: 50%; 23 | transform: translate(-50%, -50%); 24 | margin-top: 0 !important; 25 | } 26 | 27 | .el-dialog__title, 28 | .el-form-item__label, 29 | .el-tabs__item { 30 | color: #ddd; 31 | } 32 | 33 | /* markdown插件样式 */ 34 | .v-note-edit, 35 | .content-input-wrapper, 36 | .v-note-op, 37 | .v-note-panel, 38 | .op-icon.selected, 39 | .v-note-read-model, 40 | .auto-textarea-input, 41 | .v-show-content { 42 | background-color: #323232 !important; 43 | } 44 | .auto-textarea-input, 45 | .v-show-content { 46 | color: #ccc !important; 47 | } 48 | .op-icon.selected, 49 | .v-note-read-model { 50 | color: #757575 !important; 51 | } 52 | /* 抽屉样式 */ 53 | .el-drawer { 54 | background-color: #323232; 55 | } 56 | .drawer-footer { 57 | display: flex; 58 | justify-content: center; 59 | } 60 | .el-input { 61 | width: 80% !important; 62 | } 63 | .el-select { 64 | width: 100%; 65 | } 66 | 67 | 68 | 69 | a { 70 | text-decoration: none; 71 | } 72 | * { 73 | margin: 0; 74 | padding: 0; 75 | } 76 | ::-webkit-scrollbar { 77 | /*滚动条整体样式*/ 78 | width: 5px; 79 | } 80 | 81 | ::-webkit-scrollbar-thumb { 82 | /*滚动条里面小方块*/ 83 | border-radius: 5px; 84 | background: rgb(100, 100, 100); 85 | } 86 | 87 | ::-webkit-scrollbar-track { 88 | /*滚动条里面轨道*/ 89 | border-radius: 0; 90 | opacity: 0; 91 | /* background: rgba(0, 0, 0, 0); */ 92 | } 93 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/components/Foot.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | 13 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/components/Head.vue: -------------------------------------------------------------------------------- 1 | 17 | 64 | 91 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/components/Nav.vue: -------------------------------------------------------------------------------- 1 | 49 | 58 | 66 | -------------------------------------------------------------------------------- /MyBlogAdmin/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 "element-ui/lib/theme-chalk/index.css"; 6 | // import element from "element-ui"; 7 | import { has } from "./util/directive"; 8 | import "@/assets/conmon.css"; 9 | 10 | // Vue.use(element); 11 | new Vue({ 12 | router, 13 | store, 14 | render: h => h(App), 15 | }).$mount("#app"); 16 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/router/index.js: -------------------------------------------------------------------------------- 1 | // import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import { routes } from "./router"; 4 | import { getToken, getUserInfo } from "@/util"; 5 | import store from "@/store"; 6 | Vue.use(VueRouter); 7 | 8 | const router = new VueRouter({ 9 | mode: "history", 10 | base: process.env.BASE_URL, 11 | routes, 12 | }); 13 | let flag = true; 14 | router.beforeEach(async (to, from, next) => { 15 | // 如果已登录 16 | if (getToken()) { 17 | try { 18 | if (to.path === "/loginorregister") { 19 | next("/admin"); 20 | } else { 21 | if (flag) { 22 | // 判断当前用户是否已拉取完user_info信息 23 | await store.dispatch("getRoutes", getUserInfo().role); 24 | store.getters.routes.forEach(item => { 25 | router.addRoute("home", { 26 | path: item.path, 27 | name: item.name, 28 | component: () => import(`@/views/${item.component}`), 29 | meta: item.meta, 30 | }); 31 | }); 32 | flag = false; 33 | next({ ...to, replace: true }); 34 | console.log(router.getRoutes()); 35 | } else { 36 | next(); 37 | } 38 | } 39 | } catch (err) { 40 | console.log(err); 41 | } 42 | } else { 43 | //未登录 44 | if (to.fullPath == "/loginorregister") { 45 | next(); 46 | } else { 47 | next("/loginorregister"); 48 | } 49 | } 50 | }); 51 | const originalPush = VueRouter.prototype.push; 52 | VueRouter.prototype.push = function push(location, resolve, reject) { 53 | if (resolve || reject) return originalPush.call(this, location, resolve, reject); 54 | return originalPush.call(this, location).catch(err => err); 55 | }; 56 | export default router; 57 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/router/router.js: -------------------------------------------------------------------------------- 1 | export const routes = [ 2 | { 3 | path: "/admin", 4 | name: "home", 5 | component: () => import("@/views/Admin.vue"), 6 | children: [ 7 | { 8 | path: "databoard", 9 | name: "article", 10 | component: () => import("../views/DataBoard.vue"), 11 | }, 12 | // { 13 | // path: "article", 14 | // name: "article", 15 | // component: () => import("../views/Article.vue"), 16 | // }, 17 | // { 18 | // path: "photo", 19 | // name: "photo", 20 | // component: () => import("../views/Photo.vue"), 21 | // }, 22 | // { 23 | // path: "markdown", 24 | // name: "markdown", 25 | // component: () => import("../views/Markdown.vue"), 26 | // }, 27 | // { 28 | // path: "timeclue", 29 | // name: "timeclue", 30 | // component: () => import("../views/Timeclue.vue"), 31 | // }, 32 | // // { 33 | // // path: "routingmanage", 34 | // // name: "routingmanage", 35 | // // component: () => import("../views/Route.vue"), 36 | // // limits: ["管理员"], 37 | // // }, 38 | // { 39 | // path: "user", 40 | // name: "user", 41 | // component: () => import("../views/User.vue"), 42 | // limits: ["管理员"], 43 | // }, 44 | // { 45 | // path: "logs", 46 | // name: "logs", 47 | // component: () => import("../views/Log.vue"), 48 | // limits: ["管理员"], 49 | // }, 50 | // { 51 | // path: "/admin", 52 | // redirect: "article", 53 | // }, 54 | ], 55 | }, 56 | { 57 | path: "/loginorregister", 58 | name: "loginorregister", 59 | component: () => import("../views/LoginOrRegister.vue"), 60 | }, 61 | { 62 | path: "/", 63 | redirect: "/loginorregister", 64 | }, 65 | ]; 66 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/blogs.js: -------------------------------------------------------------------------------- 1 | import { getBlogs, updateBlog, deleteBlog, getBlog, addBlog, changeBlogState } from "../api/api"; 2 | const state = { 3 | blogs: [], 4 | blog: {}, 5 | }; 6 | const mutations = { 7 | BLOGS(state, blogs) { 8 | state.blogs = blogs; 9 | }, 10 | BLOG(state, blog) { 11 | state.blog = blog; 12 | }, 13 | }; 14 | const actions = { 15 | // 修改文章状态 16 | async changeBlogState({ commit }, _id) { 17 | return await changeBlogState(_id); 18 | }, 19 | // 更新文章 20 | async updateBlog({ commit }, data) { 21 | return await updateBlog(data); 22 | }, 23 | // 删除文章 24 | async deleteBlog({ commit }, data) { 25 | return await deleteBlog(data); 26 | }, 27 | // 获取文章列表 28 | async getBlogs({ commit }) { 29 | let result = await getBlogs(); 30 | if (result.status == 200) { 31 | commit("BLOGS", result.data); 32 | } else { 33 | console.log(result); 34 | } 35 | }, 36 | // 增加文章 37 | async addBlog({ commit }, data) { 38 | return await addBlog(data); 39 | }, 40 | // 获取文章 41 | async getBlog({ commit }, data) { 42 | let result = await getBlog(data); 43 | if (result.status == 200) { 44 | commit("BLOG", result.data); 45 | } else { 46 | return result; 47 | } 48 | }, 49 | }; 50 | const getters = { 51 | blog(state) { 52 | return state.blog; 53 | }, 54 | blogs(state) { 55 | return state.blogs; 56 | }, 57 | }; 58 | export default { 59 | state, 60 | mutations, 61 | actions, 62 | getters, 63 | }; 64 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/classify.js: -------------------------------------------------------------------------------- 1 | import { getClassifies, deleteClassify, updateClassifyTitle, addClassify } from "../api/api"; 2 | import { setClassifies, getClassifyList } from "../util"; 3 | const state = { 4 | classifies: [], 5 | }; 6 | const mutations = { 7 | CLASSIFYLIST(state, classifies) { 8 | state.classifies = classifies; 9 | }, 10 | }; 11 | const actions = { 12 | // 编辑专栏 13 | async updateClassifyTitle({ commit }, data) { 14 | return await updateClassifyTitle(data); 15 | }, 16 | //删除专栏 17 | async deleteClassify({ commit }, data) { 18 | return await deleteClassify(data); 19 | }, 20 | // 获取专栏列表 21 | async getClassifies({ commit }) { 22 | let result = await getClassifies(); 23 | if (result.status == 200) { 24 | commit("CLASSIFYLIST", result.data); 25 | setClassifies(result.data); 26 | } else { 27 | console.log(result); 28 | } 29 | }, 30 | 31 | async addClassify({ commit }, data) { 32 | console.log(data); 33 | return await addClassify(data); 34 | }, 35 | }; 36 | const getters = { 37 | classifies(state) { 38 | return state.classifies; 39 | }, 40 | }; 41 | export default { 42 | state, 43 | mutations, 44 | actions, 45 | getters, 46 | }; 47 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/index.js: -------------------------------------------------------------------------------- 1 | // import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import user from "./user"; 4 | import classify from "./classify"; 5 | import article from "./blogs"; 6 | import jotting from "./jotting"; 7 | import route from "./route"; 8 | import tags from "./tags"; 9 | Vue.use(Vuex); 10 | 11 | export default new Vuex.Store({ 12 | // vuex实现模块化开发,每个模块存放自己的数据 13 | getters: { 14 | routeList: state => state.route.routeList, 15 | }, 16 | modules: { 17 | user, 18 | classify, 19 | article, 20 | jotting, 21 | route, 22 | tags, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/jotting.js: -------------------------------------------------------------------------------- 1 | import { getJottings, changeJottingState, deleteJotting, addJotting, getJotting, updateJotting } from "../api/api"; 2 | const state = { 3 | jottings: [], 4 | jotting: {}, 5 | }; 6 | const mutations = { 7 | JOTTINGS(state, jottings) { 8 | state.jottings = jottings; 9 | }, 10 | JOTTING(state, jotting) { 11 | state.jotting = jotting; 12 | }, 13 | }; 14 | const actions = { 15 | // 修改文章状态 16 | async changeJottingState({ commit }, data) { 17 | return await changeJottingState(data); 18 | }, 19 | async updateJotting({ commit }, data) { 20 | return await updateJotting(data); 21 | }, 22 | // 删除文章 23 | async deleteJotting({ commit }, data) { 24 | return await deleteJotting(data); 25 | }, 26 | // 获取文章列表 27 | async getJottings({ commit }) { 28 | let result = await getJottings(); 29 | if (result.status == 200) { 30 | commit("JOTTINGS", result.data); 31 | } else { 32 | console.log(result); 33 | } 34 | }, 35 | // 添加随笔 36 | async addJotting({ commit }, data) { 37 | return await addJotting(data); 38 | }, 39 | // 获取某一随笔 40 | async getJotting({ commit }, data) { 41 | let result = await getJotting(data); 42 | if (result.status == 200) { 43 | commit("JOTTING", result.data); 44 | } else { 45 | console.log(result); 46 | } 47 | }, 48 | }; 49 | const getters = { 50 | jottings(state) { 51 | return state.jottings; 52 | }, 53 | jotting(state) { 54 | return state.jotting; 55 | }, 56 | }; 57 | export default { 58 | state, 59 | mutations, 60 | actions, 61 | getters, 62 | }; 63 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/route.js: -------------------------------------------------------------------------------- 1 | import { getRoutes, addSecondRoute, updateRoute, deleteRoute, addFirstRoute, getRouteList } from "../api/api"; 2 | 3 | const state = { 4 | routeList: [], 5 | routes: [], 6 | }; 7 | const mutations = { 8 | ROUTELIST(state, routeList) { 9 | state.routeList = routeList; 10 | }, 11 | ROUTES(state, routes) { 12 | state.routes = routes; 13 | }, 14 | CLEARROUTES(state) { 15 | state.routes = []; 16 | }, 17 | }; 18 | const actions = { 19 | // 新增一级路由 20 | async addFirstRoute({ commit }, route) { 21 | return await addFirstRoute(route); 22 | }, 23 | // 新增二级路由 24 | async addSecondRoute({ commit }, route) { 25 | return await addSecondRoute(route); 26 | }, 27 | // 更新获取路由信息 28 | async updatRoute({ commit }, data) { 29 | return await updateRoute(data); 30 | }, 31 | //删除路由 32 | async deleteRoute({ commit }, data) { 33 | return await deleteRoute(data); 34 | }, 35 | // 获取有权限路由列表 36 | async getRoutes({ commit }, role) { 37 | let result = await getRoutes({ role: role }); 38 | if (result.status == 200) { 39 | commit("ROUTES", result.data); 40 | } else { 41 | console.log(result); 42 | } 43 | }, 44 | // 获取所有路由 45 | async getRouteList({ commit }, role) { 46 | let result = await getRouteList(); 47 | if (result.status == 200) { 48 | commit("ROUTELIST", result.data); 49 | } else { 50 | console.log(result); 51 | } 52 | }, 53 | // 清空routelist 54 | clearRoutes({ commit }) { 55 | commit("CLEARROUTES"); 56 | }, 57 | }; 58 | // 返回特定路由数据 59 | const getters = { 60 | // 路由管理需要的路由信息和动态导航栏 61 | navRouteList(state) { 62 | const routeList = []; 63 | state.routes.forEach(item => { 64 | if (!item.meta.NotShow && item.name != "日志") { 65 | routeList.push(item); 66 | } 67 | }); 68 | return routeList; 69 | }, 70 | // 路由拦截需要的路由信息 71 | routes(state) { 72 | const routes = []; 73 | state.routes.forEach(item => { 74 | if (item.name) { 75 | routes.push({ 76 | id: item._id, 77 | path: item.path, 78 | name: item.name, 79 | component: item.component, 80 | meta: item.meta, 81 | }); 82 | } 83 | }); 84 | return routes; 85 | }, 86 | }; 87 | export default { 88 | state, 89 | mutations, 90 | actions, 91 | getters, 92 | }; 93 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/tags.js: -------------------------------------------------------------------------------- 1 | import { updateTag, deleteTag, getTags, addTag } from "../api/api"; 2 | const state = { 3 | tags: [], 4 | }; 5 | const mutations = { 6 | TAGS(state, tags) { 7 | state.tags = tags; 8 | }, 9 | }; 10 | const actions = { 11 | // 编辑专栏 12 | async updateTag({ commit }, data) { 13 | return await updateTag(data); 14 | }, 15 | //删除专栏 16 | async deleteTag({ commit }, data) { 17 | return await deleteTag(data); 18 | }, 19 | // 获取专栏列表 20 | async getTags({ commit }) { 21 | let result = await getTags(); 22 | console.log(result); 23 | if (result.status == 200) { 24 | commit("TAGS", result.data); 25 | } else { 26 | console.log(result); 27 | } 28 | }, 29 | 30 | async addTag({ commit }, data) { 31 | console.log(data); 32 | return await addTag(data); 33 | }, 34 | }; 35 | const getters = { 36 | tags(state) { 37 | return state.tags; 38 | }, 39 | }; 40 | export default { 41 | state, 42 | mutations, 43 | actions, 44 | getters, 45 | }; 46 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/store/user.js: -------------------------------------------------------------------------------- 1 | import { getUsers, login, deleteUser, register, getUser, updatePassword, logout, updateUserInfo, getMurmurInfos, deleteMurmurInfo } from "../api/api"; 2 | import { setToken, getToken, clearToken, setUserInfo, getUserInfo } from "../util"; 3 | const state = { 4 | token: getToken() || "", 5 | username: getUserInfo() ? getUserInfo().username : "", 6 | userList: [], 7 | murmurInfos: [], 8 | }; 9 | const mutations = { 10 | USERLOGIN(state, token) { 11 | state.token = token; 12 | }, 13 | USERINFO(state, info) { 14 | state.info = info; 15 | }, 16 | USERLIST(state, userlist) { 17 | state.userList = userlist; 18 | }, 19 | MURMURINFOS(state, murmurInfos) { 20 | state.murmurInfos = murmurInfos; 21 | }, 22 | //清除本地数据 23 | CLEAR(state) { 24 | state.token = ""; 25 | state.info = {}; 26 | clearToken(); 27 | }, 28 | }; 29 | const actions = { 30 | // 用户注册 31 | async register({ commit }, user) { 32 | return await register(user); 33 | }, 34 | // 用户登录 35 | async login({ commit }, data) { 36 | let result = await login(data); 37 | if (result.status == 200) { 38 | setUserInfo(result.data.user); 39 | setToken(result.data.token); 40 | } else { 41 | return result; 42 | } 43 | }, 44 | // 获取用户列表 45 | async getUsers({ commit }) { 46 | let result = await getUsers(); 47 | if (result.status == 200) { 48 | commit("USERLIST", result.data); 49 | } else { 50 | console.log(result); 51 | } 52 | }, 53 | // 删除用户 54 | async deleteUser({ commit }, data) { 55 | return await deleteUser(data); 56 | }, 57 | // 更新用户信息 58 | async updateUserInfo({ commit }, data) { 59 | return await updateUserInfo(data); 60 | }, 61 | // 更新密码 62 | async updatePassword({ commit }, data) { 63 | return await updatePassword(data); 64 | }, 65 | // 获取用户信息 66 | async getUser({ commit }) { 67 | let result = await getUser(); 68 | if (result.status == 200) { 69 | commit("USERINFO", result.data); 70 | } else { 71 | return result; 72 | } 73 | }, 74 | async getMurmurInfos({ commit }) { 75 | let result = await getMurmurInfos(); 76 | console.log(result, "r"); 77 | if (result.status == 200) { 78 | commit("MURMURINFOS", result.data); 79 | } else { 80 | return result; 81 | } 82 | }, 83 | async deleteMurmurInfo({ commit }, id) { 84 | return await deleteMurmurInfo(id); 85 | }, 86 | 87 | // 退出登录 88 | async logout({ commit }) { 89 | let result = await logout(); 90 | if (result.status == 200) { 91 | commit("CLEAR"); 92 | } else { 93 | return result; 94 | } 95 | }, 96 | }; 97 | const getters = { 98 | userList(state) { 99 | return state.userList; 100 | }, 101 | token(state) { 102 | return state.token; 103 | }, 104 | username(state) { 105 | return state.username; 106 | }, 107 | murmurInfos() { 108 | return state.murmurInfos; 109 | }, 110 | }; 111 | export default { 112 | state, 113 | mutations, 114 | actions, 115 | getters, 116 | }; 117 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/util/directive.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { getUserInfo } from './index'; 3 | /**权限指令**/ 4 | export const has = Vue.directive('has', { 5 | inserted: function (el, binding, vnode) { 6 | // 获取页面按钮权限 7 | let btnPermissionsArr = []; 8 | if (binding.value) { 9 | // 如果指令传值,获取指令参数,根据指令参数和当前登录人按钮权限做比较。 10 | btnPermissionsArr = Array.of(binding.value); 11 | } else { 12 | // 否则获取路由中的参数,根据路由的btnPermissionsArr和当前登录人按钮权限做比较。 13 | btnPermissionsArr = vnode.context.$route.meta.btnPermissions; 14 | } 15 | if (!Vue.prototype.$_has(btnPermissionsArr)) { 16 | el.parentNode.removeChild(el); 17 | } 18 | } 19 | }); 20 | // 权限检查方法 21 | Vue.prototype.$_has = function (value) { 22 | let isExist = false; 23 | // 获取用户按钮权限 24 | let btnPermissionsStr = getUserInfo().role; 25 | if (btnPermissionsStr == undefined || btnPermissionsStr == null) { 26 | return false; 27 | } 28 | if (value.indexOf(btnPermissionsStr) > -1) { 29 | isExist = true; 30 | } 31 | return isExist; 32 | }; 33 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/util/index.js: -------------------------------------------------------------------------------- 1 | export const setToken = token => { 2 | sessionStorage.setItem("TOKEN", JSON.stringify(token)); 3 | }; 4 | export const getToken = () => { 5 | return JSON.parse(sessionStorage.getItem("TOKEN")); 6 | }; 7 | // /清除token 8 | export const clearToken = () => { 9 | sessionStorage.removeItem("TOKEN"); 10 | sessionStorage.removeItem("userInfo"); 11 | }; 12 | export const setClassifies = classifies => { 13 | sessionStorage.setItem("CLASSIFIES", JSON.stringify(classifies)); 14 | }; 15 | export const setUserInfo = user => { 16 | sessionStorage.setItem("userInfo", JSON.stringify(user)); 17 | }; 18 | export const getUserInfo = () => { 19 | return JSON.parse(sessionStorage.getItem("userInfo")); 20 | }; 21 | export const getClassifyList = () => { 22 | return JSON.parse(sessionStorage.getItem("CLASSIFIES")); 23 | }; 24 | // 压缩图片 25 | export const pressImg = img => { 26 | // 用于压缩图片的canvas 27 | const canvas = document.createElement('canvas'); 28 | const ctx = canvas.getContext('2d'); 29 | // 瓦片canvas 30 | const tCanvas = document.createElement('canvas'); 31 | const tctx = tCanvas.getContext('2d'); 32 | const initSize = img.src.length; 33 | let width = img.width; 34 | let height = img.height; 35 | // 如果图片大于四百万像素,计算压缩比并将大小压至4万以下 36 | let ratio; 37 | if ((ratio = (width * height) / 40000) > 1) { 38 | ratio = Math.sqrt(ratio); 39 | width /= ratio; 40 | height /= ratio; 41 | } else { 42 | ratio = 1; 43 | } 44 | canvas.width = width; 45 | canvas.height = height; 46 | // 铺底色 47 | ctx.fillStyle = '#fff'; 48 | ctx.fillRect(0, 0, canvas.width, canvas.height); 49 | // 如果图片像素大于100万则使用瓦片绘制 50 | let count; 51 | if ((count = (width * height) / 10000) > 1) { 52 | count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片 53 | // 计算每块瓦片的宽和高 54 | const nw = ~~(width / count); 55 | const nh = ~~(height / count); 56 | tCanvas.width = nw; 57 | tCanvas.height = nh; 58 | for (let i = 0; i < count; i++) { 59 | for (let j = 0; j < count; j++) { 60 | tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio * 2, nh * ratio * 2, 0, 0, nw, nh); 61 | ctx.drawImage(tCanvas, i * nw, j * nh, nw * 2, nh * 2); 62 | } 63 | } 64 | } else { 65 | ctx.drawImage(img, 0, 0, width * 2, height * 2); 66 | } 67 | // 进行最小压缩 68 | const pressImgData = canvas.toDataURL('image/jpeg', 0.5); 69 | console.log('压缩前:' + initSize); 70 | console.log('压缩后:' + pressImgData.length); 71 | console.log('压缩率:' + ~~((100 * (initSize - pressImgData.length)) / initSize) + '%'); 72 | return pressImgData; 73 | }; 74 | // 图片转为二进制 75 | export const toBolb = (basestr, type) => { 76 | const text = window.atob(basestr.split(',')[1]); 77 | const buffer = new ArrayBuffer(text.length); 78 | const ubuffer = new Uint8Array(buffer); 79 | for (let i = 0; i < text.length; i++) { 80 | ubuffer[i] = text.charCodeAt(i); 81 | } 82 | const Builder = window.WebKitBlobBuilder || window.MozBlobBuilder; 83 | let blob; 84 | if (Builder) { 85 | const builder = new Builder(); 86 | builder.append(buffer); 87 | blob = builder.getBlob(type); 88 | } else { 89 | blob = new window.Blob([buffer], { type: type }); 90 | } 91 | return blob; 92 | }; -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/404.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/Admin.vue: -------------------------------------------------------------------------------- 1 | 10 | 18 | 19 | 39 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/DataBoard.vue: -------------------------------------------------------------------------------- 1 | 11 | 182 | 197 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/Log.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 86 | 87 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/Result.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 23 | 24 | 29 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/Self.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 32 | 33 | 49 | -------------------------------------------------------------------------------- /MyBlogAdmin/src/views/Timeclue.vue: -------------------------------------------------------------------------------- 1 | 40 | 139 | -------------------------------------------------------------------------------- /MyBlogAdmin/vue.config.js: -------------------------------------------------------------------------------- 1 | // const CompressionPlugin = require("compression-webpack-plugin"); //引入 2 | module.exports = { 3 | lintOnSave: false, 4 | transpileDependencies: true, 5 | devServer: { 6 | proxy: "http://localhost:3000", 7 | }, 8 | productionSourceMap: false, 9 | configureWebpack: { 10 | externals: { 11 | vue: "Vue", 12 | // 'vue-router': 'VueRouter', 13 | // vuex: 'Vuex', 14 | axios: "axios", 15 | "element-ui": "ELEMENT", 16 | }, 17 | }, 18 | configureWebpack: config => { 19 | // 公共代码抽离 20 | config.optimization = { 21 | splitChunks: { 22 | cacheGroups: { 23 | libs: { 24 | name: "chunk-libs", 25 | test: /[\\/]node_modules[\\/]/, 26 | priority: 10, 27 | chunks: "initial", // only package third parties that are initially dependent 28 | }, 29 | common: { 30 | chunks: "all", 31 | test: /[\\/]src[\\/]js[\\/]/, 32 | name: "common", 33 | minChunks: 2, 34 | maxInitialRequests: 5, 35 | minSize: 0, 36 | priority: 60, 37 | }, 38 | styles: { 39 | name: "styles", 40 | test: /\.(sa|sc|c)ss$/, 41 | chunks: "all", 42 | enforce: true, 43 | }, 44 | pinyin: { 45 | // split pinyin libs 46 | name: "chunk-pinyin", 47 | test: /[\\/]node_modules[\\/]_?pinyin(.*)/, 48 | priority: 40, 49 | chunks: "async", 50 | reuseExistingChunk: true, 51 | }, 52 | html2canvas: { 53 | // split html2canvas libs 54 | name: "chunk-html2canvas", 55 | test: /[\\/]node_modules[\\/]_?html2canvas(.*)/, 56 | priority: 40, 57 | chunks: "async", 58 | reuseExistingChunk: true, 59 | }, 60 | "vue-pdf": { 61 | // split vue-pdf libs 62 | name: "chunk-vue-pdf", 63 | test: /[\\/]node_modules[\\/]_?vue-pdf(.*)/, 64 | priority: 40, 65 | chunks: "async", 66 | reuseExistingChunk: true, 67 | }, 68 | runtimeChunk: { 69 | name: "manifest", 70 | }, 71 | }, 72 | }, 73 | }; 74 | }, 75 | // configureWebpack: config => { 76 | // if (process.env.NODE_ENV === "production") { 77 | // config.plugins.push( 78 | // new CompressionPlugin({ 79 | // algorithm: "gzip", 80 | // test: /\.js$|\.html$|\.css$|\.jpg$|\.png/, 81 | // threshold: 10240, 82 | // minRatio: 0.5, 83 | // // deleteOriginalAssets: true, // 是否删除源文件 84 | // }) 85 | // ); 86 | // } 87 | // }, 88 | }; 89 | -------------------------------------------------------------------------------- /MyBlogFront/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /MyBlogFront/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | parserOptions: { 11 | parser: '@babel/eslint-parser' 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MyBlogFront/babel.config.js: -------------------------------------------------------------------------------- 1 | const proPlugins = []; 2 | if (process.env.NODE_ENV === 'production') { 3 | proPlugins.push('transform-remove-console'); 4 | } 5 | module.exports = { 6 | presets: ['@vue/cli-plugin-babel/preset'], 7 | plugins: [...proPlugins], 8 | }; 9 | -------------------------------------------------------------------------------- /MyBlogFront/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MyBlogFront/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myblogfront", 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 | "report": "vue-cli-service build --report" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.27.2", 13 | "core-js": "^3.8.3", 14 | "fingerprintjs2": "^2.1.4", 15 | "mavon-editor": "^2.10.4", 16 | "vue": "^2.6.14", 17 | "vue-router": "^3.5.1", 18 | "vuex": "^3.6.2" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.12.16", 22 | "@babel/eslint-parser": "^7.12.16", 23 | "@vue/cli-plugin-babel": "~5.0.0", 24 | "@vue/cli-plugin-eslint": "~5.0.0", 25 | "@vue/cli-plugin-router": "~5.0.0", 26 | "@vue/cli-plugin-vuex": "~5.0.0", 27 | "@vue/cli-service": "~5.0.0", 28 | "babel-plugin-transform-remove-console": "^6.9.4", 29 | "compression-webpack-plugin": "^10.0.0", 30 | "element-ui": "^2.15.9", 31 | "eslint": "^8.23.0", 32 | "eslint-plugin-vue": "^8.0.3", 33 | "image-webpack-loader": "^8.1.0", 34 | "less": "^4.0.0", 35 | "less-loader": "^8.0.0", 36 | "vue-template-compiler": "^2.6.14" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /MyBlogFront/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/public/favicon.ico -------------------------------------------------------------------------------- /MyBlogFront/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 孤城浪人的博客 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 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 |
54 |
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 | 85 | 86 | -------------------------------------------------------------------------------- /MyBlogFront/src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 57 | 111 | -------------------------------------------------------------------------------- /MyBlogFront/src/api/api.js: -------------------------------------------------------------------------------- 1 | // 统一管理所有接口 2 | import requests from './request'; 3 | // 获取文章列表 4 | export const getPublishBlogs = params => requests.get('/blogs/getpublishblogs', { params }); 5 | 6 | // 获取某一文章 7 | export const getBlog = params => requests.get('/blogs/getblog', { params }); 8 | 9 | // 获取专栏列表 10 | export const getClassifies = () => requests.get('/classifies/getclassifies'); 11 | 12 | // 获取随笔 13 | export const getPublishJottings = params => 14 | requests.get('/jottings/getpublishjottings', { params }); 15 | 16 | // 获取随笔 17 | export const getJotting = params => requests.get('/jottings/getjotting', { params }); 18 | 19 | // 获取文章总数信息 20 | export const getWebInfo = () => requests.get('/synthesis/getwebinfo'); 21 | 22 | // 获取某书签所有博客信息 23 | export const getBlogsOfClassify = params => requests.get('/blogs/getblogsofclassify', { params }); 24 | 25 | // 博客点赞 26 | export const giveBlogALike = params => requests.get('/blogs/addfavour', { params }); 27 | 28 | // 随笔点赞 29 | export const giveJottingALike = params => requests.get('/jottings/addfavour', { params }); 30 | 31 | // 增加博客浏览量 32 | export const addBlogBrowse = params => requests.get('/blogs/addblogbrowse', { params }); 33 | // 增加随笔浏览量 34 | export const addJottingBrowse = params => requests.get('/jottings/addjottingbrowse', { params }); 35 | 36 | // 获取右边信息栏基础信息 37 | export const getSliderInfo = () => requests.get('/synthesis/getsliderinfo'); 38 | // 搜索 39 | export const search = params => requests.get('/synthesis/searcharticle', { params }); 40 | // 新增murmur 41 | export const addMurmur = data => requests.post('/murmur/addmurmurinfo', data); 42 | // 修改murmur 43 | export const updateMurmur = data => requests.post('/murmur/updatemurmurusername', data); 44 | 45 | // 获取某篇文章的所有评论 46 | export const getCommentsOfArticle = params => 47 | requests.get('/comments/getcommentsofarticle', { params }); 48 | // 一级评论点赞 49 | export const addfirstfavour = params => requests.get('/comments/addfirstfavour', { params }); 50 | // 二级评论点赞 51 | export const addsecondfavour = params => requests.get('/comments/addsecondfavour', { params }); 52 | // 新增一级评论 53 | export const addfirstcomment = data => requests.post('/comments/addfirstcomment', data); 54 | // 新增二级评论 55 | export const addsecondcomment = data => requests.post('/comments/addsecondcomment', data); 56 | // 删除一级评论 57 | export const deletefirstcomment = params => 58 | requests.delete('/comments/deletefirstcomment', { params }); 59 | // 删除二级评论 60 | export const deletesecondcomment = params => 61 | requests.delete('/comments/deletesecondcomment', { params }); 62 | // 获取时间线数据 63 | export const getTimeclues = params => requests.get('/timeclues/gettimeclues', { params }); 64 | // 获取照片墙线数据 65 | export const getPhotos = () => requests.get('/photo/getphotos'); 66 | // 根据标签获取文章 67 | export const getArticlesOfTag = params => requests.get('/synthesis/getarticlesoftag', { params }); 68 | // 上传图片 69 | export const uploadAvatar = data => 70 | requests.post('/synthesis/uploadavatar', data, { 71 | headers: { 'content-type': 'multipart/form-data' }, 72 | }); 73 | -------------------------------------------------------------------------------- /MyBlogFront/src/api/index.js: -------------------------------------------------------------------------------- 1 | //导入所有接口 2 | import * as api from './api' 3 | 4 | const install = Vue => { 5 | if (install.installed) return; 6 | 7 | install.installed = true; 8 | 9 | Object.defineProperties(Vue.prototype, { 10 | //此处挂载在 Vue 原型的 $api 对象上 11 | $api: { 12 | get() { 13 | return api 14 | } 15 | } 16 | }) 17 | } 18 | 19 | export default install -------------------------------------------------------------------------------- /MyBlogFront/src/api/request.js: -------------------------------------------------------------------------------- 1 | // 引入axios进行二次封装 2 | // import axios from 'axios'; 3 | const requests = axios.create({ 4 | // 配置对象 5 | // 基础路径 6 | baseURL: '/api', 7 | // 请求超时的时间限 制 8 | timeout: 5000, 9 | }); 10 | // 请求拦截器:在请求发出去之前做处理 11 | requests.interceptors.request.use(config => { 12 | // config:配置对象,对象信息里边有一个重要信息,请求头headers 13 | // 进度条开始 14 | return config; 15 | }); 16 | // 响应拦截器 17 | requests.interceptors.response.use( 18 | res => { 19 | // 进度条结束 20 | return res.data; 21 | }, 22 | err => { 23 | if (err.code === 'ECONNABORTED' && err.message.indexOf('timeout') !== -1) { 24 | return Promise.reject('timeout请求超时'); 25 | // return service.request(originalRequest);// 再重复请求一次 26 | } 27 | if (err.message.indexOf('Network') !== -1) { 28 | return Promise.reject('网络异常'); 29 | } 30 | if (err.response && err.response.status === 404) { 31 | return Promise.reject('请求的资源无法找到'); 32 | } else if (err.response && err.response.status === 500) { 33 | return Promise.reject('服务器繁忙'); 34 | } 35 | return err; 36 | } 37 | ); 38 | 39 | export default requests; 40 | -------------------------------------------------------------------------------- /MyBlogFront/src/assets/common.css: -------------------------------------------------------------------------------- 1 | /* 分页样式 */ 2 | .pagination { 3 | float: right; 4 | margin-bottom: 2vh; 5 | } 6 | /* 空状态 */ 7 | .el-empty__description p { 8 | color: #000; 9 | } 10 | .el-icon-search { 11 | margin-right: 10px; 12 | } 13 | .el-input__inner { 14 | transition: 0.6s; 15 | border: none; 16 | } 17 | ::-webkit-scrollbar { 18 | /*滚动条整体样式*/ 19 | width: 5px; 20 | } 21 | 22 | ::-webkit-scrollbar-thumb { 23 | /*滚动条里面小方块*/ 24 | border-radius: 5px; 25 | background: rgba(0, 0, 0, 0.2); 26 | } 27 | 28 | ::-webkit-scrollbar-track { 29 | /*滚动条里面轨道*/ 30 | border-radius: 0; 31 | background: rgba(0, 0, 0, 0); 32 | } 33 | /* hover效果 */ 34 | .card:hover { 35 | transition: 0.5s; 36 | box-shadow: 0px 9.7px 2.2px rgba(80, 80, 80, 0.134), 0px 11.6px 5.3px rgba(80, 80, 80, 0.184), 37 | 0px 12.4px 10px rgba(80, 80, 80, 0.193), 0px 13px 17.9px rgba(80, 80, 80, 0.218), 38 | 0px 13.7px 33.4px rgba(80, 80, 80, 0.309), 0px 15px 80px rgba(80, 80, 80, 0.5); 39 | } 40 | -------------------------------------------------------------------------------- /MyBlogFront/src/assets/icons/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 3179613 */ 3 | src: url('iconfont.woff2?t=1656420527418') format('woff2'), 4 | url('iconfont.woff?t=1656420527418') format('woff'), 5 | url('iconfont.ttf?t=1656420527418') format('truetype'); 6 | } 7 | 8 | .iconfont { 9 | font-family: "iconfont" !important; 10 | font-size: 16px; 11 | font-style: normal; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | .icon-icon:before { 17 | content: "\e651"; 18 | } 19 | 20 | .icon-rili:before { 21 | content: "\e602"; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /MyBlogFront/src/assets/icons/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/icons/iconfont.ttf -------------------------------------------------------------------------------- /MyBlogFront/src/assets/icons/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/icons/iconfont.woff -------------------------------------------------------------------------------- /MyBlogFront/src/assets/icons/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/icons/iconfont.woff2 -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/avatar.png -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/infoBg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/infoBg.jpg -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/lightBg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/lightBg.png -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/nightBg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/nightBg.jpg -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/slideBg/slidebg1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/slideBg/slidebg1.jpg -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/slideBg/slidebg2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/slideBg/slidebg2.jpg -------------------------------------------------------------------------------- /MyBlogFront/src/assets/img/slideBg/slidebg3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/img/slideBg/slidebg3.jpg -------------------------------------------------------------------------------- /MyBlogFront/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogFront/src/assets/logo.png -------------------------------------------------------------------------------- /MyBlogFront/src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /MyBlogFront/src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 13 | 45 | 83 | -------------------------------------------------------------------------------- /MyBlogFront/src/components/Loading/Loading.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | 27 | 124 | -------------------------------------------------------------------------------- /MyBlogFront/src/components/Loading/index.js: -------------------------------------------------------------------------------- 1 | import loadingComponent from '@/components/Loading/Loading.vue'; 2 | // import Vue from 'vue'; 3 | const LoadingConstructor = Vue.extend(loadingComponent); 4 | 5 | const instance = new LoadingConstructor({ 6 | el: document.createElement('div'), 7 | }); 8 | 9 | instance.show = false; // 默认隐藏 10 | const loading = { 11 | show(text) { 12 | // 显示方法 13 | instance.show = true; 14 | instance.text = text; 15 | document.body.appendChild(instance.$el); 16 | }, 17 | hide() { 18 | // 隐藏方法 19 | instance.show = false; 20 | }, 21 | }; 22 | 23 | export default { 24 | install() { 25 | if (!Vue.$loading) { 26 | Vue.$loading = loading; 27 | } 28 | Vue.mixin({ 29 | created() { 30 | this.$loading = Vue.$loading; 31 | }, 32 | }); 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /MyBlogFront/src/components/Nav.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 64 | 65 | 99 | -------------------------------------------------------------------------------- /MyBlogFront/src/components/Slideshow.vue: -------------------------------------------------------------------------------- 1 | 35 | 80 | 81 | 162 | -------------------------------------------------------------------------------- /MyBlogFront/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 '@/assets/icons/iconfont.css'; 6 | import '@/assets/common.css'; 7 | import api from '@/api'; 8 | // import ElementUI from 'element-ui'; 9 | 10 | // 应用封装的loading 11 | import Loading from '@/components/Loading/index'; 12 | // import 'element-ui/lib/theme-chalk/index.css'; 13 | // Vue.prototype.$ELEMENT = { size: 'small', zIndex: 3000 }; 14 | Vue.use(Loading); 15 | // Vue.use(ElementUI); 16 | Vue.config.productionTip = false; 17 | Vue.use(api); 18 | new Vue({ 19 | router, 20 | store, 21 | render: h => h(App), 22 | }).$mount('#app'); 23 | -------------------------------------------------------------------------------- /MyBlogFront/src/router/index.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | 4 | Vue.use(VueRouter); 5 | 6 | const routes = [ 7 | { 8 | path: '/list/:type', 9 | component: () => import('@/views/List.vue'), 10 | }, 11 | { 12 | path: '/about', 13 | component: () => import('@/views/About.vue'), 14 | }, 15 | { 16 | path: '/article/:type/:id', 17 | component: () => import('@/views/Article.vue'), 18 | }, 19 | 20 | { 21 | path: '/timeclue', 22 | component: () => import('@/views/TimeClue.vue'), 23 | }, 24 | { 25 | path: '/messageboard', 26 | component: () => import('@/views/MessageBoard.vue'), 27 | }, 28 | { 29 | path: '/photo', 30 | component: () => import('@/views/PhotoWall.vue'), 31 | }, 32 | { 33 | path: '/', 34 | redirect: '/list/blog', 35 | }, 36 | { 37 | path: '*', 38 | redirect: '/list/blog', 39 | }, 40 | ]; 41 | 42 | const router = new VueRouter({ 43 | mode: 'history', 44 | base: process.env.BASE_URL, 45 | routes, 46 | scrollBehavior: (to, from, savePosition) => { 47 | // 动行为,每个页面切换时自动回到顶部 48 | if (savePosition) { 49 | return { 50 | savePosition, 51 | behavior: 'smooth', // // return 期望滚动到哪个的位置 52 | }; 53 | } else { 54 | return { behavior: 'smooth', y: 0 }; 55 | } 56 | }, 57 | }); 58 | // 重定向不报错 59 | const routerPush = VueRouter.prototype.push; 60 | VueRouter.prototype.push = function push(location) { 61 | return routerPush.call(this, location).catch(error => error); 62 | }; 63 | export default router; 64 | -------------------------------------------------------------------------------- /MyBlogFront/src/store/index.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import synthesis from './synthesis'; 4 | import theme from './theme'; 5 | 6 | Vue.use(Vuex); 7 | 8 | export default new Vuex.Store({ 9 | // vuex实现模块化开发,每个模块存放自己的数据 10 | modules: { 11 | synthesis, 12 | theme, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /MyBlogFront/src/store/synthesis.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | blogs: [], 3 | jottings: [], 4 | blogsOfClassify: [], 5 | classifies: [], 6 | searchs: [], 7 | }; 8 | const getters = {}; 9 | const mutations = { 10 | SAVEBLOG(state, blogs) { 11 | state.blogs = blogs; 12 | }, 13 | SAVEJOTTING(state, jottings) { 14 | state.jottings = jottings; 15 | }, 16 | SAVEBLOGSOFCLASSIFY(state, blogsOfClassify) { 17 | state.blogsOfClassify = blogsOfClassify; 18 | }, 19 | SAVECLASSIFIES(state, classifies) { 20 | state.classifies = classifies; 21 | }, 22 | SAVESEARCHLIST(state, searchs) { 23 | state.searchs = searchs; 24 | }, 25 | }; 26 | const actions = {}; 27 | 28 | export default { 29 | state, 30 | mutations, 31 | actions, 32 | getters, 33 | }; 34 | -------------------------------------------------------------------------------- /MyBlogFront/src/store/theme.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | isLight: true, 3 | color: '#FFFFFF', 4 | infoBgColor: 'rgba(255,255,255,0.6)', 5 | mainBg: 'rgba(50,50,50,0.6)', 6 | cardBg: 'rgb(100,100,100)', 7 | animateBg: '#0088b5', 8 | headFootBg: '#545c64', 9 | }; 10 | const getters = { 11 | color(state) { 12 | if (state.isLight) { 13 | state.color = '#000000'; 14 | } else { 15 | state.color = '#dddddd'; 16 | } 17 | return 'color:' + state.color; 18 | }, 19 | infoBgColor(state) { 20 | if (state.isLight) { 21 | state.infoBgColor = 'rgba(255,255,255,0.6)'; 22 | } else { 23 | state.infoBgColor = 'rgba(0,0,0,0.6)'; 24 | } 25 | return 'background-color:' + state.infoBgColor; 26 | }, 27 | mainBg(state) { 28 | if (state.isLight) { 29 | state.mainBg = 'rgba(255,255,255,0.6)'; 30 | } else { 31 | state.mainBg = 'rgba(50,50,50,0.6)'; 32 | } 33 | return 'background-color:' + state.mainBg; 34 | }, 35 | cardBg(state) { 36 | if (state.isLight) { 37 | state.cardBg = '#ffffff'; 38 | } else { 39 | state.cardBg = '#323232'; 40 | } 41 | return 'background-color:' + state.cardBg; 42 | }, 43 | specialcardBg(state) { 44 | if (state.isLight) { 45 | state.cardBg = '#ffffff'; 46 | } else { 47 | state.cardBg = '#323232'; 48 | } 49 | return state.cardBg; 50 | }, 51 | animateBg(state) { 52 | if (state.isLight) { 53 | state.animateBg = '#0088b5'; 54 | } else { 55 | state.animateBg = '#777777'; 56 | } 57 | return 'background-color:' + state.animateBg; 58 | }, 59 | headFootBg(state) { 60 | if (state.isLight) { 61 | state.headFootBg = 'rgb(130, 130, 130)'; 62 | } else { 63 | state.headFootBg = 'rgb(50, 50, 50)'; 64 | } 65 | return 'background-color:' + state.headFootBg; 66 | }, 67 | }; 68 | const mutations = { 69 | CHANGETHEME(state) { 70 | state.isLight = !state.isLight; 71 | }, 72 | }; 73 | 74 | const actions = {}; 75 | 76 | export default { 77 | state, 78 | mutations, 79 | actions, 80 | getters, 81 | }; 82 | -------------------------------------------------------------------------------- /MyBlogFront/src/util/bgSpecialEffect.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | const flakes = []; 3 | const canvas = document.createElement('canvas'); 4 | document.body.appendChild(canvas); 5 | const ctx = canvas.getContext('2d'); 6 | canvas.setAttribute( 7 | 'style', 8 | ' top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;' 9 | ); 10 | const flakeCount = 50; 11 | let mX = -100; 12 | let mY = -100; 13 | canvas.width = window.innerWidth; 14 | canvas.height = window.innerHeight; 15 | function snow() { 16 | ctx.clearRect(0, 0, canvas.width, canvas.height); 17 | 18 | for (let i = 0; i < flakeCount; i++) { 19 | const flake = flakes[i], 20 | x = mX, 21 | y = mY, 22 | minDist = 150, 23 | x2 = flake.x, 24 | y2 = flake.y; 25 | 26 | const dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)); 27 | // (dx = x2 - x), (dy = y2 - y); 28 | 29 | if (dist < minDist) { 30 | const force = minDist / (dist * dist), 31 | xcomp = (x - x2) / dist, 32 | ycomp = (y - y2) / dist, 33 | deltaV = force / 2; 34 | 35 | flake.velX -= deltaV * xcomp; 36 | flake.velY -= deltaV * ycomp; 37 | } else { 38 | flake.velX *= 0.98; 39 | if (flake.velY <= flake.speed) { 40 | flake.velY = flake.speed; 41 | } 42 | flake.velX += Math.cos((flake.step += 0.05)) * flake.stepSize; 43 | } 44 | 45 | ctx.fillStyle = 'rgba(255,255,255,' + flake.opacity + ')'; 46 | flake.y += flake.velY; 47 | flake.x += flake.velX; 48 | 49 | if (flake.y >= canvas.height || flake.y <= 0) { 50 | reset(flake); 51 | } 52 | 53 | if (flake.x >= canvas.width || flake.x <= 0) { 54 | reset(flake); 55 | } 56 | 57 | ctx.beginPath(); 58 | ctx.arc(flake.x, flake.y, flake.size, 0, Math.PI * 2); 59 | ctx.fill(); 60 | } 61 | requestAnimationFrame(snow); 62 | } 63 | 64 | function reset(flake) { 65 | flake.x = Math.floor(Math.random() * canvas.width); 66 | flake.y = 0; 67 | flake.size = Math.random() * 3 + 2; 68 | flake.speed = Math.random() * 1 + 0.5; 69 | flake.velY = flake.speed; 70 | flake.velX = 0; 71 | flake.opacity = Math.random() * 0.5 + 0.3; 72 | } 73 | 74 | function init() { 75 | for (let i = 0; i < flakeCount; i++) { 76 | let x = Math.floor(Math.random() * canvas.width), 77 | y = Math.floor(Math.random() * canvas.height), 78 | size = Math.random() * 3 + 2, 79 | speed = Math.random() * 1 + 0.5, 80 | opacity = Math.random() * 0.5 + 0.3; 81 | 82 | flakes.push({ 83 | speed: speed, 84 | velY: speed, 85 | velX: 0, 86 | x: x, 87 | y: y, 88 | size: size, 89 | stepSize: (Math.random() / 30) * 1, 90 | step: 0, 91 | angle: 180, 92 | opacity: opacity, 93 | }); 94 | } 95 | 96 | snow(); 97 | } 98 | 99 | document.addEventListener('mousemove', function (e) { 100 | mX = e.clientX; 101 | mY = e.clientY; 102 | }); 103 | window.addEventListener('resize', function () { 104 | canvas.width = window.innerWidth; 105 | canvas.height = window.innerHeight; 106 | }); 107 | init(); 108 | }; 109 | -------------------------------------------------------------------------------- /MyBlogFront/src/util/clickSpecialEffect.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | let balls = []; 3 | let longPressed = false; 4 | let longPress; 5 | let multiplier = 0; 6 | let width, height; 7 | let origin; 8 | let normal; 9 | let ctx; 10 | const colours = ['#F73859', '#14FFEC', '#00E0FF', '#FF99FE', '#FAF15D']; 11 | const canvas = document.createElement('canvas'); 12 | document.body.appendChild(canvas); 13 | canvas.setAttribute( 14 | 'style', 15 | 'width: 100%; height: 100%; top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;' 16 | ); 17 | const pointer = document.createElement('span'); 18 | pointer.classList.add('pointer'); 19 | document.body.appendChild(pointer); 20 | 21 | if (canvas.getContext && window.addEventListener) { 22 | ctx = canvas.getContext('2d'); 23 | updateSize(); 24 | window.addEventListener('resize', updateSize, false); 25 | loop(); 26 | window.addEventListener( 27 | 'mousedown', 28 | function (e) { 29 | pushBalls(randBetween(10, 20), e.clientX, e.clientY); 30 | document.body.classList.add('is-pressed'); 31 | longPress = setTimeout(function () { 32 | document.body.classList.add('is-longpress'); 33 | longPressed = true; 34 | }, 500); 35 | }, 36 | false 37 | ); 38 | window.addEventListener( 39 | 'mouseup', 40 | function (e) { 41 | clearInterval(longPress); 42 | if (longPressed == true) { 43 | document.body.classList.remove('is-longpress'); 44 | pushBalls( 45 | randBetween(50 + Math.ceil(multiplier), 100 + Math.ceil(multiplier)), 46 | e.clientX, 47 | e.clientY 48 | ); 49 | longPressed = false; 50 | } 51 | document.body.classList.remove('is-pressed'); 52 | }, 53 | false 54 | ); 55 | window.addEventListener( 56 | 'mousemove', 57 | function (e) { 58 | let x = e.clientX; 59 | let y = e.clientY; 60 | pointer.style.top = y + 'px'; 61 | pointer.style.left = x + 'px'; 62 | }, 63 | false 64 | ); 65 | } else { 66 | console.log('canvas or addEventListener is unsupported!'); 67 | } 68 | 69 | function updateSize() { 70 | canvas.width = window.innerWidth * 2; 71 | canvas.height = window.innerHeight * 2; 72 | canvas.style.width = window.innerWidth + 'px'; 73 | canvas.style.height = window.innerHeight + 'px'; 74 | ctx.scale(2, 2); 75 | width = canvas.width = window.innerWidth; 76 | height = canvas.height = window.innerHeight; 77 | origin = { 78 | x: width / 2, 79 | y: height / 2, 80 | }; 81 | normal = { 82 | x: width / 2, 83 | y: height / 2, 84 | }; 85 | } 86 | class Ball { 87 | constructor(x = origin.x, y = origin.y) { 88 | this.x = x; 89 | this.y = y; 90 | this.angle = Math.PI * 2 * Math.random(); 91 | if (longPressed == true) { 92 | this.multiplier = randBetween(14 + multiplier, 15 + multiplier); 93 | } else { 94 | this.multiplier = randBetween(6, 12); 95 | } 96 | this.vx = (this.multiplier + Math.random() * 0.5) * Math.cos(this.angle); 97 | this.vy = (this.multiplier + Math.random() * 0.5) * Math.sin(this.angle); 98 | this.r = randBetween(8, 12) + 3 * Math.random(); 99 | this.color = colours[Math.floor(Math.random() * colours.length)]; 100 | } 101 | update() { 102 | this.x += this.vx - normal.x; 103 | this.y += this.vy - normal.y; 104 | normal.x = (-2 / window.innerWidth) * Math.sin(this.angle); 105 | normal.y = (-2 / window.innerHeight) * Math.cos(this.angle); 106 | this.r -= 0.3; 107 | this.vx *= 0.9; 108 | this.vy *= 0.9; 109 | } 110 | } 111 | 112 | function pushBalls(count = 1, x = origin.x, y = origin.y) { 113 | for (let i = 0; i < count; i++) { 114 | balls.push(new Ball(x, y)); 115 | } 116 | } 117 | 118 | function randBetween(min, max) { 119 | return Math.floor(Math.random() * max) + min; 120 | } 121 | 122 | function loop() { 123 | ctx.fillStyle = 'rgba(255, 255, 255, 0)'; 124 | ctx.clearRect(0, 0, canvas.width, canvas.height); 125 | for (let i = 0; i < balls.length; i++) { 126 | let b = balls[i]; 127 | if (b.r < 0) continue; 128 | ctx.fillStyle = b.color; 129 | ctx.beginPath(); 130 | ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2, false); 131 | ctx.fill(); 132 | b.update(); 133 | } 134 | if (longPressed == true) { 135 | multiplier += 0.2; 136 | } else if (!longPressed && multiplier >= 0) { 137 | multiplier -= 0.4; 138 | } 139 | removeBall(); 140 | requestAnimationFrame(loop); 141 | } 142 | 143 | function removeBall() { 144 | for (let i = 0; i < balls.length; i++) { 145 | let b = balls[i]; 146 | if (b.x + b.r < 0 || b.x - b.r > width || b.y + b.r < 0 || b.y - b.r > height || b.r < 0) { 147 | balls.splice(i, 1); 148 | } 149 | } 150 | } 151 | }; 152 | -------------------------------------------------------------------------------- /MyBlogFront/src/util/index.js: -------------------------------------------------------------------------------- 1 | import Fingerprint2 from 'fingerprintjs2'; 2 | // 获取浏览器指纹 3 | export const createFingerprint = () => { 4 | Fingerprint2.get(components => { 5 | const values = components.map((component, index) => { 6 | if (index === 0) { 7 | //把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样 8 | return component.value.replace(/\bNetType\/\w+\b/, ''); 9 | } 10 | return component.value; 11 | }); 12 | // 生成最终id murmur 13 | let murmur = Fingerprint2.x64hash128(values.join(''), 31); 14 | localStorage.setItem('browserId', murmur); // 存储浏览器指纹,在项目中用于校验用户身份和埋点 15 | }); 16 | }; 17 | // 压缩图片 18 | export const pressImg = img => { 19 | // 用于压缩图片的canvas 20 | const canvas = document.createElement('canvas'); 21 | const ctx = canvas.getContext('2d'); 22 | // 瓦片canvas 23 | const tCanvas = document.createElement('canvas'); 24 | const tctx = tCanvas.getContext('2d'); 25 | // const initSize = img.src.length; 26 | let width = img.width; 27 | let height = img.height; 28 | // 如果图片大于四百万像素,计算压缩比并将大小压至4万以下 29 | let ratio; 30 | if ((ratio = (width * height) / 40000) > 1) { 31 | ratio = Math.sqrt(ratio); 32 | width /= ratio; 33 | height /= ratio; 34 | } else { 35 | ratio = 1; 36 | } 37 | canvas.width = width; 38 | canvas.height = height; 39 | // 铺底色 40 | ctx.fillStyle = '#fff'; 41 | ctx.fillRect(0, 0, canvas.width, canvas.height); 42 | // 如果图片像素大于100万则使用瓦片绘制 43 | let count; 44 | if ((count = (width * height) / 10000) > 1) { 45 | count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片 46 | // 计算每块瓦片的宽和高 47 | const nw = ~~(width / count); 48 | const nh = ~~(height / count); 49 | tCanvas.width = nw; 50 | tCanvas.height = nh; 51 | for (let i = 0; i < count; i++) { 52 | for (let j = 0; j < count; j++) { 53 | tctx.drawImage( 54 | img, 55 | i * nw * ratio, 56 | j * nh * ratio, 57 | nw * ratio * 2, 58 | nh * ratio * 2, 59 | 0, 60 | 0, 61 | nw, 62 | nh 63 | ); 64 | ctx.drawImage(tCanvas, i * nw, j * nh, nw * 2, nh * 2); 65 | } 66 | } 67 | } else { 68 | ctx.drawImage(img, 0, 0, width * 2, height * 2); 69 | } 70 | // 进行最小压缩 71 | const pressImgData = canvas.toDataURL('image/jpeg', 0.5); 72 | // console.log('压缩前:' + initSize); 73 | // console.log('压缩后:' + pressImgData.length); 74 | // console.log('压缩率:' + ~~((100 * (initSize - pressImgData.length)) / initSize) + '%'); 75 | return pressImgData; 76 | }; 77 | // 图片转为二进制 78 | export const toBolb = (basestr, type) => { 79 | const text = window.atob(basestr.split(',')[1]); 80 | const buffer = new ArrayBuffer(text.length); 81 | const ubuffer = new Uint8Array(buffer); 82 | for (let i = 0; i < text.length; i++) { 83 | ubuffer[i] = text.charCodeAt(i); 84 | } 85 | const Builder = window.WebKitBlobBuilder || window.MozBlobBuilder; 86 | let blob; 87 | if (Builder) { 88 | const builder = new Builder(); 89 | builder.append(buffer); 90 | blob = builder.getBlob(type); 91 | } else { 92 | blob = new window.Blob([buffer], { type: type }); 93 | } 94 | return blob; 95 | }; 96 | // 头像更新后递归修改评论头像 97 | export const deepCommentAvatar = (murmur, avatarUrl, comments) => { 98 | comments.forEach(item => { 99 | if (murmur == item.murmur) { 100 | item.avatarUrl = avatarUrl; 101 | } 102 | if (item.replyInfo?.length > 0) { 103 | deepCommentAvatar(murmur, avatarUrl, item.replyInfo); 104 | } 105 | }); 106 | }; 107 | -------------------------------------------------------------------------------- /MyBlogFront/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 45 | 53 | 195 | -------------------------------------------------------------------------------- /MyBlogFront/src/views/List.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 148 | 149 | 216 | -------------------------------------------------------------------------------- /MyBlogFront/src/views/MessageBoard.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 48 | 49 | 61 | -------------------------------------------------------------------------------- /MyBlogFront/src/views/PhotoWall.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 123 | 124 | 151 | -------------------------------------------------------------------------------- /MyBlogFront/src/views/TimeClue.vue: -------------------------------------------------------------------------------- 1 | 19 | 49 | 74 | -------------------------------------------------------------------------------- /MyBlogFront/vue.config.js: -------------------------------------------------------------------------------- 1 | const CompressionPlugin = require('compression-webpack-plugin'); //引入 2 | module.exports = { 3 | lintOnSave: false, 4 | transpileDependencies: true, 5 | devServer: { 6 | proxy: 'http://localhost:3000', 7 | }, 8 | productionSourceMap: false, 9 | configureWebpack: { 10 | externals: { 11 | vue: 'Vue', 12 | // 'vue-router': 'VueRouter', 13 | // vuex: 'Vuex', 14 | axios: 'axios', 15 | 'element-ui': 'ELEMENT', 16 | }, 17 | }, 18 | configureWebpack: config => { 19 | // 公共代码抽离 20 | config.optimization = { 21 | splitChunks: { 22 | cacheGroups: { 23 | libs: { 24 | name: 'chunk-libs', 25 | test: /[\\/]node_modules[\\/]/, 26 | priority: 10, 27 | chunks: 'initial', // only package third parties that are initially dependent 28 | }, 29 | common: { 30 | chunks: 'all', 31 | test: /[\\/]src[\\/]js[\\/]/, 32 | name: 'common', 33 | minChunks: 2, 34 | maxInitialRequests: 5, 35 | minSize: 0, 36 | priority: 60, 37 | }, 38 | styles: { 39 | name: 'styles', 40 | test: /\.(sa|sc|c)ss$/, 41 | chunks: 'all', 42 | enforce: true, 43 | }, 44 | pinyin: { 45 | // split pinyin libs 46 | name: 'chunk-pinyin', 47 | test: /[\\/]node_modules[\\/]_?pinyin(.*)/, 48 | priority: 40, 49 | chunks: 'async', 50 | reuseExistingChunk: true, 51 | }, 52 | html2canvas: { 53 | // split html2canvas libs 54 | name: 'chunk-html2canvas', 55 | test: /[\\/]node_modules[\\/]_?html2canvas(.*)/, 56 | priority: 40, 57 | chunks: 'async', 58 | reuseExistingChunk: true, 59 | }, 60 | 'vue-pdf': { 61 | // split vue-pdf libs 62 | name: 'chunk-vue-pdf', 63 | test: /[\\/]node_modules[\\/]_?vue-pdf(.*)/, 64 | priority: 40, 65 | chunks: 'async', 66 | reuseExistingChunk: true, 67 | }, 68 | runtimeChunk: { 69 | name: 'manifest', 70 | }, 71 | }, 72 | }, 73 | }; 74 | }, 75 | // configureWebpack: config => { 76 | // if (process.env.NODE_ENV === 'production') { 77 | // config.plugins.push( 78 | // new CompressionPlugin({ 79 | // algorithm: 'gzip', 80 | // test: /\.js$|\.html$|\.css$|\.jpg$|\.png/, 81 | // threshold: 10240, 82 | // minRatio: 0.5, 83 | // deleteOriginalAssets: true, // 是否删除源文件 84 | // }) 85 | // ); 86 | // } 87 | // }, 88 | }; 89 | -------------------------------------------------------------------------------- /MyBlogServe/app.js: -------------------------------------------------------------------------------- 1 | const createError = require('http-errors'); 2 | const express = require('express'); 3 | const path = require('path'); 4 | const cookieParser = require('cookie-parser'); 5 | const logger = require('morgan'); 6 | const session = require('express-session'); 7 | // 数据库 8 | const db = require('./db/connect'); 9 | 10 | // 引入路由 11 | const usersRouter = require('./routes/users'); 12 | const arrticlesRouter = require('./routes/blogs'); 13 | const jottingsRouter = require('./routes/jottings'); 14 | const classifiesRouter = require('./routes/classifies'); 15 | const synthesisRouter = require('./routes/synthesis'); 16 | const commentRouter = require('./routes/comments'); 17 | const routeRouter = require('./routes/routes'); 18 | const murmurRouter = require('./routes/murmur'); 19 | const photoRouter = require('./routes/photo'); 20 | const timeclueRouter = require('./routes/timeclue.js'); 21 | const app = express(); 22 | 23 | app.use(session({ 24 | secret: '####', 25 | name: 'sessionId', 26 | resave: false, 27 | saveUninitialized: false, 28 | cookie: { 29 | maxAge: 1000 * 60 * 60 30 | } 31 | })); 32 | // view engine setup 33 | app.set('views', path.join(__dirname, 'views')); 34 | app.set('view engine', 'jade'); 35 | app.use(logger('dev')); 36 | app.use(express.json()); 37 | app.use(express.urlencoded({ extended: false })); 38 | app.use(cookieParser()); 39 | app.use(express.static(path.join(__dirname, 'public'))); 40 | 41 | // 注册路由 42 | app.use('/api/users', usersRouter); 43 | app.use('/api/blogs', arrticlesRouter); 44 | app.use('/api/jottings', jottingsRouter); 45 | app.use('/api/classifies', classifiesRouter); 46 | app.use('/api/synthesis', synthesisRouter); 47 | app.use('/api/comments', commentRouter); 48 | app.use('/api/timeclues', timeclueRouter); 49 | app.use('/api/routes', routeRouter); 50 | app.use('/api/murmur', murmurRouter); 51 | app.use('/api/photo', photoRouter); 52 | // catch 404 and forward to error handler 53 | app.use(function(req, res, next) { 54 | next(createError(404)); 55 | }); 56 | 57 | // error handler 58 | app.use(function(err, req, res, next) { 59 | // set locals, only providing error in development 60 | res.locals.message = err.message; 61 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 62 | 63 | // render the error page 64 | res.status(err.status || 500); 65 | res.render('error'); 66 | }); 67 | 68 | module.exports = app; 69 | -------------------------------------------------------------------------------- /MyBlogServe/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('myblogserve:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/blogs.js: -------------------------------------------------------------------------------- 1 | const BlogsModel = require('../model/blogs'); 2 | const ClassifyModel = require('../model/classifies'); 3 | const TagModel = require('../model/tag'); 4 | const util = require('../utils'); 5 | // 添加新博客 6 | const addBlog = async (req, res) => { 7 | const { title, classification, content, digest, state, tags } = req.body; 8 | console.log(classification); 9 | const blog = await BlogsModel.addblog({ 10 | date: Date.now(), 11 | title, 12 | classification, 13 | content, 14 | digest, 15 | state, 16 | tags, 17 | }); 18 | await ClassifyModel.updateClassifySum(classification, 1); 19 | if (blog) { 20 | res.send({ 21 | msg: '博客添加成功', 22 | status: 200, 23 | }); 24 | } else { 25 | res.send({ 26 | msg: '博客添加失败!', 27 | status: 0, 28 | }); 29 | } 30 | }; 31 | // 修改博客状态 32 | const changeBlogState = async (req, res) => { 33 | const { _id } = req.query; 34 | const blog = await BlogsModel.getBlog(_id); 35 | const result = await BlogsModel.changeBlogState(!blog.state, _id); 36 | if (result.acknowledged && result.modifiedCount != 0) { 37 | res.send({ 38 | msg: '博客状态修改成功', 39 | status: 200, 40 | }); 41 | } else { 42 | res.send({ 43 | msg: '博客状态修改失败!', 44 | status: 0, 45 | }); 46 | } 47 | }; 48 | // 更新博客 49 | const updateBlog = async (req, res) => { 50 | const { content, _id, digest, title, tags } = req.body; 51 | const result = await BlogsModel.updateBlog(_id, content, digest, title, tags); 52 | if (result.acknowledged && result.modifiedCount !== 0) { 53 | res.send({ 54 | msg: '博客已更新', 55 | status: 200, 56 | }); 57 | } else { 58 | res.send({ 59 | msg: '更新失败!', 60 | status: 0, 61 | }); 62 | } 63 | }; 64 | // 获取文章列表 65 | const getBlogs = async (req, res) => { 66 | const blogs = await BlogsModel.getBlogs(); 67 | blogs.forEach(item => (item.date = util.formatDate(item.date))); 68 | if (blogs) { 69 | res.send({ 70 | msg: '博客查询成功', 71 | status: 200, 72 | data: blogs, 73 | }); 74 | } else { 75 | res.send({ 76 | msg: '博客查询失败', 77 | status: 200, 78 | }); 79 | } 80 | }; 81 | // 获取已发布文章列表 82 | const getPublishBlogs = async (req, res) => { 83 | const { pageStart, pageSize } = req.query; 84 | const dataList = await BlogsModel.getPublishBlogs(pageStart, pageSize); 85 | const count = await BlogsModel.getblogSums(); 86 | dataList.forEach(item => (item.date = util.formatDate(item.date))); 87 | if (dataList) { 88 | res.send({ 89 | msg: '博客查询成功', 90 | status: 200, 91 | data: { dataList, count }, 92 | }); 93 | } else { 94 | res.send({ 95 | msg: '博客查找失败', 96 | status: 0, 97 | }); 98 | } 99 | }; 100 | // 删除文章 101 | const deleteBlog = async (req, res) => { 102 | const { _id, classification } = req.query; 103 | const deleteBlog = await BlogsModel.deleteBlog(_id); 104 | ClassifyModel.updateClassifySum(classification, -1); 105 | if (deleteBlog.acknowledged && deleteBlog.deletedCount !== 0) { 106 | res.send({ 107 | msg: '博客删除成功', 108 | status: 200, 109 | }); 110 | } else { 111 | res.send({ 112 | msg: '博客删除失败!', 113 | status: 0, 114 | }); 115 | } 116 | }; 117 | // 获取某一个文章 118 | const getBlog = async (req, res) => { 119 | const { _id } = req.query; 120 | // 这里必须要await 121 | const blog = await BlogsModel.getBlog(_id); 122 | const tags = await TagModel.getTags(); 123 | blog.tags = util.manageTags(blog.tags, tags); 124 | blog.date = util.formatDate(blog.date); 125 | const classify = await ClassifyModel.getClassify(blog.classification); 126 | blog.classifyName = classify?.title; 127 | // 查询博客所属书签 128 | if (blog) { 129 | res.send({ 130 | msg: '博客查找成功', 131 | status: 200, 132 | data: blog, 133 | }); 134 | } else { 135 | res.send({ 136 | msg: '博主正在马不停蹄的创作中,敬请谅解!', 137 | status: 0, 138 | }); 139 | } 140 | }; 141 | // 获取某专栏下所有博客 142 | const getBlogsOfClassify = async (req, res) => { 143 | const { classification } = req.query; 144 | const dataList = await BlogsModel.getBlogsOfClassify(classification); 145 | dataList.forEach(item => (item.date = util.formatDate(item.date))); 146 | if (dataList) { 147 | res.send({ 148 | msg: '查找博客成功', 149 | status: 200, 150 | data: { 151 | dataList, 152 | }, 153 | }); 154 | } else { 155 | res.send({ 156 | msg: '博主正在加班加点的创作中,敬请谅解!', 157 | status: 0, 158 | }); 159 | } 160 | }; 161 | // 点赞 162 | const addFavour = async (req, res) => { 163 | const { _id, favourMurmur } = req.query; 164 | // 增加点赞数 165 | const addFavour = await BlogsModel.addFavour(_id, favourMurmur); 166 | const getFavour = await BlogsModel.getFavour(_id); 167 | if (addFavour) { 168 | res.send({ 169 | msg: '博客点赞成功', 170 | status: 200, 171 | data: getFavour.favour, 172 | }); 173 | } else { 174 | res.send({ 175 | msg: '博客点赞失败!', 176 | status: 0, 177 | }); 178 | } 179 | }; 180 | // 增加浏览量 181 | const addBlogBrowse = async (req, res) => { 182 | const { _id } = req.query; 183 | const result = await BlogsModel.addBlogBrowse(_id); 184 | if (result.modifiedCount === 1) { 185 | res.send({ 186 | msg: '博客浏览量增加成功', 187 | status: 200, 188 | }); 189 | } else { 190 | res.send({ 191 | msg: '博客浏览量增加失败', 192 | status: 0, 193 | }); 194 | } 195 | }; 196 | module.exports = { 197 | addBlog, 198 | changeBlogState, 199 | updateBlog, 200 | getBlogs, 201 | getPublishBlogs, 202 | deleteBlog, 203 | getBlog, 204 | getBlogsOfClassify, 205 | addFavour, 206 | addBlogBrowse, 207 | }; 208 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/classifies.js: -------------------------------------------------------------------------------- 1 | const ClassifyModel = require('../model/classifies'); 2 | const util = require('../utils'); 3 | // 添加新专栏 4 | const addClassify = async (req, res) => { 5 | const { title, digest } = req.body; 6 | const result = await ClassifyModel.addClassify({ 7 | date: Date.now(), 8 | title, 9 | digest, 10 | bgColor: util.randomColor(), 11 | }); 12 | if (result) { 13 | res.send({ 14 | msg: '专栏添加成功', 15 | status: 200, 16 | }); 17 | } else { 18 | res.send({ 19 | msg: '专栏添加失败!', 20 | status: 0, 21 | }); 22 | } 23 | }; 24 | // 获取所有专栏 25 | const getClassifies = async (req, res) => { 26 | const classifies = await ClassifyModel.getClassifies(); 27 | classifies.forEach(item => item.date = util.formatDate(item.date)); 28 | if (classifies) { 29 | res.send({ 30 | msg: '专栏查询成功', 31 | status: 200, 32 | data: classifies, 33 | }); 34 | } else { 35 | res.send({ 36 | msg: '专栏查询失败', 37 | status: 0, 38 | }); 39 | } 40 | }; 41 | // 修改专栏描述标题 42 | const updateClassifyTitle = async (req, res) => { 43 | const { _id, title, digest } = req.body; 44 | const result = await ClassifyModel.updateClassifyTitle(_id, title, digest); 45 | if (result.acknowledged && result.modifiedCount !== 0) { 46 | res.send({ 47 | msg: '专栏编辑成功', 48 | status: 200, 49 | data: result, 50 | }); 51 | } else { 52 | res.send({ 53 | msg: '专栏编辑失败', 54 | status: 0, 55 | }); 56 | } 57 | }; 58 | // 删除专栏 59 | const deleteClassify = async (req, res) => { 60 | const { _id } = req.query; 61 | // 这里必须要await 62 | const article = await ClassifyModel.getClassify(_id); 63 | const { articleNum } = article; 64 | if (articleNum != 0) { 65 | res.send({ 66 | msg: '专栏博客不为零,无法删除专栏', 67 | status: 0, 68 | }); 69 | } else { 70 | const result = await ClassifyModel.deleteClassify(_id); 71 | if (result.acknowledged && result.deletedCount !== 0) { 72 | res.send({ 73 | msg: '专栏删除成功', 74 | status: 200, 75 | }); 76 | } else { 77 | res.send({ 78 | msg: '专栏删除失败!', 79 | status: 0, 80 | }); 81 | } 82 | } 83 | }; 84 | 85 | module.exports = { 86 | updateClassifyTitle, 87 | deleteClassify, 88 | addClassify, 89 | getClassifies, 90 | }; 91 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/comments.js: -------------------------------------------------------------------------------- 1 | const CommentModel = require('../model/comments'); 2 | const MurmruModel = require('../model/murmurs'); 3 | const util = require('../utils'); 4 | // 添加新一级评论 5 | const addFirstComment = async (req, res, next) => { 6 | // 获取时间字符串 7 | const { keyId, articleTitle, content, murmur, replyInfo = [] } = req.body; 8 | const result = await CommentModel.addFirstComment({ 9 | date: Date.now(), 10 | keyId, 11 | // username, 12 | content, 13 | murmur, 14 | replyInfo, 15 | articleTitle, 16 | }); 17 | const comment = result.toObject(); 18 | comment.date = util.formatTime(comment.date); 19 | if (comment) { 20 | res.send({ 21 | msg: '评论成功', 22 | status: 200, 23 | data: comment, 24 | }); 25 | } else { 26 | res.send({ 27 | msg: '评论失败!', 28 | status: 0, 29 | }); 30 | } 31 | }; 32 | // 添加新次级评论 33 | const addSecondComment = async (req, res, next) => { 34 | // 获取时间字符串 35 | const { _id, date, reply, murmur, replyName, replyId } = req.body; 36 | const result = await CommentModel.addSecondComment(_id, { 37 | date: Date.now(), 38 | // replymurmur, 39 | replyId, 40 | // username, 41 | reply, 42 | murmur, 43 | replyName, 44 | }); 45 | if (result.acknowledged && result.modifiedCount !== 0) { 46 | const comment = await CommentModel.getCommentReplyLast(_id); 47 | const newCom = comment.replyInfo.pop().toObject(); 48 | newCom.date = util.formatTime(newCom.date); 49 | res.send({ 50 | msg: '评论成功', 51 | status: 200, 52 | data: newCom, 53 | }); 54 | } else { 55 | res.send({ 56 | msg: '评论失败!', 57 | status: 0, 58 | }); 59 | } 60 | }; 61 | // 给一级评论点赞 62 | const addFirstFavour = async (req, res) => { 63 | const { _id, favourMurmur } = req.query; 64 | const result = await CommentModel.addFirstFavour(_id, favourMurmur); 65 | if (result.acknowledged && result.modifiedCount !== 0) { 66 | res.send({ 67 | msg: '点赞成功', 68 | status: 200, 69 | }); 70 | } else { 71 | res.send({ 72 | msg: '点赞失败', 73 | status: 0, 74 | }); 75 | } 76 | }; 77 | // 给次级评论点赞 78 | const addSecondFavour = async (req, res) => { 79 | const { _id, replyId, favourMurmur } = req.query; 80 | const result = await CommentModel.addSecondFavour(_id, replyId, favourMurmur); 81 | if (result.acknowledged && result.modifiedCount !== 0) { 82 | res.send({ 83 | msg: '点赞成功', 84 | status: 200, 85 | }); 86 | } else { 87 | res.send({ 88 | msg: '点赞失败', 89 | status: 0, 90 | }); 91 | } 92 | }; 93 | // 删除一级评论 94 | const deleteFirstComment = async (req, res, next) => { 95 | const { _id } = req.query; 96 | const result = await CommentModel.deleteFirstComment(_id); 97 | if (result.acknowledged && result.deletedCount !== 0) { 98 | res.send({ 99 | msg: '删除成功', 100 | status: 200, 101 | data: result, 102 | }); 103 | } else { 104 | res.send({ 105 | msg: '删除失败', 106 | status: 0, 107 | }); 108 | } 109 | }; 110 | // 删除次级评论 111 | const deleteSecondComment = async (req, res, next) => { 112 | const { _id, replyId } = req.query; 113 | const result = await CommentModel.deleteSecondComment(_id, replyId); 114 | if (result.acknowledged && result.modifiedCount !== 0) { 115 | res.send({ 116 | msg: '删除成功', 117 | status: 200, 118 | }); 119 | } else { 120 | res.send({ 121 | msg: '删除失败', 122 | status: 0, 123 | }); 124 | } 125 | }; 126 | // 查询某一篇文章的所有评论 127 | const getCommentsOfArticle = async (req, res) => { 128 | const { id, pageSize, pageStart, murmur } = req.query; 129 | // 这里必须要await 130 | let comments = await CommentModel.getCommentsOfArticle(id, pageSize, pageStart); 131 | const murmurInfos = await MurmruModel.getMurmurInfos(); 132 | const user = await MurmruModel.getMurmurInfo(murmur); 133 | comments = util.manageMurmurComments(murmurInfos, comments); 134 | if (comments) { 135 | res.send({ 136 | msg: '查询成功', 137 | status: 200, 138 | data: { comments, user }, 139 | }); 140 | } else { 141 | res.send({ 142 | msg: '查询失败', 143 | status: 0, 144 | }); 145 | } 146 | }; 147 | // 查询所有的评论 148 | const getComments = async (req, res) => { 149 | // const { pageSize, pageStart, murmur } = req.query; 150 | // 这里必须要await 151 | let comments = await CommentModel.getComments(); 152 | const murmurInfos = await MurmruModel.getMurmurInfos(); 153 | comments = util.manageMurmurComments(murmurInfos, comments); 154 | if (comments) { 155 | res.send({ 156 | msg: '查询成功', 157 | status: 200, 158 | data: comments, 159 | }); 160 | } else { 161 | res.send({ 162 | msg: '查询失败', 163 | status: 0, 164 | }); 165 | } 166 | }; 167 | module.exports = { 168 | addFirstComment, 169 | addSecondComment, 170 | addFirstFavour, 171 | addSecondFavour, 172 | deleteFirstComment, 173 | deleteSecondComment, 174 | getCommentsOfArticle, 175 | getComments, 176 | }; 177 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/jottings.js: -------------------------------------------------------------------------------- 1 | const JottingModel = require('../model/jottings'); 2 | const TagModel = require('../model/tag'); 3 | const util = require('../utils'); 4 | const addJotting = async (req, res, next) => { 5 | let { title, content, digest, state, tags } = req.body; 6 | let result = await JottingModel.addJotting({ 7 | date: Date.now(), 8 | title, 9 | content, 10 | digest, 11 | state, 12 | tags, 13 | }); 14 | if (result) { 15 | res.send({ 16 | msg: '随笔添加成功', 17 | status: 200, 18 | }); 19 | } else { 20 | res.send({ 21 | msg: '随笔添加失败', 22 | status: 0, 23 | }); 24 | } 25 | }; 26 | // 修改随笔的状态 27 | const changeState = async (req, res) => { 28 | let { _id } = req.query; 29 | let jotting = await JottingModel.getJotting(_id); 30 | let result = await JottingModel.changeJottingState(!jotting.state, _id); 31 | if (result.acknowledged && result.modifiedCount !== 0) { 32 | res.send({ 33 | msg: '随笔状态修改成功', 34 | status: 200, 35 | }); 36 | } else { 37 | res.send({ 38 | msg: '随笔状态修改失败', 39 | status: 0, 40 | }); 41 | } 42 | }; 43 | // 修改随笔内容 44 | const updateJotting = async (req, res, next) => { 45 | let { content, _id, title, digest, tags } = req.body; 46 | let result = await JottingModel.updateJotting(_id, { content, digest, title, tags }); 47 | if (result.acknowledged && result.modifiedCount !== 0) { 48 | res.send({ 49 | msg: '随笔修改成功', 50 | status: 200, 51 | }); 52 | } else { 53 | res.send({ 54 | msg: '随笔修改失败', 55 | status: 0, 56 | }); 57 | } 58 | }; 59 | // 获取随笔列表 60 | const getJottings = async (req, res, next) => { 61 | let result = await JottingModel.getJottings(); 62 | result.forEach(item => { 63 | item.date = util.formatDate(item.date); 64 | }); 65 | if (result) { 66 | res.send({ 67 | msg: '随笔查询成功', 68 | status: 200, 69 | data: result, 70 | }); 71 | } else { 72 | res.send({ 73 | msg: '博主正在加班加点的创作中,敬请谅解!', 74 | status: 0, 75 | }); 76 | } 77 | }; 78 | // 获取已发布文章列表 79 | const getPublishJottings = async (req, res, next) => { 80 | let { pageStart, pageSize } = req.query; 81 | let dataList = await JottingModel.getPublishJottings(pageStart, pageSize); 82 | dataList.forEach(item => { 83 | item.date = util.formatDate(item.date); 84 | }); 85 | 86 | let count = await JottingModel.getJottingSums(); 87 | if (dataList) { 88 | res.send({ 89 | msg: '随笔查询成功', 90 | status: 200, 91 | data: { dataList, count }, 92 | }); 93 | } else { 94 | res.send({ 95 | msg: '博主正在加班加点的创作中,敬请谅解!', 96 | status: 0, 97 | }); 98 | } 99 | }; 100 | // 获取某一随笔 101 | const getJotting = async (req, res, next) => { 102 | let { _id } = req.query; 103 | let jotting = await JottingModel.getJotting(_id); 104 | const tags = await TagModel.getTags(); 105 | jotting.tags = util.manageTags(jotting.tags, tags); 106 | jotting.date = util.formatDate(jotting.date); 107 | if (jotting) { 108 | res.send({ 109 | msg: '随笔详情查询成功', 110 | status: 200, 111 | data: jotting, 112 | }); 113 | } else { 114 | res.send({ 115 | msg: '随笔详情查询失败', 116 | status: 0, 117 | }); 118 | } 119 | }; 120 | // 点赞某一随笔 121 | const addBrowse = async (req, res, next) => { 122 | let { _id } = req.query; 123 | let jotting = await JottingModel.addBrowse(_id); 124 | if (result.acknowledged && jotting.modifiedCount !== 0) { 125 | res.send({ 126 | msg: '随笔点赞成功', 127 | status: 200, 128 | data: jotting, 129 | }); 130 | } else { 131 | res.send({ 132 | msg: '随笔点赞失败', 133 | status: 0, 134 | }); 135 | } 136 | }; 137 | // 删除随笔 138 | const deleteJotting = async (req, res, next) => { 139 | const { _id } = req.query; 140 | let result = await JottingModel.deleteJotting(_id); 141 | if (result.acknowledged && result.deletedCount !== 0) { 142 | res.send({ 143 | msg: '随笔删除成功', 144 | status: 200, 145 | }); 146 | } else { 147 | res.send({ 148 | msg: '随笔删除失败', 149 | status: 0, 150 | }); 151 | } 152 | }; 153 | // 点赞 154 | const addFavour = async (req, res) => { 155 | let { _id, favourMurmur } = req.query; 156 | let addFavour = await JottingModel.addFavour(_id, favourMurmur); 157 | let getFavour = await JottingModel.getFavour(_id); 158 | if (addFavour.acknowledged && addFavour.modifiedCount !== 0) { 159 | res.send({ 160 | msg: '点赞随笔成功', 161 | status: 200, 162 | data: getFavour.favour, 163 | }); 164 | } else { 165 | res.send({ 166 | msg: '点赞随笔失败', 167 | status: 0, 168 | }); 169 | } 170 | }; 171 | 172 | // 增加浏览量 173 | const addJottingBrowse = async (req, res) => { 174 | let { _id } = req.query; 175 | let addBrowse = await JottingModel.addJottingBrowse(_id); 176 | if (addBrowse.acknowledged && addBrowse.modifiedCount !== 0) { 177 | res.send({ 178 | msg: '随笔浏览量增加成功', 179 | status: 200, 180 | }); 181 | } else { 182 | res.send({ 183 | msg: '随笔浏览量增加失败', 184 | status: 0, 185 | }); 186 | } 187 | }; 188 | module.exports = { 189 | getJottings, 190 | deleteJotting, 191 | updateJotting, 192 | addJotting, 193 | changeState, 194 | getPublishJottings, 195 | getJotting, 196 | addFavour, 197 | addBrowse, 198 | addJottingBrowse, 199 | }; 200 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/murmur.js: -------------------------------------------------------------------------------- 1 | const MurmruModel = require('../model/murmurs'); 2 | const util = require('../utils'); 3 | // 新增指纹信息 4 | const addMurmurInfo = async (req, res) => { 5 | const { murmur, username, avatarUrl } = req.body; 6 | const result = await MurmruModel.addMurmur({ date: Date.now(), murmur, username, avatarUrl }); 7 | if (result) { 8 | res.send({ 9 | msg: '新增浏览器指纹信息成功', 10 | status: 200, 11 | data: result, 12 | }); 13 | } else { 14 | res.send({ 15 | msg: '新增浏览器指纹信息失败', 16 | status: 0, 17 | }); 18 | } 19 | }; 20 | // 更新用户名 21 | const updateMurmurUsername = async (req, res, next) => { 22 | const { murmur, username } = req.body; 23 | let result = await MurmruModel.updateMurmurUsername(murmur, username); 24 | if (result.acknowledged && result.modifiedCount != 0) { 25 | res.send({ 26 | msg: '更新用户名成功', 27 | status: 200, 28 | }); 29 | } else { 30 | res.send({ 31 | msg: '更新用户名失败', 32 | status: 0, 33 | }); 34 | } 35 | }; 36 | //查询所有用户信息 37 | const getMurmurInfos = async (req, res, next) => { 38 | let result = await MurmruModel.getMurmurInfos(); 39 | result.forEach(item => (item.date = util.formatDate(item.date))); 40 | if (result) { 41 | res.send({ 42 | msg: '查询成功', 43 | status: 200, 44 | data: result, 45 | }); 46 | } else { 47 | res.send({ 48 | msg: '查询失败', 49 | status: 0, 50 | }); 51 | } 52 | }; 53 | //查询所有用户信息 54 | const deleteMurmurInfo = async (req, res, next) => { 55 | const { id } = req.query; 56 | const result = await MurmruModel.deleteMurmurInfo(id); 57 | if (result.acknowledged && result.deletedCount != 0) { 58 | res.send({ 59 | msg: '删除成功', 60 | status: 200, 61 | }); 62 | } else { 63 | res.send({ 64 | msg: '删除失败', 65 | status: 0, 66 | }); 67 | } 68 | }; 69 | module.exports = { 70 | addMurmurInfo, 71 | updateMurmurUsername, 72 | getMurmurInfos, 73 | deleteMurmurInfo, 74 | }; 75 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/photo.js: -------------------------------------------------------------------------------- 1 | const PhotoModel = require('../model/photo'); 2 | const util = require('../utils'); 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | // 添加新图片 6 | const addPhoto = async (req, res) => { 7 | const { digest, shootingTime } = req.body; 8 | const file = req.file; 9 | const photoUrl = util.imgBaseUrl('photo') + file.filename; 10 | const url = path.join(__dirname, '../public/photos/', file.filename); 11 | 12 | const result = await PhotoModel.addPhoto({ 13 | uploadTime: Date.now(), 14 | shootingTime, 15 | photoUrl, 16 | digest, 17 | thumbnailUrl: '', 18 | preBg: util.randomColor(), 19 | }); 20 | console.log(fs.existsSync(url), result); 21 | if (result && fs.existsSync(url)) { 22 | res.send({ 23 | msg: '照片添加成功', 24 | status: 200, 25 | }); 26 | } else { 27 | res.send({ 28 | msg: '照片添加失败!', 29 | status: 0, 30 | }); 31 | } 32 | }; 33 | // 获取照片 34 | const getPhotos = async (req, res) => { 35 | const photos = await PhotoModel.getPhotos(); 36 | photos.forEach(item => { 37 | item.uploadTime = util.formatDate(item.uploadTime); 38 | item.shootingTime = util.formatDate(item.shootingTime); 39 | }); 40 | if (photos) { 41 | res.send({ 42 | msg: '查询成功', 43 | status: 200, 44 | data: photos, 45 | }); 46 | } else { 47 | res.send({ 48 | msg: '查询失败', 49 | status: 0, 50 | }); 51 | } 52 | }; 53 | // 修改照片信息 54 | const updatePhotoDigest = async (req, res) => { 55 | const { _id, digest, shootingTime } = req.body; 56 | const result = await PhotoModel.updatePhoto(_id, digest, shootingTime); 57 | if (result.acknowledged && result.modifiedCount !== 0) { 58 | res.send({ 59 | msg: '照片信息编辑成功', 60 | status: 200, 61 | data: result, 62 | }); 63 | } else { 64 | res.send({ 65 | msg: '照片信息编辑失败', 66 | status: 0, 67 | }); 68 | } 69 | }; 70 | // 删除照片 71 | const deletePhoto = async (req, res) => { 72 | const { _id } = req.query; 73 | const result = await PhotoModel.deletePhoto(_id); 74 | if (result.acknowledged && result.deletedCount !== 0) { 75 | res.send({ 76 | msg: '照片删除成功', 77 | status: 200, 78 | }); 79 | } else { 80 | res.send({ 81 | msg: '照片删除失败!', 82 | status: 0, 83 | }); 84 | } 85 | }; 86 | 87 | module.exports = { 88 | updatePhotoDigest, 89 | deletePhoto, 90 | addPhoto, 91 | getPhotos, 92 | }; 93 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/routes.js: -------------------------------------------------------------------------------- 1 | const RouteModel = require('../model/routes'); 2 | const { sign, verify, hash, compare, date } = require('../utils'); 3 | // 添加新路由 4 | const addFirstRoute = async (req, res) => { 5 | const { route } = req.body; 6 | const result = await RouteModel.addFirstRoute(route); 7 | if (result) { 8 | res.send({ 9 | msg: '添加成功', 10 | status: 200, 11 | }); 12 | } else { 13 | res.send({ 14 | msg: '添加失败!', 15 | status: 0, 16 | }); 17 | } 18 | }; 19 | const addSecondRoute = async (req, res, next) => { 20 | const { route, parentRouteName } = req.body; 21 | const router = await RouteModel.getRouteByPath(route.path); 22 | if (router) { 23 | res.send({ 24 | msg: '路径重复!', 25 | status: 0, 26 | }); 27 | } else { 28 | const result = await RouteModel.addSecondRoute(parentRouteName, route); 29 | if (result.acknowledged && result.modifiedCount !== 0) { 30 | res.send({ 31 | msg: '添加成功', 32 | status: 200, 33 | }); 34 | } else { 35 | res.send({ 36 | msg: '添加失败!', 37 | status: 0, 38 | }); 39 | } 40 | } 41 | }; 42 | // 修改路由 43 | const updatRoute = async (req, res, next) => { 44 | const { route } = req.body; 45 | const result = await RouteModel.updateFirstRouteInfo(route); 46 | if (result.acknowledged && result.modifiedCount != 0) { 47 | res.send({ 48 | msg: '修改成功', 49 | status: 200, 50 | }); 51 | } else { 52 | res.send({ 53 | msg: '修改失败', 54 | status: 0, 55 | }); 56 | } 57 | }; 58 | // 获取路由列表 59 | const getRoutes = async (req, res, next) => { 60 | const { role } = req.query; 61 | const result = await RouteModel.getRoutes(); 62 | // console.log('rew', result); 63 | 64 | const route = _filterRoute(role, result); 65 | if (result) { 66 | res.send({ 67 | msg: '查询成功', 68 | status: 200, 69 | data: route, 70 | }); 71 | } else { 72 | res.send({ 73 | msg: '查询失败', 74 | status: -1, 75 | }); 76 | } 77 | }; 78 | // 获取所有路由列表 79 | const getRouteList = async (req, res, next) => { 80 | const result = await RouteModel.getRoutes(); 81 | if (result) { 82 | res.send({ 83 | msg: '查询所有路由成功', 84 | status: 200, 85 | data: result, 86 | }); 87 | } else { 88 | res.send({ 89 | msg: '查询失败', 90 | status: 0, 91 | }); 92 | } 93 | }; 94 | // 递归处理符合条件的路由 95 | const _filterRoute = (role, routeList) => { 96 | const route = []; 97 | // console.log('r', routeList); 98 | routeList.forEach(item => { 99 | if (item.limits && item.limits.includes(role)) { 100 | const obj = {}; 101 | obj._id = item._id; 102 | obj.path = item.path; 103 | obj.name = item.name; 104 | obj.component = item.component; 105 | obj.limits = item.limits; 106 | if (item.meta) { 107 | obj.meta = item.meta; 108 | } 109 | if (item.children && item.children.length !== 0) { 110 | obj.children = _filterRoute(role, item.children); 111 | } 112 | route.push(obj); 113 | } 114 | }); 115 | return route; 116 | }; 117 | // 删除路由 118 | const deleteRoute = async (req, res) => { 119 | const { _id } = req.query; 120 | const result = await RouteModel.deleteFirstRoute(_id); 121 | // if (!name) { 122 | // } else { 123 | // result = await RouteModel.deleteSecondRoute(_id, name); 124 | // } 125 | if (result.acknowledged && result.deletedCount != 0) { 126 | res.send({ 127 | msg: '路由删除成功!', 128 | status: 200, 129 | }); 130 | } else { 131 | res.send({ 132 | msg: '路由删除失败!', 133 | status: -1, 134 | }); 135 | } 136 | }; 137 | 138 | module.exports = { 139 | addSecondRoute, 140 | addFirstRoute, 141 | updatRoute, 142 | getRoutes, 143 | deleteRoute, 144 | getRouteList, 145 | }; 146 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/timeclue.js: -------------------------------------------------------------------------------- 1 | const TimeclueModel = require('../model/timeclue'); 2 | const util = require('../utils'); 3 | const addTimeclue = async (req, res) => { 4 | const { title, digest, date } = req.body; 5 | const timeclue = await TimeclueModel.addTimeclue({ title, date, digest }); 6 | if (timeclue) { 7 | res.send({ 8 | msg: '新增时间线信息成功', 9 | status: 200, 10 | data: timeclue, 11 | }); 12 | } else { 13 | res.send({ 14 | msg: '新增时间线信息失败', 15 | status: 0, 16 | }); 17 | } 18 | }; 19 | const updateTimeclue = async (req, res) => { 20 | const { _id, date, title, digest } = req.body; 21 | const timeclue = await TimeclueModel.uptateTimeclue(_id, date, title, digest); 22 | if (timeclue.acknowledged && timeclue.modifiedCount != 0) { 23 | res.send({ 24 | msg: '时间线信息修改成功', 25 | status: 200, 26 | }); 27 | } else { 28 | res.send({ 29 | msg: '时间线信息修改失败', 30 | status: 0, 31 | }); 32 | } 33 | }; 34 | const changeTimeNodeState = async (req, res) => { 35 | const { id } = req.query; 36 | const { state } = await TimeclueModel.getTimeclue(id); 37 | const timeclue = await TimeclueModel.changeTimeNodeState(id, !state); 38 | if (timeclue.acknowledged && timeclue.modifiedCount != 0) { 39 | res.send({ 40 | msg: '状态修改成功', 41 | status: 200, 42 | }); 43 | } else { 44 | res.send({ 45 | msg: '状态修改失败', 46 | status: 0, 47 | }); 48 | } 49 | }; 50 | //删除时间线信息 51 | const deleteTimeclue = async (req, res) => { 52 | const { _id } = req.query; 53 | const timeclue = await TimeclueModel.deleteTimeclue(_id); 54 | if (timeclue.acknowledged && timeclue.deletedCount != 0) { 55 | res.send({ 56 | msg: '删除时间线信息成功', 57 | status: 200, 58 | }); 59 | } else { 60 | res.send({ 61 | msg: '删除时间线信息失败', 62 | status: 0, 63 | }); 64 | } 65 | }; 66 | 67 | //查找某一个时间线信息 68 | const getTimeclue = async (req, res) => { 69 | const { _id } = req.query; 70 | const timeclue = await TimeclueModel.getTimeclue(_id); 71 | if (timeclue) { 72 | res.send({ 73 | msg: '查询时间线信息成功', 74 | status: 200, 75 | data: timeclue, 76 | }); 77 | } else { 78 | res.send({ 79 | msg: '查询时间线信息成功', 80 | status: 0, 81 | }); 82 | } 83 | }; 84 | 85 | //获取所有时间线信息 86 | const getTimeclues = async (req, res) => { 87 | const timeclues = await TimeclueModel.getTimeclues(); 88 | timeclues.forEach(item => (item.date = util.formatDate(item.date))); 89 | if (timeclues) { 90 | res.send({ 91 | msg: '获取时间线信息列表成功', 92 | status: 200, 93 | data: timeclues, 94 | }); 95 | } else { 96 | res.send({ 97 | msg: '获取时间线信息列表失败', 98 | status: 0, 99 | }); 100 | } 101 | }; 102 | module.exports = { 103 | addTimeclue, 104 | deleteTimeclue, 105 | getTimeclue, 106 | getTimeclues, 107 | updateTimeclue, 108 | changeTimeNodeState, 109 | }; 110 | -------------------------------------------------------------------------------- /MyBlogServe/controllers/users.js: -------------------------------------------------------------------------------- 1 | const UserModel = require('../model/users'); 2 | const { sign, verify, hash, compare, formatDate } = require('../utils'); 3 | // 添加新用户 4 | const register = async (req, res, next) => { 5 | let { username, password, email, role } = req.body; 6 | // 密码加密 7 | const bcryptPassword = await hash(password); 8 | // 检查此邮箱是否已经被注册 9 | const Email = await UserModel.getUser(email); 10 | if (!Email) { 11 | let result = await UserModel.addUser({ 12 | username, 13 | password: bcryptPassword, 14 | email, 15 | date: Date.now(), 16 | role, 17 | }); 18 | 19 | if (result) { 20 | res.send({ 21 | msg: '注册成功', 22 | status: 200, 23 | }); 24 | } else { 25 | res.send({ 26 | msg: '注册失败了!请检查信息', 27 | status: 0, 28 | }); 29 | } 30 | } else { 31 | res.send({ 32 | msg: '此邮箱已经被注册,换个邮箱吧!', 33 | status: 0, 34 | }); 35 | } 36 | }; 37 | // 登录 38 | const login = async (req, res, next) => { 39 | let { email, password } = req.body; 40 | // 查找用户是否存在 41 | let user = await UserModel.getUser(email); 42 | if (user) { 43 | let { password: hash } = user; 44 | // 比较密码 45 | let compareResult = await compare(password, hash); 46 | if (compareResult) { 47 | let userInfo = { 48 | username: user.username, 49 | limits: user.limits, 50 | role: user.role, 51 | avatarUrl:user.avatarUrl 52 | }; 53 | const token = sign(email); 54 | res.send({ 55 | msg: '登陆成功', 56 | status: 200, 57 | data: { 58 | token: token, 59 | user: userInfo, 60 | }, 61 | }); 62 | } else { 63 | res.send({ 64 | msg: '密码错误!', 65 | status: 0, 66 | }); 67 | } 68 | } else { 69 | res.send({ 70 | msg: '账号信息不存在!', 71 | status: 0, 72 | }); 73 | } 74 | }; 75 | // 登出 76 | const logout = async (req, res, next) => { 77 | req.session = null; 78 | res.send({ 79 | msg: '退出成功', 80 | status: 200, 81 | }); 82 | }; 83 | // 进入登录态 84 | const getUserState = async (req, res, next) => { 85 | try { 86 | // 验证token 87 | let result = verify(token); 88 | res.send({ 89 | msg: '已登录', 90 | status: 200, 91 | data: { 92 | username: result.username, 93 | }, 94 | }); 95 | } catch (err) { 96 | res.send({ 97 | msg: '请登录', 98 | status: 0, 99 | }); 100 | } 101 | }; 102 | // 修改用户信息 103 | const updateUserInfo = async (req, res, next) => { 104 | let { email, role, username } = req.body; 105 | let result = await UserModel.updateUserInfo(email, role, username); 106 | if (result.acknowledged && result.modifiedCount !== 0) { 107 | res.send({ 108 | msg: '用户信息修改成功', 109 | status: 200, 110 | }); 111 | } else { 112 | res.send({ 113 | msg: '用户信息修改失败', 114 | status: 0, 115 | }); 116 | } 117 | }; 118 | 119 | // 修改密码 120 | const updatePassword = async (req, res, next) => { 121 | let { email, password } = req.body; 122 | const bcryptPassword = await hash(password); 123 | let result = await UserModel.updatePassword(email, bcryptPassword); 124 | if (result.acknowledged && result.modifiedCount !== 0) { 125 | res.send({ 126 | msg: '密码修改成功', 127 | status: 200, 128 | }); 129 | } else { 130 | res.send({ 131 | msg: '密码修改失败', 132 | status: 0, 133 | }); 134 | } 135 | }; 136 | // 获取用户列表 137 | const getUsers = async (req, res, next) => { 138 | const users = await UserModel.getUsers(); 139 | users.forEach(item => (item.date = formatDate(item.date))); 140 | if (users) { 141 | res.send({ 142 | msg: '查询用户成功', 143 | status: 200, 144 | data: users, 145 | }); 146 | } else { 147 | res.send({ 148 | msg: '查询用户失败', 149 | status: 0, 150 | }); 151 | } 152 | }; 153 | // 删除用户 154 | const deleteUser = async (req, res, next) => { 155 | const { email } = req.query; 156 | // 这里必须要await 157 | let result = await UserModel.deleteUser(email); 158 | if (result.acknowledged && result.deletedCount != 0) { 159 | res.send({ 160 | msg: '用户注销成功!', 161 | status: 200, 162 | }); 163 | } else { 164 | res.send({ 165 | msg: '用户注销失败!', 166 | status: 0, 167 | }); 168 | } 169 | }; 170 | 171 | module.exports = { 172 | login, 173 | logout, 174 | getUserState, 175 | updateUserInfo, 176 | getUsers, 177 | register, 178 | deleteUser, 179 | updatePassword, 180 | }; 181 | -------------------------------------------------------------------------------- /MyBlogServe/db/connect.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | // 连接数据库 3 | mongoose.connect('mongodb://localhost:27017/MyBlog', (err) => { 4 | if (err) { 5 | console.log('数据库链接失败!'); 6 | // console.log(err) 7 | } else { 8 | console.log('数据库链接成功!'); 9 | } 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /MyBlogServe/keys/rsa_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAv/s8O3PlaGwc9EeABBC3coaAfKOle4H2d+64bXwA84IWGKPQ 3 | Xvsvx+viTlCovicvEMuP3di8JURMURJT0hJ37VYgHZNBhjOI5f8gyXa+JjtCtbaH 4 | tMogRestNhFhSLtQm9QY/pVotPgT9khkf4fJMhRsZOGmeEsKK2ALXwdHGveY1RdB 5 | uzny+9xogAFW5CVSWyeAYq7YRrIqdx5LmqBstmcv+VKBMzM4rySbtc9fAO+Oyr3Z 6 | DnLAStntB3nKaCDj657mHn8YBi1dUcxTe9aSuhAlV25mReQOquu5uakpz6WV3afk 7 | Fd2blqe2qRUjH8cQaLkGONDLBisIuEJf+kGkvQIDAQABAoIBAGw/o/m94pebhkPy 8 | 4Orp5hZMYrxkpZVbdXawgwswxXSIYB8qlv5HUey/Q453Cn6Vp4Mn1In5gDTfKsz3 9 | sY2c3kRTsK4cbvDVtBZDYeBW9OanuXiuYBx/b+0cqxR2fk09WTlUQXejFTQdQVw3 10 | +3qxPK/hNjE3zt67KRPGBwNhHiXEhVfIZ+fNPaHhF7lK2Zs5RZJdonaIOS20wpsR 11 | rPqGkS+s/x00Iyrn6rBBWsW09VunS04ELudzPBICKBMRuhdSm8C0zQmrzWQtS8kq 12 | jYN4cDJU0dMCMIgnYUbvsCq+I6FRfNIOsur14rWn+/Kgu/P2XdysqLn/5DvPCr/d 13 | GtG0eF0CgYEA8aqspis5igODdcptf+kkI3saDVyKzyGR7z0e3HuzroIf+rioyNjp 14 | R4sXdQLnwB4loKQX+0YsLPBLVQKCTA7tGn6dMQQ/i5OEb+bWwrm9h8UPPCXKWnGm 15 | k1zVC/zqaORGMg+6ntPxHjwvBn8Snvk+OMoa5ZgJl7isgELzK3NwFFMCgYEAy14r 16 | EZwBno/mb4X5IXIu2h++mytBNdmfAabGXr/L5pICSRzrztjA9oXAsJLqF+iuBM8z 17 | 7wHWTu1OKJXh1h2JMrmWuXTwq0+fI4iwz2CwAAbV3GnYZS4u7/j5kVLfpNFC39ku 18 | R8namsWMYupxevr2wjg3KHHjFTX1emVHmARVQK8CgYEA0zY12q0ghsz3UjVvakGb 19 | Qh9O76qX7twKLaufk1fR/Izh4kEN0ywxBkQ8Zhn57mDqxfFkvEniRgxl6pBczJin 20 | BWbvf22VFCoDr8FypZGsYkMKQ6lLp6x4x4Z09RtAzBfmec5hbnsR2zkCaI0a+zIe 21 | /Yc15r/wclgG+7qHyMwFgt0CgYAddsQ4peiaJ3EUYU2p6dgd5BGCe67T9XaTD62X 22 | 1qPdAPRx0U3cxwyV6uTy8CYYVq63pal5jEOXZcw4FxcEJX1WKwtKTUX9G+kLhedP 23 | 9EsrhdIAQBmI9zr3q5PE2UPrpiHROq742abhW5OuVRch4TBVDT34jx9+WDX7iKbp 24 | wF71owKBgAIlsZw06TLkVHSpOmJa4dv8w/ojZp5p4yVmNSb+6DcupJt4b8kBiN/r 25 | 2BY8bvBS9zUrAgNfB3h4CDNjTk7NLaSTdBD5raSjjPqKt0wzpOe7Hxq2wHKpGcVt 26 | E+0nFO89X3HqVvC/gPSAPEJgKDWinbAX+roTJ6mqbHio+WSZ++RT 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /MyBlogServe/keys/rsa_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/s8O3PlaGwc9EeABBC3 3 | coaAfKOle4H2d+64bXwA84IWGKPQXvsvx+viTlCovicvEMuP3di8JURMURJT0hJ3 4 | 7VYgHZNBhjOI5f8gyXa+JjtCtbaHtMogRestNhFhSLtQm9QY/pVotPgT9khkf4fJ 5 | MhRsZOGmeEsKK2ALXwdHGveY1RdBuzny+9xogAFW5CVSWyeAYq7YRrIqdx5LmqBs 6 | tmcv+VKBMzM4rySbtc9fAO+Oyr3ZDnLAStntB3nKaCDj657mHn8YBi1dUcxTe9aS 7 | uhAlV25mReQOquu5uakpz6WV3afkFd2blqe2qRUjH8cQaLkGONDLBisIuEJf+kGk 8 | vQIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /MyBlogServe/model/blogs.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const BlogSchema = new mongoose.Schema({ 3 | //创建博客模型 4 | date: { type: Date }, //创建日期 5 | title: { type: String, require: true }, 6 | classification: { type: mongoose.Types.ObjectId, require: true }, //所属专栏 7 | favour: [ 8 | { 9 | type: String, 10 | }, 11 | ], //点赞的浏览器指纹数组 12 | tags: [ 13 | { 14 | type: mongoose.Types.ObjectId, 15 | require: true, 16 | }, 17 | ], 18 | browse: { type: Number, default: 0 }, 19 | content: { type: String, require: true }, 20 | digest: { type: String }, // 描述信息 21 | state: { type: Boolean, default: false }, // 状态:是否发布 22 | }); 23 | const BlogModel = mongoose.model('blogs', BlogSchema); 24 | // 新增文章 25 | const addblog = data => { 26 | let article = new BlogModel(data); 27 | return article 28 | .save() 29 | .then(res => { 30 | return true; 31 | }) 32 | .catch(() => { 33 | return false; 34 | }); 35 | }; 36 | // 更新博客内容 37 | const updateBlog = (_id, content, digest, title, tags) => { 38 | console.log(tags); 39 | return BlogModel.updateOne({ _id }, { $set: { content, title, digest, tags } }); 40 | }; 41 | // 修改博客状态 42 | const changeBlogState = (state, id) => { 43 | // return BlogModel.updateOne(id, { $set: { state } }); 44 | return BlogModel.updateOne({ _id: id }, { $set: { state } }); 45 | }; 46 | // 删除博客 47 | const deleteBlog = _id => { 48 | return BlogModel.deleteOne({ _id }).lean(); 49 | }; 50 | // 查询某一博客 51 | const getBlog = id => { 52 | return BlogModel.findById(id).lean(); 53 | // return BlogModel.aggregate([ 54 | // { 55 | // $lookup: { 56 | // from: 'classifies', // 关联 articles 表 57 | // localField: 'classification', // 根据 comments 里 articleId 字段查询 58 | // foreignField: '_id', // 查找 articles 表里对应的 _id 的数据 59 | // pipeline: [{ $project: { title: 1 } }], 60 | // as: 'classify', // 返回的字段别名 61 | // }, 62 | // }, 63 | // { $match: { _id: id } }, 64 | // { $unwind: '$userinfo' }, //数据打散 65 | // ]); 66 | }; 67 | // 查询所有文章 68 | const getBlogs = () => { 69 | return BlogModel.find().sort({ date: -1 }).lean(); 70 | }; 71 | // 查询所有已发布的博客 72 | const getPublishBlogs = (pageStart = 0, pageSize = 5) => { 73 | return BlogModel.find({ state: true }, '_id date digest favour title browse classification').skip(pageStart).limit(pageSize).lean(); 74 | }; 75 | // 查询所有已发布的博客的数量 76 | const getblogSums = () => { 77 | return BlogModel.find({ state: true }).count(); 78 | }; 79 | // 查询某一专栏下的所有博客 80 | const getBlogsOfClassify = classification => { 81 | return BlogModel.find({ classification, state: true }, '_id date digest favour title browse').lean(); 82 | }; 83 | // 查询某一书签下的所有博客 84 | const getBlogsOfTag = searchTag => { 85 | return BlogModel.find({ tags: { $in: searchTag } }, '_id date digest favour title browse').lean(); 86 | }; 87 | // 增加点赞 88 | const addFavour = (id, favourMurmur) => { 89 | return BlogModel.findByIdAndUpdate(id, { $push: { favour: favourMurmur } }); 90 | }; 91 | // 获取点赞数 92 | const getFavour = _id => { 93 | return BlogModel.findById(_id, 'favour'); 94 | }; 95 | // 增加浏览量 96 | const addBlogBrowse = _id => { 97 | return BlogModel.updateOne({ _id }, { $inc: { browse: 1 } }); 98 | }; 99 | // 模糊查询所有文章 100 | const searchBlogs = searchValue => { 101 | let regexp = new RegExp(searchValue, 'i'); 102 | return BlogModel.find({ 103 | $or: [{ title: { $regex: regexp } }], 104 | state: true, 105 | }).lean(); 106 | }; 107 | module.exports = { 108 | addblog, 109 | updateBlog, 110 | changeBlogState, 111 | deleteBlog, 112 | getBlog, 113 | getBlogs, 114 | getPublishBlogs, 115 | getblogSums, 116 | getBlogsOfClassify, 117 | addFavour, 118 | addBlogBrowse, 119 | getFavour, 120 | searchBlogs, 121 | getBlogsOfTag, 122 | }; 123 | -------------------------------------------------------------------------------- /MyBlogServe/model/classifies.js: -------------------------------------------------------------------------------- 1 | // 专栏数据模型 2 | const mongoose = require('mongoose'); 3 | const ClassifySchema = new mongoose.Schema({ 4 | //创建表 5 | date: { type: Date }, 6 | title: { type: String }, 7 | digest: { type: String }, // 描述信息 8 | articleNum: { type: Number, default: 0 }, // 文章数量 9 | bgColor: { type: String }, 10 | }); 11 | const ClassifyModel = mongoose.model('classify', ClassifySchema); 12 | // 新增专栏 13 | const addClassify = data => { 14 | const Classify = new ClassifyModel(data); 15 | return Classify.save() 16 | .then(() => { 17 | return true; 18 | }) 19 | .catch(() => { 20 | return false; 21 | }); 22 | }; 23 | // 查询某一专栏信息 24 | const getClassify = id => { 25 | return ClassifyModel.findById(id); 26 | }; 27 | // 数据面板需要数据 28 | const getClassifyForDataBoard = () => { 29 | return ClassifyModel.find({},'title articleNum'); 30 | }; 31 | // 删除专栏 32 | const deleteClassify = _id => { 33 | return ClassifyModel.deleteOne({ _id }); 34 | }; 35 | // 更新某一专栏文章数量 36 | const updateClassifySum = (_id, num) => { 37 | return ClassifyModel.updateOne({ _id }, { $inc: { articleNum: num } }); 38 | }; 39 | // 更新某一专栏 40 | const updateClassifyTitle = (_id, title, digest) => { 41 | return ClassifyModel.updateOne({ _id }, { $set: { title, digest } }); 42 | }; 43 | // 查询所有专栏 44 | const getClassifies = () => { 45 | return ClassifyModel.find().lean(); 46 | }; 47 | // 查询所有专栏的数量 48 | const getClassifySums = () => { 49 | return ClassifyModel.count(); 50 | }; 51 | module.exports = { 52 | addClassify, 53 | deleteClassify, 54 | getClassifies, 55 | updateClassifySum, 56 | getClassify, 57 | updateClassifyTitle, 58 | getClassifySums, 59 | getClassifyForDataBoard 60 | }; 61 | -------------------------------------------------------------------------------- /MyBlogServe/model/comments.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const CommentSchema = new mongoose.Schema({ 3 | //创建博客模型 4 | date: { type: Date, require: true }, //创建日期 5 | keyId: { type: String, require: true }, // 评论的文章id 6 | articleTitle: { type: String, require: true }, 7 | favour: [ 8 | { 9 | type: String, 10 | }, 11 | ], 12 | content: { type: String, default: '' }, 13 | murmur: { type: String, require: true }, 14 | replyInfo: [ 15 | { 16 | date: { type: Date, require: true }, //创建日期 17 | // replymurmur: { type: String, require: true },// 回复的指纹 18 | // replyId: { type: mongoose.Types.ObjectId, require: true }, // 回复的id 19 | replyName: { type: String, require: true }, 20 | // username: { type: String, require: true }, 21 | favour: [ 22 | { 23 | type: String, 24 | }, 25 | ], 26 | reply: { type: String, default: '' }, 27 | murmur: { type: String, require: true }, // 当前此条回复的指纹 28 | }, 29 | ], 30 | }); 31 | 32 | const CommentModel = mongoose.model('comment', CommentSchema); 33 | // 新增一级评论 34 | const addFirstComment = data => { 35 | let comment = new CommentModel(data); 36 | return comment 37 | .save() 38 | .then(res => res) 39 | .catch(err => { 40 | return false; 41 | }); 42 | }; 43 | // 新增次级评论 44 | const addSecondComment = (_id, reply) => { 45 | return CommentModel.updateOne({ _id }, { $push: { replyInfo: reply } }); 46 | }; 47 | // 给一级评论点赞 48 | const addFirstFavour = (_id, favourMurmur) => { 49 | return CommentModel.updateOne({ _id }, { $push: { favour: favourMurmur } }); 50 | }; 51 | // // 给次级评论点赞 52 | const addSecondFavour = async (_id, replyId, favourMurmur) => { 53 | return CommentModel.updateOne({ _id, replyInfo: { $elemMatch: { _id: replyId } } }, { $push: { 'replyInfo.$.favour': favourMurmur } }); 54 | }; 55 | // 删除一级评论 56 | const deleteFirstComment = _id => { 57 | return CommentModel.deleteOne({ _id }); 58 | }; 59 | // 删除次级评论 60 | const deleteSecondComment = (_id, replyId) => { 61 | return CommentModel.updateOne({ _id }, { $pull: { replyInfo: { _id: replyId } } }); 62 | }; 63 | // 查询所有评论 64 | const getCommentsOfArticle = (_id, pageSize = 5, pageStart = 0) => { 65 | return CommentModel.find({ keyId: _id }).skip(pageStart).limit(pageSize).lean(); 66 | }; 67 | const getComments = (pageSize = 5, pageStart = 0) => { 68 | return CommentModel.find().lean(); 69 | // return CommentModel.aggregate([ 70 | // { 71 | // $lookup: { 72 | // from: "murmurs", // 关联 articles 表 73 | // localField: "murmur", // 根据 comments 里 articleId 字段查询 74 | // foreignField: "murmur", // 查找 articles 表里对应的 _id 的数据 75 | // pipeline: [ {$project: {username: 1} } ], 76 | // as: "userinfo",// 返回的字段别名 77 | // }, 78 | // }, 79 | // { $unwind: "$userinfo" },//数据打散 80 | // ]); 81 | // .skip(pageStart).limit(pageSize).lean(); 82 | }; 83 | // 查询某一个评论 84 | const getCommentReplyLast = id => { 85 | return CommentModel.findById(id); 86 | }; 87 | 88 | module.exports = { 89 | addFirstComment, 90 | addSecondComment, 91 | addFirstFavour, 92 | deleteFirstComment, 93 | deleteSecondComment, 94 | getComments, 95 | addSecondFavour, 96 | getCommentReplyLast, 97 | getCommentsOfArticle, 98 | }; 99 | -------------------------------------------------------------------------------- /MyBlogServe/model/jottings.js: -------------------------------------------------------------------------------- 1 | // 随笔数据模型 2 | const mongoose = require('mongoose'); 3 | const JottingSchema = new mongoose.Schema({ 4 | //创建表 5 | date: { type: Date }, 6 | title: { type: String, require: true }, 7 | favour: [ 8 | { 9 | type: String, 10 | default: 0, 11 | }, 12 | ], 13 | tags: [ 14 | { 15 | type: mongoose.Types.ObjectId, 16 | require: true, 17 | }, 18 | ], 19 | browse: { type: Number, default: 0 }, 20 | content: { type: String, require: true }, 21 | digest: { type: String }, // 描述信息 22 | state: { type: Boolean, default: false }, // 状态:是否发布 23 | }); 24 | const JottingModel = mongoose.model('jotting', JottingSchema); 25 | // 新增随笔 26 | const addJotting = data => { 27 | let jotting = new JottingModel(data); 28 | return jotting 29 | .save() 30 | .then(() => { 31 | return true; 32 | }) 33 | .catch(() => { 34 | return false; 35 | }); 36 | }; 37 | // 更新随笔 38 | const updateJotting = (_id, { content, digest, title, tags }) => { 39 | return JottingModel.updateOne({ _id }, { $set: { content, digest, title, tags } }); 40 | }; 41 | // 修改随笔状态 42 | const changeJottingState = (state, _id) => { 43 | return JottingModel.updateOne({ _id }, { $set: { state } }); 44 | }; 45 | // 删除随笔 46 | const deleteJotting = _id => { 47 | return JottingModel.deleteOne({ _id }); 48 | }; 49 | // 查询某一随笔 50 | const getJotting = id => { 51 | return JottingModel.findById(id).lean(); 52 | }; 53 | // 查询所有随笔 54 | const getJottings = () => { 55 | return JottingModel.find().sort({date:-1}).lean(); 56 | }; 57 | // 查询所有已发布随笔 58 | const getPublishJottings = (pageStart = 0, pageSize = 5) => { 59 | return JottingModel.find({ state: true }, '_id date digest favour title browse').skip(pageStart).limit(pageSize).lean(); 60 | }; 61 | // 查询某一书签下的所有博客 62 | const getJottingsOfTag = searchTag => { 63 | return JottingModel.find({ tags: { $in: searchTag } }, '_id date digest favour title browse').lean(); 64 | }; 65 | // 查询所有已发布的随笔数量 66 | const getJottingSums = () => { 67 | return JottingModel.find({ state: true }).count(); 68 | }; 69 | // 增加点赞 70 | const addFavour = (_id, favourMurmur) => { 71 | return JottingModel.updateOne({ _id }, { $push: { favour: favourMurmur } }); 72 | }; 73 | // 获取点赞数 74 | const getFavour = id => { 75 | return JottingModel.findById(id, 'favour'); 76 | }; 77 | // 增加浏览量 78 | const addJottingBrowse = _id => { 79 | return JottingModel.updateOne({ _id }, { $inc: { browse: 1 } }); 80 | }; 81 | // 模糊查询所有随笔 82 | const searchJottings = searchValue => { 83 | let regexp = new RegExp(searchValue, 'i'); 84 | return JottingModel.find({ 85 | $or: [{ title: { $regex: regexp } }], 86 | state: true, 87 | }).lean(); 88 | }; 89 | module.exports = { 90 | addJotting, 91 | updateJotting, 92 | changeJottingState, 93 | deleteJotting, 94 | getJotting, 95 | getJottings, 96 | getPublishJottings, 97 | getJottingSums, 98 | addJottingBrowse, 99 | addFavour, 100 | getFavour, 101 | searchJottings, 102 | getJottingsOfTag, 103 | }; 104 | -------------------------------------------------------------------------------- /MyBlogServe/model/murmurs.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const MurmurSchema = new mongoose.Schema({ 3 | date: { type: Date, require: true }, 4 | username: { type: String, require: true }, 5 | murmur: { type: String, require: true, unique: true }, 6 | avatarUrl: { type: String }, 7 | }); 8 | const MurmurModel = mongoose.model('murmur', MurmurSchema); 9 | 10 | /** 11 | *新增浏览器指纹信息 12 | * @param {object} data 浏览器指纹的相关信息 13 | * @return 成功返回新增的指纹信息,否则返回false 14 | */ 15 | const addMurmur = data => { 16 | const murmur = new MurmurModel(data); 17 | return murmur 18 | .save() 19 | .then(res => res) 20 | .catch(() => false); 21 | }; 22 | 23 | /** 24 | *修改浏览器指纹对应用户名 25 | * @param {string} murmur 浏览器指纹 26 | * @param {string} username 浏览器指纹对应用户名 27 | */ 28 | const updateMurmurUsername = (murmur, username) => { 29 | return MurmurModel.updateOne({ murmur }, { $set: { username } }); 30 | }; 31 | 32 | /** 33 | *更新用户头像 34 | * @param {string} murmur 浏览器指纹 35 | * @param {string} avatarUrl 浏览器指纹对应头像地址 36 | */ 37 | const updateMurmurAvatar = (murmur, avatarUrl) => { 38 | return MurmurModel.updateOne({ murmur }, { $set: { avatarUrl } }); 39 | }; 40 | 41 | // // 删除用户 42 | const deleteMurmurInfo = id => { 43 | return MurmurModel.deleteOne({ _id: id }); 44 | }; 45 | // 查找某一个用户,如果用户信息不存在返回null 46 | 47 | /** 48 | * @param {string} murmur 浏览器指纹 49 | * @return {object} 查找到的指纹信息 50 | */ 51 | const getMurmurInfo = murmur => { 52 | return MurmurModel.findOne({ murmur }); 53 | }; 54 | 55 | /** 56 | *获取所有指纹信息 57 | @return {Array} 查找到的指纹信息对象数组 58 | */ 59 | const getMurmurInfos = () => { 60 | return MurmurModel.find().lean(); 61 | }; 62 | module.exports = { 63 | addMurmur, 64 | getMurmurInfo, 65 | updateMurmurUsername, 66 | updateMurmurAvatar, 67 | getMurmurInfos, 68 | deleteMurmurInfo, 69 | }; 70 | -------------------------------------------------------------------------------- /MyBlogServe/model/photo.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const PhotoSchema = new mongoose.Schema({ 3 | uploadTime: { type: Date, require: true }, 4 | shootingTime: { type: String, required: true }, 5 | digest: { type: String, required: true }, 6 | photoUrl: { type: String, required: true, unique: true }, 7 | thumbnailUrl: { type: String }, 8 | preBg: { type: String }, 9 | }); 10 | const PhotoModel = mongoose.model('Photo', PhotoSchema); 11 | 12 | /** 13 | *新增照片 14 | * @param {object} data 照片的相关信息 15 | * @return 成功返回新增的照片信息,否则返回false 16 | */ 17 | const addPhoto = data => { 18 | console.log(data); 19 | const Photo = new PhotoModel(data); 20 | return Photo.save() 21 | .then(res => res) 22 | .catch(err => false); 23 | }; 24 | 25 | /** 26 | *删除照片 27 | * @param {string} _id 28 | */ 29 | const deletePhoto = _id => { 30 | return PhotoModel.deleteOne({ _id }); 31 | }; 32 | 33 | /** 34 | * 查找某一个照片 35 | * @param {string} id 照片的_id 36 | * @return {object} 查找到的照片 37 | */ 38 | const getPhoto = id => { 39 | return PhotoModel.findById(id); 40 | }; 41 | /** 42 | * 更新某一个照片 43 | * @param {string} id 照片的_id 44 | * @param {string} digest 新的描述信息 45 | * @return {object} 更新操作结果 46 | */ 47 | const updatePhoto = (_id, digest, shootingTime) => { 48 | return PhotoModel.updateOne({ _id }, { $set: { digest, shootingTime } }); 49 | }; 50 | /** 51 | *获取所有照片 52 | @return {Array} 查找到的照片对象数组 53 | */ 54 | const getPhotos = () => { 55 | return PhotoModel.find().lean(); 56 | }; 57 | 58 | /** 59 | *获取所有照片的数量 60 | * @return {number} 照片数量 61 | */ 62 | const getPhotoSums = () => { 63 | return PhotoModel.count(); 64 | }; 65 | 66 | module.exports = { 67 | getPhotos, 68 | getPhoto, 69 | deletePhoto, 70 | addPhoto, 71 | getPhotoSums, 72 | updatePhoto, 73 | }; 74 | -------------------------------------------------------------------------------- /MyBlogServe/model/routes.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const RouteSchema = new mongoose.Schema({ 3 | //创建表 4 | path: { type: String, require: true, unique: true }, 5 | name: { type: String }, 6 | meta: { type: Object, default: {} }, 7 | // children: [ 8 | // { 9 | // path: { type: String,unique: true }, 10 | // name: { type: String }, 11 | // meta: { type: Object, default: {} }, 12 | // limits: [ 13 | // { 14 | // type: String, 15 | // }, 16 | // ], 17 | // component: { type: String }, //index: { unique: true } 18 | // }, 19 | // ], 20 | limits: [ 21 | { 22 | type: String, 23 | require: true, 24 | }, 25 | ], 26 | component: { type: String }, //index: { unique: true } 27 | }); 28 | 29 | const RouteModel = mongoose.model('route', RouteSchema); 30 | // 新增一级路由 31 | const addFirstRoute = route => { 32 | const user = new RouteModel(route); 33 | return user 34 | .save() 35 | .then(() => true) 36 | .catch(() => false); 37 | }; 38 | // 新增二级路由 39 | const addSecondRoute = (parentRouteName, route) => { 40 | return RouteModel.updateOne({ name: parentRouteName }, { $push: { children: route } }); 41 | }; 42 | // 更新一级路由信息 43 | const updateFirstRouteInfo = ({ _id, name, path, component, limits }) => { 44 | return RouteModel.updateOne({ _id }, { $set: { name, path, component, limits } }); 45 | }; 46 | // 更新二级路由信息 47 | const updateSecondRouteInfo = ({ _id, path, name, component, limits }) => { 48 | return RouteModel.updateOne({ _id, children: { $elemMatch: { path } } }, { $set: { name, component, limits } }); 49 | }; 50 | // 删除一级路由 51 | const deleteFirstRoute = _id => { 52 | return RouteModel.deleteOne({ _id }); 53 | }; 54 | // 删除二级路由 55 | const deleteSecondRoute = (id, path) => { 56 | return RouteModel.findByIdAndUpdate(id, { $pull: { children: { path } } }); 57 | }; 58 | // 查找所有路由 59 | const getRoutes = () => { 60 | return RouteModel.find(); 61 | }; 62 | // 根据path查找路由 63 | const getRouteByPath = path => { 64 | return RouteModel.findOne({ path }); 65 | }; 66 | 67 | module.exports = { 68 | addFirstRoute, 69 | addSecondRoute, 70 | updateFirstRouteInfo, 71 | updateSecondRouteInfo, 72 | deleteFirstRoute, 73 | deleteSecondRoute, 74 | getRoutes, 75 | getRouteByPath, 76 | }; 77 | -------------------------------------------------------------------------------- /MyBlogServe/model/tag.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const TagSchema = new mongoose.Schema({ 3 | date: { type: Date, require: true }, 4 | title: { type: String, require: true, unique: true }, 5 | digest: { type: String, require: true }, 6 | bg: { type: String }, 7 | }); 8 | const TagModel = mongoose.model('tag', TagSchema); 9 | 10 | /** 11 | *新增标签 12 | * @param {object} data 标签的相关信息 13 | * @return 成功返回新增的标签信息,否则返回false 14 | */ 15 | const addTag = data => { 16 | const tag = new TagModel(data); 17 | return tag 18 | .save() 19 | .then(res => res) 20 | .catch(() => false); 21 | }; 22 | 23 | /** 24 | *删除标签 25 | * @param {string} murmur 浏览器指纹 26 | */ 27 | const deleteTag = _id => { 28 | return TagModel.deleteOne({ _id }); 29 | }; 30 | 31 | /** 32 | * 查找某一个标签 33 | * @param {string} id 标签的_id 34 | * @return {object} 查找到的标签 35 | */ 36 | const getTag = id => { 37 | return TagModel.findById(id); 38 | }; 39 | /** 40 | * 查找某一个标签 41 | * @param {string} id 标签的_id 42 | * @return {object} 更新操作结果 43 | */ 44 | const uptateTag = (_id, title, digest) => { 45 | console.log(_id, title, digest); 46 | return TagModel.updateOne({ _id }, { $set: { title, digest } }); 47 | }; 48 | /** 49 | *获取所有标签 50 | @return {Array} 查找到的标签对象数组 51 | */ 52 | const getTags = () => { 53 | return TagModel.find().lean(); 54 | }; 55 | /** 56 | *获取所有标签的数量 57 | @return {number} 查找到的标签数量 58 | */ 59 | const getTagSums = () => { 60 | return TagModel.count(); 61 | }; 62 | 63 | module.exports = { 64 | getTags, 65 | getTag, 66 | deleteTag, 67 | addTag, 68 | getTagSums, 69 | uptateTag, 70 | }; 71 | -------------------------------------------------------------------------------- /MyBlogServe/model/timeclue.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const TimeclueSchema = new mongoose.Schema({ 3 | date: { type: String }, 4 | title: { type: String, require: true }, 5 | state: { type: Boolean, require: true }, 6 | digest: { type: String }, 7 | }); 8 | const TimeclueModel = mongoose.model('timeclue', TimeclueSchema); 9 | /** 10 | *新增时间线信息 11 | * @param {object} data 时间线信息的相关信息 12 | * @return 成功返回新增的时间线信息信息,否则返回false 13 | */ 14 | const addTimeclue = data => { 15 | const Timeclue = new TimeclueModel(data); 16 | return Timeclue.save() 17 | .then(res => res) 18 | .catch(() => false); 19 | }; 20 | 21 | /** 22 | *删除时间线信息 23 | * @param {string} murmur 浏览器指纹 24 | */ 25 | const deleteTimeclue = _id => { 26 | return TimeclueModel.deleteOne({ _id }); 27 | }; 28 | 29 | /** 30 | * 查找某一个时间线信息 31 | * @param {string} id 时间线信息的_id 32 | * @return {object} 查找到的时间线信息 33 | */ 34 | const getTimeclue = id => { 35 | return TimeclueModel.findById(id); 36 | }; 37 | /** 38 | * 查找某一个时间线信息 39 | * @param {string} id 时间线信息的_id 40 | * @return {object} 更新操作结果 41 | */ 42 | const uptateTimeclue = (id, date, title, digest) => { 43 | return TimeclueModel.updateOne({ _id: id }, { $set: { date, title, digest } }); 44 | }; 45 | const changeTimeNodeState = (id, state) => { 46 | return TimeclueModel.updateOne({ _id: id }, { $set: { state } }); 47 | }; 48 | /** 49 | *获取所有时间线信息 50 | @return {Array} 查找到的时间线信息对象数组 51 | */ 52 | const getTimeclues = () => { 53 | return TimeclueModel.find().sort({ date: -1 }).lean(); 54 | }; 55 | /** 56 | *获取所有时间线信息的数量 57 | @return {number} 查找到的时间线信息数量 58 | */ 59 | // const getTimeclueSums = () => { 60 | // return TimeclueModel.count(); 61 | // }; 62 | 63 | module.exports = { 64 | getTimeclues, 65 | getTimeclue, 66 | deleteTimeclue, 67 | addTimeclue, 68 | // getTimeclueSums, 69 | uptateTimeclue, 70 | changeTimeNodeState, 71 | }; 72 | -------------------------------------------------------------------------------- /MyBlogServe/model/users.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const UserSchema = new mongoose.Schema({ 4 | //创建表 5 | username: { type: String, require: true }, 6 | password: { type: String, require: true }, 7 | email: { type: String, require: true, unique: true }, //index: { unique: true } 8 | date: { type: Date }, 9 | avatarUrl: { type: String }, 10 | role: { type: String, require: true, default: '普通用户' }, 11 | }); 12 | const UserModel = mongoose.model('user', UserSchema); 13 | // 新增用户 14 | const addUser = data => { 15 | const user = new UserModel(data); 16 | return user 17 | .save() 18 | .then(() => true) 19 | .catch(() => false); 20 | }; 21 | const uploadAvatar = (email, avatarUrl) => { 22 | return UserModel.updateOne({ email }, { $set: { avatarUrl } }); 23 | }; 24 | // 更新用户信息 25 | const updateUserInfo = (email, role, username) => { 26 | return UserModel.updateOne({ email }, { $set: { username, role } }); 27 | }; 28 | // 更新用户信息 29 | const updatePassword = (email, password) => { 30 | return UserModel.updateOne({ email }, { $set: { password } }); 31 | }; 32 | // 删除用户 33 | const deleteUser = email => { 34 | return UserModel.deleteOne({ email }); 35 | }; 36 | // 查找某一个用户,如果用户信息不存在返回null 37 | const getUser = email => { 38 | return UserModel.findOne({ email }); 39 | }; 40 | // 查询所有用户 41 | const getUsers = () => { 42 | return UserModel.find().lean(); 43 | }; 44 | module.exports = { 45 | addUser, 46 | updateUserInfo, 47 | getUsers, 48 | deleteUser, 49 | getUser, 50 | updatePassword, 51 | uploadAvatar, 52 | }; 53 | -------------------------------------------------------------------------------- /MyBlogServe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myblogserve", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "nodemon ./bin/www" 7 | }, 8 | "dependencies": { 9 | "bcrypt": "^5.0.1", 10 | "connect-multiparty": "^2.2.0", 11 | "cookie-parser": "~1.4.4", 12 | "debug": "~2.6.9", 13 | "express": "~4.16.1", 14 | "express-session": "^1.17.2", 15 | "http-errors": "~1.6.3", 16 | "jade": "~1.11.0", 17 | "jsonwebtoken": "^8.5.1", 18 | "mongoose": "^6.2.8", 19 | "morgan": "~1.9.1", 20 | "multer": "^1.4.5-lts.1", 21 | "nodemon": "^2.0.15" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /MyBlogServe/public/avatars/1661779453078: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/avatars/1661779453078 -------------------------------------------------------------------------------- /MyBlogServe/public/avatars/1662256970035: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/avatars/1662256970035 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662046452834: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662046452834 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662046521921: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662046521921 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662046564119: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662046564119 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662046595682: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662046595682 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662047030636: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662047030636 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662047054759: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662047054759 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662047189170: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662047189170 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049020699: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049020699 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049188808: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049188808 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049270170: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049270170 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049353519: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049353519 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049446197: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049446197 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049505602: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049505602 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049548427: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049548427 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049654510: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049654510 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049758833: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049758833 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049791176: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049791176 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662049883085: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662049883085 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662050480857: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662050480857 -------------------------------------------------------------------------------- /MyBlogServe/public/photos/1662050583435: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/MyBlogServe/public/photos/1662050583435 -------------------------------------------------------------------------------- /MyBlogServe/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /MyBlogServe/routes/blogs.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var articleController = require('../controllers/blogs'); 4 | /* GET users listing. */ 5 | router.get('/getblogs', articleController.getBlogs); 6 | router.delete('/deleteblog', articleController.deleteBlog); 7 | router.post('/updateblog', articleController.updateBlog); 8 | router.post('/addblog', articleController.addBlog); 9 | router.get('/changeblogstate', articleController.changeBlogState); 10 | router.get('/getblog', articleController.getBlog); 11 | router.get('/getpublishblogs', articleController.getPublishBlogs); 12 | router.get('/getblogsofclassify', articleController.getBlogsOfClassify); 13 | router.get('/addfavour', articleController.addFavour); 14 | router.get('/addblogbrowse', articleController.addBlogBrowse); 15 | module.exports = router; 16 | -------------------------------------------------------------------------------- /MyBlogServe/routes/classifies.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var classifyController = require('../controllers/classifies'); 4 | /* GET users listing. */ 5 | router.get('/getclassifies', classifyController.getClassifies); 6 | router.delete('/deleteclassify', classifyController.deleteClassify); 7 | router.post('/addclassify', classifyController.addClassify); 8 | router.post('/updateclassifytitle', classifyController.updateClassifyTitle) 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /MyBlogServe/routes/comments.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var commentController = require('../controllers/comments'); 4 | /* GET users listing. */ 5 | router.post('/addfirstcomment', commentController.addFirstComment); 6 | router.post('/addsecondcomment', commentController.addSecondComment); 7 | router.delete('/deletefirstcomment', commentController.deleteFirstComment); 8 | router.delete('/deletesecondcomment', commentController.deleteSecondComment); 9 | router.get('/addfirstfavour', commentController.addFirstFavour); 10 | router.get('/addsecondfavour', commentController.addSecondFavour); 11 | router.get('/getcomments', commentController.getComments); 12 | router.get('/getcommentsofarticle', commentController.getCommentsOfArticle); 13 | module.exports = router; 14 | -------------------------------------------------------------------------------- /MyBlogServe/routes/jottings.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var jottingController = require('../controllers/jottings'); 4 | /* GET users listing. */ 5 | router.get('/getjottings', jottingController.getJottings); 6 | router.delete('/deletejotting', jottingController.deleteJotting); 7 | router.post('/updatejotting', jottingController.updateJotting); 8 | router.post('/addjotting', jottingController.addJotting); 9 | router.get('/changestate', jottingController.changeState); 10 | router.get('/getpublishjottings', jottingController.getPublishJottings); 11 | router.get('/getjotting', jottingController.getJotting); 12 | router.get('/addfavour', jottingController.addFavour); 13 | router.get('/addjottingbrowse', jottingController.addJottingBrowse); 14 | module.exports = router; 15 | -------------------------------------------------------------------------------- /MyBlogServe/routes/murmur.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var murmurController = require('../controllers/murmur'); 4 | 5 | /* GET users listing. */ 6 | router.post('/addmurmurinfo', murmurController.addMurmurInfo); 7 | router.post('/updatemurmurusername', murmurController.updateMurmurUsername); 8 | router.get('/getmurmurinfos', murmurController.getMurmurInfos); 9 | router.delete('/deletemurmurinfo', murmurController.deleteMurmurInfo); 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /MyBlogServe/routes/photo.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var PhotoController = require('../controllers/photo'); 4 | const multer = require('multer'); 5 | const path = require('path'); 6 | // 照片墙上传图片上传 7 | var storagePhoto = multer.diskStorage({ 8 | // 配置文件上传后存储的路径 9 | destination: function (req, file, cb) { 10 | cb(null, path.join(__dirname, '../public/photos')); 11 | }, 12 | // 配置文件上传后存储的路径和文件名 13 | filename: function (req, file, cb) { 14 | cb(null, Date.now() + path.extname(file.originalname)); 15 | }, 16 | }); 17 | const uploadPhoto = multer({ storage: storagePhoto }); 18 | /* GET users listing. */ 19 | router.get('/getphotos', PhotoController.getPhotos); 20 | router.delete('/deletephoto', PhotoController.deletePhoto); 21 | router.post('/addphoto',uploadPhoto.single('photo'), PhotoController.addPhoto); 22 | router.post('/updatephotodigest', PhotoController.updatePhotoDigest) 23 | module.exports = router; 24 | -------------------------------------------------------------------------------- /MyBlogServe/routes/routes.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var routeController = require('../controllers/routes'); 4 | /* GET users listing. */ 5 | router.post('/addfirstroute', routeController.addFirstRoute); 6 | router.post('/addsecondroute', routeController.addSecondRoute); 7 | router.post('/updatroute', routeController.updatRoute); 8 | router.get('/getroutes', routeController.getRoutes); 9 | router.get('/getroutelist', routeController.getRouteList); 10 | router.delete('/deleteroute', routeController.deleteRoute); 11 | module.exports = router; 12 | -------------------------------------------------------------------------------- /MyBlogServe/routes/synthesis.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var synthesisControll = require('../controllers/synthesis'); 4 | const multer = require('multer'); 5 | const path = require('path'); 6 | // markdown编辑文章上传图片 7 | var storageArtimg = multer.diskStorage({ 8 | // 配置文件上传后存储的路径 9 | destination: function (req, file, cb) { 10 | cb(null, path.join(__dirname, '../public/images')); 11 | }, 12 | // 配置文件上传后存储的路径和文件名 13 | filename: function (req, file, cb) { 14 | cb(null, Date.now() + path.extname(file.originalname)); 15 | }, 16 | }); 17 | // 上传头像 18 | var storageAvatar = multer.diskStorage({ 19 | // 配置文件上传后存储的路径 20 | destination: function (req, file, cb) { 21 | cb(null, path.join(__dirname, '../public/avatars')); 22 | }, 23 | // 配置文件上传后存储的路径和文件名 24 | filename: function (req, file, cb) { 25 | cb(null, Date.now() + path.extname(file.originalname)); 26 | }, 27 | }); 28 | 29 | const uploadArtimg = multer({ storage: storageArtimg }); 30 | const uploadAvatar = multer({ storage: storageAvatar }); 31 | 32 | router.get('/getwebinfo', synthesisControll.getWebInfo); 33 | router.get('/getsliderinfo', synthesisControll.getSliderInfo); 34 | router.get('/searcharticle', synthesisControll.searchArticle); 35 | router.post('/uploadartimg', uploadArtimg.single('artimg'), synthesisControll.uploadArtimg); 36 | router.post('/uploadavatar', uploadAvatar.single('avatar'), synthesisControll.uploadAvatar); 37 | router.get('/gettags', synthesisControll.getTags); 38 | router.get('/gettag', synthesisControll.getTag); 39 | router.delete('/deletetag', synthesisControll.deleteTag); 40 | router.post('/addtag', synthesisControll.addTag); 41 | router.post('/updatetag', synthesisControll.updateTag); 42 | router.get('/getarticlesoftag', synthesisControll.getArticlesOfTag); 43 | router.get('/getdatafordataboard', synthesisControll.getDataForDataBoard); 44 | module.exports = router; 45 | -------------------------------------------------------------------------------- /MyBlogServe/routes/timeclue.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | const TimeclueControll = require('../controllers/timeclue'); 4 | router.get('/changetimenodestate', TimeclueControll.changeTimeNodeState); 5 | router.get('/gettimeclue', TimeclueControll.getTimeclue); 6 | router.get('/gettimeclues', TimeclueControll.getTimeclues); 7 | router.delete('/deletetimeclue', TimeclueControll.deleteTimeclue); 8 | router.post('/addtimeclue', TimeclueControll.addTimeclue); 9 | router.post('/updatetimeclue', TimeclueControll.updateTimeclue); 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /MyBlogServe/routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var usersController = require('../controllers/users'); 4 | /* GET users listing. */ 5 | router.post('/login', usersController.login); 6 | router.get('/logout', usersController.logout); 7 | router.get('/getuserstate', usersController.getUserState); 8 | router.post('/updateuserinfo', usersController.updateUserInfo); 9 | router.get('/getusers', usersController.getUsers); 10 | router.post('/register', usersController.register); 11 | router.delete('/deleteuser', usersController.deleteUser); 12 | router.post('/updatepassword', usersController.updatePassword); 13 | module.exports = router; 14 | -------------------------------------------------------------------------------- /MyBlogServe/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /MyBlogServe/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /MyBlogServe/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 我的博客(MyBlog) 2 | 3 | ## 技术栈:vue2 + vuex + vue-router + axios + nodejs + express + mongodb + element-ui + echarts 4 | 5 | ## 项目介绍 6 | 7 | 本项目分为三个部分:后端接口、后台管理系统、前台系统,它们分别实现了 8 | 9 | 前台系统:博客展示、心情展示、瀑布流照片墙、留言板、时间线、关于、搜索、评论、专栏博客展示、书签文章展示、暗黑模式、头像上传 10 | 11 | 后台管理系统:权限管理、动态路由、登录、注册、文章管理、心情管理、专栏管理、书签管理、评论管理、照片管理、markdown 编辑文章、时间节点管理、路由管理、用户管理、数据看板 12 | 13 | 后端:MVC 模式使用 express 框架和 mongodb 数据库 14 | 15 | ## 性能优化: 16 | 17 | 1. 图片资源本地压缩,控制在 100kb 左右。 18 | 2. vue、element-ui、axios 采用 CDN 方式引入项目。 19 | 3. 开启 gzip 压缩,效果很明显,特别是项目上线后访问速度提高很多。 20 | 4. 优化了一些逻辑,减少了 http 请求。 21 | 5. 打包时不生成 map 文件(效果很明显)、将公共代码抽离、图片资源压缩(效果不是很明显)。 22 | 6. 在用户上传头像是使用 canvas 压缩后再上传,压缩效果很好。 23 | 24 | ## 使用体验优化 25 | 26 | 1. 前台系统首次加载白屏动画,切换路由使用过渡动画。 27 | 2. 多个页面使用 css 动画效果和平滑阴影给你更真实的体验。 28 | 3. 瀑布流照片墙,定宽不定高,给你极致体验。 29 | 4. 前台系统全局暗黑模式,更丰富的使用效果。 30 | 31 | ## 安装运行 32 | 33 | ### 导入数据库数据 34 | 35 | 我是使用 compass 可视化工具导出的,使用其他可视化工具导入可能略有不同,请自行百度导入。 36 | 37 | - 路由数据:`./MongodbData/routes.json`,若未导入则后台管理系统因没有路由数据将无法正常访问。 38 | - 时间线数据:`./MongodbData/timeclues.json`,此部分数据记录了项目的开发历程,可选 39 | - 用户数据:`./MongodbData/users.json`,用户数据,包含一个管理员与一个普通用户信息 40 | - 管理员账号:123@qq.com;密码:12345678 41 | - 普通用户:234@qq.com;密码:12345678 42 | 43 | ### 前台系统 44 | 45 | ```js 46 | // 安装依赖 47 | yarn 48 | // 运行 49 | yarn serve 50 | ``` 51 | 52 | ### 后台管理系统 53 | 54 | ```js 55 | // 安装依赖 56 | yarn 57 | // 运行 58 | yarn serve 59 | ``` 60 | 61 | ### 后端 62 | 63 | 连接 mongodb 数据库配置文件`db`,使用默认端口`27017`,数据库名称`MyBlog` 64 | 65 | ```js 66 | // 安装依赖 67 | yarn 68 | // 运行 69 | yarn start 70 | ``` 71 | 72 | ## 效果展示 73 | 74 | ### 博客 75 | ![博客](./ReadmeImg/1.png) 76 | ### 心情 77 | ![心情](./ReadmeImg/2.png) 78 | ### 瀑布流照片墙 79 | ![瀑布流照片墙](./ReadmeImg/3.png) 80 | ### 留言板 81 | ![留言板](./ReadmeImg/4.png) 82 | ### 时间线 83 | ![时间线](./ReadmeImg/5.png) 84 | ### 关于 85 | ![关于](./ReadmeImg/6.png) 86 | ### 文章管理 87 | ![文章管理](./ReadmeImg/7.png) 88 | ### 照片管理 89 | ![照片管理](./ReadmeImg/8.png) 90 | ### markdown编辑文章 91 | ![markdown编辑文章](./ReadmeImg/9.png) 92 | ### 路由管理 93 | ![路由管理](./ReadmeImg/10.png) 94 | ### 时间节点管理 95 | ![时间节点管理](./ReadmeImg/11.png) 96 | ### 用户管理 97 | ![用户管理](./ReadmeImg/12.png) 98 | ### 数据看板 99 | ![数据看板](./ReadmeImg/13.png) 100 | ### 暗黑模式 101 | ![暗黑模式](./ReadmeImg/14.png) 102 | ### 登录注册 103 | ![登录注册](./ReadmeImg/15.png) 104 | 105 | # 结语 106 | 本项目还有很多可以继续完善的地方,你可以拉取本项目继续开发,不要忘了给个star哦! -------------------------------------------------------------------------------- /ReadmeImg/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/1.png -------------------------------------------------------------------------------- /ReadmeImg/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/10.png -------------------------------------------------------------------------------- /ReadmeImg/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/11.png -------------------------------------------------------------------------------- /ReadmeImg/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/12.png -------------------------------------------------------------------------------- /ReadmeImg/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/13.png -------------------------------------------------------------------------------- /ReadmeImg/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/14.png -------------------------------------------------------------------------------- /ReadmeImg/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/15.png -------------------------------------------------------------------------------- /ReadmeImg/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/2.png -------------------------------------------------------------------------------- /ReadmeImg/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/3.png -------------------------------------------------------------------------------- /ReadmeImg/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/4.png -------------------------------------------------------------------------------- /ReadmeImg/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/5.png -------------------------------------------------------------------------------- /ReadmeImg/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/6.png -------------------------------------------------------------------------------- /ReadmeImg/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/7.png -------------------------------------------------------------------------------- /ReadmeImg/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/8.png -------------------------------------------------------------------------------- /ReadmeImg/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wind-Breaker1/MyBlog/b4c409fcb046709201b70a29ebdcd5f9a792b89e/ReadmeImg/9.png -------------------------------------------------------------------------------- /default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | 5 | #access_log /var/log/nginx/host.access.log main; 6 | 7 | location / { 8 | root /usr/share/nginx/html; 9 | index index.html index.htm; 10 | } 11 | # 反向代理 12 | location /api { 13 | proxy_pass http://127.0.0.1; 14 | } 15 | #error_page 404 /404.html; 16 | 17 | # redirect server error pages to the static page /50x.html 18 | # 19 | error_page 500 502 503 504 /50x.html; 20 | location = /50x.html { 21 | root /usr/share/nginx/html; 22 | } 23 | 24 | # proxy the PHP scripts to Apache listening on 127.0.0.1:80 25 | # 26 | # location ~ \.php$ { 27 | # proxy_pass http://127.0.0.1; 28 | # } 29 | 30 | # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 31 | # 32 | #location ~ \.php$ { 33 | # root html; 34 | # fastcgi_pass 127.0.0.1:9000; 35 | # fastcgi_index index.php; 36 | # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 37 | # include fastcgi_params; 38 | #} 39 | 40 | # deny access to .htaccess files, if Apache's document root 41 | # concurs with nginx's one 42 | # 43 | #location ~ /\.ht { 44 | # deny all; 45 | #} 46 | } 47 | 48 | --------------------------------------------------------------------------------