diff --git a/.DS_Store b/.DS_Store index 8f052a65..0fb6f821 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/README.md b/README.md index ded117d6..89b47226 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,48 @@ # vue2-blog -![image](https://img.shields.io/badge/vue-2.5.9-blue.svg) +![image](https://img.shields.io/badge/vue-2.5.13-blue.svg) ![image](https://img.shields.io/badge/vue--router-3.0.1-blue.svg) ![image](https://img.shields.io/badge/vuex-3.0.1-blue.svg) -![image](https://img.shields.io/badge/element--ui-2.0.7-blue.svg) +![image](https://img.shields.io/badge/element--ui-2.0.11-blue.svg) -#### 还在开发,敬请期待! (已完成90%) -> 你的 "star" 是我最大的动力!🌹 - - -## 前言 - -该项目是基于 vue全家桶 + element-ui组件库,构建的一个后台类应用模板,也是一个后台应用实例。目的是为了帮助开发人员快速的搭建基于 vue-cli 开发的后台应用和vue学习者参考学习。 - - -## 说明 -> 如果对您有帮助,您可以点右上角 "star"一下!非常感谢!^_^ 🌹 - -> 或者您可以 "follow(关注)" 作者,我会不断开源更多实用的项目。 - -> 如有问题可以直接在 Issues 中提,或者加入我们下方的vue群更进一步地交流。 - - -## 其他开源项目 -- 第一阶段:echo回声(移动端,难度:简单 ~ 中等) —— [仓库地址](https://github.com/uncleLian/vue2-echo) —— [演示地址](http://echo.liansixin.win) - -- 第二阶段:今日头条(移动端 & native,难度:困难) —— [仓库地址](https://github.com/uncleLian/vue2-news) —— [web演示地址](http://toutiao.liansixin.win), [native端演示地址](http://native.liansixin.win) - -- 第三阶段:头条号(pc端,难度:中等 ~ 困难) —— [仓库地址](https://github.com/uncleLian/vue2-health) —— [演示地址](http://health.liansixin.win) (还在开发,敬请期待!已实现核心功能) +## 简介 +vue2-blog 是一个后台集成解决方案,它基于 [vue.js](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)。使用了最新的前端技术栈。内置登录、动态路由、I18n国际化等功能特性。目的是为了帮助开发人员快速搭建后台应用和vue学习者参考学习。 ## 项目演示 #### [演示地址](http://blog.liansixin.win) - -## 基本功能 -##### 1、element ui 组件库(完成) -##### 2、登录登出(完成) -##### 3、根据路由表递归生成侧边栏(可配置图标、登录、展开子菜单等)(完成) -##### 4、根据当前路由生成面包屑(完成) -##### 5、统一的API请求、拦截以及错误处理(完成) -##### 6、自动匹配开发环境和生产环境的请求链接(完成) -##### 7、没有相匹配的路由将跳转至404页面(完成) -##### 8、全局捕捉错误信息(完成) -##### 9、面包屑、图钉、返回顶部(完成) - -## 自定义组件 -##### 1、面包屑:breadcrumb.vue(完成) -##### 2、图钉:sticky.vue(完成) -##### 3、返回顶部:backTop.vue(完成) -##### 4、动态数值:countTo.vue(完成) -##### 5、加载提示:loading.vue(完成) - -## 集成功能 -##### 1、进度条(完成) -##### 2、剪贴板(完成) -##### 3、导入导出 excel 文件(完成) -##### 4、图表echarts(完成) -##### 5、富文本编辑器(完成) -##### 6、Markdown(完成) -##### 7、国际化(完成) -##### 8、换肤(完成) -##### 9、第三方登录 - -## 综合实例 -##### 1、拖拽列表(完成) -##### 2、拖拽表格(完成) -##### 3、自定义图片上传、草稿、预览等(完成) - -## 更多 -##### 1、404 页面(完成) -##### 2、错误日志(完成) - -## 第三方依赖 -##### 1、[element-ui](https://github.com/ElemeFE/element)(UI组件库) -##### 2、[axios](https://github.com/axios/axios)(请求库) -##### 3、[vue-progressbar](https://github.com/hilongjw/vue-progressbar)(进度条) -##### 4、[vue-quill-editor](https://github.com/surmon-china/vue-quill-editor)(富文本编辑器) -##### 5、[vuedraggable](https://github.com/SortableJS/Vue.Draggable)(基于sortablejs的vue的拖拽库) -##### 6、[sortablejs](https://github.com/RubaXa/Sortable)(拖拽库) -##### 7、[vue-clipboard-pack](https://github.com/uncleLian/vue-clipboard-pack)(本人基于clipboard.js封装的剪贴板) -##### 8、[mockjs](https://github.com/nuysoft/Mock/tree/refactoring)(数据模拟) -##### 9、[font-awesome](http://fontawesome.io/icons/)(字体库) -##### 10、babel-polyfill(JS语法库,修复IE不支持语法问题) -##### 11、[js-cookie](https://github.com/js-cookie/js-cookie)(方便处理cookie的JS库) -##### 12、[stylus](https://github.com/stylus/stylus) stylus-loader(css预处理器) -##### 13、less less-loader(css预处理器) -##### 14、[js-xlsx](https://github.com/SheetJS/js-xlsx)(电子表格处理库) -##### 15、[simplemde](https://github.com/sparksuite/simplemde-markdown-editor)(Markdown编辑器) -##### 16、[showdown](https://github.com/showdownjs/showdown)(Markdown转换成HTML的库) -##### 17、[vue-i18n](https://github.com/showdownjs/showdown)(实现多语言的库) +## 功能 +- [x] 登录/注销 +- [x] 多环境发布 +- [x] 前端mock数据 +- [x] 动态侧边栏(支持多级路由和一键配置图标、登录、展开、缓存等选项) +- [x] 动态面包屑 +- [x] 动态换肤(实现element-ui官网的换肤功能) +- [x] 国际化多语言(中文、English) +- [x] 进度条 +- [x] [剪贴板](https://github.com/uncleLian/vue-clipboard-pack)(另一个项目,打个广告~) +- [x] 富文本编辑器(自定义图片上传、草稿、预览等) +- [x] Markdown编辑器(搭配Markdown语法转HTML功能) +- [x] 导入.md文件 +- [x] 导入导出Excel +- [x] Echarts 图表 +- [x] 拖拽列表、表格 +- [x] 404页面 +- [x] 错误日志(全局错误捕捉) +- [x] Iconfont图标 +- [x] 图钉 +- [x] 返回顶部 +- [x] 动态数值 +- [x] 加载提示(3种状态:加载中,无数据,出现错误且支持点击重新请求) + +##### 待更新 +- [ ] 权限验证 +- [ ] 文档 + +## 部分截图 + + ## 安装运行 @@ -97,21 +50,42 @@ # install dependencies npm install -# serve with hot reload at localhost:8084 or localhost:8020 +# serve with hot reload at localhost:8020 npm run dev # build for production with minification -npm run build +npm run build(File in the docs folder) ``` -## 交流 +## 更新日志 +[发行说明](https://github.com/uncleLian/vue2-blog/releases)中记录了每个版本的详细更改。 +## 传送门 +- 第一阶段:echo回声(移动端,难度:简单,入门项目) —— [仓库地址](https://github.com/uncleLian/vue2-echo) —— [演示地址](http://echo.liansixin.win) + +- 第二阶段:今日头条(移动端 & native,难度:困难,进阶项目) —— [仓库地址](https://github.com/uncleLian/vue2-news) —— [web演示地址](http://toutiao.liansixin.win), [native端演示地址](http://native.liansixin.win) + +- 第三阶段:头条号(pc端,难度:中等,过渡项目) —— [仓库地址](https://github.com/uncleLian/vue2-health) —— [演示地址](http://health.liansixin.win) (还在开发,敬请期待!已实现核心功能) + + +## 说明 +> 如果对您有帮助,你可以点右上角 "star"支持一下🌹 + +> 或者您可以 "follow(关注)" 作者,我正在不断开源更多实用的项目。 + +> 如有问题可以直接在 Issues 中提,或者加入我们下方的vue群更进一步地交流。 + + +## 交流 欢迎热爱学习、忠于分享的朋友一起来交流 - QQ:771674109 - Vue交流群:338241465 —— 广州-小鑫 -## License +## 捐赠 + + +## License [MIT](http://opensource.org/licenses/MIT) Copyright (c) 2017-present,uncleLian diff --git a/screenshots/donate.jpg b/screenshots/donate.jpg new file mode 100644 index 00000000..78e1da73 Binary files /dev/null and b/screenshots/donate.jpg differ diff --git a/screenshots/home.jpg b/screenshots/home.jpg new file mode 100644 index 00000000..2613b8a4 Binary files /dev/null and b/screenshots/home.jpg differ diff --git a/screenshots/login.jpg b/screenshots/login.jpg new file mode 100644 index 00000000..aeef8df9 Binary files /dev/null and b/screenshots/login.jpg differ diff --git a/src/api/index.js b/src/api/index.js index 7b30f43f..07de5e23 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,5 +1,10 @@ import { request, instance } from '@/utils/request' +// Tip: +// 1、request方法适用于普遍的GET、POST方法 +// 2、instance方法适用于需要做特殊处理的请求,如:自定义Header、其他的http方法等 +// 3、使用解构参数,方便阅读和管理。 + // 登录 export function getLogin(form) { let res = request('/login', 'POST', form) @@ -19,7 +24,7 @@ export function getList() { } // 图片 -export async function getPicture(data) { - let res = await instance.get('http://api.toutiaojk.com/e/extend/jkh/picsearch', { params: data }) +export async function getPicture({key, page}) { + let res = await instance.get('http://api.toutiaojk.com/e/extend/jkh/picsearch', { params: {key, page} }) return res.data } diff --git a/src/main.js b/src/main.js index 92b208d7..fefa88f3 100644 --- a/src/main.js +++ b/src/main.js @@ -70,25 +70,26 @@ Object.keys(filters).forEach(key => { // 全局路由登录验证 router.beforeEach((to, from, next) => { - let token = cache.getToken() - if (to.path === '/login' && token) { - next('/') - } else if (to.matched.some(record => record.meta.login)) { - if (token) { - if (store.getters.user) { - next() + if (to.matched.some(record => record.meta.login)) { + if (cache.getToken()) { + if (to.path === '/login') { + next('/') } else { - store.dispatch('get_user_data') - .then(res => { + if (store.getters.user) { next() - }) - .catch(() => { - window.alert('账号在别处登录,请重新登录') - next({ - path: '/login', - query: { redirect: to.fullPath } + } else { + store.dispatch('get_user_data').then(() => { + next() }) - }) + .catch(() => { + // 可根据错误信息,做相应需求,这里默认token值失效 + window.alert('登录已失效,请重新登录') + next({ + path: '/login', + query: { redirect: to.fullPath } + }) + }) + } } } else { next({ diff --git a/src/mock/index.js b/src/mock/index.js index 6bea216a..f88df1fd 100644 --- a/src/mock/index.js +++ b/src/mock/index.js @@ -1,5 +1,6 @@ /* eslint-disable */ var Mock = require('mockjs') + // 开发测试数据 // 登录 Mock.mock('http://blog.liansixin.win/api-dev/login', { @@ -7,8 +8,13 @@ Mock.mock('http://blog.liansixin.win/api-dev/login', { }) // 用户信息 Mock.mock('http://blog.liansixin.win/api-dev/user', { - nickname: '思鑫', - headimgurl: 'https://avatars1.githubusercontent.com/u/25951301?s=40&v=4' + code: 200, + msg: 'success', + data: { + nickname: '思鑫', + headimgurl: 'https://avatars1.githubusercontent.com/u/25951301?s=40&v=4', + role: 'admin' + } }) // 列表 Mock.mock('http://blog.liansixin.win/api-dev/list', { @@ -2199,7 +2205,8 @@ Mock.mock('http://blog.liansixin.win/api-prod/login', { // 用户信息 Mock.mock('http://blog.liansixin.win/api-prod/user', { nickname: 'uncleLian', - headimgurl: 'https://avatars1.githubusercontent.com/u/25951301?s=40&v=4' + headimgurl: 'https://avatars1.githubusercontent.com/u/25951301?s=40&v=4', + role: 'admin' }) // 列表 Mock.mock('http://blog.liansixin.win/api-prod/list', { diff --git a/src/page/index/children/home/components/homeTable.vue b/src/page/index/children/home/components/homeTable.vue index 267c596c..80a07464 100644 --- a/src/page/index/children/home/components/homeTable.vue +++ b/src/page/index/children/home/components/homeTable.vue @@ -60,7 +60,7 @@ export default { mounted() { getList().then(res => { if (res) { - this.tableJson = res.data.slice(0, 6) + this.tableJson = res.data.slice(0, 7) } }) } diff --git a/src/router/index.js b/src/router/index.js index 8e5b0d1d..8376fe45 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -268,8 +268,14 @@ export const routes = [ component: login }, { - path: '*', + name: '404', + path: '/404', + meta: { login: true }, component: page404 + }, + { + path: '*', + redirect: '/404' } ] diff --git a/src/store/index.js b/src/store/index.js index 2a794320..db8e818a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -7,10 +7,10 @@ import i18n from '@/language' Vue.use(Vuex) const state = { - user: '', - logs: [], - language: 'zh', - theme: '#42B983' + user: '', // 用户信息 + logs: [], // 错误日志 + language: 'zh', // 语言 + theme: '#42B983' // 主题颜色 } const getters = { @@ -42,12 +42,12 @@ const actions = { async get_login_data({ commit }, params) { return new Promise((resolve, reject) => { getLogin(params).then(res => { - // console.log('token', res) + // console.log('login', res) if (res && res.token) { cache.setToken(res.token) resolve() } else { - reject(new Error('nothing data')) + reject(new Error('nothing login data')) } }) .catch(err => { @@ -59,9 +59,10 @@ const actions = { async get_user_data({ commit }, token) { return new Promise((resolve, reject) => { getUser(token).then(res => { - if (res) { - commit('set_user', res) - resolve() + // console.log('user', res) + if (res && res.code === 200 && res.data) { + commit('set_user', res.data) + resolve(res) } else { reject(new Error('nothing user data')) }