├── .env ├── .env.development ├── .env.production ├── .env.sit ├── .gitignore ├── .travis.yml ├── README.md ├── babel.config.js ├── gh-pages.sh ├── package.json ├── public ├── favicon.ico ├── index.html └── manage.html ├── src ├── 404.vue ├── api │ └── baseUrlConfig.js ├── assets │ ├── 404.png │ ├── avatar │ │ └── admin.jpg │ ├── banner1.jpg │ ├── banner2.jpg │ ├── banner3.jpg │ ├── banner4.jpg │ ├── banner5.jpg │ ├── error.jpg │ ├── errorImg.jpg │ ├── laravel.png │ ├── loginlogo.png │ ├── logo.png │ ├── message.jpg │ ├── nav-map.jpg │ └── vue.jpg ├── components │ ├── MyLoading.js │ ├── MyPage.js │ ├── NewPage.js │ ├── SpinLoading.js │ ├── TextLoading.js │ ├── myLoading.vue │ ├── newPage.vue │ ├── page.vue │ ├── spinLoading.vue │ └── textLoading.vue ├── directive │ └── index.js ├── modules │ ├── index │ │ ├── App.vue │ │ ├── api │ │ │ ├── article.js │ │ │ ├── baseUrlConfig.js │ │ │ ├── comment.js │ │ │ ├── common.js │ │ │ ├── index.js │ │ │ ├── message.js │ │ │ └── user.js │ │ ├── components │ │ │ ├── commonPage.vue │ │ │ ├── footer.vue │ │ │ ├── headnav.vue │ │ │ └── skills.vue │ │ ├── main.js │ │ ├── page │ │ │ ├── about.vue │ │ │ ├── blog.vue │ │ │ ├── detail.vue │ │ │ ├── donate.vue │ │ │ ├── link.vue │ │ │ └── message.vue │ │ ├── router │ │ │ ├── index.js │ │ │ └── router.js │ │ └── user │ │ │ ├── login.vue │ │ │ ├── password.vue │ │ │ ├── person.vue │ │ │ ├── recover.vue │ │ │ └── register.vue │ └── manage │ │ ├── App.vue │ │ ├── api │ │ ├── baseUrlConfig.js │ │ └── index.js │ │ ├── headnav.vue │ │ ├── home.vue │ │ ├── leftnav.vue │ │ ├── login.vue │ │ ├── main.js │ │ ├── page │ │ ├── ad.vue │ │ ├── addArticle.vue │ │ ├── article.vue │ │ ├── comment.vue │ │ ├── link.vue │ │ ├── message.vue │ │ ├── password.vue │ │ ├── setting.vue │ │ └── users.vue │ │ └── router │ │ ├── manage.js │ │ └── router.js ├── plugins │ ├── element.js │ ├── highlightjs.js │ ├── iview.js │ ├── mavonEditor.js │ └── vuescroll.js ├── store │ ├── index.js │ └── modules │ │ ├── blog.js │ │ ├── todos.js │ │ └── user.js ├── style │ ├── common.styl │ ├── hybrid.styl │ ├── index.styl │ ├── message.styl │ └── table.styl └── utils │ ├── common.js │ ├── directive.js │ ├── fetch.js │ ├── httpIndex.js │ ├── httpManage.js │ └── loginStatus.js ├── vue.config.js ├── vue.config.twoEntry.js └── yarn.lock /.env: -------------------------------------------------------------------------------- 1 | VUE_APP_API_URL = http://api.golang365.top/api/v2 2 | VUE_APP_STATIC_URL = http://img.golang365.top/ 3 | VUE_APP_AVATAR_URL = https://api.dicebear.com/7.x/bottts-neutral/svg 4 | VUE_APP_OUTPUT_DIR = dev 5 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | // 开发环境 2 | VUE_APP_API_URL = http://localhost:8080/api/v2 3 | // VUE_APP_STATIC_URL = http://localhost:9000/ 4 | VUE_APP_STATIC_URL = https://img.golang365.top/ 5 | VUE_APP_OUTPUT_DIR = dev -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | // 生产环境 2 | BASE_URL = https://api.golang365.top/api/v2 3 | VUE_APP_API_URL = https://api.golang365.top/api/v2 4 | VUE_APP_STATIC_URL = https://img.golang365.top/ 5 | VUE_APP_AVATAR_URL = https://api.dicebear.com/7.x/bottts-neutral/svg 6 | VUE_APP_OUTPUT_DIR = prod -------------------------------------------------------------------------------- /.env.sit: -------------------------------------------------------------------------------- 1 | // sit环境 2 | NODE_ENV = 'sit' 3 | VUE_APP_API_URL = http://localhost:8080/api/v2 4 | // VUE_APP_STATIC_URL = http://localhost:9000/ 5 | VUE_APP_STATIC_URL = http://static.golang365.top/ 6 | VUE_APP_OUTPUT_DIR = sit 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /prod 5 | /gh-pages 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 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw* 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | 5 | cache: npm 6 | 7 | script: npm run build 8 | 9 | deploy: 10 | provider: pages 11 | skip_cleanup: true 12 | github_token: $GITHUB_TOKEN 13 | local_dir: dist 14 | on: 15 | branch: master -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-blog v2 重构 2 | 3 | **base on vue-cli3** 4 | 博客页面:[http://www.golang365.top](http://www.golang365.top) 5 | 后台页面:[http://www.golang365.top/manage.html#/login](http://www.golang365.top/manage.html#/login) 6 | 7 | 1.多页面配置,博客页面和后台页面分离 8 | 2.图片上传又拍云 9 | 3.博客页面用 iview UI 10 | 4.后台页面用 element UI 11 | 12 | ### vue-cli3 13 | 14 | ### 安装依赖 15 | 16 | ``` 17 | npm install 18 | ``` 19 | 20 | ### 启动项目 21 | 22 | ``` 23 | npm run serve 24 | ``` 25 | 26 | ### 打包 27 | 28 | ``` 29 | npm run build 30 | ``` 31 | 32 | ### 打包并提交代码到分支 gh-pages,服务器就可以直接拉取 gh-pages 的代码 33 | 34 | ```bash 35 | # 打包提交到sit分支 36 | npm run deploy:sit 37 | # 打包提交到prod分支 38 | npm run deploy 39 | ``` 40 | 41 | ### 环境变量 42 | 43 | ``` 44 | .env # 在所有的环境中被载入 45 | .env.local # 在所有的环境中被载入,但会被 git 忽略 46 | .env.[mode] # 只在指定的模式中被载入 47 | .env.[mode].local # 只在指定的模式中被载入,但会被 git 忽略 48 | 49 | process.env.VUE_APP_VERSION 50 | 以 VUE_APP_ 开头 51 | ``` 52 | 53 | ### `vue.config.js`开发环境文件配置 54 | 55 | 这是多页面配置,2 个入口,`index.html`指向`/`路由,`manage.html`指向`manage.html#/`路由 56 | 57 | ```js 58 | pages: { 59 | index: { 60 | // 应用入口配置,相当于单页面应用的main.js,必需项 61 | entry: 'src/modules/index/main.js', 62 | // 应用的模版,相当于单页面应用的public/index.html,可选项,省略时默认与模块名一致 63 | template: 'public/index.html', 64 | // 编译后在dist目录的输出文件名,可选项,省略时默认与模块名一致 65 | filename: 'index.html', 66 | // 标题,可选项,一般情况不使用,通常是在路由切换时设置title 67 | // 需要注意的是使用title属性template 中的 title 标签需要是 <%= htmlWebpackPlugin.options.title %> 68 | title: 'index page', 69 | // 包含的模块,可选项 70 | // chunks: ['chunk-vendors', 'chunk-common', 'index'] 71 | }, 72 | manage: { 73 | entry: 'src/modules/manage/main.js', 74 | template: 'public/manage.html', 75 | filename: 'manage.html', 76 | title: 'manage page', 77 | // chunks: ['chunk-vendors', 'chunk-common', 'index'] 78 | }, 79 | }, 80 | ``` 81 | 82 | **配置 api 请求地址和 serve 启动端口号** 83 | 84 | ```js 85 | devServer: { 86 | port: 9000, // 端口号 87 | host: "0.0.0.0", 88 | https: false, // https:{type:Boolean} 89 | open: true, //配置自动启动浏览器 90 | proxy: { 91 | "/apis": { 92 | target: "http://127.0.0.1:8080/api/v2", // 需要请求的地址 93 | changeOrigin: true, // 是否跨域 94 | pathRewrite: { 95 | "^/apis": "" // 替换target中的请求地址,也就是说,在请求的时候,url用'/proxy'代替' 96 | } 97 | } 98 | // '/foo': { 99 | // target: '' 100 | // } 101 | // 配置多个代理 102 | } 103 | ``` 104 | 105 | ### 生产环境 api 接口映射 106 | 107 | 解决方法:修改宝塔里 vue 项目的 nginx 配置文件 108 | 109 | ``` 110 | server 111 | { 112 | ... 113 | // 添加下面三行 114 | location /api { 115 | add_header 'Access-Control-Allow-Origin' '*'; 116 | proxy_pass http://api.golang365.top/api/v2; 117 | } 118 | ... 119 | } 120 | ``` 121 | 122 | ### 修改服务器 nginx 配置文件,开启 gzip 123 | 124 | ``` 125 | server 126 | { 127 | listen 80; 128 | 129 | // 添加下面 130 | gzip on; 131 | 132 | # 不压缩临界值,大于1K的才压缩,一般不用改 133 | gzip_min_length 1k; 134 | 135 | 136 | gzip_buffers 4 16k; 137 | 138 | # 压缩级别,1-10,数字越大压缩的越好,时间也越长,看心情随便改吧 139 | gzip_comp_level 9; 140 | 141 | # 进行压缩的文件类型,缺啥补啥就行了,JavaScript有两种写法,最好都写上吧,总有人抱怨js文件没有压缩,其实多写一种格式就行了 142 | gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; 143 | 144 | # 跟Squid等缓存服务有关,on的话会在Header里增加"Vary: Accept-Encoding",我不需要这玩意,自己对照情况看着办吧 145 | gzip_vary off; 146 | 147 | # IE6对Gzip不怎么友好,不给它Gzip了 148 | gzip_disable "MSIE [1-6]\."; 149 | 150 | ... 151 | } 152 | ``` 153 | 154 | ### 自己写的自动打包提交编译文件到 gh-pages 155 | 156 | ``` 157 | 新建gh-pages目录 158 | gh-pages目录创建gh-pages分支的git,并把gh-pages添加到.gitignore文件 159 | 160 | gh-pages.sh文件 161 | 162 | 开启权限才能运行sh文件 163 | chmod 777 gh-pages.sh 164 | 165 | 运行文件 166 | ./gh-pages.sh 167 | 168 | 将自动打包文件,把打包后的文件复制到gh-pages文件,并提交gh-pages文件到gh-pages分支 169 | ``` 170 | 171 | ### 未解决问题 172 | 173 | - [ ] 目前已经是配置多页面,但是打包后 js 还是合并在一起,有没有大佬知道怎么解决多页面 js 分开打包 174 | 175 | ### vue-cli3启动报错问题 176 | 找到/node_modules/sockjs-client/dist/sockjs.js 177 | 2.找到代码的 1605行 178 | ```js 179 | try { 180 | // self.xhr.send(payload); 把这里注掉 181 | } catch (e) { 182 | self.emit('finish', 0, ''); 183 | self._cleanup(false); 184 | } 185 | ``` 186 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /gh-pages.sh: -------------------------------------------------------------------------------- 1 | cd gh-pages 2 | 3 | echo 拉取最新代码 4 | git pull 5 | 6 | echo 删除拉取的代码 7 | rm -rf gh-pages/* 8 | 9 | cd .. 10 | 11 | echo 编译文件 12 | npm run build 13 | 14 | echo 复制编译后代码到gh-pages文件 15 | cp -r ./dist/* ./gh-pages 16 | 17 | cd gh-pages 18 | 19 | echo 提交代码 20 | cd gh-pages 21 | git add . 22 | git commit -m "自动提交代码" 23 | git push 24 | 25 | echo 提交完毕 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli3-blog", 3 | "version": "1.0.0", 4 | "homepage": "https://sweida.github.io/vue-cli3-demo", 5 | "private": true, 6 | "scripts": { 7 | "start": "vue-cli-service serve", 8 | "build": "vue-cli-service build", 9 | "build:sit": "vue-cli-service build --mode sit", 10 | "predeploy": "npm run build", 11 | "deploy": "gh-pages -d dist", 12 | "deploy:push": "gh-pages -d dist", 13 | "predeploy:sit": "npm run build:sit", 14 | "deploy:sit": "gh-pages -d dist --branch sit", 15 | "lint": "vue-cli-service lint" 16 | }, 17 | "dependencies": { 18 | "axios": "^1.6.8", 19 | "core-js": "^2.6.5", 20 | "gh-pages": "^2.0.1", 21 | "highlight.js": "^10.4.1", 22 | "iview": "^3.0.1", 23 | "mavon-editor": "^2.8.2", 24 | "vue": "2.7.16", 25 | "vue-fragment": "^1.6.0", 26 | "vue-marked": "^0.1.1", 27 | "vue-router": "^3.0.1", 28 | "vue-savedata": "^2.0.2", 29 | "vuex": "^3.0.1" 30 | }, 31 | "devDependencies": { 32 | "@vue/cli-plugin-babel": "^3.11.0", 33 | "@vue/cli-plugin-eslint": "^3.11.0", 34 | "@vue/cli-service": "^3.11.0", 35 | "babel-eslint": "^10.0.1", 36 | "compression-webpack-plugin": "^3.0.0", 37 | "eslint": "^5.16.0", 38 | "eslint-plugin-vue": "^5.0.0", 39 | "stylus": "^0.54.5", 40 | "stylus-loader": "^3.0.2", 41 | "vue-cli-plugin-element": "^1.0.0", 42 | "vue-cli-plugin-iview": "^1.0.6", 43 | "vue-template-compiler": "^2.6.10" 44 | }, 45 | "eslintConfig": { 46 | "root": true, 47 | "env": { 48 | "node": true 49 | }, 50 | "extends": [ 51 | "plugin:vue/essential", 52 | "eslint:recommended" 53 | ], 54 | "rules": {}, 55 | "parserOptions": { 56 | "parser": "babel-eslint" 57 | } 58 | }, 59 | "postcss": { 60 | "plugins": { 61 | "autoprefixer": {} 62 | } 63 | }, 64 | "browserslist": [ 65 | "> 1%", 66 | "last 2 versions" 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Start Here 天行九歌的博客 13 | 14 | 15 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /public/manage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Start Here 天行九歌的博客后台管理系统 13 | 14 | 15 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/404.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | 24 | 38 | -------------------------------------------------------------------------------- /src/api/baseUrlConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 定义各个API的 baseURL 3 | */ 4 | const common = { 5 | static_url: 'http://static.golang365.top/', 6 | } 7 | 8 | const baseURL = { 9 | /** 生产 */ 10 | production: { 11 | ...common, 12 | api_url: 'https://api.golang365.top/api/v2', 13 | dist_name: 'prod', 14 | }, 15 | /** 开发 */ 16 | development: { 17 | ...common, 18 | api_url: "https://api.golang365.top/api/v2", 19 | dist_name: 'dev', 20 | }, 21 | /** 测试 */ 22 | test: { 23 | ...common, 24 | api_url: "http://blog-test.golang365.top/api/v2", 25 | dist_name: 'test', 26 | }, 27 | /** sit */ 28 | sit: { 29 | ...common, 30 | api_url: "http://blog-sit.golang365.top/api/v2", 31 | dist_name: 'sit', 32 | } 33 | }[process.env.NODE_ENV || 'production'] 34 | 35 | export default baseURL; 36 | 37 | -------------------------------------------------------------------------------- /src/assets/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/404.png -------------------------------------------------------------------------------- /src/assets/avatar/admin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/avatar/admin.jpg -------------------------------------------------------------------------------- /src/assets/banner1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/banner1.jpg -------------------------------------------------------------------------------- /src/assets/banner2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/banner2.jpg -------------------------------------------------------------------------------- /src/assets/banner3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/banner3.jpg -------------------------------------------------------------------------------- /src/assets/banner4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/banner4.jpg -------------------------------------------------------------------------------- /src/assets/banner5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/banner5.jpg -------------------------------------------------------------------------------- /src/assets/error.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/error.jpg -------------------------------------------------------------------------------- /src/assets/errorImg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/errorImg.jpg -------------------------------------------------------------------------------- /src/assets/laravel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/laravel.png -------------------------------------------------------------------------------- /src/assets/loginlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/loginlogo.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/message.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/message.jpg -------------------------------------------------------------------------------- /src/assets/nav-map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/nav-map.jpg -------------------------------------------------------------------------------- /src/assets/vue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sweida/vue-blog-index/6ebbfc90625ea23db68c91dc6fc461bbf50ad6cf/src/assets/vue.jpg -------------------------------------------------------------------------------- /src/components/MyLoading.js: -------------------------------------------------------------------------------- 1 | import loading from './myLoading.vue' 2 | // 这里是重点 3 | const MyLoading = { 4 | install: function(Vue) { 5 | Vue.component('MyLoading', loading) 6 | }, 7 | } 8 | 9 | // 导出组件 10 | export default MyLoading 11 | -------------------------------------------------------------------------------- /src/components/MyPage.js: -------------------------------------------------------------------------------- 1 | import page from './page.vue' 2 | // 这里是重点 3 | const MyPage = { 4 | install: function(Vue) { 5 | Vue.component('MyPage', page) 6 | }, 7 | } 8 | 9 | // 导出组件 10 | export default MyPage 11 | -------------------------------------------------------------------------------- /src/components/NewPage.js: -------------------------------------------------------------------------------- 1 | import newPage from './newPage.vue' 2 | // 这里是重点 3 | const NewPage = { 4 | install: function(Vue) { 5 | Vue.component("NewPage", newPage); 6 | }, 7 | } 8 | 9 | // 导出组件 10 | export default NewPage 11 | -------------------------------------------------------------------------------- /src/components/SpinLoading.js: -------------------------------------------------------------------------------- 1 | import spinLoading from './spinLoading.vue' 2 | // 这里是重点 3 | const SpinLoading = { 4 | install: function(Vue) { 5 | Vue.component('SpinLoading', spinLoading) 6 | }, 7 | } 8 | 9 | // 导出组件 10 | export default SpinLoading 11 | -------------------------------------------------------------------------------- /src/components/TextLoading.js: -------------------------------------------------------------------------------- 1 | import textloading from "./textLoading.vue"; 2 | // 这里是重点 3 | const TextLoading = { 4 | install: function(Vue) { 5 | Vue.component("TextLoading", textloading); 6 | }, 7 | } 8 | 9 | // 导出组件 10 | export default TextLoading; 11 | -------------------------------------------------------------------------------- /src/components/myLoading.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /src/components/newPage.vue: -------------------------------------------------------------------------------- 1 | 13 | 37 | 38 | -------------------------------------------------------------------------------- /src/components/page.vue: -------------------------------------------------------------------------------- 1 | 32 | 52 | 115 | -------------------------------------------------------------------------------- /src/components/spinLoading.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 29 | 30 | -------------------------------------------------------------------------------- /src/components/textLoading.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 28 | 29 | -------------------------------------------------------------------------------- /src/directive/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const defaultErrorImg = require("@/assets/errorImg.jpg"); 4 | const staticUrl = process.env.VUE_APP_STATIC_URL 5 | 6 | //全局注册自定义指令,用于判断当前图片是否能够加载成功,可以加载成功则赋值为img的src属性,否则使用默认图片 7 | Vue.directive("imgUrl", async function(el, binding) { 8 | let imgURL = binding.value; //获取图片地址 9 | //获取错误图片地址,如果没有则获取默认的 10 | let errorImg = el.getAttribute("error-img") || defaultErrorImg; 11 | let totalImgUrl = staticUrl + imgURL 12 | 13 | if (imgURL) { 14 | // 是否http开头 15 | let isHttp = imgURL.indexOf('http') 16 | if (isHttp > -1) { 17 | let exist = await imageIsExist(imgURL); 18 | if (exist) { 19 | el.setAttribute("src", imgURL); 20 | } else { 21 | el.setAttribute("src", errorImg); 22 | el.setAttribute("img-data", totalImgUrl); 23 | } 24 | } else { 25 | let exist = await imageIsExist(totalImgUrl); 26 | if (exist) { 27 | el.setAttribute("src", totalImgUrl); 28 | } else { 29 | el.setAttribute("src", errorImg); 30 | el.setAttribute("img-data", totalImgUrl); 31 | } 32 | } 33 | } else { 34 | el.setAttribute("src", errorImg); 35 | el.setAttribute("img-data", totalImgUrl); 36 | } 37 | }); 38 | 39 | // exist 判断有问题 40 | Vue.directive("real-img", async function(el, binding) { 41 | let imgURL = binding.value; //获取图片地址 42 | let errorImg = el.getAttribute("error-img"); //获取默认图片地址 43 | if (imgURL) { 44 | let exist = await imageIsExist(imgURL); 45 | if (exist) { 46 | el.setAttribute("src", imgURL); 47 | } else { 48 | el.setAttribute("src", errorImg); 49 | } 50 | } 51 | }); 52 | 53 | /** 54 | * 检测图片是否存在 55 | * @param url 56 | */ 57 | let imageIsExist = function(url) { 58 | return new Promise(resolve => { 59 | var img = new Image(); 60 | img.onload = function() { 61 | if (this.complete == true) { 62 | resolve(true); 63 | img = null; 64 | } 65 | }; 66 | img.onerror = function() { 67 | resolve(false); 68 | img = null; 69 | }; 70 | img.src = url; 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /src/modules/index/App.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 65 | 66 | 114 | -------------------------------------------------------------------------------- /src/modules/index/api/article.js: -------------------------------------------------------------------------------- 1 | import request from "@/utils/httpIndex"; 2 | import baseURL from "./baseUrlConfig"; 3 | 4 | // 文章详情 5 | export function ArticleDetial (data) { 6 | return request({ 7 | // baseURL: baseURL.host, 8 | url: '/apis/article', 9 | method: 'post', 10 | data 11 | }) 12 | } 13 | 14 | // 文章列表 15 | export function ArticleList (data) { 16 | return request({ 17 | // baseURL: baseURL.host, 18 | url: '/apis/article/list', 19 | method: 'post', 20 | data 21 | }) 22 | } 23 | 24 | // 点赞 25 | export function ArticleLike (data) { 26 | return request({ 27 | // baseURL: baseURL.host, 28 | url: '/apis/article/like', 29 | method: 'post', 30 | data 31 | }) 32 | } 33 | 34 | // 技能skill 35 | export function getClassify (data) { 36 | return request({ 37 | // baseURL: baseURL.host, 38 | url: '/apis/article/classify', 39 | method: 'get', 40 | data 41 | }) 42 | } 43 | 44 | // 标签 45 | export function TagList (data) { 46 | return request({ 47 | // baseURL: baseURL.host, 48 | url: '/apis/tag/list', 49 | method: 'post', 50 | data 51 | }) 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/modules/index/api/baseUrlConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 定义各个API的 baseURL 3 | */ 4 | const common = {} 5 | 6 | const baseURL = { 7 | /** 生产 */ 8 | production: { 9 | ...common, 10 | host: '', 11 | auth: '', 12 | prefix: '', 13 | channel: '' 14 | }, 15 | /** 开发 */ 16 | development: { 17 | ...common, 18 | host: '', 19 | auth: '', 20 | prefix: '', 21 | channel: '', 22 | } 23 | }[process.env.NODE_ENV || 'production'] 24 | 25 | export default baseURL; 26 | -------------------------------------------------------------------------------- /src/modules/index/api/comment.js: -------------------------------------------------------------------------------- 1 | import request from "utils/httpIndex"; 2 | 3 | // 获取评论 4 | export function CommentList (data) { 5 | return request({ 6 | url: '/apis/comment/read', 7 | method: 'post', 8 | data 9 | }) 10 | } 11 | 12 | // 提交评论 13 | export function CommentAdd (data) { 14 | return request({ 15 | url: '/apis/comment/add', 16 | method: 'post', 17 | data 18 | }) 19 | } 20 | 21 | // 删除评论 22 | export function CommentDelete (data) { 23 | return request({ 24 | url: '/apis/comment/delete', 25 | method: 'post', 26 | data 27 | }) 28 | } 29 | 30 | // 个人留言 31 | export function CommentPerson (data) { 32 | return request({ 33 | url: '/apis/comment/person', 34 | method: 'post', 35 | data 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /src/modules/index/api/common.js: -------------------------------------------------------------------------------- 1 | import request from "utils/httpIndex"; 2 | import baseURL from "./baseUrlConfig"; 3 | 4 | 5 | export function getWebInfo (data) { 6 | return request({ 7 | // baseURL: baseURL.host, 8 | url: '/apis/webinfo/read', 9 | method: 'get', 10 | data 11 | }) 12 | } 13 | 14 | export function getAd (data) { 15 | return request({ 16 | // baseURL: baseURL.host, 17 | url: '/apis/ad', 18 | method: 'post', 19 | data 20 | }) 21 | } 22 | 23 | // 友链 24 | export function LinkList (data) { 25 | return request({ 26 | // baseURL: baseURL.host, 27 | url: '/apis/link/list', 28 | method: 'post', 29 | data 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /src/modules/index/api/index.js: -------------------------------------------------------------------------------- 1 | 2 | export { 3 | getAd, 4 | LinkList, 5 | getWebInfo, 6 | } from './common' 7 | 8 | export { 9 | ArticleDetial, 10 | ArticleList, 11 | ArticleLike, 12 | TagList, 13 | getClassify, 14 | } from './article' 15 | 16 | export { 17 | CommentList, 18 | CommentAdd, 19 | CommentDelete, 20 | CommentPerson, 21 | } from './comment' 22 | 23 | export { 24 | MessageList, 25 | MessageAdd, 26 | MessageDelete, 27 | MessageReply, 28 | MessageReplyDelete, 29 | MessagePerson, 30 | } from'./message' 31 | 32 | export { 33 | getUserInfo, 34 | Login, 35 | Signup, 36 | ResetPassword, 37 | SendEmail, 38 | CheckCaptcha, 39 | } from './user' 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/modules/index/api/message.js: -------------------------------------------------------------------------------- 1 | import request from "utils/httpIndex"; 2 | import baseURL from "./baseUrlConfig"; 3 | 4 | // 留言列表 5 | export function MessageList (data) { 6 | return request({ 7 | url: '/apis/message/list', 8 | method: 'post', 9 | data 10 | }) 11 | } 12 | 13 | // 新增留言 14 | export function MessageAdd (data) { 15 | return request({ 16 | url: '/apis/message/add', 17 | method: 'post', 18 | data 19 | }) 20 | } 21 | 22 | // 删除留言 23 | export function MessageDelete (data) { 24 | return request({ 25 | url: '/apis/message/delete', 26 | method: 'post', 27 | data 28 | }) 29 | } 30 | 31 | // 回复留言 32 | export function MessageReply (data) { 33 | return request({ 34 | url: '/apis/message/reply', 35 | method: 'post', 36 | data 37 | }) 38 | } 39 | 40 | // 删除回复 41 | export function MessageReplyDelete (data) { 42 | return request({ 43 | url: '/apis/message/reply/delete', 44 | method: 'post', 45 | data 46 | }) 47 | } 48 | 49 | // 个人留言 50 | export function MessagePerson (data) { 51 | return request({ 52 | url: '/apis/message/person', 53 | method: 'post', 54 | data 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /src/modules/index/api/user.js: -------------------------------------------------------------------------------- 1 | import request from "utils/httpIndex"; 2 | 3 | export function Login (data) { 4 | return request({ 5 | url: '/apis/login', 6 | method: 'post', 7 | data 8 | }) 9 | } 10 | 11 | export function Signup (data) { 12 | return request({ 13 | url: '/apis/signup', 14 | method: 'post', 15 | data 16 | }) 17 | } 18 | 19 | export function getUserInfo (data) { 20 | return request({ 21 | url: '/apis/user/info', 22 | method: 'get', 23 | data 24 | }) 25 | } 26 | 27 | // 修改密码 28 | export function ResetPassword (data) { 29 | return request({ 30 | url: '/apis/user/resetpassword', 31 | method: 'post', 32 | data 33 | }) 34 | } 35 | 36 | export function SendEmail (data) { 37 | return request({ 38 | url: '/apis/user/send_email', 39 | method: 'post', 40 | data 41 | }) 42 | } 43 | 44 | export function CheckCaptcha (data) { 45 | return request({ 46 | url: '/apis/user/check_captcha', 47 | method: 'post', 48 | data 49 | }) 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/modules/index/components/commonPage.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/modules/index/components/footer.vue: -------------------------------------------------------------------------------- 1 | 8 | 27 | 28 | 72 | 73 | 104 | -------------------------------------------------------------------------------- /src/modules/index/components/headnav.vue: -------------------------------------------------------------------------------- 1 | 109 | 110 | 186 | 187 | 210 | 211 | 355 | -------------------------------------------------------------------------------- /src/modules/index/components/skills.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 75 | 76 | 77 | 164 | -------------------------------------------------------------------------------- /src/modules/index/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router/router' 4 | import store from 'store/index' 5 | 6 | import http from 'utils/httpIndex' 7 | import * as API from './api/index' 8 | 9 | import 'plugins/mavonEditor.js' 10 | import 'plugins/iview.js' 11 | import 'plugins/highlightjs' 12 | 13 | // 自定义指令 14 | import '@/directive/index' 15 | 16 | // 全局自定义组件 17 | import MyLoading from 'components/MyLoading' 18 | Vue.use(MyLoading) 19 | 20 | import SpinLoading from 'components/SpinLoading' 21 | Vue.use(SpinLoading) 22 | 23 | import MyPage from 'components/MyPage' 24 | Vue.use(MyPage) 25 | 26 | import NewPage from 'components/NewPage' 27 | Vue.use(NewPage) 28 | 29 | import TextLoading from 'components/TextLoading' 30 | Vue.use(TextLoading) 31 | 32 | import { Plugin } from 'vue-fragment' 33 | Vue.use(Plugin) 34 | // import Fragment from 'vue-fragment' 35 | // Vue.use(Fragment.Plugin) 36 | 37 | // // 引入ivew, 38 | // import iView from 'iview' 39 | // import 'iview/dist/styles/iview.css' 40 | // Vue.use(iView) 41 | // // 路由跳转开启进度条 42 | // router.beforeEach((to, from, next) => { 43 | // iView.LoadingBar.start(); 44 | // next(); 45 | // }); 46 | // router.afterEach(route => { 47 | // iView.LoadingBar.finish(); 48 | // }); 49 | 50 | Vue.prototype.$get = http.get 51 | Vue.prototype.$post = http.post 52 | Vue.prototype.$baseApiUrl = process.env.VUE_APP_API_URL 53 | Vue.prototype.$staticUrl = process.env.VUE_APP_STATIC_URL 54 | Vue.prototype.$avatarUrl = process.env.VUE_APP_AVATAR_URL 55 | Vue.prototype.$api = API 56 | 57 | Vue.config.productionTip = false 58 | 59 | new Vue({ 60 | router, 61 | store, 62 | render: (h) => h(App), 63 | }).$mount('#app') 64 | -------------------------------------------------------------------------------- /src/modules/index/page/about.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 89 | 90 | 249 | -------------------------------------------------------------------------------- /src/modules/index/page/donate.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 43 | 44 | 58 | -------------------------------------------------------------------------------- /src/modules/index/page/link.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 80 | 184 | -------------------------------------------------------------------------------- /src/modules/index/page/message.vue: -------------------------------------------------------------------------------- 1 | 121 | 122 | 261 | 262 | 355 | -------------------------------------------------------------------------------- /src/modules/index/router/index.js: -------------------------------------------------------------------------------- 1 | 2 | // import home from "@/modules/index/home" 3 | import blog from "@/modules/index/page/blog" 4 | import about from "@/modules/index/page/about" 5 | 6 | const detail = resolve => require(["@/modules/index/page/detail"], resolve); 7 | const message = resolve => require(["@/modules/index/page/message"], resolve); 8 | const link = resolve => require(["@/modules/index/page/link"], resolve); 9 | const donate = resolve => require(["@/modules/index/page/donate"], resolve); 10 | 11 | const login = resolve => require(["@/modules/index/user/login"], resolve); 12 | const register = resolve => require(["@/modules/index/user/register"], resolve); 13 | const recover = resolve => require(["@/modules/index/user/recover"], resolve); 14 | const password = resolve => require(["@/modules/index/user/password"], resolve); 15 | const person = resolve => require(["@/modules/index/user/person"], resolve); 16 | 17 | const index = [ 18 | { 19 | path: "/", 20 | component: blog, 21 | meta: { 22 | keepAlive: true // 需要被缓存 23 | } 24 | }, 25 | { 26 | path: "/about", 27 | component: about, 28 | name: "about" 29 | }, 30 | { 31 | path: "/login", 32 | component: login, 33 | name: "login" 34 | }, 35 | { 36 | path: "/register", 37 | component: register, 38 | name: "register" 39 | }, 40 | { 41 | path: "/blog", 42 | component: blog, 43 | name: "blog", 44 | meta: { 45 | keepAlive: true // 需要被缓存 46 | } 47 | }, 48 | { 49 | path: "/blog/:id", 50 | component: detail, 51 | name: "detail" 52 | }, 53 | { 54 | path: "/message", 55 | component: message, 56 | name: "message", 57 | meta: { 58 | keepAlive: true 59 | } 60 | }, 61 | { 62 | path: "/link", 63 | component: link, 64 | name: "link", 65 | meta: { 66 | keepAlive: true 67 | } 68 | }, 69 | { 70 | path: "/recover", 71 | component: recover, 72 | name: "recover" 73 | }, 74 | { 75 | path: "/password", 76 | component: password, 77 | name: "password" 78 | }, 79 | { 80 | path: "/donate", 81 | component: donate, 82 | name: "donate", 83 | meta: { 84 | keepAlive: true 85 | } 86 | }, 87 | { 88 | path: "/person", 89 | component: person, 90 | name: "person" 91 | } 92 | ]; 93 | export default index 94 | -------------------------------------------------------------------------------- /src/modules/index/router/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import store from "@/store/index" 3 | 4 | import Router from 'vue-router' 5 | import NotFound from '@/404' 6 | 7 | import index from './index' 8 | 9 | Vue.use(Router) 10 | 11 | const router = new Router({ 12 | // mode: 'history', 13 | routes: [ 14 | { 15 | path: '*', 16 | component: NotFound, 17 | }, 18 | ...index, 19 | 20 | ], 21 | // 新开页面滚动条回到顶部,后退回到之前位置 22 | scrollBehavior(to, from, savedPosition) { 23 | if (savedPosition) { 24 | return savedPosition 25 | } else { 26 | return { x: 0, y: 0 } 27 | } 28 | } 29 | 30 | }) 31 | 32 | router.beforeEach((to, from, next) => { 33 | // 使用钩子函数对路由进行权限跳转 34 | // 如果用户已经登录,访问登录和注册时,自动跳转到首页 35 | setTimeout(() => { 36 | const login = store.state.user.user 37 | if (!login && (to.path == "/password" || to.path == "/person")) { 38 | next("/blog") 39 | } else { 40 | next(); 41 | } 42 | }, 1000); 43 | 44 | const role = store.state.user.user 45 | if (role && (to.path == '/login' || to.path == '/register')) { 46 | next('/blog') 47 | } else { 48 | next(); 49 | } 50 | }) 51 | 52 | export default router -------------------------------------------------------------------------------- /src/modules/index/user/login.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 137 | 138 | 139 | 140 | 175 | -------------------------------------------------------------------------------- /src/modules/index/user/password.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 37 | 108 | 109 | 110 | 111 | 130 | -------------------------------------------------------------------------------- /src/modules/index/user/person.vue: -------------------------------------------------------------------------------- 1 | 80 | 81 | 82 | 160 | 161 | 162 | 254 | -------------------------------------------------------------------------------- /src/modules/index/user/recover.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 145 | 146 | 147 | 148 | 187 | -------------------------------------------------------------------------------- /src/modules/index/user/register.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 40 | 103 | 104 | 105 | 106 | 125 | -------------------------------------------------------------------------------- /src/modules/manage/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 32 | 33 | 42 | -------------------------------------------------------------------------------- /src/modules/manage/api/baseUrlConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 定义各个API的 baseURL 3 | */ 4 | const common = {} 5 | 6 | const baseURL = { 7 | /** 生产 */ 8 | production: { 9 | ...common, 10 | host: '', 11 | auth: '', 12 | prefix: '', 13 | channel: '' 14 | }, 15 | /** 开发 */ 16 | development: { 17 | ...common, 18 | host: '', 19 | auth: '', 20 | prefix: '', 21 | channel: '', 22 | } 23 | }[process.env.NODE_ENV || 'production'] 24 | 25 | export default baseURL; 26 | -------------------------------------------------------------------------------- /src/modules/manage/api/index.js: -------------------------------------------------------------------------------- 1 | 2 | export { BranchList } from './common' 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/modules/manage/headnav.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 70 | 71 | 140 | -------------------------------------------------------------------------------- /src/modules/manage/home.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 40 | 41 | 66 | -------------------------------------------------------------------------------- /src/modules/manage/leftnav.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 56 | 57 | 102 | -------------------------------------------------------------------------------- /src/modules/manage/login.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 71 | 157 | -------------------------------------------------------------------------------- /src/modules/manage/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router/router' 4 | import store from '@/store' 5 | 6 | import http from '@/utils/httpManage' 7 | Vue.prototype.$get = http.get 8 | Vue.prototype.$post = http.post 9 | 10 | // import '@/plugins/element.js' 11 | import '@/plugins/mavonEditor.js' 12 | import '@/plugins/iview.js' 13 | import '@/plugins/highlightjs' 14 | 15 | // 全局自定义组件 16 | import MyLoading from '@/components/MyLoading' 17 | Vue.use(MyLoading) 18 | 19 | import MyPage from '@/components/MyPage' 20 | Vue.use(MyPage) 21 | 22 | import TextLoading from '@/components/TextLoading' 23 | Vue.use(TextLoading) 24 | 25 | Vue.prototype.$baseUrl = process.env.VUE_APP_URL 26 | Vue.prototype.$staticUrl = process.env.VUE_APP_STATIC_URL 27 | Vue.prototype.$avatarUrl = process.env.VUE_APP_AVATAR_URL 28 | // } 29 | // Vue.prototype.$baseUrl = baseUrl 30 | // // 引入ivew, 31 | // import iView from 'iview' 32 | // import 'iview/dist/styles/iview.css' 33 | // Vue.use(iView) 34 | // // 路由跳转开启进度条 35 | // router.beforeEach((to, from, next) => { 36 | // iView.LoadingBar.start(); 37 | // next(); 38 | // }); 39 | // router.afterEach(route => { 40 | // iView.LoadingBar.finish(); 41 | // }); 42 | 43 | Vue.config.productionTip = false 44 | // console.log(process.env.VUE_APP_URL, 5657) 45 | // console.log(process.env.NODE_ENV, 5658) 46 | new Vue({ 47 | router, 48 | store, 49 | render: h => h(App), 50 | }).$mount('#app') -------------------------------------------------------------------------------- /src/modules/manage/page/ad.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 201 | 202 | 210 | 211 | -------------------------------------------------------------------------------- /src/modules/manage/page/addArticle.vue: -------------------------------------------------------------------------------- 1 | 66 | 67 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /src/modules/manage/page/article.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 113 | 114 | -------------------------------------------------------------------------------- /src/modules/manage/page/comment.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 93 | 94 | -------------------------------------------------------------------------------- /src/modules/manage/page/link.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 153 | 154 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /src/modules/manage/page/message.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 117 | 118 | -------------------------------------------------------------------------------- /src/modules/manage/page/password.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 59 | 60 | -------------------------------------------------------------------------------- /src/modules/manage/page/setting.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/modules/manage/page/users.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 191 | 192 | -------------------------------------------------------------------------------- /src/modules/manage/router/manage.js: -------------------------------------------------------------------------------- 1 | const Login = resolve => require(["@/modules/manage/login"], resolve); 2 | const Home = resolve => require(["@/modules/manage/home.vue"], resolve); 3 | const Setting = resolve => require(["@/modules/manage/page/setting"], resolve); 4 | const Article = resolve => require(["@/modules/manage/page/article"], resolve); 5 | const AddArticle = resolve => require(["@/modules/manage/page/addArticle"], resolve); 6 | const Users = resolve => require(["@/modules/manage/page/users"], resolve); 7 | const Message = resolve => require(["@/modules/manage/page/message"], resolve); 8 | const Comment = resolve => require(["@/modules/manage/page/comment"], resolve); 9 | const Rassword = resolve => require(["@/modules/manage/page/password"], resolve); 10 | const Link = resolve => require(["@/modules/manage/page/link"], resolve); 11 | const Ad = resolve => require(["@/modules/manage/page/ad"], resolve); 12 | 13 | 14 | const manage = [ 15 | { 16 | path: "/", 17 | component: Login, 18 | redirect: { name: "manageLogin" } 19 | }, 20 | { 21 | path: "/login", 22 | component: Login, 23 | name: "manageLogin" 24 | }, 25 | { 26 | path: "/home", 27 | component: Home, 28 | name: "manageHome", 29 | meta: { 30 | requireAuth: true // 添加该字段,表示进入这个路由是需要登录的 31 | }, 32 | children: [ 33 | { 34 | path: "/setting", 35 | component: Setting, 36 | name: "基础设置", 37 | meta: { 38 | requireAuth: true 39 | } 40 | }, 41 | { 42 | path: "/articlelist", 43 | component: Article, 44 | name: "博文列表", 45 | meta: { 46 | requireAuth: true 47 | } 48 | }, 49 | { 50 | path: "/article/add", 51 | component: AddArticle, 52 | name: "写博客", 53 | meta: { 54 | requireAuth: true 55 | } 56 | }, 57 | { 58 | path: "/article/edit/:id", 59 | component: AddArticle, 60 | name: "编辑博文", 61 | meta: { 62 | requireAuth: true 63 | } 64 | }, 65 | { 66 | path: "/users", 67 | component: Users, 68 | name: "会员列表", 69 | meta: { 70 | requireAuth: true 71 | } 72 | }, 73 | { 74 | path: "/message", 75 | component: Message, 76 | name: "留言板", 77 | meta: { 78 | requireAuth: true 79 | } 80 | }, 81 | { 82 | path: "/comment", 83 | component: Comment, 84 | name: "评论列表", 85 | meta: { 86 | requireAuth: true 87 | } 88 | }, 89 | { 90 | path: "/resetpassword", 91 | component: Rassword, 92 | name: "修改密码", 93 | meta: { 94 | requireAuth: true 95 | } 96 | }, 97 | { 98 | path: "/link", 99 | component: Link, 100 | name: "友情链接", 101 | meta: { 102 | requireAuth: true 103 | } 104 | }, 105 | { 106 | path: "/ad", 107 | component: Ad, 108 | name: "广告图", 109 | meta: { 110 | requireAuth: true 111 | } 112 | }, 113 | { path: "/*", redirect: { name: "基础设置" } } 114 | ] 115 | } 116 | ]; 117 | export default manage -------------------------------------------------------------------------------- /src/modules/manage/router/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import store from "@/store/index" 3 | 4 | import Router from 'vue-router' 5 | import NotFound from '@/404' 6 | 7 | import manage from './manage' 8 | 9 | Vue.use(Router) 10 | 11 | const router = new Router({ 12 | // mode: 'history', 13 | mode: "hash", 14 | routes: [ 15 | { 16 | path: '*', 17 | component: NotFound, 18 | }, 19 | ...manage, 20 | 21 | ], 22 | // 新开页面滚动条回到顶部,后退回到之前位置 23 | scrollBehavior(to, from, savedPosition) { 24 | if (savedPosition) { 25 | return savedPosition 26 | } else { 27 | return { x: 0, y: 0 } 28 | } 29 | } 30 | 31 | }) 32 | 33 | 34 | 35 | router.beforeEach((to, from, next) => { 36 | // 使用钩子函数对路由进行权限跳转 37 | // 如果用户已经登录,访问登录和注册时,自动跳转到首页 38 | const isadmin = store.state.user.user.admin 39 | // 判断该路由是否需要登录权限 40 | if (to.meta.requireAuth) { 41 | if (isadmin) { // 通过vuex state获取是否管理员 42 | next(); 43 | } else { 44 | next({ 45 | path: '/login', 46 | query: { redirect: to.fullPath } // 将跳转的路由path作为参数,登录成功后跳转到该路由 47 | }) 48 | } 49 | } 50 | else { 51 | next(); 52 | } 53 | 54 | if (isadmin && to.path == "/login") { 55 | next("/articlelist") 56 | } 57 | 58 | }) 59 | 60 | 61 | 62 | export default router -------------------------------------------------------------------------------- /src/plugins/element.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Element from 'element-ui' 3 | import 'element-ui/lib/theme-chalk/index.css' 4 | 5 | Vue.use(Element) 6 | -------------------------------------------------------------------------------- /src/plugins/highlightjs.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import hljs from 'highlight.js' 3 | import 'highlight.js/styles/atom-one-dark-reasonable.css' //样式文件 4 | 5 | Vue.directive('highlight', function(el) { 6 | let blocks = el.querySelectorAll('pre code') 7 | blocks.forEach(block => { 8 | hljs.highlightBlock(block) 9 | }) 10 | }) 11 | 12 | // 高亮颜色 13 | // a11y-dark.css 还可以 14 | // atom-one-dark-reasonable.css 还可以atom 15 | // gruvbox-dark.css 太深,还可以 16 | // ir-black.css 就是这个颜色了 17 | // monokai.css 经典颜色 18 | // railscasts.css rainbow.css 修改一下还可以 19 | // solarized-dark.css 太亮了,还可以 20 | // vs2015.css 手机看还行 21 | -------------------------------------------------------------------------------- /src/plugins/iview.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import iView from 'iview' 3 | 4 | Vue.use(iView) 5 | 6 | import 'iview/dist/styles/iview.css' 7 | -------------------------------------------------------------------------------- /src/plugins/mavonEditor.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import mavonEditor from 'mavon-editor' 3 | import 'mavon-editor/dist/css/index.css' 4 | 5 | Vue.use(mavonEditor) -------------------------------------------------------------------------------- /src/plugins/vuescroll.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import vuescroll from "vuescroll"; 3 | import "vuescroll/dist/vuescroll.css"; 4 | 5 | Vue.use(vuescroll); -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import todos from './modules/todos' 4 | import user from './modules/user' 5 | import blog from './modules/blog' 6 | import createPersiste from 'vue-savedata' 7 | 8 | Vue.use(Vuex) 9 | 10 | const persiste = createPersiste({ 11 | ciphertext: true, // 加密存本地, 默认为false 12 | LS: [ 13 | { 14 | module: user, 15 | storePath: 'user' // __storePath:(和Vuex中的option.modules:{key:value}的key,一,一对应)__ 16 | } 17 | ], 18 | SS: [ 19 | { 20 | module: todos, 21 | storePath: 'todos' 22 | }, 23 | { 24 | module: blog, 25 | storePath: 'blog' 26 | } 27 | ], 28 | }) 29 | 30 | const store = new Vuex.Store({ 31 | modules: { 32 | user, 33 | blog, 34 | todos, 35 | }, 36 | //缓存所有store数据到本地 也可以单独缓存 37 | plugins: [persiste], 38 | }) 39 | 40 | export default store; -------------------------------------------------------------------------------- /src/store/modules/blog.js: -------------------------------------------------------------------------------- 1 | import { getWebInfo, getAd } from '@/modules/index/api' 2 | 3 | const state = { 4 | webinfo: "", 5 | tag: "", 6 | classify: "", 7 | banners: [ 8 | { 9 | url: require("@/assets/banner1.jpg") 10 | }, 11 | { 12 | url: require("@/assets/banner2.jpg") 13 | }, 14 | { 15 | url: require("@/assets/banner3.jpg") 16 | }, 17 | { 18 | url: require("@/assets/banner4.jpg") 19 | }, 20 | { 21 | url: require("@/assets/banner5.jpg") 22 | }, 23 | { 24 | url: require("@/assets/message.jpg") 25 | } 26 | ] 27 | }; 28 | 29 | // 获取state的数据 30 | const getters = { 31 | webInfo: state => state.webinfo, 32 | tag: state => state.tag, 33 | classify: state => state.classify, 34 | banners: state => state.banners 35 | } 36 | 37 | // 更新state的数据 38 | const mutations = { 39 | WEBINFO (state, data) { 40 | state.webinfo = data 41 | }, 42 | TAG (state, data) { 43 | state.tag = data 44 | state.classify = '' 45 | }, 46 | CLASSIFY (state, data) { 47 | state.classify = data 48 | state.tag = '' 49 | }, 50 | BANNERS (state, data) { 51 | state.banners = data 52 | } 53 | } 54 | 55 | // 更新state数据的动作 56 | const actions = { 57 | async WebInfo ({ commit }, data) { 58 | const res = await getWebInfo() 59 | console.log(res.data, 'webinfo'); 60 | commit('WEBINFO', res.data) 61 | }, 62 | Tag ({ commit }, data) { 63 | commit('TAG', data) 64 | }, 65 | Classify ({ commit }, data) { 66 | commit('CLASSIFY', data) 67 | }, 68 | async Banners ({ commit }, data) { 69 | const res = await getAd({ type: 'banner' }) 70 | console.log(res.data, 'banner'); 71 | 72 | commit('BANNERS', res.data) 73 | } 74 | } 75 | 76 | 77 | export default { state, getters, mutations, actions } 78 | 79 | -------------------------------------------------------------------------------- /src/store/modules/todos.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const state = { 4 | todos: [] 5 | } 6 | 7 | // 获取state的数据 8 | const getters = { 9 | Todolist: state => state.todos 10 | } 11 | 12 | // 更新state的数据 13 | const mutations = { 14 | setTodos(state, todos){ 15 | state.todos = todos 16 | }, 17 | postTodo(state, todo){ 18 | state.todos.unshift(todo) 19 | }, 20 | delTodo(state, id){ 21 | state.todos = state.todos.filter(todo => todo.id != id) 22 | } 23 | } 24 | 25 | // 更新state数据的动作 26 | const actions = { 27 | async getTodos({ commit }){ 28 | const res = await axios.get('https://jsonplaceholder.typicode.com/todos') 29 | commit('setTodos', res.data) 30 | }, 31 | async addTodo({ commit }, todo) { 32 | const res = await axios.post('https://jsonplaceholder.typicode.com/todos', todo) 33 | commit('postTodo', res.data) 34 | }, 35 | async delteTodo({ commit }, id) { 36 | const res = await axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`) 37 | commit('delTodo', id) 38 | }, 39 | async filterTodos({ commit }, limit) { 40 | const res = await axios.get( 41 | `http://jsonplaceholder.typicode.com/todos?_limit=${limit}` 42 | ); 43 | commit("setTodos", res.data); 44 | }, 45 | } 46 | 47 | 48 | export default {state, getters, mutations, actions} 49 | 50 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import { getUserInfo } from '@/modules/index/api' 2 | 3 | import http from '@/utils/httpIndex' 4 | 5 | const state = { 6 | user: '', 7 | token: localStorage.getItem('so_token') || '', 8 | } 9 | 10 | // 获取state的数据 11 | const getters = { 12 | user: state => state.user, 13 | token: state => state.token 14 | } 15 | 16 | // 更新state的数据 17 | const mutations = { 18 | TOKEN (state, data) { 19 | state.token = data 20 | }, 21 | USERINFO (state, data) { 22 | state.user = data 23 | }, 24 | LOGOUT (state) { 25 | state.user = '', 26 | state.token = '' 27 | } 28 | } 29 | 30 | // 更新state数据的动作 31 | const actions = { 32 | async UserInfo ({ commit }, data) { 33 | const res = await getUserInfo() 34 | commit('USERINFO', res.data) 35 | }, 36 | Token ({ commit }, data) { 37 | localStorage.setItem("so_token", data); 38 | commit('TOKEN', data) 39 | }, 40 | Logout ({ commit }) { 41 | localStorage.removeItem("so_token"); 42 | commit('LOGOUT') 43 | }, 44 | } 45 | 46 | 47 | export default { state, getters, mutations, actions } 48 | 49 | -------------------------------------------------------------------------------- /src/style/common.styl: -------------------------------------------------------------------------------- 1 | body { 2 | margin:0; 3 | // font-family: "PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 4 | font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 5 | } 6 | li 7 | list-style: none 8 | .animate03{ 9 | -webkit-transition-duration:0.3s; 10 | -moz-transition-duration:0.3s; 11 | -ms-transition-duration:0.3s; 12 | transition-duration:0.3s; 13 | } 14 | .animate05{ 15 | -webkit-transition-duration:0.5s; 16 | -moz-transition-duration:0.5s; 17 | -ms-transition-duration:0.5s; 18 | transition-duration:0.5s; 19 | } 20 | 21 | main 22 | box-sizing: border-box; 23 | flex:1; 24 | height: 100%; 25 | display: flex; 26 | flex-direction: column; 27 | background: #fff 28 | header 29 | height: 48px; 30 | line-height: 48px; 31 | background: #F7F7F7; 32 | text-indent: 30px; 33 | .wrap 34 | position: relative; 35 | flex: 1; 36 | background: #fff; 37 | padding: 20px 30px; 38 | box-sizing: border-box; 39 | .head{ 40 | height: 60px; 41 | span{ 42 | padding-right: 5px; 43 | } 44 | } 45 | // .main-table .el-icon-edit, .main-table .el-icon-delete, .main-table .el-icon-search{ 46 | // font-size: 20px; 47 | // color:#888; 48 | // margin: 4px 10px; 49 | // cursor: pointer; 50 | // } 51 | footer 52 | height: 55px; 53 | box-sizing: border-box; 54 | border-top: 1px solid #f2f2f2; 55 | width: 100%; 56 | display: flex; 57 | align-items: center; 58 | background: #F7f7f7; 59 | .el-button 60 | margin: 0 30px; 61 | 62 | 63 | // 上传图片 64 | .avatar-uploader .el-upload { 65 | border: 1px dashed #d9d9d9; 66 | border-radius: 6px; 67 | cursor: pointer; 68 | position: relative; 69 | overflow: hidden; 70 | } 71 | .avatar-uploader .el-upload:hover { 72 | border-color: #409EFF; 73 | } 74 | .avatar-uploader-icon { 75 | font-size: 28px; 76 | color: #8c939d; 77 | width: 200px; 78 | height: 140px; 79 | line-height: 140px; 80 | text-align: center; 81 | } 82 | .avatar { 83 | width: 200px; 84 | height: 140px; 85 | display: block; 86 | object-fit: cover; 87 | } 88 | 89 | 90 | 91 | // .content{ 92 | // position: absolute; 93 | // top: 60px; 94 | // bottom: 0; 95 | // overflow: hidden; 96 | // width: 100%; 97 | // padding:20px 40px; 98 | // box-sizing: border-box; 99 | // background: #edeef1; 100 | // display: flex; 101 | // } 102 | // .main{ 103 | // position: relative; 104 | // width: calc(100% - 320px); 105 | // height: 100%; 106 | // display: flex; 107 | // flex-direction: column; 108 | // box-sizing: border-box; 109 | // background: #fff; 110 | // .header_title{ 111 | // padding: 0 20px; 112 | // background: #f7f7f7; 113 | // font-weight: bold; 114 | // display: flex; 115 | // box-sizing: border-box; 116 | // height: 50px; 117 | // align-items: center; 118 | // justify-content: space-between; 119 | // a{ 120 | // color:#000; 121 | // } 122 | // .el-icon-info{ 123 | // color: #3bb3ff; 124 | // font-size: 20px; 125 | // } 126 | // } 127 | // .main-content{ 128 | // width: 100%; 129 | // flex: 1; 130 | // padding:0 40px; 131 | // box-sizing: border-box; 132 | // h4{ 133 | // padding: 40px 0; 134 | // color: #475669; 135 | // } 136 | // } 137 | // .footer{ 138 | // height: 55px; 139 | // padding:30px; 140 | // box-sizing: border-box; 141 | // border-top: 1px solid #f2f2f2; 142 | // width: 100%; 143 | // display: flex; 144 | // align-items: center; 145 | // justify-content: flex-end; 146 | // background: #Fff; 147 | // } 148 | // .el-icon-edit, .el-icon-delete{ 149 | // cursor: pointer; 150 | // padding:5px 0; 151 | // font-size: 20px; 152 | // color:#979797; 153 | // } 154 | // } 155 | .warp 156 | flex 1 157 | .el-tag 158 | margin-right: 8px 159 | 160 | // 弹框表格 161 | .burbox .el-dialog__body { 162 | padding: 0; 163 | } 164 | .tableDialog{ 165 | display: flex; 166 | height: 550px; 167 | .tabs{ 168 | width: 170px; 169 | border-right: 2px solid #f3f8fe; 170 | .nav-title{ 171 | margin-top: 40px; 172 | background: #f7f7f7; 173 | line-height: 40px; 174 | text-indent: 15px; 175 | font-size: 17px; 176 | font-weight: bold; 177 | color: #000; 178 | } 179 | p{ 180 | margin-top: 40px; 181 | background: #f7f7f7; 182 | line-height: 36px; 183 | text-indent: 20px; 184 | color:#20a1ff; 185 | } 186 | .el-menu { 187 | border-right: 0; 188 | .title{ 189 | font-size: 15px; 190 | font-weight: bold; 191 | } 192 | .el-menu-item, .el-submenu__title { 193 | height: 45px; 194 | line-height: 45px; 195 | } 196 | } 197 | } 198 | .burli1{ 199 | width: 400px; 200 | border-right: 2px solid #f3f8fe; 201 | padding: 40px 20px 0 20px; 202 | } 203 | .burli2{ 204 | width: 400px; 205 | margin-bottom: 20px; 206 | padding: 40px 20px 0 20px; 207 | } 208 | .burli3{ 209 | width: 500px; 210 | margin-bottom: 20px; 211 | padding: 40px 20px 0 20px; 212 | } 213 | } 214 | 215 | 216 | i,em{ 217 | font-style: normal; 218 | } 219 | /*颜色*/ 220 | .red{ 221 | color: red; 222 | } 223 | .blue{ 224 | color: #3DB4FF; 225 | } 226 | .success{ 227 | color: #00aa20; 228 | } 229 | .orange{ 230 | color: #fdad00; 231 | } 232 | .zise{ 233 | color: #6a66ff; 234 | } 235 | .bold{ 236 | font-weight: bold; 237 | } 238 | .right{ 239 | float: right; 240 | } 241 | .clear{ 242 | clear:both; 243 | } 244 | /*****全局滚动条样式 ******/ 245 | /*滚动条整体部分,其中的属性有width,height,background,border等(就和一个块级元素一样)(位置1)*/ 246 | .scroll{ 247 | overflow-y: scroll; 248 | } 249 | .scroll::-webkit-scrollbar{ 250 | width:7px; 251 | height:7px; 252 | } 253 | /*滚动条里面可以拖动的那部分(位置5) 主要部分*/ 254 | .scroll::-webkit-scrollbar-thumb{ 255 | // background:-webkit-gradient(linear, 0 0, 0 bottom, from(#85d5fe), to(#207bee)); 256 | border-radius:10px; 257 | background: #c5ced7; 258 | } 259 | // 选择框滚动条 260 | .el-cascader-menu::-webkit-scrollbar{ 261 | width:7px; 262 | height:7px; 263 | } 264 | .el-cascader-menu::-webkit-scrollbar-thumb{ 265 | border-radius:10px; 266 | background: #c5ced7; 267 | } 268 | // 富文本滚动条 269 | .ql-editor{ 270 | overflow-y: scroll; 271 | } 272 | .ql-editor::-webkit-scrollbar{ 273 | width:7px; 274 | height:7px; 275 | } 276 | .ql-editor::-webkit-scrollbar-thumb{ 277 | border-radius:10px; 278 | background: #c5ced7; 279 | } 280 | // 横向滚动条 281 | .scroll-x{ 282 | overflow-x: scroll; 283 | } 284 | .scroll-x::-webkit-scrollbar{ 285 | width:7px; 286 | height:7px; 287 | } 288 | .scroll-x::-webkit-scrollbar-thumb{ 289 | border-radius:10px; 290 | background: #c5ced7; 291 | } 292 | /*表格滚动条*/ 293 | .el-table__body-wrapper::-webkit-scrollbar{ 294 | width:7px; 295 | height:7px; 296 | } 297 | .el-table__body-wrapper::-webkit-scrollbar-thumb{ 298 | background:#c5ced7; 299 | border-radius:10px; 300 | } 301 | // 弹框滚动条 302 | .el-dialog__wrapper::-webkit-scrollbar{ 303 | width:7px; 304 | height:7px; 305 | } 306 | .el-dialog__wrapper::-webkit-scrollbar-thumb{ 307 | background:#c5ced7; 308 | border-radius:10px; 309 | } 310 | /*****全局滚动条样式 ******/ 311 | /* 弹框样式 */ 312 | // .el-dialog__header{ 313 | // background: #f7f7f7; 314 | // } 315 | // .el-dialog__title{ 316 | // font-weight: bold; 317 | // } 318 | .el-dialog__footer { 319 | border-top: 1px solid #f7f7f7; 320 | } 321 | 322 | 323 | 324 | 325 | .el-button--danger { 326 | background-color: #FF546C !important; 327 | border-color: #FF546C !important; 328 | } 329 | .el-button--danger:hover{ 330 | background-color: #ff7488 !important; 331 | } 332 | .el-button--info 333 | background-color: #aa3bce !important 334 | border-color: #aa3bce !important 335 | .el-button--info:hover 336 | background-color: #9b2bbf !important; -------------------------------------------------------------------------------- /src/style/hybrid.styl: -------------------------------------------------------------------------------- 1 | // 代码高亮 2 | .higtlight 3 | .article 4 | h2 5 | font-size 1.5em 6 | h3 7 | font-size 1.4em 8 | h4 9 | font-size 1.3em 10 | h1, h2, h3, h4, h5, h6 11 | position relative 12 | font-family: monospace; 13 | h1:before, 14 | h2:before, 15 | h3:before, 16 | h4:before, 17 | h5:before, 18 | h6:before 19 | content '#' 20 | margin 0 .4rem 21 | color #f72d84 22 | font-family: none 23 | li 24 | list-style: none 25 | line-height: 28px 26 | position relative 27 | li:before 28 | content: '~'; 29 | margin 0 .4rem 30 | color: #f72d84; 31 | img 32 | max-width 100% 33 | display block 34 | margin: 3px 0 12px 35 | p 36 | margin 7px 0 37 | pre 38 | position relative 39 | margin 10px 0 40 | code 41 | margin 0 42 | .hljs 43 | font-size 14px !important 44 | padding 18px !important 45 | color #f7f7f7 !important 46 | background #282a36 !important 47 | border-top 34px solid #222329 !important 48 | -webkit-overflow-scrolling touch 49 | // font-family: inherit 50 | // font-size 15px 51 | pre:before 52 | content ' ' 53 | position absolute 54 | -webkit-border-radius 50% 55 | border-radius 50% 56 | background #ff5f56 57 | width 12px 58 | height 12px 59 | left 20px 60 | margin-top 10px 61 | -webkit-box-shadow 20px 0 #ffbd2e, 40px 0 #27c93f 62 | box-shadow 20px 0 #ffbd2e, 40px 0 #27c93f 63 | z-index 2 64 | // 注释 65 | .hljs-comment, .hljs-quote 66 | color #6272a4 !important 67 | font-style normal !important 68 | // 布尔 69 | .hljs-literal 70 | color #ffde2f !important 71 | // import 72 | .hljs-keyword, .hljs-operator 73 | color #66d9ef !important 74 | 75 | .hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string 76 | color #ae81ff !important 77 | .hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number 78 | color #a6e22e !important 79 | .hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst 80 | color #f92672 !important 81 | .hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title 82 | color #03A9F4 !important 83 | .hljs-built_in, .hljs-class .hljs-title 84 | color #ffae37 !important 85 | 86 | h3, h2 87 | padding 14px 0 5px !important 88 | font-weight: 600 89 | code 90 | background: #ecf0f1 91 | padding: 1px 6px; 92 | border-radius: 3px; 93 | margin 0 3px 94 | color #ef4135 95 | h4 96 | padding 8px 0 4px !important 97 | h5 98 | padding 6px 0 3px !important 99 | blockquote 100 | background: #f5f7f9 101 | padding: 6px 15px !important; 102 | border-left: 4px solid #fb4b87; 103 | margin: 8px 0 20px !important 104 | table 105 | border-spacing 0px 106 | border-collapse collapse 107 | th, td 108 | padding 6px 8px !important 109 | border 1px solid #dadada 110 | min-width: 50px 111 | // word-break: break-all -------------------------------------------------------------------------------- /src/style/index.styl: -------------------------------------------------------------------------------- 1 | body{ 2 | margin:0; 3 | color: #3d4852; 4 | font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 5 | // font-family: "PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 6 | } 7 | .ivu-loading-bar-inner 8 | height 3px !important 9 | a 10 | text-decoration: none 11 | li 12 | list-style: none 13 | .text-center 14 | text-align: center 15 | 16 | 17 | .animate03{ 18 | -webkit-transition-duration:0.3s; 19 | -moz-transition-duration:0.3s; 20 | -ms-transition-duration:0.3s; 21 | transition-duration:0.3s; 22 | transition: transform .3s 23 | } 24 | .animate05{ 25 | -webkit-transition-duration:0.5s; 26 | -moz-transition-duration:0.5s; 27 | -ms-transition-duration:0.5s; 28 | transition-duration:0.5s; 29 | } 30 | .el-textarea__inner 31 | font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; 32 | .flex 33 | display: flex 34 | 35 | main 36 | box-sizing: border-box; 37 | flex:1; 38 | height: 100%; 39 | display: flex; 40 | flex-direction: column; 41 | background: #fff 42 | header 43 | height: 48px; 44 | line-height: 48px; 45 | background: #F7F7F7; 46 | text-indent: 30px; 47 | .wrap 48 | position: relative; 49 | flex: 1; 50 | background: #fff; 51 | padding: 20px 30px; 52 | box-sizing: border-box; 53 | .head{ 54 | height: 60px; 55 | span{ 56 | padding-right: 5px; 57 | } 58 | } 59 | 60 | footer 61 | height: 55px; 62 | box-sizing: border-box; 63 | border-top: 1px solid #f2f2f2; 64 | width: 100%; 65 | display: flex; 66 | align-items: center; 67 | background: #F7f7f7; 68 | .el-button 69 | margin: 0 30px; 70 | 71 | 72 | // banner样式 73 | .banner 74 | position relative 75 | height 450px 76 | width 100% 77 | img 78 | width 100% 79 | position absolute 80 | top 0 81 | object-fit cover 82 | height 100% 83 | .bg 84 | background #848484 85 | mix-blend-mode multiply 86 | height 100% 87 | position absolute 88 | top 0 89 | width 100% 90 | .text-box 91 | position absolute 92 | height 100% 93 | width 100% 94 | padding 20px 95 | font-size 18px 96 | top 0 97 | color #fff 98 | display flex 99 | flex-direction column 100 | align-items center 101 | text-align center 102 | justify-content center 103 | 104 | 105 | .main 106 | flex 1 107 | max-width 940px 108 | margin 60px auto 109 | padding: 0 20px 110 | .el-tag 111 | margin-right: 8px 112 | 113 | // 弹框表格 114 | .burbox .el-dialog__body { 115 | padding: 0; 116 | } 117 | .tableDialog{ 118 | display: flex; 119 | height: 550px; 120 | .tabs{ 121 | width: 170px; 122 | border-right: 2px solid #f3f8fe; 123 | .nav-title{ 124 | margin-top: 40px; 125 | background: #f7f7f7; 126 | line-height: 40px; 127 | text-indent: 15px; 128 | font-size: 17px; 129 | font-weight: bold; 130 | color: #000; 131 | } 132 | p{ 133 | margin-top: 40px; 134 | background: #f7f7f7; 135 | line-height: 36px; 136 | text-indent: 20px; 137 | color:#20a1ff; 138 | } 139 | .el-menu { 140 | border-right: 0; 141 | .title{ 142 | font-size: 15px; 143 | font-weight: bold; 144 | } 145 | .el-menu-item, .el-submenu__title { 146 | height: 45px; 147 | line-height: 45px; 148 | } 149 | } 150 | } 151 | .burli1{ 152 | width: 400px; 153 | border-right: 2px solid #f3f8fe; 154 | padding: 40px 20px 0 20px; 155 | } 156 | .burli2{ 157 | width: 400px; 158 | margin-bottom: 20px; 159 | padding: 40px 20px 0 20px; 160 | } 161 | .burli3{ 162 | width: 500px; 163 | margin-bottom: 20px; 164 | padding: 40px 20px 0 20px; 165 | } 166 | } 167 | 168 | 169 | i,em{ 170 | font-style: normal; 171 | } 172 | .pink 173 | color #f7576c 174 | /*颜色*/ 175 | .red{ 176 | color: red; 177 | } 178 | .blue{ 179 | color: #3DB4FF; 180 | } 181 | .success{ 182 | color: #00aa20; 183 | } 184 | .orange{ 185 | color: #fdad00; 186 | } 187 | .zise{ 188 | color: #6a66ff; 189 | } 190 | .bold{ 191 | font-weight: bold; 192 | } 193 | .right{ 194 | float: right; 195 | } 196 | .clear{ 197 | clear:both; 198 | } 199 | /*****全局滚动条样式 ******/ 200 | /*滚动条整体部分,其中的属性有width,height,background,border等(就和一个块级元素一样)(位置1)*/ 201 | .scroll{ 202 | overflow-y: auto; 203 | } 204 | .scroll::-webkit-scrollbar{ 205 | width:7px; 206 | height:7px; 207 | } 208 | /*滚动条里面可以拖动的那部分(位置5) 主要部分*/ 209 | .scroll::-webkit-scrollbar-thumb{ 210 | // background:-webkit-gradient(linear, 0 0, 0 bottom, from(#85d5fe), to(#207bee)); 211 | border-radius:10px; 212 | background: #c5ced7; 213 | } 214 | 215 | .el-dialog__footer { 216 | border-top: 1px solid #f7f7f7; 217 | } 218 | 219 | 220 | 221 | 222 | 223 | // 输入框颜色 224 | input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill 225 | -webkit-box-shadow 0 0 0 1000px white inset 226 | 227 | -------------------------------------------------------------------------------- /src/style/message.styl: -------------------------------------------------------------------------------- 1 | // 输入框 2 | .input-box 3 | margin 15px 0 4 | display flex 5 | .textbox 6 | flex 1 7 | textarea.ivu-input 8 | resize none 9 | .submit-box 10 | margin-top 15px 11 | display flex 12 | justify-content flex-end 13 | .ykname 14 | flex 1 15 | .userbox 16 | display flex 17 | .user-img 18 | width 60px 19 | margin-right 15px 20 | h4 21 | line-height 26px 22 | font-size 14px 23 | text-align center 24 | color #f7576c 25 | img 26 | width 100% 27 | border-radius 50% 28 | box-shadow 3px 3px 11px #d6d6d6 29 | background: #fff 30 | 31 | .commentList 32 | display flex 33 | font-size 14px 34 | padding 12px 0 35 | .user-ava 36 | width 60px 37 | min-width: 60px; 38 | margin-right 15px 39 | img 40 | width 100% 41 | border-radius 50% 42 | box-shadow 3px 3px 11px #d6d6d6 43 | background: #fff 44 | .comment-box 45 | position relative 46 | line-height 22px 47 | flex 1 48 | min-height 120px 49 | border 1px solid #ecf0f1 50 | border-radius 3px 51 | // width 0 52 | background: #fff; 53 | .username 54 | line-height 30px 55 | font-weight bold 56 | color #f7576c 57 | background #ECF0F1 58 | padding 6px 15px 59 | display flex 60 | align-items center 61 | justify-content space-between 62 | .created 63 | margin-left 10px 64 | font-weight 100 65 | color #7F8C8D 66 | i 67 | margin-right 5px 68 | em 69 | color #009688 70 | .com_detail 71 | padding 15px 25px 72 | font-size 16px 73 | a 74 | word-break: break-all 75 | .floor 76 | flex 0 0 42px 77 | text-align right 78 | .delete 79 | position absolute 80 | right 10px 81 | bottom 7px 82 | font-size 20px 83 | color #657f86 84 | cursor pointer 85 | i 86 | font-size 20px 87 | .comment-box:hover 88 | box-shadow 2px 2px 15px #d2e7fd 89 | .reply 90 | border-bottom 1px solid #ecf0f1 91 | color #8fa0a5 92 | padding 9px 0 93 | margin 0 20px 94 | overflow hidden 95 | text-overflow ellipsis 96 | white-space nowrap 97 | span 98 | font-weight bold 99 | margin 0 5px 100 | color #f7576c 101 | 102 | @media screen and (max-width: 750px) 103 | // .commentList .user-ava 104 | // display none 105 | .commentList .comment-box .username .created 106 | font-family: sans-serif 107 | .comment-box 108 | box-shadow 2px 2px 15px #d2e7fd -------------------------------------------------------------------------------- /src/style/table.styl: -------------------------------------------------------------------------------- 1 | /*表格样式*/ 2 | main .el-table{ 3 | th{ 4 | background: #E5E9F2; 5 | padding:8px 0; 6 | color:#4e5b6c; 7 | text-align: center; 8 | } 9 | th:first-child div{ 10 | border-left:0; 11 | } 12 | td{ 13 | padding:6px 0; 14 | color:#333; 15 | text-align: center; 16 | i{ 17 | font-size: 20px; 18 | color:#888; 19 | margin: 4px 10px; 20 | cursor: pointer; 21 | } 22 | } 23 | .el-table--striped .el-table__body tr.el-table__row--striped td { 24 | background: #fbfbfc; 25 | } 26 | .el-table--enable-row-hover .el-table__body tr:hover>td{ 27 | background-color: #f2f5fb; 28 | } 29 | .el-table--enable-row-hover .el-table__body .current-row:hover>td{ 30 | background-color: #f1f1f1; 31 | } 32 | thead.is-group th { 33 | background: #E5E9F2; 34 | } 35 | // .cell{ 36 | // overflow: hidden; 37 | // text-overflow: ellipsis; 38 | // white-space: nowrap; 39 | // } 40 | } 41 | .el-table--fit{ 42 | border-left:1px solid #ebeef5; 43 | border-right:1px solid #ebeef5; 44 | } 45 | /*加减按钮*/ 46 | main .el-dialog .el-table{ 47 | .el-input-number{ 48 | width: 80px; 49 | height: 24px; 50 | line-height: 24px; 51 | } 52 | .el-input-number__decrease, .el-input-number__increase { 53 | width: 24px; 54 | } 55 | .el-input-number .el-input__inner { 56 | padding-left: 24px; 57 | padding-right: 24px; 58 | } 59 | .el-input__inner{ 60 | height: 24px; 61 | border-radius:0; 62 | line-height: 24px; 63 | } 64 | .el-input-number__decrease, .el-input-number__increase { 65 | height: 22px; 66 | line-height: 22px; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/utils/common.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.prototype.$get = http.get 4 | Vue.prototype.$post = http.post 5 | Vue.prototype.$baseApiUrl = process.env.VUE_APP_API_URL 6 | Vue.prototype.$staticUrl = process.env.VUE_APP_STATIC_URL -------------------------------------------------------------------------------- /src/utils/directive.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const defaultErrorImg = require("@/assets/errorImg.jpg"); 4 | 5 | //全局注册自定义指令,用于判断当前图片是否能够加载成功,可以加载成功则赋值为img的src属性,否则使用默认图片 6 | Vue.directive("imgUrl", function(el, binding) { 7 | let imgURL = binding.value; //获取图片地址 8 | let errorImg = el.getAttribute("error-img"); //获取错误图片地址,如果没有则获取默认的 9 | if (imgURL) { 10 | // 是否http开头 11 | let isHttp = imgURL.indexOf('http') 12 | if (isHttp > -1) { 13 | el.setAttribute("src", imgURL); 14 | } else { 15 | el.setAttribute("src", process.env.VUE_APP_STATIC_URL + imgURL); 16 | } 17 | } else { 18 | el.setAttribute("src", errorImg || defaultErrorImg); 19 | } 20 | }); 21 | 22 | // exist 判断有问题 23 | Vue.directive("real-img", async function(el, binding) { 24 | let imgURL = binding.value; //获取图片地址 25 | let errorImg = el.getAttribute("error-img"); //获取默认图片地址 26 | if (imgURL) { 27 | let exist = await imageIsExist(imgURL); 28 | if (exist) { 29 | el.setAttribute("src", imgURL); 30 | } else { 31 | el.setAttribute("src", errorImg || defaultErrorImg); 32 | } 33 | } 34 | }); 35 | 36 | /** 37 | * 检测图片是否存在 38 | * @param url 39 | */ 40 | let imageIsExist = function(url) { 41 | return new Promise(resolve => { 42 | var img = new Image(); 43 | img.onload = function() { 44 | if (this.complete == true) { 45 | resolve(true); 46 | img = null; 47 | } 48 | }; 49 | img.onerror = function() { 50 | resolve(false); 51 | img = null; 52 | }; 53 | img.src = url; 54 | }); 55 | }; -------------------------------------------------------------------------------- /src/utils/fetch.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import router from '@/router' 3 | // import store from "../store"; 4 | import { Message } from 'element-ui' 5 | import { removeLogin } from './loginStatus' 6 | 7 | // 创建axios实例 8 | const service = axios.create({ 9 | baseURL: process.env.BASE_API, // api的base_url 10 | timeout: 10000, // 请求超时时间 11 | }) 12 | 13 | // request拦截器 14 | service.interceptors.request.use( 15 | config => { 16 | if (config.url == 'apis/authentication/form') { 17 | config.headers['Content-Type'] = 'application/x-www-form-urlencoded' 18 | config.headers['deviceId'] = '9001' 19 | } else { 20 | config.headers['Content-Type'] = 'application/json;charset=utf-8' 21 | // let Authorization = "bearer " + getToken().access_token; 22 | // config.headers["Authorization"] = Authorization; 23 | } 24 | return config 25 | }, 26 | error => { 27 | // Do something with request error 28 | console.log(error) // for debug 29 | Promise.reject(error) 30 | }, 31 | ) 32 | 33 | // respone拦截器 34 | service.interceptors.response.use( 35 | res => { 36 | if (res.data.status == 401) { 37 | Message({ 38 | message: res.data.msg, 39 | type: 'error', 40 | duration: 2000, 41 | onClose() { 42 | removeLogin() 43 | router.push('/admin/login') 44 | }, 45 | }) 46 | return res 47 | } else { 48 | resolve(res) 49 | } 50 | if (res.status == 401) { 51 | Message({ 52 | message: res.data.msg, 53 | type: 'error', 54 | duration: 2000, 55 | onClose() { 56 | // removeToken(); 57 | router.push('/') 58 | }, 59 | }) 60 | return res 61 | } else if (res.status == 500) { 62 | Message({ 63 | message: '服务器错误', 64 | type: 'error', 65 | duration: 2000, 66 | onClose() { 67 | // removeToken(); 68 | router.push('/') 69 | }, 70 | }) 71 | } else { 72 | return res 73 | } 74 | }, 75 | error => { 76 | if (error.response.status == 401) { 77 | Message({ 78 | message: '登录信息过期,请重新登录!', 79 | type: 'error', 80 | duration: 800, 81 | onClose() { 82 | // removeToken(); 83 | router.push('/login') 84 | }, 85 | }) 86 | } 87 | if (error.response.status == 504) { 88 | Message({ 89 | message: '服务器异常!', 90 | type: 'error', 91 | duration: 800, 92 | onClose() { 93 | // removeToken(); 94 | router.push('/login') 95 | }, 96 | }) 97 | } 98 | // Message({ 99 | // message: error.response.data.message, 100 | // type: 'error', 101 | // duration: 5 * 1000 102 | // }) 103 | return Promise.reject(error) 104 | }, 105 | ) 106 | 107 | export default service 108 | 109 | // export default { 110 | // get (_url, _params) { 111 | // return new Promise((resolve, reject) => { 112 | // axios({ 113 | // url: _url, 114 | // method: 'get', 115 | // data: _params || {}, 116 | // headers: { 117 | // 'Content-Type': 'application/x-www-form-urlencoded' 118 | // }, 119 | // transformRequest: [function (data) { 120 | // let ret = '' 121 | // for (let it in data) { 122 | // ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&' 123 | // } 124 | // return ret 125 | // }] 126 | // }).then((res) => { 127 | // if (res.data.status == 401) { 128 | // Message({ 129 | // message: res.data.msg, 130 | // type: "error", 131 | // duration: 2000, 132 | // onClose() { 133 | // removeLogin(); 134 | // router.push("/admin/login"); 135 | // } 136 | // }) 137 | // } else { 138 | // resolve(res); 139 | // } 140 | // }).catch((error) => { 141 | // reject(error) 142 | // }) 143 | // }) 144 | // }, 145 | // post (_url, _params) { 146 | // return new Promise((resolve, reject) => { 147 | // axios({ 148 | // url: _url, 149 | // method: 'post', 150 | // data: _params || {}, 151 | // headers: { 152 | // 'Content-Type': 'application/json;charset=UTF-8' 153 | // }, 154 | // timeout: 20000 155 | // }).then((res) => { 156 | // if (res.data.status == 401) { 157 | // Message({ 158 | // message: res.data.msg, 159 | // type: "error", 160 | // duration: 2000, 161 | // onClose() { 162 | // removeLogin(); 163 | // router.push("/admin/login"); 164 | // } 165 | // }) 166 | // } else { 167 | // resolve(res) 168 | // } 169 | // }).catch((error) => { 170 | // reject(error) 171 | // }) 172 | // }) 173 | // } 174 | // } 175 | -------------------------------------------------------------------------------- /src/utils/httpIndex.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import router from '@/modules/index/router/router' 3 | import { Notice } from 'iview' 4 | import store from "../store/index" 5 | // import baseURL from '@/api/baseUrlConfig' 6 | 7 | // 配置开发和生产的请求接口 8 | const service = axios.create({ 9 | // baseURL: baseURL.api_url, 10 | timeout: 20000 11 | }) 12 | 13 | // 设置header请求头,发起请求前做的事情 14 | service.interceptors.request.use( 15 | config => { 16 | if (store.state.user.token) { 17 | config.headers['Authorization'] = 'Bearer ' + store.state.user.token 18 | } 19 | config.headers['X-Requested-With'] = 'XMLHttpRequest' 20 | return config 21 | }, 22 | error => { 23 | // console.log(error) // for debug 24 | Promise.reject(error) 25 | }, 26 | ) 27 | 28 | // respone拦截器,发起请求后做的事情 29 | service.interceptors.response.use((res) => { 30 | // 当有新的token时自动更新新的token 31 | if (res.headers.authorization) { 32 | let token = res.headers.authorization.split(' ')[1] 33 | store.dispatch("Token", token); 34 | } 35 | 36 | // window.vm.$loading.hide() 37 | // 统一处理错误 38 | // 在这里对返回的数据进行处理 39 | if (res.data.status == 'success') { 40 | // return res.data 41 | return Promise.resolve(res.data) 42 | } else { 43 | Notice.error({ 44 | title: '错误提示', 45 | desc: res.data.message, 46 | duration: 2 47 | }) 48 | } 49 | // return res.data 50 | // 打印错误信息 51 | return Promise.reject(res.data) 52 | }, (error) => { 53 | if (error.response.status == 401) { 54 | // 登录过期 55 | Notice.warning({ 56 | title: '登录提示', 57 | desc: error.response.data.message, 58 | duration: 2, 59 | onClose () { 60 | store.dispatch("Logout"); 61 | // router.push({ 62 | // path: '/login', 63 | // query: { redirect: window.location.hash.substr(1) } 64 | // }) 65 | }, 66 | }); 67 | } else if (error.response.status == 422) { 68 | // token过期 69 | Notice.warning({ 70 | title: '温馨提示', 71 | desc: error.response.data.message, 72 | duration: 2, 73 | onClose () { 74 | store.dispatch("Logout") 75 | }, 76 | }); 77 | // setTimeout(() => { 78 | // router.push({ 79 | // path: "/login", 80 | // query: { redirect: window.location.hash.substr(1) } 81 | // }); 82 | // }, 1500) 83 | } else if (error.response.status == 403) { 84 | // 没有权限 85 | Notice.warning({ 86 | title: '用户权限提示', 87 | desc: error.response.data.message, 88 | duration: 2, 89 | onClose () { 90 | store.dispatch("Logout"); 91 | router.push('/login') 92 | }, 93 | }); 94 | } else if (error.response.status == 500) { 95 | // 服务器连接失败 96 | Notice.error({ 97 | title: '网络提示', 98 | desc: '服务器连接失败,请稍后再试', 99 | duration: 2, 100 | }); 101 | } else { 102 | Notice.error({ 103 | title: '错误提示 ' + error.response.status, 104 | desc: error.response.data.message, 105 | duration: 2, 106 | }); 107 | } 108 | return Promise.reject(error) 109 | }, 110 | ) 111 | 112 | 113 | export default service 114 | -------------------------------------------------------------------------------- /src/utils/httpManage.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import router from '@/modules/manage/router/router' 3 | import { Notice } from 'iview' 4 | // import { removeLogin } from './loginStatus' 5 | import store from "../store/index" 6 | 7 | // 配置开发和生产的请求接口 8 | const service = axios.create({ 9 | // baseURL: process.env.VUE_APP_URL, 10 | timeout: 10000 11 | }) 12 | 13 | // 设置header请求头,发起请求前做的事情 14 | service.interceptors.request.use( 15 | config => { 16 | config.headers['Authorization'] = 'Bearer ' + store.state.user.token 17 | config.headers['X-Requested-With'] = 'XMLHttpRequest' 18 | return config 19 | }, 20 | error => { 21 | // console.log(error) // for debug 22 | Promise.reject(error) 23 | }, 24 | ) 25 | 26 | // respone拦截器,发起请求后做的事情 27 | service.interceptors.response.use( 28 | res => { 29 | // 当有新的token时自动更新新的token 30 | if (res.headers.authorization) { 31 | let token = res.headers.authorization.split(' ')[1] 32 | store.dispatch("Token", token); 33 | } 34 | 35 | // window.vm.$loading.hide() 36 | // 统一处理错误 37 | // 在这里对返回的数据进行处理 38 | if (res.data.status == 'success') { 39 | return Promise.resolve(res.data) 40 | } else { 41 | Notice.error({ 42 | title: '错误提示', 43 | desc: res.data.message, 44 | duration: 2 45 | }) 46 | } 47 | return Promise.reject(res.data) 48 | }, 49 | error => { 50 | if (error.response.status == 401) { 51 | // 登录过期 52 | Notice.warning({ 53 | title: '登录提示', 54 | desc: error.response.data.message, 55 | duration: 2, 56 | onClose () { 57 | store.dispatch("Logout"); 58 | router.push({ 59 | path: '/login', 60 | query: { redirect: window.location.hash.substr(1) } 61 | }) 62 | }, 63 | }); 64 | } else if (error.response.status == 422) { 65 | // token过期 66 | Notice.warning({ 67 | title: '温馨提示', 68 | desc: error.response.data.message, 69 | duration: 2, 70 | onClose () { 71 | store.dispatch("Logout") 72 | router.push({ 73 | path: '/login', 74 | query: { redirect: window.location.hash.substr(1) } 75 | }) 76 | }, 77 | }); 78 | } else if (error.response.status == 403) { 79 | // 没有权限 80 | Notice.warning({ 81 | title: '用户权限提示', 82 | desc: error.response.data.message, 83 | duration: 2, 84 | onClose () { 85 | store.dispatch("Logout"); 86 | router.push('/login') 87 | }, 88 | }); 89 | } else if (error.response.status == 500) { 90 | // 服务器链接失败 91 | Notice.error({ 92 | title: '网络提示', 93 | desc: '服务器连接失败,请稍后再试', 94 | duration: 2, 95 | }); 96 | } else { 97 | Notice.error({ 98 | title: '错误提示 ' + error.response.status, 99 | desc: error.response.data.message, 100 | duration: 2, 101 | }); 102 | } 103 | return Promise.reject(error) 104 | }, 105 | ) 106 | 107 | 108 | export default service 109 | -------------------------------------------------------------------------------- /src/utils/loginStatus.js: -------------------------------------------------------------------------------- 1 | import store from "../store/index"; 2 | 3 | export function Logout() { 4 | store.commit("LOGOUT"); 5 | } 6 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | function resolve (dir) { 3 | return path.join(__dirname, dir); 4 | } 5 | 6 | const CompressionWebpackPlugin = require('compression-webpack-plugin'); 7 | const productionGzipExtensions = ['js', 'css']; 8 | const isProduction = process.env.NODE_ENV === 'production'; 9 | 10 | module.exports = { 11 | // outputDir: process.env.VUE_APP_OUTPUT_DIR, 12 | publicPath: "./", 13 | assetsDir: "static", 14 | outputDir: "dist", 15 | pages: { 16 | index: { 17 | // 应用入口配置,相当于单页面应用的main.js,必需项 18 | entry: "src/modules/index/main.js", 19 | // 应用的模版,相当于单页面应用的public/index.html,可选项,省略时默认与模块名一致 20 | template: "public/index.html", 21 | // 编译后在dist目录的输出文件名,可选项,省略时默认与模块名一致 22 | filename: "index.html", 23 | // 标题,可选项,一般情况不使用,通常是在路由切换时设置title 24 | // 需要注意的是使用title属性template 中的 title 标签需要是 <%= htmlWebpackPlugin.options.title %> 25 | title: "index page", 26 | // 包含的模块,可选项 27 | chunks: ["chunk-vendors", "chunk-common", "index"] 28 | }, 29 | manage: { 30 | entry: "src/modules/manage/main.js", 31 | template: "public/manage.html", 32 | filename: "manage.html", 33 | title: "manage page", 34 | chunks: ["chunk-vendors", "chunk-common", "manage"] 35 | } 36 | }, 37 | lintOnSave: false, 38 | productionSourceMap: false, 39 | 40 | // 文件路径缩写 41 | chainWebpack: config => { 42 | config.resolve.alias 43 | // key,value自行定义,比如.set('@assets', resolve('src/assets')) 44 | .set("style", resolve("src/style")) 45 | .set("utils", resolve("src/utils")) 46 | .set("store", resolve("src/store")) 47 | .set("plugins", resolve("src/plugins")) 48 | .set("components", resolve("src/components")) 49 | .set("assets", resolve("src/assets")) 50 | .set("api", resolve("src/api")) 51 | .set("modules", resolve("src/modules")); 52 | }, 53 | devServer: { 54 | sockHost: "localhost", 55 | disableHostCheck: true, 56 | port: 7000, // 端口号 57 | host: "0.0.0.0", 58 | // https: false, // https:{type:Boolean} 59 | open: true, //配置自动启动浏览器 60 | proxy: { 61 | "/apis": { 62 | // target: "http://127.0.0.1:8080/api/v2", // 需要请求的地址 63 | // target: "http://114.132.76.194:8100/api/v2", // 生产环境 64 | target: "https://api.golang365.top/api/v2", // 生产环境 65 | // target: process.env.VUE_APP_URL, // 需要请求的地址 66 | changeOrigin: true, // 是否跨域 67 | pathRewrite: { 68 | "^/apis": "" // 替换target中的请求地址,也就是说,在请求的时候,url用'/proxy'代替'http://ip.taobao.com' 69 | } 70 | } 71 | } 72 | }, 73 | // 启动gzip压缩 74 | configureWebpack: config => { 75 | if (isProduction) { 76 | config.plugins.push( 77 | // 超过10kb的压缩gzip 78 | new CompressionWebpackPlugin({ 79 | algorithm: "gzip", 80 | test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"), 81 | threshold: 10240, 82 | minRatio: 0.8 83 | }) 84 | ); 85 | } 86 | } 87 | }; 88 | -------------------------------------------------------------------------------- /vue.config.twoEntry.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | function resolve(dir) { 3 | return path.join(__dirname, dir); 4 | } 5 | 6 | const CompressionWebpackPlugin = require('compression-webpack-plugin'); 7 | const productionGzipExtensions = ['js', 'css']; 8 | const isProduction = process.env.NODE_ENV === 'production'; 9 | 10 | 11 | let objectProject = { 12 | index: { 13 | // 应用入口配置,相当于单页面应用的main.js,必需项 14 | entry: "src/modules/index/main.js", 15 | // 应用的模版,相当于单页面应用的public/index.html,可选项,省略时默认与模块名一致 16 | template: "public/index.html", 17 | // 编译后在dist目录的输出文件名,可选项,省略时默认与模块名一致 18 | filename: "index.html", 19 | // 标题,可选项,一般情况不使用,通常是在路由切换时设置title 20 | // 需要注意的是使用title属性template 中的 title 标签需要是 <%= htmlWebpackPlugin.options.title %> 21 | title: "index page", 22 | // 包含的模块,可选项 23 | chunks: ["chunk-vendors", "chunk-common", "index"] 24 | }, 25 | manage: { 26 | entry: "src/modules/manage/main.js", 27 | template: "public/manage.html", 28 | filename: "manage.html", 29 | title: "manage page", 30 | chunks: ["chunk-vendors", "chunk-common", "manage"] 31 | } 32 | } 33 | let page = {}; 34 | let projectname = process.argv[3]; // 获取执行哪个文件 35 | if (process.env.NODE_ENV == "development") { 36 | page = objectProject; 37 | } else { 38 | page[projectname] = objectProject[projectname]; 39 | } 40 | 41 | module.exports = { 42 | publicPath: "./", 43 | outputDir: "dist" + projectname, //标识是打包哪个文件 44 | //默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存。如果你无法使用 Vue CLI 生成的 index HTML,你可以通过将这个选项设为 false 来关闭文件名哈希。 45 | filenameHashing: true, 46 | pages: page, 47 | lintOnSave: false, 48 | productionSourceMap: false, 49 | // 文件路径缩写 50 | chainWebpack: config => { 51 | config.resolve.alias 52 | // key,value自行定义,比如.set('@assets', resolve('src/assets')) 53 | .set("style", resolve("src/style")) 54 | .set("utils", resolve("src/utils")) 55 | .set("store", resolve("src/store")) 56 | .set("plugins", resolve("src/plugins")) 57 | .set("components", resolve("src/components")) 58 | .set("assets", resolve("src/assets")) 59 | .set("modules", resolve("src/modules")); 60 | }, 61 | devServer: { 62 | sockHost: "localhost", 63 | disableHostCheck: true, 64 | port: 9000, // 端口号 65 | host: "0.0.0.0", 66 | https: false, // https:{type:Boolean} 67 | open: true, //配置自动启动浏览器 68 | proxy: { 69 | "/apis": { 70 | target: "http://127.0.0.1:8080/api/v2", // 需要请求的地址 71 | // target: process.env.VUE_APP_URL, // 需要请求的地址 72 | changeOrigin: true, // 是否跨域 73 | pathRewrite: { 74 | "^/apis": "" // 替换target中的请求地址,也就是说,在请求的时候,url用'/proxy'代替'http://ip.taobao.com' 75 | } 76 | } 77 | } 78 | }, 79 | // 启动gzip压缩 80 | configureWebpack: config => { 81 | if (isProduction) { 82 | config.plugins.push( 83 | // 超过10kb的压缩gzip 84 | new CompressionWebpackPlugin({ 85 | algorithm: "gzip", 86 | test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"), 87 | threshold: 10240, 88 | minRatio: 0.8 89 | }) 90 | ); 91 | } 92 | } 93 | }; 94 | --------------------------------------------------------------------------------