├── bin ├── build.bat ├── package.bat └── run-web.bat ├── babel.config.js ├── src ├── views │ ├── content │ │ └── blog │ │ │ ├── page.vue │ │ │ ├── components │ │ │ └── Dropdown │ │ │ │ ├── index.js │ │ │ │ ├── SourceUrl.vue │ │ │ │ ├── Comment.vue │ │ │ │ └── Platform.vue │ │ │ ├── add.vue │ │ │ └── edit.vue │ ├── system │ │ ├── log │ │ │ └── index.vue │ │ └── user │ │ │ └── profile │ │ │ ├── userInfo.vue │ │ │ └── resetPwd.vue │ ├── redirect.vue │ ├── components │ │ └── icons │ │ │ ├── svg-icons.js │ │ │ └── index.vue │ ├── monitor │ │ └── druid │ │ │ └── index.vue │ ├── tool │ │ ├── swagger │ │ │ └── index.vue │ │ └── gen │ │ │ └── basicInfoForm.vue │ ├── dashboard │ │ ├── mixins │ │ │ └── resize.js │ │ ├── PieChart.vue │ │ └── BarChart.vue │ ├── error │ │ └── 401.vue │ └── index.vue ├── assets │ ├── logo │ │ └── logo.png │ ├── 401_images │ │ └── 401.gif │ ├── 404_images │ │ ├── 404.png │ │ └── 404_cloud.png │ ├── image │ │ ├── profile.jpg │ │ └── login-background.jpg │ ├── icons │ │ ├── svg │ │ │ ├── chart.svg │ │ │ ├── size.svg │ │ │ ├── link.svg │ │ │ ├── guide.svg │ │ │ ├── money.svg │ │ │ ├── email.svg │ │ │ ├── drag.svg │ │ │ ├── documentation.svg │ │ │ ├── fullscreen.svg │ │ │ ├── lock.svg │ │ │ ├── user.svg │ │ │ ├── excel.svg │ │ │ ├── example.svg │ │ │ ├── star.svg │ │ │ ├── slider.svg │ │ │ ├── table.svg │ │ │ ├── search.svg │ │ │ ├── education.svg │ │ │ ├── tab.svg │ │ │ ├── message.svg │ │ │ ├── switch.svg │ │ │ ├── theme.svg │ │ │ ├── druid.svg │ │ │ ├── code.svg │ │ │ ├── peoples.svg │ │ │ ├── input.svg │ │ │ ├── server.svg │ │ │ ├── textarea.svg │ │ │ ├── time.svg │ │ │ ├── edit.svg │ │ │ ├── nested.svg │ │ │ ├── row.svg │ │ │ ├── monitor.svg │ │ │ ├── tree-table.svg │ │ │ ├── eye.svg │ │ │ ├── build.svg │ │ │ ├── clipboard.svg │ │ │ ├── list.svg │ │ │ ├── download.svg │ │ │ ├── icon.svg │ │ │ ├── international.svg │ │ │ ├── question.svg │ │ │ ├── wechat.svg │ │ │ ├── skill.svg │ │ │ ├── people.svg │ │ │ ├── post.svg │ │ │ ├── language.svg │ │ │ ├── checkbox.svg │ │ │ ├── eye-open.svg │ │ │ ├── validCode.svg │ │ │ ├── radio.svg │ │ │ ├── select.svg │ │ │ ├── gitee.svg │ │ │ ├── upload.svg │ │ │ ├── 404.svg │ │ │ ├── zip.svg │ │ │ ├── phone.svg │ │ │ ├── log.svg │ │ │ ├── bug.svg │ │ │ ├── github.svg │ │ │ ├── pdf.svg │ │ │ ├── logininfor.svg │ │ │ ├── rate.svg │ │ │ ├── job.svg │ │ │ ├── exit-fullscreen.svg │ │ │ ├── tree.svg │ │ │ ├── swagger.svg │ │ │ ├── password.svg │ │ │ ├── date-range.svg │ │ │ ├── shopping.svg │ │ │ ├── cascader.svg │ │ │ ├── dashboard.svg │ │ │ ├── component.svg │ │ │ ├── form.svg │ │ │ └── tool.svg │ │ ├── index.js │ │ └── svgo.yml │ └── styles │ │ ├── variables.scss │ │ ├── element-variables.scss │ │ ├── transition.scss │ │ ├── element-ui.scss │ │ ├── mixin.scss │ │ └── btn.scss ├── App.vue ├── api │ ├── menu.js │ ├── monitor │ │ ├── server.js │ │ ├── online.js │ │ ├── operlog.js │ │ ├── jobLog.js │ │ ├── logininfor.js │ │ └── job.js │ ├── content │ │ ├── requestlog.js │ │ ├── comment.js │ │ ├── tag.js │ │ ├── type.js │ │ ├── friend.js │ │ └── blog.js │ ├── login.js │ ├── system │ │ ├── notice.js │ │ ├── post.js │ │ ├── dept.js │ │ ├── menu.js │ │ ├── dict │ │ │ ├── type.js │ │ │ └── data.js │ │ ├── config.js │ │ └── role.js │ └── tool │ │ └── gen.js ├── layout │ ├── components │ │ ├── index.js │ │ ├── Sidebar │ │ │ ├── Item.vue │ │ │ ├── FixiOSBug.js │ │ │ ├── Link.vue │ │ │ ├── index.vue │ │ │ └── Logo.vue │ │ └── AppMain.vue │ └── mixin │ │ └── ResizeHandler.js ├── directive │ ├── waves │ │ ├── index.js │ │ ├── waves.css │ │ └── waves.js │ └── permission │ │ ├── index.js │ │ ├── hasRole.js │ │ └── hasPermi.js ├── components │ ├── IconSelect │ │ ├── requireIcons.js │ │ └── index.vue │ ├── RuoYi │ │ ├── Doc │ │ │ └── index.vue │ │ └── Git │ │ │ └── index.vue │ ├── Tinymce │ │ ├── toolbar.js │ │ ├── plugins.js │ │ └── dynamicLoadScript.js │ ├── Screenfull │ │ └── index.vue │ ├── Hamburger │ │ └── index.vue │ ├── SvgIcon │ │ └── index.vue │ ├── SizeSelect │ │ └── index.vue │ ├── Sticky │ │ └── index.vue │ ├── Breadcrumb │ │ └── index.vue │ └── Pagination │ │ └── index.vue ├── utils │ ├── auth.js │ ├── generator │ │ ├── css.js │ │ └── drawingDefalut.js │ ├── jsencrypt.js │ ├── permission.js │ ├── zipdownload.js │ ├── request.js │ ├── scroll-to.js │ └── validate.js ├── store │ ├── index.js │ ├── getters.js │ └── modules │ │ ├── settings.js │ │ ├── app.js │ │ └── permission.js ├── settings.js ├── styles │ ├── variables.scss │ ├── element-variables.scss │ ├── transition.scss │ ├── element-ui.scss │ ├── mixin.scss │ └── btn.scss ├── permission.js └── main.js ├── public └── favicon.ico ├── .env.production ├── .env.staging ├── .env.development ├── .eslintignore ├── .gitignore ├── .editorconfig └── README.md /bin/build.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/bin/build.bat -------------------------------------------------------------------------------- /bin/package.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/bin/package.bat -------------------------------------------------------------------------------- /bin/run-web.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/bin/run-web.bat -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/views/content/blog/page.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/views/system/log/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/src/assets/logo/logo.png -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # 生产环境配置 2 | ENV = 'production' 3 | 4 | # 若依管理系统/生产环境 5 | VUE_APP_BASE_API = '/peng' 6 | -------------------------------------------------------------------------------- /src/assets/401_images/401.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/src/assets/401_images/401.gif -------------------------------------------------------------------------------- /src/assets/404_images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/src/assets/404_images/404.png -------------------------------------------------------------------------------- /src/assets/image/profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/src/assets/image/profile.jpg -------------------------------------------------------------------------------- /src/assets/404_images/404_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/src/assets/404_images/404_cloud.png -------------------------------------------------------------------------------- /src/assets/image/login-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lurenha/MyBlogVue/HEAD/src/assets/image/login-background.jpg -------------------------------------------------------------------------------- /.env.staging: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | 3 | # 测试环境配置 4 | ENV = 'staging' 5 | 6 | # 若依管理系统/测试环境 7 | VUE_APP_BASE_API = '/stage-api' 8 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | # 开发环境配置 2 | ENV = 'development' 3 | 4 | # 若依管理系统/开发环境 5 | VUE_APP_BASE_API = '/peng' 6 | 7 | # 路由懒加载 8 | VUE_CLI_BABEL_TRANSPILE_MODULES = true 9 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/api/menu.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 获取路由 4 | export const getRouters = () => { 5 | return request({ 6 | url: '/getRouters', 7 | method: 'get' 8 | }) 9 | } -------------------------------------------------------------------------------- /src/api/monitor/server.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询服务器详细 4 | export function getServer() { 5 | return request({ 6 | url: '/monitor/server', 7 | method: 'get' 8 | }) 9 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # 忽略build目录下类型为js的文件的语法检查 2 | build/*.js 3 | # 忽略src/assets目录下文件的语法检查 4 | src/assets 5 | # 忽略public目录下文件的语法检查 6 | public 7 | # 忽略当前目录下为js的文件的语法检查 8 | *.js 9 | # 忽略当前目录下为vue的文件的语法检查 10 | *.vue -------------------------------------------------------------------------------- /src/assets/icons/svg/chart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/content/blog/components/Dropdown/index.js: -------------------------------------------------------------------------------- 1 | export { default as CommentDropdown } from './Comment' 2 | export { default as PlatformDropdown } from './Platform' 3 | export { default as SourceUrlDropdown } from './SourceUrl' 4 | -------------------------------------------------------------------------------- /src/assets/icons/svg/size.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/layout/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as AppMain } from './AppMain' 2 | export { default as Navbar } from './Navbar' 3 | export { default as Settings } from './Settings' 4 | export { default as Sidebar } from './Sidebar/index.vue' 5 | export { default as TagsView } from './TagsView/index.vue' 6 | -------------------------------------------------------------------------------- /src/views/content/blog/add.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /src/views/content/blog/edit.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/icons/svg/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/directive/waves/index.js: -------------------------------------------------------------------------------- 1 | import waves from './waves' 2 | 3 | const install = function(Vue) { 4 | Vue.directive('waves', waves) 5 | } 6 | 7 | if (window.Vue) { 8 | window.waves = waves 9 | Vue.use(install); // eslint-disable-line 10 | } 11 | 12 | waves.install = install 13 | export default waves 14 | -------------------------------------------------------------------------------- /src/views/redirect.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/components/IconSelect/requireIcons.js: -------------------------------------------------------------------------------- 1 | 2 | const req = require.context('../../assets/icons/svg', false, /\.svg$/) 3 | const requireAll = requireContext => requireContext.keys() 4 | 5 | const re = /\.\/(.*)\.svg/ 6 | 7 | const icons = requireAll(req).map(i => { 8 | return i.match(re)[1] 9 | }) 10 | 11 | export default icons 12 | -------------------------------------------------------------------------------- /src/views/components/icons/svg-icons.js: -------------------------------------------------------------------------------- 1 | const req = require.context('../../../assets/icons/svg', false, /\.svg$/) 2 | const requireAll = requireContext => requireContext.keys() 3 | 4 | const re = /\.\/(.*)\.svg/ 5 | 6 | const svgIcons = requireAll(req).map(i => { 7 | return i.match(re)[1] 8 | }) 9 | 10 | export default svgIcons 11 | -------------------------------------------------------------------------------- /src/assets/icons/svg/guide.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import SvgIcon from '@/components/SvgIcon'// svg component 3 | 4 | // register globally 5 | Vue.component('svg-icon', SvgIcon) 6 | 7 | const req = require.context('./svg', false, /\.svg$/) 8 | const requireAll = requireContext => requireContext.keys().map(requireContext) 9 | requireAll(req) 10 | -------------------------------------------------------------------------------- /src/assets/icons/svg/money.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/auth.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const TokenKey = 'Admin-Token' 4 | 5 | export function getToken() { 6 | return Cookies.get(TokenKey) 7 | } 8 | 9 | export function setToken(token) { 10 | return Cookies.set(TokenKey, token) 11 | } 12 | 13 | export function removeToken() { 14 | return Cookies.remove(TokenKey) 15 | } 16 | -------------------------------------------------------------------------------- /src/assets/icons/svg/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | **/*.log 8 | 9 | tests/**/coverage/ 10 | tests/e2e/reports 11 | selenium-debug.log 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.local 21 | 22 | package-lock.json 23 | yarn.lock 24 | -------------------------------------------------------------------------------- /src/assets/icons/svg/drag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svgo.yml: -------------------------------------------------------------------------------- 1 | # replace default config 2 | 3 | # multipass: true 4 | # full: true 5 | 6 | plugins: 7 | 8 | # - name 9 | # 10 | # or: 11 | # - name: false 12 | # - name: true 13 | # 14 | # or: 15 | # - name: 16 | # param1: 1 17 | # param2: 2 18 | 19 | - removeAttrs: 20 | attrs: 21 | - 'fill' 22 | - 'fill-rule' 23 | -------------------------------------------------------------------------------- /src/api/monitor/online.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询在线用户列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/online/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 强退用户 13 | export function forceLogout(tokenId) { 14 | return request({ 15 | url: '/monitor/online/' + tokenId, 16 | method: 'delete' 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/components/RuoYi/Doc/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/directive/permission/index.js: -------------------------------------------------------------------------------- 1 | import hasRole from './hasRole' 2 | import hasPermi from './hasPermi' 3 | 4 | const install = function(Vue) { 5 | Vue.directive('hasRole', hasRole) 6 | Vue.directive('hasPermi', hasPermi) 7 | } 8 | 9 | if (window.Vue) { 10 | window['hasRole'] = hasRole 11 | window['hasPermi'] = hasPermi 12 | Vue.use(install); // eslint-disable-line 13 | } 14 | 15 | export default install 16 | -------------------------------------------------------------------------------- /src/api/content/requestlog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询日志列表 4 | export function listLog(query) { 5 | return request({ 6 | url: '/admin/log/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除日志 13 | export function delLog(logId) { 14 | return request({ 15 | url: '/admin/log/delete/' + logId, 16 | method: 'get' 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/icons/svg/documentation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/lock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # 告诉EditorConfig插件,这是根文件,不用继续往上查找 2 | root = true 3 | 4 | # 匹配全部文件 5 | [*] 6 | # 设置字符集 7 | charset = utf-8 8 | # 缩进风格,可选space、tab 9 | indent_style = space 10 | # 缩进的空格数 11 | indent_size = 2 12 | # 结尾换行符,可选lf、cr、crlf 13 | end_of_line = lf 14 | # 在文件结尾插入新行 15 | insert_final_newline = true 16 | # 删除一行中的前后空格 17 | trim_trailing_whitespace = true 18 | 19 | # 匹配md结尾的文件 20 | [*.md] 21 | insert_final_newline = false 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /src/assets/icons/svg/excel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/RuoYi/Git/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/api/content/comment.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | export function getCommentWithChildById(id) { 4 | return request({ 5 | url: '/admin/comment/getCommentWithChildById/' + id, 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export function setDeleted(coId, isDelete) { 11 | const data = { 12 | coId, 13 | isDelete 14 | } 15 | return request({ 16 | url: '/admin/comment/setDeleted', 17 | method: 'post', 18 | data: data 19 | }) 20 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/example.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Tinymce/toolbar.js: -------------------------------------------------------------------------------- 1 | // Here is a list of the toolbar 2 | // Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols 3 | 4 | const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'] 5 | 6 | export default toolbar 7 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import app from './modules/app' 4 | import user from './modules/user' 5 | import tagsView from './modules/tagsView' 6 | import permission from './modules/permission' 7 | import settings from './modules/settings' 8 | import getters from './getters' 9 | 10 | Vue.use(Vuex) 11 | 12 | const store = new Vuex.Store({ 13 | modules: { 14 | app, 15 | user, 16 | tagsView, 17 | permission, 18 | settings 19 | }, 20 | getters 21 | }) 22 | 23 | export default store 24 | -------------------------------------------------------------------------------- /src/assets/icons/svg/star.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/slider.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/generator/css.js: -------------------------------------------------------------------------------- 1 | const styles = { 2 | 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}', 3 | 'el-upload': '.el-upload__tip{line-height: 1.2;}' 4 | } 5 | 6 | function addCss(cssList, el) { 7 | const css = styles[el.tag] 8 | css && cssList.indexOf(css) === -1 && cssList.push(css) 9 | if (el.children) { 10 | el.children.forEach(el2 => addCss(cssList, el2)) 11 | } 12 | } 13 | 14 | export function makeUpCss(conf) { 15 | const cssList = [] 16 | conf.fields.forEach(el => addCss(cssList, el)) 17 | return cssList.join('\n') 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/icons/svg/table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Tinymce/plugins.js: -------------------------------------------------------------------------------- 1 | // Any plugins you want to use has to be imported 2 | // Detail plugins list see https://www.tinymce.com/docs/plugins/ 3 | // Custom builds see https://www.tinymce.com/download/custom-builds/ 4 | 5 | const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount'] 6 | 7 | export default plugins 8 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/Item.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | sidebar: state => state.app.sidebar, 3 | size: state => state.app.size, 4 | device: state => state.app.device, 5 | visitedViews: state => state.tagsView.visitedViews, 6 | cachedViews: state => state.tagsView.cachedViews, 7 | token: state => state.user.token, 8 | avatar: state => state.user.avatar, 9 | name: state => state.user.name, 10 | introduction: state => state.user.introduction, 11 | roles: state => state.user.roles, 12 | permissions: state => state.user.permissions, 13 | permission_routes: state => state.permission.routes 14 | } 15 | export default getters 16 | -------------------------------------------------------------------------------- /src/assets/icons/svg/education.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tab.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/settings.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'MyBlog管理系统', 3 | 4 | /** 5 | * 是否系统布局配置 6 | */ 7 | showSettings: false, 8 | 9 | /** 10 | * 是否显示 tagsView 11 | */ 12 | tagsView: true, 13 | 14 | /** 15 | * 是否固定头部 16 | */ 17 | fixedHeader: false, 18 | 19 | /** 20 | * 是否显示logo 21 | */ 22 | sidebarLogo: true, 23 | 24 | /** 25 | * @type {string | array} 'production' | ['production', 'development'] 26 | * @description Need show err logs component. 27 | * The default is only used in the production env 28 | * If you want to also use it in dev, you can pass ['production', 'development'] 29 | */ 30 | errorLog: 'production' 31 | } 32 | -------------------------------------------------------------------------------- /src/assets/icons/svg/switch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/theme.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyBlogVue 2 | 3 | > 一个基于Vue的个人博客管理后台。 4 | 参考[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 5 | 参考[http://www.ruoyi.vip/](http://www.ruoyi.vip/) 6 | 7 | > [线上地址](http://lurenpeng.cn:8088/) 8 | ## 开发 9 | 10 | ```bash 11 | # 克隆项目 12 | git clone git@github.com:lurenha/MyBlogVue.git 13 | 14 | # 进入项目目录 15 | cd MyBlogVue 16 | 17 | # 安装依赖 18 | npm install 19 | 20 | # 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 21 | npm install --registry=https://registry.npm.taobao.org 22 | 23 | # 启动服务 24 | npm run dev 25 | ``` 26 | 27 | 浏览器访问 http://localhost 28 | 29 | ## 发布 30 | 31 | ```bash 32 | # 构建测试环境 33 | npm run build:stage 34 | 35 | # 构建生产环境 36 | npm run build:prod 37 | ``` 38 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/FixiOSBug.js: -------------------------------------------------------------------------------- 1 | export default { 2 | computed: { 3 | device() { 4 | return this.$store.state.app.device 5 | } 6 | }, 7 | mounted() { 8 | // In order to fix the click on menu on the ios device will trigger the mouseleave bug 9 | this.fixBugIniOS() 10 | }, 11 | methods: { 12 | fixBugIniOS() { 13 | const $subMenu = this.$refs.subMenu 14 | if ($subMenu) { 15 | const handleMouseleave = $subMenu.handleMouseleave 16 | $subMenu.handleMouseleave = (e) => { 17 | if (this.device === 'mobile') { 18 | return 19 | } 20 | handleMouseleave(e) 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/assets/icons/svg/druid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/peoples.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/generator/drawingDefalut.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | layout: 'colFormItem', 4 | tagIcon: 'input', 5 | label: '手机号', 6 | vModel: 'mobile', 7 | formId: 6, 8 | tag: 'el-input', 9 | placeholder: '请输入手机号', 10 | defaultValue: '', 11 | span: 24, 12 | style: { width: '100%' }, 13 | clearable: true, 14 | prepend: '', 15 | append: '', 16 | 'prefix-icon': 'el-icon-mobile', 17 | 'suffix-icon': '', 18 | maxlength: 11, 19 | 'show-word-limit': true, 20 | readonly: false, 21 | disabled: false, 22 | required: true, 23 | changeTag: true, 24 | regList: [{ 25 | pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', 26 | message: '手机号格式错误' 27 | }] 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /src/assets/icons/svg/input.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/login.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 登录方法 4 | export function login(username, password, code, uuid) { 5 | const data = { 6 | username, 7 | password, 8 | code, 9 | uuid 10 | } 11 | return request({ 12 | url: '/login', 13 | method: 'post', 14 | params: data 15 | }) 16 | } 17 | 18 | // 获取用户详细信息 19 | export function getInfo() { 20 | return request({ 21 | url: '/getInfo', 22 | method: 'get' 23 | }) 24 | } 25 | 26 | // 退出方法 27 | export function logout() { 28 | return request({ 29 | url: '/logout', 30 | method: 'post' 31 | }) 32 | } 33 | 34 | // 获取验证码 35 | export function getCodeImg() { 36 | return request({ 37 | url: '/captchaImage', 38 | method: 'get' 39 | }) 40 | } -------------------------------------------------------------------------------- /src/api/monitor/operlog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询操作日志列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/operlog/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除操作日志 13 | export function delOperlog(operId) { 14 | return request({ 15 | url: '/monitor/operlog/' + operId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空操作日志 21 | export function cleanOperlog() { 22 | return request({ 23 | url: '/monitor/operlog/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | 28 | // 导出操作日志 29 | export function exportOperlog(query) { 30 | return request({ 31 | url: '/monitor/operlog/export', 32 | method: 'get', 33 | params: query 34 | }) 35 | } -------------------------------------------------------------------------------- /src/directive/permission/hasRole.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 角色权限处理 3 | * Copyright (c) 2019 ruoyi 4 | */ 5 | 6 | import store from '@/store' 7 | 8 | export default { 9 | inserted(el, binding, vnode) { 10 | const { value } = binding 11 | const super_admin = "admin"; 12 | const roles = store.getters && store.getters.roles 13 | 14 | if (value && value instanceof Array && value.length > 0) { 15 | const roleFlag = value 16 | 17 | const hasRole = roles.some(role => { 18 | return super_admin === role || roleFlag.includes(role) 19 | }) 20 | 21 | if (!hasRole) { 22 | el.parentNode && el.parentNode.removeChild(el) 23 | } 24 | } else { 25 | throw new Error(`请设置角色权限标签值"`) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/api/monitor/jobLog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询调度日志列表 4 | export function listJobLog(query) { 5 | return request({ 6 | url: '/monitor/jobLog/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除调度日志 13 | export function delJobLog(jobLogId) { 14 | return request({ 15 | url: '/monitor/jobLog/' + jobLogId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空调度日志 21 | export function cleanJobLog() { 22 | return request({ 23 | url: '/monitor/jobLog/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | 28 | // 导出调度日志 29 | export function exportJobLog(query) { 30 | return request({ 31 | url: '/monitor/jobLog/export', 32 | method: 'get', 33 | params: query 34 | }) 35 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/server.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/Link.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 37 | -------------------------------------------------------------------------------- /src/api/monitor/logininfor.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询登录日志列表 4 | export function list(query) { 5 | return request({ 6 | url: '/monitor/logininfor/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 删除登录日志 13 | export function delLogininfor(infoId) { 14 | return request({ 15 | url: '/monitor/logininfor/' + infoId, 16 | method: 'delete' 17 | }) 18 | } 19 | 20 | // 清空登录日志 21 | export function cleanLogininfor() { 22 | return request({ 23 | url: '/monitor/logininfor/clean', 24 | method: 'delete' 25 | }) 26 | } 27 | 28 | // 导出登录日志 29 | export function exportLogininfor(query) { 30 | return request({ 31 | url: '/monitor/logininfor/export', 32 | method: 'get', 33 | params: query 34 | }) 35 | } -------------------------------------------------------------------------------- /src/api/content/tag.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | export function fetchTagList() { 4 | return request({ 5 | url: '/admin/tag/list', 6 | method: 'get' 7 | }) 8 | } 9 | 10 | export function deleteTagById(id) { 11 | return request({ 12 | url: '/admin/tag/delete/' + id, 13 | method: 'get' 14 | }) 15 | } 16 | 17 | // 新增 18 | export function addTag(name) { 19 | const data = { 20 | name 21 | } 22 | return request({ 23 | url: '/admin/tag/add', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改 30 | export function updateTag(taId, name) { 31 | const data = { 32 | taId, 33 | name 34 | } 35 | return request({ 36 | url: '/admin/tag/update', 37 | method: 'post', 38 | data: data 39 | }) 40 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/textarea.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/monitor/druid/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 27 | -------------------------------------------------------------------------------- /src/views/tool/swagger/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 27 | -------------------------------------------------------------------------------- /src/api/content/type.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | export function fetchTypeList() { 4 | return request({ 5 | url: '/admin/type/list', 6 | method: 'get' 7 | }) 8 | } 9 | 10 | 11 | export function deleteTypeById(id) { 12 | return request({ 13 | url: '/admin/type/delete/' + id, 14 | method: 'get' 15 | }) 16 | } 17 | 18 | // 新增 19 | export function addType(name) { 20 | const data = { 21 | name 22 | } 23 | return request({ 24 | url: '/admin/type/add', 25 | method: 'post', 26 | data: data 27 | }) 28 | } 29 | 30 | // 修改 31 | export function updateType(tyId,name) { 32 | const data = { 33 | tyId, 34 | name 35 | } 36 | return request({ 37 | url: '/admin/type/update', 38 | method: 'post', 39 | data: data 40 | }) 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/assets/icons/svg/time.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/directive/permission/hasPermi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 操作权限处理 3 | * Copyright (c) 2019 ruoyi 4 | */ 5 | 6 | import store from '@/store' 7 | 8 | export default { 9 | inserted(el, binding, vnode) { 10 | const { value } = binding 11 | const all_permission = "*:*:*"; 12 | const permissions = store.getters && store.getters.permissions 13 | 14 | if (value && value instanceof Array && value.length > 0) { 15 | const permissionFlag = value 16 | 17 | const hasPermissions = permissions.some(permission => { 18 | return all_permission === permission || permissionFlag.includes(permission) 19 | }) 20 | 21 | if (!hasPermissions) { 22 | el.parentNode && el.parentNode.removeChild(el) 23 | } 24 | } else { 25 | throw new Error(`请设置操作权限标签值`) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/store/modules/settings.js: -------------------------------------------------------------------------------- 1 | import variables from '@/assets/styles/element-variables.scss' 2 | import defaultSettings from '@/settings' 3 | 4 | const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings 5 | 6 | const state = { 7 | theme: variables.theme, 8 | showSettings: showSettings, 9 | tagsView: tagsView, 10 | fixedHeader: fixedHeader, 11 | sidebarLogo: sidebarLogo 12 | } 13 | 14 | const mutations = { 15 | CHANGE_SETTING: (state, { key, value }) => { 16 | if (state.hasOwnProperty(key)) { 17 | state[key] = value 18 | } 19 | } 20 | } 21 | 22 | const actions = { 23 | changeSetting({ commit }, data) { 24 | commit('CHANGE_SETTING', data) 25 | } 26 | } 27 | 28 | export default { 29 | namespaced: true, 30 | state, 31 | mutations, 32 | actions 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/assets/icons/svg/nested.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/content/friend.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | export function fetchFriendList() { 3 | return request({ 4 | url: '/admin/friend/list', 5 | method: 'get' 6 | }) 7 | } 8 | export function deleteFriendById(id) { 9 | return request({ 10 | url: '/admin/friend/delete/' + id, 11 | method: 'get' 12 | }) 13 | } 14 | 15 | export function getFriendByid(id) { 16 | return request({ 17 | url: '/admin/friend/find/' + id, 18 | method: 'get' 19 | }) 20 | } 21 | 22 | // 新增 23 | export function addFriend(data) { 24 | return request({ 25 | url: '/admin/friend/add', 26 | method: 'post', 27 | data: data 28 | }) 29 | } 30 | 31 | // 修改 32 | export function updateFriend(data) { 33 | return request({ 34 | url: '/admin/friend/update', 35 | method: 'post', 36 | data: data 37 | }) 38 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/row.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/monitor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tree-table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/system/notice.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询公告列表 4 | export function listNotice(query) { 5 | return request({ 6 | url: '/system/notice/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询公告详细 13 | export function getNotice(noticeId) { 14 | return request({ 15 | url: '/system/notice/' + noticeId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增公告 21 | export function addNotice(data) { 22 | return request({ 23 | url: '/system/notice', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改公告 30 | export function updateNotice(data) { 31 | return request({ 32 | url: '/system/notice', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除公告 39 | export function delNotice(noticeId) { 40 | return request({ 41 | url: '/system/notice/' + noticeId, 42 | method: 'delete' 43 | }) 44 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/eye.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/variables.scss: -------------------------------------------------------------------------------- 1 | // base color 2 | $blue:#324157; 3 | $light-blue:#3A71A8; 4 | $red:#C03639; 5 | $pink: #E65D6E; 6 | $green: #30B08F; 7 | $tiffany: #4AB7BD; 8 | $yellow:#FEC171; 9 | $panGreen: #30B08F; 10 | 11 | // sidebar 12 | $menuText:#bfcbd9; 13 | $menuActiveText:#409EFF; 14 | $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951 15 | 16 | $menuBg:#304156; 17 | $menuHover:#263445; 18 | 19 | $subMenuBg:#1f2d3d; 20 | $subMenuHover:#001528; 21 | 22 | $sideBarWidth: 210px; 23 | 24 | // the :export directive is the magic sauce for webpack 25 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 26 | :export { 27 | menuText: $menuText; 28 | menuActiveText: $menuActiveText; 29 | subMenuActiveText: $subMenuActiveText; 30 | menuBg: $menuBg; 31 | menuHover: $menuHover; 32 | subMenuBg: $subMenuBg; 33 | subMenuHover: $subMenuHover; 34 | sideBarWidth: $sideBarWidth; 35 | } 36 | -------------------------------------------------------------------------------- /src/styles/element-variables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * I think element-ui's default theme color is too light for long-term use. 3 | * So I modified the default color and you can modify it to your liking. 4 | **/ 5 | 6 | /* theme color */ 7 | $--color-primary: #1890ff; 8 | $--color-success: #13ce66; 9 | $--color-warning: #FFBA00; 10 | $--color-danger: #ff4949; 11 | // $--color-info: #1E1E1E; 12 | 13 | $--button-font-weight: 400; 14 | 15 | // $--color-text-regular: #1f2d3d; 16 | 17 | $--border-color-light: #dfe4ed; 18 | $--border-color-lighter: #e6ebf5; 19 | 20 | $--table-border:1px solid#dfe6ec; 21 | 22 | /* icon font path, required */ 23 | $--font-path: '~element-ui/lib/theme-chalk/fonts'; 24 | 25 | @import "~element-ui/packages/theme-chalk/src/index"; 26 | 27 | // the :export directive is the magic sauce for webpack 28 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 29 | :export { 30 | theme: $--color-primary; 31 | } 32 | -------------------------------------------------------------------------------- /src/assets/styles/variables.scss: -------------------------------------------------------------------------------- 1 | // base color 2 | $blue:#324157; 3 | $light-blue:#3A71A8; 4 | $red:#C03639; 5 | $pink: #E65D6E; 6 | $green: #30B08F; 7 | $tiffany: #4AB7BD; 8 | $yellow:#FEC171; 9 | $panGreen: #30B08F; 10 | 11 | // sidebar 12 | $menuText:#bfcbd9; 13 | $menuActiveText:#409EFF; 14 | $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951 15 | 16 | $menuBg:#304156; 17 | $menuHover:#263445; 18 | 19 | $subMenuBg:#1f2d3d; 20 | $subMenuHover:#001528; 21 | 22 | $sideBarWidth: 200px; 23 | 24 | // the :export directive is the magic sauce for webpack 25 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 26 | :export { 27 | menuText: $menuText; 28 | menuActiveText: $menuActiveText; 29 | subMenuActiveText: $subMenuActiveText; 30 | menuBg: $menuBg; 31 | menuHover: $menuHover; 32 | subMenuBg: $subMenuBg; 33 | subMenuHover: $subMenuHover; 34 | sideBarWidth: $sideBarWidth; 35 | } 36 | -------------------------------------------------------------------------------- /src/directive/waves/waves.css: -------------------------------------------------------------------------------- 1 | .waves-ripple { 2 | position: absolute; 3 | border-radius: 100%; 4 | background-color: rgba(0, 0, 0, 0.15); 5 | background-clip: padding-box; 6 | pointer-events: none; 7 | -webkit-user-select: none; 8 | -moz-user-select: none; 9 | -ms-user-select: none; 10 | user-select: none; 11 | -webkit-transform: scale(0); 12 | -ms-transform: scale(0); 13 | transform: scale(0); 14 | opacity: 1; 15 | } 16 | 17 | .waves-ripple.z-active { 18 | opacity: 0; 19 | -webkit-transform: scale(2); 20 | -ms-transform: scale(2); 21 | transform: scale(2); 22 | -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; 23 | transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; 24 | transition: opacity 1.2s ease-out, transform 0.6s ease-out; 25 | transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; 26 | } -------------------------------------------------------------------------------- /src/styles/transition.scss: -------------------------------------------------------------------------------- 1 | // global transition css 2 | 3 | /* fade */ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /* fade-transform */ 15 | .fade-transform-leave-active, 16 | .fade-transform-enter-active { 17 | transition: all .5s; 18 | } 19 | 20 | .fade-transform-enter { 21 | opacity: 0; 22 | transform: translateX(-30px); 23 | } 24 | 25 | .fade-transform-leave-to { 26 | opacity: 0; 27 | transform: translateX(30px); 28 | } 29 | 30 | /* breadcrumb transition */ 31 | .breadcrumb-enter-active, 32 | .breadcrumb-leave-active { 33 | transition: all .5s; 34 | } 35 | 36 | .breadcrumb-enter, 37 | .breadcrumb-leave-active { 38 | opacity: 0; 39 | transform: translateX(20px); 40 | } 41 | 42 | .breadcrumb-move { 43 | transition: all .5s; 44 | } 45 | 46 | .breadcrumb-leave-active { 47 | position: absolute; 48 | } 49 | -------------------------------------------------------------------------------- /src/assets/icons/svg/build.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/styles/element-variables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * I think element-ui's default theme color is too light for long-term use. 3 | * So I modified the default color and you can modify it to your liking. 4 | **/ 5 | 6 | /* theme color */ 7 | $--color-primary: #1890ff; 8 | $--color-success: #13ce66; 9 | $--color-warning: #FFBA00; 10 | $--color-danger: #ff4949; 11 | // $--color-info: #1E1E1E; 12 | 13 | $--button-font-weight: 400; 14 | 15 | // $--color-text-regular: #1f2d3d; 16 | 17 | $--border-color-light: #dfe4ed; 18 | $--border-color-lighter: #e6ebf5; 19 | 20 | $--table-border:1px solid#dfe6ec; 21 | 22 | /* icon font path, required */ 23 | $--font-path: '~element-ui/lib/theme-chalk/fonts'; 24 | 25 | @import "~element-ui/packages/theme-chalk/src/index"; 26 | 27 | // the :export directive is the magic sauce for webpack 28 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass 29 | :export { 30 | theme: $--color-primary; 31 | } 32 | -------------------------------------------------------------------------------- /src/assets/styles/transition.scss: -------------------------------------------------------------------------------- 1 | // global transition css 2 | 3 | /* fade */ 4 | .fade-enter-active, 5 | .fade-leave-active { 6 | transition: opacity 0.28s; 7 | } 8 | 9 | .fade-enter, 10 | .fade-leave-active { 11 | opacity: 0; 12 | } 13 | 14 | /* fade-transform */ 15 | .fade-transform-leave-active, 16 | .fade-transform-enter-active { 17 | transition: all .5s; 18 | } 19 | 20 | .fade-transform-enter { 21 | opacity: 0; 22 | transform: translateX(-30px); 23 | } 24 | 25 | .fade-transform-leave-to { 26 | opacity: 0; 27 | transform: translateX(30px); 28 | } 29 | 30 | /* breadcrumb transition */ 31 | .breadcrumb-enter-active, 32 | .breadcrumb-leave-active { 33 | transition: all .5s; 34 | } 35 | 36 | .breadcrumb-enter, 37 | .breadcrumb-leave-active { 38 | opacity: 0; 39 | transform: translateX(20px); 40 | } 41 | 42 | .breadcrumb-move { 43 | transition: all .5s; 44 | } 45 | 46 | .breadcrumb-leave-active { 47 | position: absolute; 48 | } 49 | -------------------------------------------------------------------------------- /src/assets/icons/svg/clipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/content/blog/components/Dropdown/SourceUrl.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Link 5 | 6 | 7 | 8 | 9 | 10 | 11 | URL 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 39 | -------------------------------------------------------------------------------- /src/api/system/post.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询岗位列表 4 | export function listPost(query) { 5 | return request({ 6 | url: '/system/post/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询岗位详细 13 | export function getPost(postId) { 14 | return request({ 15 | url: '/system/post/' + postId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增岗位 21 | export function addPost(data) { 22 | return request({ 23 | url: '/system/post', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改岗位 30 | export function updatePost(data) { 31 | return request({ 32 | url: '/system/post', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除岗位 39 | export function delPost(postId) { 40 | return request({ 41 | url: '/system/post/' + postId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 导出岗位 47 | export function exportPost(query) { 48 | return request({ 49 | url: '/system/post/export', 50 | method: 'get', 51 | params: query 52 | }) 53 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/content/blog/components/Dropdown/Comment.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ comment_disabled?'评论: 开启':'评论: 关闭' }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 关闭评论 12 | 13 | 14 | 开启评论 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 42 | -------------------------------------------------------------------------------- /src/assets/icons/svg/international.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/question.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/wechat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/skill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/people.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/post.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/system/dept.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询部门列表 4 | export function listDept(query) { 5 | return request({ 6 | url: '/system/dept/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询部门详细 13 | export function getDept(deptId) { 14 | return request({ 15 | url: '/system/dept/' + deptId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 查询部门下拉树结构 21 | export function treeselect() { 22 | return request({ 23 | url: '/system/dept/treeselect', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 根据角色ID查询部门树结构 29 | export function roleDeptTreeselect(roleId) { 30 | return request({ 31 | url: '/system/dept/roleDeptTreeselect/' + roleId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | // 新增部门 37 | export function addDept(data) { 38 | return request({ 39 | url: '/system/dept', 40 | method: 'post', 41 | data: data 42 | }) 43 | } 44 | 45 | // 修改部门 46 | export function updateDept(data) { 47 | return request({ 48 | url: '/system/dept', 49 | method: 'put', 50 | data: data 51 | }) 52 | } 53 | 54 | // 删除部门 55 | export function delDept(deptId) { 56 | return request({ 57 | url: '/system/dept/' + deptId, 58 | method: 'delete' 59 | }) 60 | } -------------------------------------------------------------------------------- /src/api/system/menu.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询菜单列表 4 | export function listMenu(query) { 5 | return request({ 6 | url: '/system/menu/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询菜单详细 13 | export function getMenu(menuId) { 14 | return request({ 15 | url: '/system/menu/' + menuId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 查询菜单下拉树结构 21 | export function treeselect() { 22 | return request({ 23 | url: '/system/menu/treeselect', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 根据角色ID查询菜单下拉树结构 29 | export function roleMenuTreeselect(roleId) { 30 | return request({ 31 | url: '/system/menu/roleMenuTreeselect/' + roleId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | // 新增菜单 37 | export function addMenu(data) { 38 | return request({ 39 | url: '/system/menu', 40 | method: 'post', 41 | data: data 42 | }) 43 | } 44 | 45 | // 修改菜单 46 | export function updateMenu(data) { 47 | return request({ 48 | url: '/system/menu', 49 | method: 'put', 50 | data: data 51 | }) 52 | } 53 | 54 | // 删除菜单 55 | export function delMenu(menuId) { 56 | return request({ 57 | url: '/system/menu/' + menuId, 58 | method: 'delete' 59 | }) 60 | } -------------------------------------------------------------------------------- /src/layout/components/AppMain.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 24 | 25 | 49 | 50 | 58 | -------------------------------------------------------------------------------- /src/utils/jsencrypt.js: -------------------------------------------------------------------------------- 1 | import JSEncrypt from 'jsencrypt/bin/jsencrypt' 2 | 3 | // 密钥对生成 http://web.chacuo.net/netrsakeypair 4 | 5 | const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n' + 6 | '2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==' 7 | 8 | const privateKey = 'MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8\n' + 9 | 'mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9p\n' + 10 | 'B6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue\n' + 11 | '/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZ\n' + 12 | 'UBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6\n' + 13 | 'vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha\n' + 14 | '4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3\n' + 15 | 'tTbklZkD2A==' 16 | 17 | // 加密 18 | export function encrypt(txt) { 19 | const encryptor = new JSEncrypt() 20 | encryptor.setPublicKey(publicKey) // 设置公钥 21 | return encryptor.encrypt(txt) // 对需要加密的数据进行加密 22 | } 23 | 24 | // 解密 25 | export function decrypt(txt) { 26 | const encryptor = new JSEncrypt() 27 | encryptor.setPrivateKey(privateKey) 28 | return encryptor.decrypt(txt) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/assets/icons/svg/language.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/tool/gen.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询生成表数据 4 | export function listTable(query) { 5 | return request({ 6 | url: '/tool/gen/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | // 查询db数据库列表 12 | export function listDbTable(query) { 13 | return request({ 14 | url: '/tool/gen/db/list', 15 | method: 'get', 16 | params: query 17 | }) 18 | } 19 | 20 | // 查询表详细信息 21 | export function getGenTable(tableId) { 22 | return request({ 23 | url: '/tool/gen/' + tableId, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 修改代码生成信息 29 | export function updateGenTable(data) { 30 | return request({ 31 | url: '/tool/gen', 32 | method: 'put', 33 | data: data 34 | }) 35 | } 36 | 37 | // 导入表 38 | export function importTable(data) { 39 | return request({ 40 | url: '/tool/gen/importTable', 41 | method: 'post', 42 | params: data 43 | }) 44 | } 45 | // 预览生成代码 46 | export function previewTable(tableId) { 47 | return request({ 48 | url: '/tool/gen/preview/' + tableId, 49 | method: 'get' 50 | }) 51 | } 52 | // 删除表数据 53 | export function delTable(tableId) { 54 | return request({ 55 | url: '/tool/gen/' + tableId, 56 | method: 'delete' 57 | }) 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/assets/icons/svg/checkbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/eye-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/system/dict/type.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询字典类型列表 4 | export function listType(query) { 5 | return request({ 6 | url: '/system/dict/type/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询字典类型详细 13 | export function getType(dictId) { 14 | return request({ 15 | url: '/system/dict/type/' + dictId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增字典类型 21 | export function addType(data) { 22 | return request({ 23 | url: '/system/dict/type', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改字典类型 30 | export function updateType(data) { 31 | return request({ 32 | url: '/system/dict/type', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除字典类型 39 | export function delType(dictId) { 40 | return request({ 41 | url: '/system/dict/type/' + dictId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 导出字典类型 47 | export function exportType(query) { 48 | return request({ 49 | url: '/system/dict/type/export', 50 | method: 'get', 51 | params: query 52 | }) 53 | } 54 | 55 | // 获取字典选择框列表 56 | export function optionselect() { 57 | return request({ 58 | url: '/system/dict/type/optionselect', 59 | method: 'get' 60 | }) 61 | } -------------------------------------------------------------------------------- /src/api/content/blog.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | export function fetchBlogList(query) { 4 | return request({ 5 | url: '/admin/blog/list', 6 | method: 'get', 7 | params: query 8 | }) 9 | } 10 | 11 | export function setPublished(blId, published) { 12 | const data = { 13 | blId, 14 | published 15 | } 16 | return request({ 17 | url: '/admin/blog/setPublished', 18 | method: 'post', 19 | data: data 20 | }) 21 | } 22 | 23 | export function deleteBlogById(id) { 24 | return request({ 25 | url: '/admin/blog/delete/' + id, 26 | method: 'get' 27 | }) 28 | } 29 | 30 | export function getBlogById(id) { 31 | return request({ 32 | url: '/admin/blog/find/' + id, 33 | method: 'get' 34 | }) 35 | } 36 | 37 | // 新增Blog 38 | export function addBlog(data) { 39 | return request({ 40 | url: '/admin/blog/add', 41 | method: 'post', 42 | data: data 43 | }) 44 | } 45 | 46 | // 修改Blog 47 | export function updateBlog(data) { 48 | return request({ 49 | url: '/admin/blog/update', 50 | method: 'post', 51 | data: data 52 | }) 53 | } 54 | 55 | 56 | // 拥有评论的BLog(字典) 57 | export function hasCommentDic() { 58 | return request({ 59 | url: '/admin/blog/hasCommentDic', 60 | method: 'get', 61 | }) 62 | } -------------------------------------------------------------------------------- /src/api/system/config.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询参数列表 4 | export function listConfig(query) { 5 | return request({ 6 | url: '/system/config/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询参数详细 13 | export function getConfig(configId) { 14 | return request({ 15 | url: '/system/config/' + configId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 根据参数键名查询参数值 21 | export function getConfigKey(configKey) { 22 | return request({ 23 | url: '/system/config/configKey/' + configKey, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增参数配置 29 | export function addConfig(data) { 30 | return request({ 31 | url: '/system/config', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改参数配置 38 | export function updateConfig(data) { 39 | return request({ 40 | url: '/system/config', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除参数配置 47 | export function delConfig(configId) { 48 | return request({ 49 | url: '/system/config/' + configId, 50 | method: 'delete' 51 | }) 52 | } 53 | 54 | // 导出参数 55 | export function exportConfig(query) { 56 | return request({ 57 | url: '/system/config/export', 58 | method: 'get', 59 | params: query 60 | }) 61 | } -------------------------------------------------------------------------------- /src/api/system/dict/data.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询字典数据列表 4 | export function listData(query) { 5 | return request({ 6 | url: '/system/dict/data/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询字典数据详细 13 | export function getData(dictCode) { 14 | return request({ 15 | url: '/system/dict/data/' + dictCode, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 根据字典类型查询字典数据信息 21 | export function getDicts(dictType) { 22 | return request({ 23 | url: '/system/dict/data/dictType/' + dictType, 24 | method: 'get' 25 | }) 26 | } 27 | 28 | // 新增字典数据 29 | export function addData(data) { 30 | return request({ 31 | url: '/system/dict/data', 32 | method: 'post', 33 | data: data 34 | }) 35 | } 36 | 37 | // 修改字典数据 38 | export function updateData(data) { 39 | return request({ 40 | url: '/system/dict/data', 41 | method: 'put', 42 | data: data 43 | }) 44 | } 45 | 46 | // 删除字典数据 47 | export function delData(dictCode) { 48 | return request({ 49 | url: '/system/dict/data/' + dictCode, 50 | method: 'delete' 51 | }) 52 | } 53 | 54 | // 导出字典数据 55 | export function exportData(query) { 56 | return request({ 57 | url: '/system/dict/data/export', 58 | method: 'get', 59 | params: query 60 | }) 61 | } -------------------------------------------------------------------------------- /src/assets/icons/svg/validCode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/permission.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | /** 4 | * 字符权限校验 5 | * @param {Array} value 校验值 6 | * @returns {Boolean} 7 | */ 8 | export function checkPermi(value) { 9 | if (value && value instanceof Array && value.length > 0) { 10 | const permissions = store.getters && store.getters.permissions 11 | const permissionDatas = value 12 | 13 | const hasPermission = permissions.some(permission => { 14 | return permissionDatas.includes(permission) 15 | }) 16 | 17 | if (!hasPermission) { 18 | return false 19 | } 20 | return true 21 | } else { 22 | console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) 23 | return false 24 | } 25 | } 26 | 27 | /** 28 | * 角色权限校验 29 | * @param {Array} value 校验值 30 | * @returns {Boolean} 31 | */ 32 | export function checkRole(value) { 33 | if (value && value instanceof Array && value.length > 0) { 34 | const roles = store.getters && store.getters.roles 35 | const permissionRoles = value 36 | 37 | const hasRole = roles.some(role => { 38 | return permissionRoles.includes(role) 39 | }) 40 | 41 | if (!hasRole) { 42 | return false 43 | } 44 | return true 45 | } else { 46 | console.error(`need roles! Like checkRole="['admin','editor']"`) 47 | return false 48 | } 49 | } -------------------------------------------------------------------------------- /src/components/Screenfull/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 50 | 51 | 61 | -------------------------------------------------------------------------------- /src/assets/icons/svg/radio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/select.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/gitee.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Hamburger/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 32 | 33 | 45 | -------------------------------------------------------------------------------- /src/assets/icons/svg/upload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | // cover some element-ui styles 2 | 3 | .el-breadcrumb__inner, 4 | .el-breadcrumb__inner a { 5 | font-weight: 400 !important; 6 | } 7 | 8 | .el-upload { 9 | input[type="file"] { 10 | display: none !important; 11 | } 12 | } 13 | 14 | .el-upload__input { 15 | display: none; 16 | } 17 | 18 | .cell { 19 | .el-tag { 20 | margin-right: 0px; 21 | } 22 | } 23 | 24 | .small-padding { 25 | .cell { 26 | padding-left: 5px; 27 | padding-right: 5px; 28 | } 29 | } 30 | 31 | .fixed-width { 32 | .el-button--mini { 33 | padding: 7px 10px; 34 | width: 60px; 35 | } 36 | } 37 | 38 | .status-col { 39 | .cell { 40 | padding: 0 10px; 41 | text-align: center; 42 | 43 | .el-tag { 44 | margin-right: 0px; 45 | } 46 | } 47 | } 48 | 49 | // to fixed https://github.com/ElemeFE/element/issues/2461 50 | .el-dialog { 51 | transform: none; 52 | left: 0; 53 | position: relative; 54 | margin: 0 auto; 55 | } 56 | 57 | // refine element ui upload 58 | .upload-container { 59 | .el-upload { 60 | width: 100%; 61 | 62 | .el-upload-dragger { 63 | width: 100%; 64 | height: 200px; 65 | } 66 | } 67 | } 68 | 69 | // dropdown 70 | .el-dropdown-menu { 71 | a { 72 | display: block 73 | } 74 | } 75 | 76 | // fix date-picker ui bug in filter-item 77 | .el-range-editor.el-input__inner { 78 | display: inline-flex !important; 79 | } 80 | -------------------------------------------------------------------------------- /src/assets/icons/svg/404.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/zipdownload.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { getToken } from '@/utils/auth' 3 | 4 | const mimeMap = { 5 | xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 6 | zip: 'application/zip' 7 | } 8 | 9 | const baseUrl = process.env.VUE_APP_BASE_API 10 | export function downLoadZip(str, filename) { 11 | var url = baseUrl + str 12 | axios({ 13 | method: 'get', 14 | url: url, 15 | responseType: 'blob', 16 | headers: { 'Peng-Token': getToken() } 17 | }).then(res => { 18 | resolveBlob(res, mimeMap.zip) 19 | }) 20 | } 21 | /** 22 | * 解析blob响应内容并下载 23 | * @param {*} res blob响应内容 24 | * @param {String} mimeType MIME类型 25 | */ 26 | export function resolveBlob(res, mimeType) { 27 | const aLink = document.createElement('a') 28 | var blob = new Blob([res.data], { type: mimeType }) 29 | // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; 30 | var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*') 31 | var contentDisposition = decodeURI(res.headers['content-disposition']) 32 | var result = patt.exec(contentDisposition) 33 | var fileName = result[1] 34 | fileName = fileName.replace(/\"/g, '') 35 | aLink.href = URL.createObjectURL(blob) 36 | aLink.setAttribute('download', fileName) // 设置下载文件名称 37 | document.body.appendChild(aLink) 38 | aLink.click() 39 | document.body.appendChild(aLink) 40 | } 41 | -------------------------------------------------------------------------------- /src/assets/icons/svg/zip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/layout/mixin/ResizeHandler.js: -------------------------------------------------------------------------------- 1 | import store from '@/store' 2 | 3 | const { body } = document 4 | const WIDTH = 992 // refer to Bootstrap's responsive design 5 | 6 | export default { 7 | watch: { 8 | $route(route) { 9 | if (this.device === 'mobile' && this.sidebar.opened) { 10 | store.dispatch('app/closeSideBar', { withoutAnimation: false }) 11 | } 12 | } 13 | }, 14 | beforeMount() { 15 | window.addEventListener('resize', this.$_resizeHandler) 16 | }, 17 | beforeDestroy() { 18 | window.removeEventListener('resize', this.$_resizeHandler) 19 | }, 20 | mounted() { 21 | const isMobile = this.$_isMobile() 22 | if (isMobile) { 23 | store.dispatch('app/toggleDevice', 'mobile') 24 | store.dispatch('app/closeSideBar', { withoutAnimation: true }) 25 | } 26 | }, 27 | methods: { 28 | // use $_ for mixins properties 29 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential 30 | $_isMobile() { 31 | const rect = body.getBoundingClientRect() 32 | return rect.width - 1 < WIDTH 33 | }, 34 | $_resizeHandler() { 35 | if (!document.hidden) { 36 | const isMobile = this.$_isMobile() 37 | store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') 38 | 39 | if (isMobile) { 40 | store.dispatch('app/closeSideBar', { withoutAnimation: true }) 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/views/content/blog/components/Dropdown/Platform.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 标签({{ platforms.length }}) 5 | 6 | 7 | 8 | 9 | 10 | {{ item.name }} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 53 | -------------------------------------------------------------------------------- /src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 46 | 47 | 62 | -------------------------------------------------------------------------------- /src/store/modules/app.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | const state = { 4 | sidebar: { 5 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, 6 | withoutAnimation: false 7 | }, 8 | device: 'desktop', 9 | size: Cookies.get('size') || 'medium' 10 | } 11 | 12 | const mutations = { 13 | TOGGLE_SIDEBAR: state => { 14 | state.sidebar.opened = !state.sidebar.opened 15 | state.sidebar.withoutAnimation = false 16 | if (state.sidebar.opened) { 17 | Cookies.set('sidebarStatus', 1) 18 | } else { 19 | Cookies.set('sidebarStatus', 0) 20 | } 21 | }, 22 | CLOSE_SIDEBAR: (state, withoutAnimation) => { 23 | Cookies.set('sidebarStatus', 0) 24 | state.sidebar.opened = false 25 | state.sidebar.withoutAnimation = withoutAnimation 26 | }, 27 | TOGGLE_DEVICE: (state, device) => { 28 | state.device = device 29 | }, 30 | SET_SIZE: (state, size) => { 31 | state.size = size 32 | Cookies.set('size', size) 33 | } 34 | } 35 | 36 | const actions = { 37 | toggleSideBar({ commit }) { 38 | commit('TOGGLE_SIDEBAR') 39 | }, 40 | closeSideBar({ commit }, { withoutAnimation }) { 41 | commit('CLOSE_SIDEBAR', withoutAnimation) 42 | }, 43 | toggleDevice({ commit }, device) { 44 | commit('TOGGLE_DEVICE', device) 45 | }, 46 | setSize({ commit }, size) { 47 | commit('SET_SIZE', size) 48 | } 49 | } 50 | 51 | export default { 52 | namespaced: true, 53 | state, 54 | mutations, 55 | actions 56 | } 57 | -------------------------------------------------------------------------------- /src/assets/icons/svg/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/system/role.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询角色列表 4 | export function listRole(query) { 5 | return request({ 6 | url: '/system/role/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询角色详细 13 | export function getRole(roleId) { 14 | return request({ 15 | url: '/system/role/' + roleId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增角色 21 | export function addRole(data) { 22 | return request({ 23 | url: '/system/role/add', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改角色 30 | export function updateRole(data) { 31 | return request({ 32 | url: '/system/role/update', 33 | method: 'post', 34 | data: data 35 | }) 36 | } 37 | 38 | // 角色数据权限 39 | export function dataScope(data) { 40 | return request({ 41 | url: '/system/role/dataScope', 42 | method: 'put', 43 | data: data 44 | }) 45 | } 46 | 47 | // 角色状态修改 48 | export function changeRoleStatus(roleId, status) { 49 | const data = { 50 | roleId, 51 | status 52 | } 53 | return request({ 54 | url: '/system/role/changeStatus', 55 | method: 'put', 56 | data: data 57 | }) 58 | } 59 | 60 | // 删除角色 61 | export function delRole(roleId) { 62 | return request({ 63 | url: '/system/role/delete/' + roleId, 64 | method: 'get' 65 | }) 66 | } 67 | 68 | // 导出角色 69 | export function exportRole(query) { 70 | return request({ 71 | url: '/system/role/export', 72 | method: 'get', 73 | params: query 74 | }) 75 | } -------------------------------------------------------------------------------- /src/assets/styles/element-ui.scss: -------------------------------------------------------------------------------- 1 | // cover some element-ui styles 2 | 3 | .el-breadcrumb__inner, 4 | .el-breadcrumb__inner a { 5 | font-weight: 400 !important; 6 | } 7 | 8 | .el-upload { 9 | input[type="file"] { 10 | display: none !important; 11 | } 12 | } 13 | 14 | .el-upload__input { 15 | display: none; 16 | } 17 | 18 | .cell { 19 | .el-tag { 20 | margin-right: 0px; 21 | } 22 | } 23 | 24 | .small-padding { 25 | .cell { 26 | padding-left: 5px; 27 | padding-right: 5px; 28 | } 29 | } 30 | 31 | .fixed-width { 32 | .el-button--mini { 33 | padding: 7px 10px; 34 | width: 60px; 35 | } 36 | } 37 | 38 | .status-col { 39 | .cell { 40 | padding: 0 10px; 41 | text-align: center; 42 | 43 | .el-tag { 44 | margin-right: 0px; 45 | } 46 | } 47 | } 48 | 49 | // to fixed https://github.com/ElemeFE/element/issues/2461 50 | .el-dialog { 51 | transform: none; 52 | left: 0; 53 | position: relative; 54 | margin: 0 auto; 55 | } 56 | 57 | // refine element ui upload 58 | .upload-container { 59 | .el-upload { 60 | width: 100%; 61 | 62 | .el-upload-dragger { 63 | width: 100%; 64 | height: 200px; 65 | } 66 | } 67 | } 68 | 69 | // dropdown 70 | .el-dropdown-menu { 71 | a { 72 | display: block 73 | } 74 | } 75 | 76 | // fix date-picker ui bug in filter-item 77 | .el-range-editor.el-input__inner { 78 | display: inline-flex !important; 79 | } 80 | 81 | // to fix el-date-picker css style 82 | .el-range-separator { 83 | box-sizing: content-box; 84 | } 85 | -------------------------------------------------------------------------------- /src/assets/icons/svg/log.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/bug.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/api/monitor/job.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request' 2 | 3 | // 查询定时任务调度列表 4 | export function listJob(query) { 5 | return request({ 6 | url: '/monitor/job/list', 7 | method: 'get', 8 | params: query 9 | }) 10 | } 11 | 12 | // 查询定时任务调度详细 13 | export function getJob(jobId) { 14 | return request({ 15 | url: '/monitor/job/' + jobId, 16 | method: 'get' 17 | }) 18 | } 19 | 20 | // 新增定时任务调度 21 | export function addJob(data) { 22 | return request({ 23 | url: '/monitor/job', 24 | method: 'post', 25 | data: data 26 | }) 27 | } 28 | 29 | // 修改定时任务调度 30 | export function updateJob(data) { 31 | return request({ 32 | url: '/monitor/job', 33 | method: 'put', 34 | data: data 35 | }) 36 | } 37 | 38 | // 删除定时任务调度 39 | export function delJob(jobId) { 40 | return request({ 41 | url: '/monitor/job/' + jobId, 42 | method: 'delete' 43 | }) 44 | } 45 | 46 | // 导出定时任务调度 47 | export function exportJob(query) { 48 | return request({ 49 | url: '/monitor/job/export', 50 | method: 'get', 51 | params: query 52 | }) 53 | } 54 | 55 | // 任务状态修改 56 | export function changeJobStatus(jobId, status) { 57 | const data = { 58 | jobId, 59 | status 60 | } 61 | return request({ 62 | url: '/monitor/job/changeStatus', 63 | method: 'put', 64 | data: data 65 | }) 66 | } 67 | 68 | 69 | // 定时任务立即执行一次 70 | export function runJob(jobId, jobGroup) { 71 | const data = { 72 | jobId, 73 | jobGroup 74 | } 75 | return request({ 76 | url: '/monitor/job/run', 77 | method: 'put', 78 | data: data 79 | }) 80 | } -------------------------------------------------------------------------------- /src/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | 30 | @mixin pct($pct) { 31 | width: #{$pct}; 32 | position: relative; 33 | margin: 0 auto; 34 | } 35 | 36 | @mixin triangle($width, $height, $color, $direction) { 37 | $width: $width/2; 38 | $color-border-style: $height solid $color; 39 | $transparent-border-style: $width solid transparent; 40 | height: 0; 41 | width: 0; 42 | 43 | @if $direction==up { 44 | border-bottom: $color-border-style; 45 | border-left: $transparent-border-style; 46 | border-right: $transparent-border-style; 47 | } 48 | 49 | @else if $direction==right { 50 | border-left: $color-border-style; 51 | border-top: $transparent-border-style; 52 | border-bottom: $transparent-border-style; 53 | } 54 | 55 | @else if $direction==down { 56 | border-top: $color-border-style; 57 | border-left: $transparent-border-style; 58 | border-right: $transparent-border-style; 59 | } 60 | 61 | @else if $direction==left { 62 | border-right: $color-border-style; 63 | border-top: $transparent-border-style; 64 | border-bottom: $transparent-border-style; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/components/SizeSelect/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ 9 | item.label }} 10 | 11 | 12 | 13 | 14 | 15 | 58 | -------------------------------------------------------------------------------- /src/assets/styles/mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix { 2 | &:after { 3 | content: ""; 4 | display: table; 5 | clear: both; 6 | } 7 | } 8 | 9 | @mixin scrollBar { 10 | &::-webkit-scrollbar-track-piece { 11 | background: #d3dce6; 12 | } 13 | 14 | &::-webkit-scrollbar { 15 | width: 6px; 16 | } 17 | 18 | &::-webkit-scrollbar-thumb { 19 | background: #99a9bf; 20 | border-radius: 20px; 21 | } 22 | } 23 | 24 | @mixin relative { 25 | position: relative; 26 | width: 100%; 27 | height: 100%; 28 | } 29 | 30 | @mixin pct($pct) { 31 | width: #{$pct}; 32 | position: relative; 33 | margin: 0 auto; 34 | } 35 | 36 | @mixin triangle($width, $height, $color, $direction) { 37 | $width: $width/2; 38 | $color-border-style: $height solid $color; 39 | $transparent-border-style: $width solid transparent; 40 | height: 0; 41 | width: 0; 42 | 43 | @if $direction==up { 44 | border-bottom: $color-border-style; 45 | border-left: $transparent-border-style; 46 | border-right: $transparent-border-style; 47 | } 48 | 49 | @else if $direction==right { 50 | border-left: $color-border-style; 51 | border-top: $transparent-border-style; 52 | border-bottom: $transparent-border-style; 53 | } 54 | 55 | @else if $direction==down { 56 | border-top: $color-border-style; 57 | border-left: $transparent-border-style; 58 | border-right: $transparent-border-style; 59 | } 60 | 61 | @else if $direction==left { 62 | border-right: $color-border-style; 63 | border-top: $transparent-border-style; 64 | border-bottom: $transparent-border-style; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/assets/icons/svg/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 55 | -------------------------------------------------------------------------------- /src/views/dashboard/mixins/resize.js: -------------------------------------------------------------------------------- 1 | import { debounce } from '@/utils' 2 | 3 | export default { 4 | data() { 5 | return { 6 | $_sidebarElm: null, 7 | $_resizeHandler: null 8 | } 9 | }, 10 | mounted() { 11 | this.initListener() 12 | }, 13 | activated() { 14 | if (!this.$_resizeHandler) { 15 | // avoid duplication init 16 | this.initListener() 17 | } 18 | 19 | // when keep-alive chart activated, auto resize 20 | this.resize() 21 | }, 22 | beforeDestroy() { 23 | this.destroyListener() 24 | }, 25 | deactivated() { 26 | this.destroyListener() 27 | }, 28 | methods: { 29 | // use $_ for mixins properties 30 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential 31 | $_sidebarResizeHandler(e) { 32 | if (e.propertyName === 'width') { 33 | this.$_resizeHandler() 34 | } 35 | }, 36 | initListener() { 37 | this.$_resizeHandler = debounce(() => { 38 | this.resize() 39 | }, 100) 40 | window.addEventListener('resize', this.$_resizeHandler) 41 | 42 | this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] 43 | this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) 44 | }, 45 | destroyListener() { 46 | window.removeEventListener('resize', this.$_resizeHandler) 47 | this.$_resizeHandler = null 48 | 49 | this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) 50 | }, 51 | resize() { 52 | const { chart } = this 53 | chart && chart.resize() 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/assets/icons/svg/pdf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/logininfor.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/rate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/store/modules/permission.js: -------------------------------------------------------------------------------- 1 | import { constantRoutes } from '@/router' 2 | import { getRouters } from '@/api/menu' 3 | import Layout from '@/layout/index' 4 | 5 | const permission = { 6 | state: { 7 | routes: [], 8 | addRoutes: [] 9 | }, 10 | mutations: { 11 | SET_ROUTES: (state, routes) => { 12 | state.addRoutes = routes 13 | state.routes = constantRoutes.concat(routes) 14 | } 15 | }, 16 | actions: { 17 | // 生成路由 18 | GenerateRoutes({ commit }) { 19 | return new Promise(resolve => { 20 | // 向后端请求路由数据 21 | getRouters().then(res => { 22 | const accessedRoutes = filterAsyncRouter(res) 23 | accessedRoutes.push({ path: '*', redirect: '/404', hidden: true }) 24 | commit('SET_ROUTES', accessedRoutes) 25 | resolve(accessedRoutes) 26 | }) 27 | }) 28 | } 29 | } 30 | } 31 | 32 | // 遍历后台传来的路由字符串,转换为组件对象 33 | function filterAsyncRouter(asyncRouterMap) { 34 | return asyncRouterMap.filter(route => { 35 | if (route.component) { 36 | // Layout组件特殊处理 37 | if (route.component === 'Layout') { 38 | route.component = Layout 39 | } else { 40 | route.component = loadView(route.component) 41 | } 42 | } 43 | if (route.children != null && route.children && route.children.length) { 44 | route.children = filterAsyncRouter(route.children) 45 | } 46 | return true 47 | }) 48 | } 49 | 50 | export const loadView = (view) => { // 路由懒加载 51 | // return () => import(`@/views/${view}`) 52 | //Vue配置动态路由报错:Error: Cannot find module ‘@/views/login/index’ 53 | return (resolve) => require([`@/views/${view}`], resolve) 54 | } 55 | 56 | export default permission 57 | -------------------------------------------------------------------------------- /src/assets/icons/svg/job.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { Notification, MessageBox, Message } from 'element-ui' 3 | import store from '@/store' 4 | import { getToken } from '@/utils/auth' 5 | 6 | axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' 7 | // 创建axios实例 8 | const service = axios.create({ 9 | // axios中请求配置有baseURL选项,表示请求URL公共部分 10 | baseURL: process.env.VUE_APP_BASE_API, 11 | // 超时 12 | timeout: 10000 13 | }) 14 | // request拦截器 15 | service.interceptors.request.use( 16 | config => { 17 | if (getToken()) { 18 | config.headers['Peng-Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 19 | } 20 | return config 21 | }, 22 | error => { 23 | console.log(error) 24 | Promise.reject(error) 25 | } 26 | ) 27 | 28 | // 响应拦截器 29 | service.interceptors.response.use(res => { 30 | const code = res.data.code 31 | if (code === 401) { 32 | MessageBox.confirm( 33 | '登录状态已过期,您可以继续留在该页面,或者重新登录', 34 | '系统提示', 35 | { 36 | confirmButtonText: '重新登录', 37 | cancelButtonText: '取消', 38 | type: 'warning' 39 | } 40 | ).then(() => { 41 | store.dispatch('LogOut').then(() => { 42 | location.reload() // 为了重新实例化vue-router对象 避免bug 43 | }) 44 | }) 45 | } else if (code !== 0) { 46 | Notification.error({ 47 | title: res.data.msg 48 | }) 49 | return Promise.reject('error') 50 | } else { 51 | return res.data.data 52 | } 53 | }, 54 | error => { 55 | console.log('err' + error) 56 | Message({ 57 | message: error.message, 58 | type: 'error', 59 | duration: 5 * 1000 60 | }) 61 | return Promise.reject(error) 62 | } 63 | ) 64 | 65 | export default service 66 | -------------------------------------------------------------------------------- /src/assets/icons/svg/exit-fullscreen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tree.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/swagger.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/password.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Tinymce/dynamicLoadScript.js: -------------------------------------------------------------------------------- 1 | let callbacks = [] 2 | 3 | function loadedTinymce() { 4 | // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144 5 | // check is successfully downloaded script 6 | return window.tinymce 7 | } 8 | 9 | const dynamicLoadScript = (src, callback) => { 10 | const existingScript = document.getElementById(src) 11 | const cb = callback || function() {} 12 | 13 | if (!existingScript) { 14 | const script = document.createElement('script') 15 | script.src = src // src url for the third-party library being loaded. 16 | script.id = src 17 | document.body.appendChild(script) 18 | callbacks.push(cb) 19 | const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd 20 | onEnd(script) 21 | } 22 | 23 | if (existingScript && cb) { 24 | if (loadedTinymce()) { 25 | cb(null, existingScript) 26 | } else { 27 | callbacks.push(cb) 28 | } 29 | } 30 | 31 | function stdOnEnd(script) { 32 | script.onload = function() { 33 | // this.onload = null here is necessary 34 | // because even IE9 works not like others 35 | this.onerror = this.onload = null 36 | for (const cb of callbacks) { 37 | cb(null, script) 38 | } 39 | callbacks = null 40 | } 41 | script.onerror = function() { 42 | this.onerror = this.onload = null 43 | cb(new Error('Failed to load ' + src), script) 44 | } 45 | } 46 | 47 | function ieOnEnd(script) { 48 | script.onreadystatechange = function() { 49 | if (this.readyState !== 'complete' && this.readyState !== 'loaded') return 50 | this.onreadystatechange = null 51 | for (const cb of callbacks) { 52 | cb(null, script) // there is no way to catch loading errors in IE8 53 | } 54 | callbacks = null 55 | } 56 | } 57 | } 58 | 59 | export default dynamicLoadScript 60 | -------------------------------------------------------------------------------- /src/components/IconSelect/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{ item }} 11 | 12 | 13 | 14 | 15 | 16 | 45 | 46 | 70 | -------------------------------------------------------------------------------- /src/styles/btn.scss: -------------------------------------------------------------------------------- 1 | @import './variables.scss'; 2 | 3 | @mixin colorBtn($color) { 4 | background: $color; 5 | 6 | &:hover { 7 | color: $color; 8 | 9 | &:before, 10 | &:after { 11 | background: $color; 12 | } 13 | } 14 | } 15 | 16 | .blue-btn { 17 | @include colorBtn($blue) 18 | } 19 | 20 | .light-blue-btn { 21 | @include colorBtn($light-blue) 22 | } 23 | 24 | .red-btn { 25 | @include colorBtn($red) 26 | } 27 | 28 | .pink-btn { 29 | @include colorBtn($pink) 30 | } 31 | 32 | .green-btn { 33 | @include colorBtn($green) 34 | } 35 | 36 | .tiffany-btn { 37 | @include colorBtn($tiffany) 38 | } 39 | 40 | .yellow-btn { 41 | @include colorBtn($yellow) 42 | } 43 | 44 | .pan-btn { 45 | font-size: 14px; 46 | color: #fff; 47 | padding: 14px 36px; 48 | border-radius: 8px; 49 | border: none; 50 | outline: none; 51 | transition: 600ms ease all; 52 | position: relative; 53 | display: inline-block; 54 | 55 | &:hover { 56 | background: #fff; 57 | 58 | &:before, 59 | &:after { 60 | width: 100%; 61 | transition: 600ms ease all; 62 | } 63 | } 64 | 65 | &:before, 66 | &:after { 67 | content: ''; 68 | position: absolute; 69 | top: 0; 70 | right: 0; 71 | height: 2px; 72 | width: 0; 73 | transition: 400ms ease all; 74 | } 75 | 76 | &::after { 77 | right: inherit; 78 | top: inherit; 79 | left: 0; 80 | bottom: 0; 81 | } 82 | } 83 | 84 | .custom-button { 85 | display: inline-block; 86 | line-height: 1; 87 | white-space: nowrap; 88 | cursor: pointer; 89 | background: #fff; 90 | color: #fff; 91 | -webkit-appearance: none; 92 | text-align: center; 93 | box-sizing: border-box; 94 | outline: 0; 95 | margin: 0; 96 | padding: 10px 15px; 97 | font-size: 14px; 98 | border-radius: 4px; 99 | } 100 | -------------------------------------------------------------------------------- /src/assets/styles/btn.scss: -------------------------------------------------------------------------------- 1 | @import './variables.scss'; 2 | 3 | @mixin colorBtn($color) { 4 | background: $color; 5 | 6 | &:hover { 7 | color: $color; 8 | 9 | &:before, 10 | &:after { 11 | background: $color; 12 | } 13 | } 14 | } 15 | 16 | .blue-btn { 17 | @include colorBtn($blue) 18 | } 19 | 20 | .light-blue-btn { 21 | @include colorBtn($light-blue) 22 | } 23 | 24 | .red-btn { 25 | @include colorBtn($red) 26 | } 27 | 28 | .pink-btn { 29 | @include colorBtn($pink) 30 | } 31 | 32 | .green-btn { 33 | @include colorBtn($green) 34 | } 35 | 36 | .tiffany-btn { 37 | @include colorBtn($tiffany) 38 | } 39 | 40 | .yellow-btn { 41 | @include colorBtn($yellow) 42 | } 43 | 44 | .pan-btn { 45 | font-size: 14px; 46 | color: #fff; 47 | padding: 14px 36px; 48 | border-radius: 8px; 49 | border: none; 50 | outline: none; 51 | transition: 600ms ease all; 52 | position: relative; 53 | display: inline-block; 54 | 55 | &:hover { 56 | background: #fff; 57 | 58 | &:before, 59 | &:after { 60 | width: 100%; 61 | transition: 600ms ease all; 62 | } 63 | } 64 | 65 | &:before, 66 | &:after { 67 | content: ''; 68 | position: absolute; 69 | top: 0; 70 | right: 0; 71 | height: 2px; 72 | width: 0; 73 | transition: 400ms ease all; 74 | } 75 | 76 | &::after { 77 | right: inherit; 78 | top: inherit; 79 | left: 0; 80 | bottom: 0; 81 | } 82 | } 83 | 84 | .custom-button { 85 | display: inline-block; 86 | line-height: 1; 87 | white-space: nowrap; 88 | cursor: pointer; 89 | background: #fff; 90 | color: #fff; 91 | -webkit-appearance: none; 92 | text-align: center; 93 | box-sizing: border-box; 94 | outline: 0; 95 | margin: 0; 96 | padding: 10px 15px; 97 | font-size: 14px; 98 | border-radius: 4px; 99 | } 100 | -------------------------------------------------------------------------------- /src/utils/scroll-to.js: -------------------------------------------------------------------------------- 1 | Math.easeInOutQuad = function(t, b, c, d) { 2 | t /= d / 2 3 | if (t < 1) { 4 | return c / 2 * t * t + b 5 | } 6 | t-- 7 | return -c / 2 * (t * (t - 2) - 1) + b 8 | } 9 | 10 | // requestAnimationFrame for Smart Animating http://goo.gl/sx5sts 11 | var requestAnimFrame = (function() { 12 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } 13 | })() 14 | 15 | /** 16 | * Because it's so fucking difficult to detect the scrolling element, just move them all 17 | * @param {number} amount 18 | */ 19 | function move(amount) { 20 | document.documentElement.scrollTop = amount 21 | document.body.parentNode.scrollTop = amount 22 | document.body.scrollTop = amount 23 | } 24 | 25 | function position() { 26 | return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop 27 | } 28 | 29 | /** 30 | * @param {number} to 31 | * @param {number} duration 32 | * @param {Function} callback 33 | */ 34 | export function scrollTo(to, duration, callback) { 35 | const start = position() 36 | const change = to - start 37 | const increment = 20 38 | let currentTime = 0 39 | duration = (typeof (duration) === 'undefined') ? 500 : duration 40 | var animateScroll = function() { 41 | // increment the time 42 | currentTime += increment 43 | // find the value with the quadratic in-out easing function 44 | var val = Math.easeInOutQuad(currentTime, start, change, duration) 45 | // move the document.body 46 | move(val) 47 | // do the animation unless its over 48 | if (currentTime < duration) { 49 | requestAnimFrame(animateScroll) 50 | } else { 51 | if (callback && typeof (callback) === 'function') { 52 | // the animation is done so lets callback 53 | callback() 54 | } 55 | } 56 | } 57 | animateScroll() 58 | } 59 | -------------------------------------------------------------------------------- /src/views/tool/gen/basicInfoForm.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 62 | -------------------------------------------------------------------------------- /src/views/dashboard/PieChart.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 80 | -------------------------------------------------------------------------------- /src/permission.js: -------------------------------------------------------------------------------- 1 | import router from './router' 2 | import store from './store' 3 | import { Message } from 'element-ui' 4 | import NProgress from 'nprogress' 5 | import 'nprogress/nprogress.css' 6 | import { getToken } from '@/utils/auth' 7 | 8 | NProgress.configure({ showSpinner: false }) 9 | 10 | const whiteList = ['/login', '/auth-redirect', '/bind', '/register'] 11 | 12 | router.beforeEach((to, from, next) => { 13 | NProgress.start() 14 | if (getToken()) { 15 | /* has token*/ 16 | if (to.path === '/login') { 17 | next({ path: '/' }) 18 | NProgress.done() 19 | } else { 20 | if (store.getters.roles.length === 0) { 21 | // 判断当前用户是否已拉取完user_info信息 22 | store.dispatch('GetInfo').then(res => { 23 | // 拉取user_info 24 | const roles = res.roles 25 | store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => { 26 | // 测试 默认静态页面 27 | // store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => { 28 | // 根据roles权限生成可访问的路由表 29 | router.addRoutes(accessRoutes) // 动态添加可访问路由表 30 | next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 31 | }) 32 | }) 33 | .catch(err => { 34 | store.dispatch('FedLogOut').then(() => { 35 | Message.error(err) 36 | next({ path: '/' }) 37 | }) 38 | }) 39 | } else { 40 | next() 41 | // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓ 42 | // if (hasPermission(store.getters.roles, to.meta.roles)) { 43 | // next() 44 | // } else { 45 | // next({ path: '/401', replace: true, query: { noGoBack: true }}) 46 | // } 47 | // 可删 ↑ 48 | } 49 | } 50 | } else { 51 | // 没有token 52 | if (whiteList.indexOf(to.path) !== -1) { 53 | // 在免登录白名单,直接进入 54 | next() 55 | } else { 56 | next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页 57 | NProgress.done() 58 | } 59 | } 60 | }) 61 | 62 | router.afterEach(() => { 63 | NProgress.done() 64 | }) 65 | -------------------------------------------------------------------------------- /src/assets/icons/svg/date-range.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/layout/components/Sidebar/Logo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ title }} 7 | 8 | 9 | 10 | {{ title }} 11 | 12 | 13 | 14 | 15 | 16 | 35 | 36 | 85 | -------------------------------------------------------------------------------- /src/views/error/401.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 返回 5 | 6 | 7 | 8 | 9 | 401错误! 10 | 11 | 您没有访问权限! 12 | 对不起,您没有访问权限,请不要进行非法操作!您可以返回主页面 13 | 14 | 15 | 16 | 回首页 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 49 | 50 | 89 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import Cookies from 'js-cookie' 4 | 5 | import 'normalize.css/normalize.css' // a modern alternative to CSS resets 6 | 7 | import Element from 'element-ui' 8 | import './assets/styles/element-variables.scss' 9 | 10 | import '@/assets/styles/index.scss' // global css 11 | import '@/assets/styles/ruoyi.scss' // ruoyi css 12 | import App from './App' 13 | import store from './store' 14 | import router from './router' 15 | import permission from './directive/permission' 16 | 17 | import './assets/icons' // icon 18 | import './permission' // permission control 19 | import { getDicts } from "@/api/system/dict/data"; 20 | import { getConfigKey } from "@/api/system/config"; 21 | import { parseTime, resetForm, addDateRange, selectDictLabel, download, handleTree } from "@/utils/ruoyi"; 22 | import Pagination from "@/components/Pagination"; 23 | 24 | // 全局方法挂载 25 | Vue.prototype.getDicts = getDicts 26 | Vue.prototype.getConfigKey = getConfigKey 27 | Vue.prototype.parseTime = parseTime 28 | Vue.prototype.resetForm = resetForm 29 | Vue.prototype.addDateRange = addDateRange 30 | Vue.prototype.selectDictLabel = selectDictLabel 31 | Vue.prototype.download = download 32 | Vue.prototype.handleTree = handleTree 33 | 34 | Vue.prototype.msgSuccess = function (msg) { 35 | this.$message({ showClose: true, message: msg, type: "success" }); 36 | } 37 | 38 | Vue.prototype.msgError = function (msg) { 39 | this.$message({ showClose: true, message: msg, type: "error" }); 40 | } 41 | 42 | Vue.prototype.msgInfo = function (msg) { 43 | this.$message.info(msg); 44 | } 45 | 46 | // 全局组件挂载 47 | Vue.component('Pagination', Pagination) 48 | 49 | Vue.use(permission) 50 | 51 | /** 52 | * If you don't want to use mock-server 53 | * you want to use MockJs for mock api 54 | * you can execute: mockXHR() 55 | * 56 | * Currently MockJs will be used in the production environment, 57 | * please remove it before going online! ! ! 58 | */ 59 | 60 | Vue.use(Element, { 61 | size: Cookies.get('size') || 'medium' // set element-ui default size 62 | }) 63 | 64 | Vue.config.productionTip = false 65 | 66 | new Vue({ 67 | el: '#app', 68 | router, 69 | store, 70 | render: h => h(App) 71 | }) 72 | -------------------------------------------------------------------------------- /src/assets/icons/svg/shopping.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/svg/cascader.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utils/validate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} path 3 | * @returns {Boolean} 4 | */ 5 | export function isExternal(path) { 6 | return /^(https?:|mailto:|tel:)/.test(path) 7 | } 8 | 9 | /** 10 | * @param {string} str 11 | * @returns {Boolean} 12 | */ 13 | export function validUsername(str) { 14 | const valid_map = ['admin', 'editor'] 15 | return valid_map.indexOf(str.trim()) >= 0 16 | } 17 | 18 | /** 19 | * @param {string} url 20 | * @returns {Boolean} 21 | */ 22 | export function validURL(url) { 23 | const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ 24 | return reg.test(url) 25 | } 26 | 27 | /** 28 | * @param {string} str 29 | * @returns {Boolean} 30 | */ 31 | export function validLowerCase(str) { 32 | const reg = /^[a-z]+$/ 33 | return reg.test(str) 34 | } 35 | 36 | /** 37 | * @param {string} str 38 | * @returns {Boolean} 39 | */ 40 | export function validUpperCase(str) { 41 | const reg = /^[A-Z]+$/ 42 | return reg.test(str) 43 | } 44 | 45 | /** 46 | * @param {string} str 47 | * @returns {Boolean} 48 | */ 49 | export function validAlphabets(str) { 50 | const reg = /^[A-Za-z]+$/ 51 | return reg.test(str) 52 | } 53 | 54 | /** 55 | * @param {string} email 56 | * @returns {Boolean} 57 | */ 58 | export function validEmail(email) { 59 | const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 60 | return reg.test(email) 61 | } 62 | 63 | /** 64 | * @param {string} str 65 | * @returns {Boolean} 66 | */ 67 | export function isString(str) { 68 | if (typeof str === 'string' || str instanceof String) { 69 | return true 70 | } 71 | return false 72 | } 73 | 74 | /** 75 | * @param {Array} arg 76 | * @returns {Boolean} 77 | */ 78 | export function isArray(arg) { 79 | if (typeof Array.isArray === 'undefined') { 80 | return Object.prototype.toString.call(arg) === '[object Array]' 81 | } 82 | return Array.isArray(arg) 83 | } 84 | -------------------------------------------------------------------------------- /src/views/components/icons/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | {{ generateIconCode(item) }} 13 | 14 | 15 | 16 | {{ item }} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | {{ generateElementIconCode(item) }} 26 | 27 | 28 | 29 | {{ item }} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 60 | 61 | 88 | -------------------------------------------------------------------------------- /src/assets/icons/svg/dashboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Sticky/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | sticky 9 | 10 | 11 | 12 | 13 | 14 | 92 | -------------------------------------------------------------------------------- /src/components/Breadcrumb/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ item.meta.title }} 6 | {{ item.meta.title }} 7 | 8 | 9 | 10 | 11 | 12 | 68 | 69 | 82 | -------------------------------------------------------------------------------- /src/assets/icons/svg/component.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/system/user/profile/userInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 保存 24 | 关闭 25 | 26 | 27 | 28 | 29 | 80 | -------------------------------------------------------------------------------- /src/assets/icons/svg/form.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Pagination/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 92 | 93 | 102 | -------------------------------------------------------------------------------- /src/directive/waves/waves.js: -------------------------------------------------------------------------------- 1 | import './waves.css' 2 | 3 | const context = '@@wavesContext' 4 | 5 | function handleClick(el, binding) { 6 | function handle(e) { 7 | const customOpts = Object.assign({}, binding.value) 8 | const opts = Object.assign({ 9 | ele: el, // 波纹作用元素 10 | type: 'hit', // hit 点击位置扩散 center中心点扩展 11 | color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色 12 | }, 13 | customOpts 14 | ) 15 | const target = opts.ele 16 | if (target) { 17 | target.style.position = 'relative' 18 | target.style.overflow = 'hidden' 19 | const rect = target.getBoundingClientRect() 20 | let ripple = target.querySelector('.waves-ripple') 21 | if (!ripple) { 22 | ripple = document.createElement('span') 23 | ripple.className = 'waves-ripple' 24 | ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px' 25 | target.appendChild(ripple) 26 | } else { 27 | ripple.className = 'waves-ripple' 28 | } 29 | switch (opts.type) { 30 | case 'center': 31 | ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px' 32 | ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px' 33 | break 34 | default: 35 | ripple.style.top = 36 | (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop || 37 | document.body.scrollTop) + 'px' 38 | ripple.style.left = 39 | (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || 40 | document.body.scrollLeft) + 'px' 41 | } 42 | ripple.style.backgroundColor = opts.color 43 | ripple.className = 'waves-ripple z-active' 44 | return false 45 | } 46 | } 47 | 48 | if (!el[context]) { 49 | el[context] = { 50 | removeHandle: handle 51 | } 52 | } else { 53 | el[context].removeHandle = handle 54 | } 55 | 56 | return handle 57 | } 58 | 59 | export default { 60 | bind(el, binding) { 61 | el.addEventListener('click', handleClick(el, binding), false) 62 | }, 63 | update(el, binding) { 64 | el.removeEventListener('click', el[context].removeHandle, false) 65 | el.addEventListener('click', handleClick(el, binding), false) 66 | }, 67 | unbind(el) { 68 | el.removeEventListener('click', el[context].removeHandle, false) 69 | el[context] = null 70 | delete el[context] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/views/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 79 | 80 | 99 | -------------------------------------------------------------------------------- /src/assets/icons/svg/tool.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/system/user/profile/resetPwd.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 保存 14 | 关闭 15 | 16 | 17 | 18 | 19 | 77 | -------------------------------------------------------------------------------- /src/views/dashboard/BarChart.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 103 | --------------------------------------------------------------------------------