├── src ├── components │ ├── tools │ │ ├── index.js │ │ ├── DetailList.vue │ │ ├── Logo.vue │ │ ├── Breadcrumb.vue │ │ ├── HeadInfo.vue │ │ ├── UserMenu.vue │ │ └── TwoStepCaptcha.vue │ ├── Menu │ │ ├── index.js │ │ └── SideMenu.vue │ ├── Result │ │ ├── index.js │ │ └── Result.vue │ ├── Trend │ │ ├── index.js │ │ ├── index.less │ │ ├── index.md │ │ └── Trend.vue │ ├── Ellipsis │ │ ├── index.js │ │ ├── index.md │ │ └── Ellipsis.vue │ ├── CountDown │ │ ├── index.js │ │ ├── index.md │ │ └── CountDown.vue │ ├── NoticeIcon │ │ ├── index.js │ │ └── NoticeIcon.vue │ ├── PageHeader │ │ └── index.js │ ├── NumberInfo │ │ ├── index.js │ │ ├── index.md │ │ ├── NumberInfo.vue │ │ └── index.less │ ├── Exception │ │ ├── index.js │ │ └── type.js │ ├── GlobalFooter │ │ ├── index.js │ │ └── GlobalFooter.vue │ ├── GlobalHeader │ │ └── index.js │ ├── IconSelector │ │ ├── index.js │ │ ├── README.md │ │ └── IconSelector.vue │ ├── SettingDrawer │ │ ├── index.js │ │ ├── SettingItem.vue │ │ └── themeColor.js │ ├── DescriptionList │ │ └── index.js │ ├── AvatarList │ │ ├── index.js │ │ ├── Item.vue │ │ ├── index.less │ │ ├── index.md │ │ └── List.vue │ ├── MultiTab │ │ ├── index.js │ │ └── index.less │ ├── StandardFormRow │ │ └── index.js │ ├── ArticleListContent │ │ ├── index.js │ │ └── ArticleListContent.vue │ ├── FooterToolbar │ │ ├── index.js │ │ ├── index.less │ │ ├── FooterToolBar.vue │ │ └── index.md │ ├── index.less │ ├── Charts │ │ ├── chart.less │ │ ├── smooth.area.less │ │ ├── MiniSmoothArea.vue │ │ ├── MiniBar.vue │ │ ├── MiniArea.vue │ │ ├── TransferBar.vue │ │ ├── Bar.vue │ │ ├── Liquid.vue │ │ ├── Radar.vue │ │ ├── MiniProgress.vue │ │ ├── RankList.vue │ │ └── Trend.vue │ ├── PageLoading │ │ └── index.jsx │ ├── _util │ │ └── util.js │ ├── TagSelect │ │ └── TagSelectOption.jsx │ ├── Editor │ │ └── WangEditor.vue │ └── index.js ├── assets │ ├── logo.png │ └── icons │ │ └── bx-analyse.svg ├── views │ ├── account │ │ ├── center │ │ │ └── page │ │ │ │ ├── index.js │ │ │ │ └── Article.vue │ │ └── settings │ │ │ ├── Binding.vue │ │ │ ├── Notification.vue │ │ │ ├── Security.vue │ │ │ └── Custom.vue │ ├── 404.vue │ ├── dashboard │ │ ├── Monitor.vue │ │ └── Analysis.vue │ ├── exception │ │ ├── 403.vue │ │ ├── 404.vue │ │ └── 500.vue │ ├── list │ │ ├── search │ │ │ ├── components │ │ │ │ ├── IconText.vue │ │ │ │ └── CardInfo.vue │ │ │ └── SearchLayout.vue │ │ ├── QueryList.vue │ │ └── modules │ │ │ ├── CreateForm.vue │ │ │ └── TaskForm.vue │ ├── other │ │ ├── IconSelectorView.vue │ │ └── modules │ │ │ └── OrgModal.vue │ ├── user │ │ └── RegisterResult.vue │ ├── result │ │ └── Error.vue │ ├── form │ │ └── stepForm │ │ │ ├── StepForm.vue │ │ │ └── Step3.vue │ ├── usergroup │ │ ├── CreateForm.vue │ │ ├── RoleConfigForm.vue │ │ └── UserConfigForm.vue │ └── common │ │ └── CreateForm.vue ├── layouts │ ├── BlankLayout.vue │ ├── index.js │ ├── IframeView.vue │ └── RouteView.vue ├── router │ └── index.js ├── api │ ├── index.js │ ├── tool.js │ ├── crole.js │ ├── cuser.js │ ├── manage.js │ ├── task.js │ ├── ads.js │ ├── media.js │ ├── login.js │ ├── param.js │ ├── loginlog.js │ ├── gallery.js │ ├── tasklog.js │ ├── dictdata.js │ ├── article.js │ ├── dictcatalog.js │ ├── operationlog.js │ ├── systemnotice.js │ ├── userrolemapping.js │ ├── articlecontent.js │ ├── post.js │ ├── userdeptmapping.js │ ├── userpostmapping.js │ ├── roleresourcemapping.js │ ├── usergroupmapping.js │ ├── resource.js │ ├── usergrouprolemapping.js │ ├── cresource.js │ ├── role.js │ ├── dept.js │ ├── articlecategory.js │ ├── user.js │ └── usergroup.js ├── core │ ├── icons.js │ ├── lazy_use.js │ ├── use.js │ ├── bootstrap.js │ ├── directives │ │ └── action.js │ └── lazy_lib │ │ └── components_use.js ├── store │ ├── index.js │ ├── getters.js │ └── mutation-types.js ├── App.vue ├── utils │ ├── domUtil.js │ ├── filter.js │ ├── axios.js │ ├── device.js │ ├── utils.less │ ├── permissions.js │ ├── helper │ │ └── permission.js │ ├── storage.js │ ├── util.js │ ├── request.js │ └── mixin.js ├── mock │ ├── index.js │ ├── util.js │ └── services │ │ └── auth.js ├── main.js ├── config │ ├── router.config.js │ └── defaultSettings.js └── permission.js ├── .gitattributes ├── .env ├── .env.preview ├── public ├── logo.png ├── avatar2.jpg ├── loading │ ├── loading.html │ ├── option2 │ │ ├── loading.css │ │ ├── loading.svg │ │ └── html_code_segment.html │ └── loading.css └── index.html ├── tests └── unit │ └── .eslintrc.js ├── .prettierrc ├── .travis.yml ├── jsconfig.json ├── .gitignore ├── webstorm.config.js ├── README.md ├── babel.config.js ├── jest.config.js ├── docs ├── multi-tabs.md ├── add-page-loading-animate.md ├── webpack-bundle-analyzer.md └── load-on-demand.md ├── .editorconfig └── LICENSE /src/components/tools/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | public/* linguist-vendored -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | VUE_APP_PREVIEW=false 3 | -------------------------------------------------------------------------------- /.env.preview: -------------------------------------------------------------------------------- 1 | NODE_ENV=production 2 | VUE_APP_PREVIEW=true 3 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huntermr/xadmin-web/HEAD/public/logo.png -------------------------------------------------------------------------------- /src/components/Menu/index.js: -------------------------------------------------------------------------------- 1 | import SMenu from './menu' 2 | export default SMenu 3 | -------------------------------------------------------------------------------- /public/avatar2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huntermr/xadmin-web/HEAD/public/avatar2.jpg -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huntermr/xadmin-web/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "semi": false, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /src/components/Result/index.js: -------------------------------------------------------------------------------- 1 | import Result from './Result.vue' 2 | export default Result 3 | -------------------------------------------------------------------------------- /src/components/Trend/index.js: -------------------------------------------------------------------------------- 1 | import Trend from './Trend.vue' 2 | 3 | export default Trend 4 | -------------------------------------------------------------------------------- /src/components/Ellipsis/index.js: -------------------------------------------------------------------------------- 1 | import Ellipsis from './Ellipsis' 2 | 3 | export default Ellipsis 4 | -------------------------------------------------------------------------------- /src/components/CountDown/index.js: -------------------------------------------------------------------------------- 1 | import CountDown from './CountDown' 2 | 3 | export default CountDown 4 | -------------------------------------------------------------------------------- /src/components/NoticeIcon/index.js: -------------------------------------------------------------------------------- 1 | import NoticeIcon from './NoticeIcon' 2 | export default NoticeIcon 3 | -------------------------------------------------------------------------------- /src/components/PageHeader/index.js: -------------------------------------------------------------------------------- 1 | import PageHeader from './PageHeader' 2 | export default PageHeader 3 | -------------------------------------------------------------------------------- /src/components/NumberInfo/index.js: -------------------------------------------------------------------------------- 1 | import NumberInfo from './NumberInfo' 2 | 3 | export default NumberInfo 4 | -------------------------------------------------------------------------------- /src/components/Exception/index.js: -------------------------------------------------------------------------------- 1 | import ExceptionPage from './ExceptionPage.vue' 2 | export default ExceptionPage 3 | -------------------------------------------------------------------------------- /src/components/GlobalFooter/index.js: -------------------------------------------------------------------------------- 1 | import GlobalFooter from './GlobalFooter' 2 | export default GlobalFooter 3 | -------------------------------------------------------------------------------- /src/components/GlobalHeader/index.js: -------------------------------------------------------------------------------- 1 | import GlobalHeader from './GlobalHeader' 2 | export default GlobalHeader 3 | -------------------------------------------------------------------------------- /src/components/IconSelector/index.js: -------------------------------------------------------------------------------- 1 | import IconSelector from './IconSelector' 2 | export default IconSelector 3 | -------------------------------------------------------------------------------- /src/components/SettingDrawer/index.js: -------------------------------------------------------------------------------- 1 | import SettingDrawer from './SettingDrawer' 2 | export default SettingDrawer 3 | -------------------------------------------------------------------------------- /src/components/DescriptionList/index.js: -------------------------------------------------------------------------------- 1 | import DescriptionList from './DescriptionList' 2 | export default DescriptionList 3 | -------------------------------------------------------------------------------- /src/components/AvatarList/index.js: -------------------------------------------------------------------------------- 1 | import AvatarList from './List' 2 | import './index.less' 3 | 4 | export default AvatarList 5 | -------------------------------------------------------------------------------- /src/components/MultiTab/index.js: -------------------------------------------------------------------------------- 1 | import MultiTab from './MultiTab' 2 | import './index.less' 3 | 4 | export default MultiTab 5 | -------------------------------------------------------------------------------- /src/components/StandardFormRow/index.js: -------------------------------------------------------------------------------- 1 | import StandardFormRow from './StandardFormRow' 2 | 3 | export default StandardFormRow 4 | -------------------------------------------------------------------------------- /src/components/ArticleListContent/index.js: -------------------------------------------------------------------------------- 1 | import ArticleListContent from './ArticleListContent' 2 | 3 | export default ArticleListContent 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10.15.0 4 | cache: yarn 5 | script: 6 | - yarn 7 | - yarn run lint --no-fix && yarn run build 8 | -------------------------------------------------------------------------------- /src/components/FooterToolbar/index.js: -------------------------------------------------------------------------------- 1 | import FooterToolBar from './FooterToolBar' 2 | import './index.less' 3 | 4 | export default FooterToolBar 5 | -------------------------------------------------------------------------------- /src/components/index.less: -------------------------------------------------------------------------------- 1 | @import "~ant-design-vue/lib/style/index"; 2 | 3 | // The prefix to use on all css classes from ant-pro. 4 | @ant-pro-prefix : ant-pro; -------------------------------------------------------------------------------- /src/components/tools/DetailList.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/views/account/center/page/index.js: -------------------------------------------------------------------------------- 1 | import AppPage from './App' 2 | import ArticlePage from './Article' 3 | import ProjectPage from './Project' 4 | 5 | export { AppPage, ArticlePage, ProjectPage } 6 | -------------------------------------------------------------------------------- /public/loading/loading.html: -------------------------------------------------------------------------------- 1 |
Loading
-------------------------------------------------------------------------------- /src/views/404.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/views/dashboard/Monitor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["src/*"] 7 | } 8 | }, 9 | "exclude": ["node_modules", "dist"], 10 | "include": ["src/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /src/layouts/BlankLayout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /src/components/Charts/chart.less: -------------------------------------------------------------------------------- 1 | .antv-chart-mini { 2 | position: relative; 3 | width: 100%; 4 | 5 | .chart-wrapper { 6 | position: absolute; 7 | bottom: -28px; 8 | width: 100%; 9 | 10 | /* margin: 0 -5px; 11 | overflow: hidden;*/ 12 | } 13 | } -------------------------------------------------------------------------------- /src/components/PageLoading/index.jsx: -------------------------------------------------------------------------------- 1 | import { Spin } from 'ant-design-vue' 2 | 3 | export default { 4 | name: 'PageLoading', 5 | render () { 6 | return (
7 | 8 |
) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/views/exception/403.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /src/views/exception/404.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /src/views/exception/500.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /public/loading/option2/loading.css: -------------------------------------------------------------------------------- 1 | .preloading-animate{background:#ffffff;width:100%;height:100%;position:fixed;left:0;top:0;z-index:299;}.preloading-animate .preloading-wrapper{position:absolute;width:5rem;height:5rem;left:50%;top:50%;transform:translate(-50%,-50%);}.preloading-animate .preloading-wrapper .preloading-balls{font-size:5rem;} -------------------------------------------------------------------------------- /src/components/Charts/smooth.area.less: -------------------------------------------------------------------------------- 1 | @import "../index"; 2 | 3 | @smoothArea-prefix-cls: ~"@{ant-pro-prefix}-smooth-area"; 4 | 5 | .@{smoothArea-prefix-cls} { 6 | position: relative; 7 | width: 100%; 8 | 9 | .chart-wrapper { 10 | position: absolute; 11 | bottom: -28px; 12 | width: 100%; 13 | } 14 | } -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import { constantRouterMap } from '@/config/router.config' 4 | 5 | Vue.use(Router) 6 | 7 | export default new Router({ 8 | mode: 'history', 9 | base: process.env.BASE_URL, 10 | scrollBehavior: () => ({ y: 0 }), 11 | routes: constantRouterMap 12 | }) 13 | -------------------------------------------------------------------------------- /src/layouts/index.js: -------------------------------------------------------------------------------- 1 | import UserLayout from './UserLayout' 2 | import BlankLayout from './BlankLayout' 3 | import BasicLayout from './BasicLayout' 4 | import RouteView from './RouteView' 5 | import PageView from './PageView' 6 | import IframeView from './IframeView' 7 | 8 | export { UserLayout, BasicLayout, BlankLayout, RouteView, PageView, IframeView } 9 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | const api = { 2 | Login: '/auth/login', 3 | Logout: '/auth/logout', 4 | ForgePassword: '/auth/forge-password', 5 | Register: '/auth/register', 6 | twoStepCode: '/auth/2step-code', 7 | SendSms: '/account/sms', 8 | SendSmsErr: '/account/sms_err', 9 | // get my info 10 | UserInfo: '/user/info' 11 | } 12 | export default api 13 | -------------------------------------------------------------------------------- /src/core/icons.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom icon list 3 | * All icons are loaded here for easy management 4 | * @see https://vue.ant.design/components/icon/#Custom-Font-Icon 5 | * 6 | * 自定义图标加载表 7 | * 所有图标均从这里加载,方便管理 8 | */ 9 | import bxAnaalyse from '@/assets/icons/bx-analyse.svg?inline' // path to your '*.svg?inline' file. 10 | 11 | export { bxAnaalyse } 12 | -------------------------------------------------------------------------------- /webstorm.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | 4 | function resolve (dir) { 5 | return path.join(__dirname, '.', dir) 6 | } 7 | 8 | module.exports = { 9 | context: path.resolve(__dirname, './'), 10 | resolve: { 11 | extensions: ['.js', '.vue', '.json'], 12 | alias: { 13 | '@': resolve('src') 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/views/account/settings/Binding.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /src/views/account/settings/Notification.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xadmin系列——前端 2 | 3 | ### 前后分离的通用后台管理系统,前端基于Ant Design Pro-Vue,后端基于SpringBoo 2.x。 4 | 5 | ##### 包含:定时任务管控、基于JWT的配合Shiro的鉴权、一键生成前后端增删改查代码、基于RBAC权限管控、用户管理、组织架构、各类日志(操作日志/定时任务日志/登录日志)等模块 6 | 7 | ##### xadmin系列链接 8 | ##### 前端 https://github.com/huntermr/xadmin-web 9 | ##### 服务端 https://github.com/huntermr/xadmin 10 | ##### 资源(包括但不限于ER图、系列教程、使用文档等等) https://github.com/huntermr/xadmin-resource 11 | 12 | >> 文档完善中... -------------------------------------------------------------------------------- /src/views/list/search/components/IconText.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app', 4 | [ 5 | '@babel/preset-env', 6 | { 7 | 'useBuiltIns': 'entry' 8 | } 9 | ] 10 | ] 11 | // if your use import on Demand, Use this code 12 | // , 13 | // plugins: [ 14 | // [ 'import', { 15 | // 'libraryName': 'ant-design-vue', 16 | // 'libraryDirectory': 'es', 17 | // 'style': true // `style: true` 会加载 less 文件 18 | // } ] 19 | // ] 20 | } 21 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import app from './modules/app' 5 | import user from './modules/user' 6 | import permission from './modules/permission' 7 | import getters from './getters' 8 | 9 | Vue.use(Vuex) 10 | 11 | export default new Vuex.Store({ 12 | modules: { 13 | app, 14 | user, 15 | permission 16 | }, 17 | state: { 18 | 19 | }, 20 | mutations: { 21 | 22 | }, 23 | actions: { 24 | 25 | }, 26 | getters 27 | }) 28 | -------------------------------------------------------------------------------- /src/components/FooterToolbar/index.less: -------------------------------------------------------------------------------- 1 | @import "../index"; 2 | 3 | @footer-toolbar-prefix-cls: ~"@{ant-pro-prefix}-footer-toolbar"; 4 | 5 | .@{footer-toolbar-prefix-cls} { 6 | position: fixed; 7 | width: 100%; 8 | bottom: 0; 9 | right: 0; 10 | height: 56px; 11 | line-height: 56px; 12 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03); 13 | background: #fff; 14 | border-top: 1px solid #e8e8e8; 15 | padding: 0 24px; 16 | z-index: 9; 17 | 18 | &:after { 19 | content: ""; 20 | display: block; 21 | clear: both; 22 | } 23 | } -------------------------------------------------------------------------------- /src/components/Exception/type.js: -------------------------------------------------------------------------------- 1 | const types = { 2 | 403: { 3 | img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg', 4 | title: '403', 5 | desc: '抱歉,你无权访问该页面' 6 | }, 7 | 404: { 8 | img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg', 9 | title: '404', 10 | desc: '抱歉,你访问的页面不存在或仍在开发中' 11 | }, 12 | 500: { 13 | img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg', 14 | title: '500', 15 | desc: '抱歉,服务器出错了' 16 | } 17 | } 18 | 19 | export default types 20 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | 30 | -------------------------------------------------------------------------------- /src/core/lazy_use.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueStorage from 'vue-ls' 3 | import config from '@/config/defaultSettings' 4 | 5 | // base library 6 | import '@/core/lazy_lib/components_use' 7 | import Viser from 'viser-vue' 8 | 9 | // ext library 10 | import VueClipboard from 'vue-clipboard2' 11 | import PermissionHelper from '@/utils/helper/permission' 12 | import './directives/action' 13 | 14 | VueClipboard.config.autoSetContainer = true 15 | 16 | Vue.use(Viser) 17 | 18 | Vue.use(VueStorage, config.storageOptions) 19 | Vue.use(VueClipboard) 20 | Vue.use(PermissionHelper) 21 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | const getters = { 2 | device: state => state.app.device, 3 | theme: state => state.app.theme, 4 | color: state => state.app.color, 5 | token: state => state.user.token, 6 | avatar: state => state.user.avatar, 7 | nickname: state => state.user.name, 8 | welcome: state => state.user.welcome, 9 | roles: state => state.user.roles, 10 | resources: state => state.user.resources, 11 | userInfo: state => state.user.info, 12 | addRouters: state => state.permission.addRouters, 13 | multiTab: state => state.app.multiTab 14 | } 15 | 16 | export default getters 17 | -------------------------------------------------------------------------------- /src/utils/domUtil.js: -------------------------------------------------------------------------------- 1 | export const setDocumentTitle = function (title) { 2 | document.title = title 3 | const ua = navigator.userAgent 4 | // eslint-disable-next-line 5 | const regex = /\bMicroMessenger\/([\d\.]+)/ 6 | if (regex.test(ua) && /ip(hone|od|ad)/i.test(ua)) { 7 | const i = document.createElement('iframe') 8 | i.src = '/favicon.ico' 9 | i.style.display = 'none' 10 | i.onload = function () { 11 | setTimeout(function () { 12 | i.remove() 13 | }, 9) 14 | } 15 | document.body.appendChild(i) 16 | } 17 | } 18 | 19 | export const domTitle = 'Xadmin' 20 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: [ 3 | 'js', 4 | 'jsx', 5 | 'json', 6 | 'vue' 7 | ], 8 | transform: { 9 | '^.+\\.vue$': 'vue-jest', 10 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', 11 | '^.+\\.jsx?$': 'babel-jest' 12 | }, 13 | moduleNameMapper: { 14 | '^@/(.*)$': '/src/$1' 15 | }, 16 | snapshotSerializers: [ 17 | 'jest-serializer-vue' 18 | ], 19 | testMatch: [ 20 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 21 | ], 22 | testURL: 'http://localhost/' 23 | } 24 | -------------------------------------------------------------------------------- /src/api/tool.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/gen' 4 | 5 | const api = { 6 | tableList: moudulePath + '/tables', 7 | genCode: moudulePath + '/include' 8 | } 9 | 10 | export function getTableList (parameter) { 11 | return axios({ 12 | url: api.tableList, 13 | method: 'get', 14 | params: parameter 15 | }) 16 | } 17 | 18 | export function genCode (parameter) { 19 | return axios({ 20 | url: api.genCode, 21 | method: 'post', 22 | headers: { 23 | 'Content-Type': 'application/json;charset=UTF-8' 24 | }, 25 | data: parameter 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs2' 2 | 3 | // 判断环境不是 prod 或者 preview 是 true 时,加载 mock 服务 4 | if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') { 5 | // 使用同步加载依赖 6 | // 防止 vuex 中的 GetInfo 早于 mock 运行,导致无法 mock 请求返回结果 7 | console.log('mock mounting') 8 | require('./services/auth') 9 | require('./services/user') 10 | require('./services/manage') 11 | require('./services/other') 12 | require('./services/tagCloud') 13 | require('./services/article') 14 | 15 | Mock.setup({ 16 | timeout: 800 // setter delay time 17 | }) 18 | console.log('mock mounted') 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/filter.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import moment from 'moment' 3 | import 'moment/locale/zh-cn' 4 | moment.locale('zh-cn') 5 | 6 | Vue.filter('NumberFormat', function (value) { 7 | if (!value) { 8 | return '0' 9 | } 10 | const intPartFormat = value.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') // 将整数部分逢三一断 11 | return intPartFormat 12 | }) 13 | 14 | Vue.filter('dayjs', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') { 15 | return moment(dataStr).format(pattern) 16 | }) 17 | 18 | Vue.filter('moment', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') { 19 | return moment(dataStr).format(pattern) 20 | }) 21 | -------------------------------------------------------------------------------- /src/components/FooterToolbar/FooterToolBar.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /src/views/other/IconSelectorView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 28 | -------------------------------------------------------------------------------- /docs/multi-tabs.md: -------------------------------------------------------------------------------- 1 | 多(页签)标签 模式 2 | ==== 3 | 4 | 5 | ## 让框架支持打开的页面增加多标签,可随时切换 6 | 7 | ### 关于如何移除该功能 组件 8 | 1. 移除 `/src/layouts/BasicLayout.vue` L44, L69, L80 9 | ```vue 10 | // L44 11 | 12 | 13 | // L69 14 | import MultiTab from '@/components/MultiTab' 15 | 16 | // L80 17 | MultiTab, 18 | ``` 19 | 2. 移除 `/src/config/defaultSettings.js` L25 20 | 21 | 3. 移除 `src/store/modules/app.js` L27, L76-L79, L118-L120 22 | 23 | 4. 移除 `src/utils/mixin.js` L21 24 | 25 | 5. 删除组件目录 `src/components/MultiTab` 26 | 27 | > 以上 `L x` 均代表行N ,如 L3 = 行3 28 | 29 | -------------------------------------------------------------------------------- /src/components/MultiTab/index.less: -------------------------------------------------------------------------------- 1 | @import '../index'; 2 | 3 | @multi-tab-prefix-cls: ~"@{ant-pro-prefix}-multi-tab"; 4 | @multi-tab-wrapper-prefix-cls: ~"@{ant-pro-prefix}-multi-tab-wrapper"; 5 | 6 | /* 7 | .topmenu .@{multi-tab-prefix-cls} { 8 | max-width: 1200px; 9 | margin: -23px auto 24px auto; 10 | } 11 | */ 12 | .@{multi-tab-prefix-cls} { 13 | margin: -23px -24px 24px -24px; 14 | background: #fff; 15 | } 16 | 17 | .topmenu .@{multi-tab-wrapper-prefix-cls} { 18 | max-width: 1200px; 19 | margin: 0 auto; 20 | } 21 | 22 | .topmenu.content-width-Fluid .@{multi-tab-wrapper-prefix-cls} { 23 | max-width: 100%; 24 | margin: 0 auto; 25 | } 26 | -------------------------------------------------------------------------------- /src/components/tools/Logo.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 32 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // ie polyfill 2 | import '@babel/polyfill' 3 | 4 | import Vue from 'vue' 5 | import App from './App.vue' 6 | import router from './router' 7 | import store from './store/' 8 | import { VueAxios } from './utils/request' 9 | 10 | // mock 11 | // import './mock' 12 | 13 | import bootstrap from './core/bootstrap' 14 | import './core/use' 15 | import './permission' // permission control 16 | import './utils/filter' // global filter 17 | 18 | Vue.config.productionTip = false 19 | 20 | // mount axios Vue.$http and this.$http 21 | Vue.use(VueAxios) 22 | 23 | new Vue({ 24 | router, 25 | store, 26 | created () { 27 | bootstrap() 28 | }, 29 | render: h => h(App) 30 | }).$mount('#app') 31 | -------------------------------------------------------------------------------- /src/components/CountDown/index.md: -------------------------------------------------------------------------------- 1 | # CountDown 倒计时 2 | 3 | 倒计时组件。 4 | 5 | 6 | 7 | 引用方式: 8 | 9 | ```javascript 10 | import CountDown from '@/components/CountDown/CountDown' 11 | 12 | export default { 13 | components: { 14 | CountDown 15 | } 16 | } 17 | ``` 18 | 19 | 20 | 21 | ## 代码演示 [demo](https://pro.loacg.com/test/home) 22 | 23 | ```html 24 | 25 | ``` 26 | 27 | 28 | 29 | ## API 30 | 31 | | 参数 | 说明 | 类型 | 默认值 | 32 | |----------|------------------------------------------|-------------|-------| 33 | | target | 目标时间 | Date | - | 34 | | onEnd | 倒计时结束回调 | funtion | -| 35 | -------------------------------------------------------------------------------- /src/core/use.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueStorage from 'vue-ls' 3 | import config from '@/config/defaultSettings' 4 | 5 | // base library 6 | import Antd from 'ant-design-vue' 7 | import Viser from 'viser-vue' 8 | import VueCropper from 'vue-cropper' 9 | import 'ant-design-vue/dist/antd.less' 10 | 11 | // ext library 12 | import VueClipboard from 'vue-clipboard2' 13 | import PermissionHelper from '@/utils/helper/permission' 14 | // import '@/components/use' 15 | import './directives/action' 16 | 17 | VueClipboard.config.autoSetContainer = true 18 | 19 | Vue.use(Antd) 20 | Vue.use(Viser) 21 | 22 | Vue.use(VueStorage, config.storageOptions) 23 | Vue.use(VueClipboard) 24 | Vue.use(PermissionHelper) 25 | Vue.use(VueCropper) 26 | -------------------------------------------------------------------------------- /docs/add-page-loading-animate.md: -------------------------------------------------------------------------------- 1 | 为首屏增加 加载动画 2 | ==== 3 | 4 | 5 | 6 | ## 需求 7 | 8 | > 为了缓解用户第一次访问时,加载 JS 过大所导致用户等待白屏时间过长导致的用户体验不好,进行的一个优化动效。 9 | 10 | 11 | 12 | ## 实现方案 13 | 14 | 1. 将 动画加载 dom 元素放在 #app 内,Vue 生命周期开始时,会自动清掉 #app 下的所有元素。 15 | 2. 将 动画加载 dom 元素放在 body 下,Vue 生命周期开始时 App.vue (created, mounted) 调用 `@/utils/utll` 下的 removeLoadingAnimate(#id, timeout) 则会移除加载动画 16 | 17 | 最后一步: 18 | ​ 将样式插入到 `public/index.html` 文件的 `` 最好写成内联 `` 19 | 20 | 21 | 22 | ---- 23 | 24 | 目前提供有两个样式,均在 `public/loading` 文件夹内。且 pro 已经默认使用了一套 loading 动画方案,可以直接参考 `public/index.html` 25 | 26 | 27 | ## 写在最后 28 | 29 | 目前 pro 有页面 overflow 显示出浏览器滚动条时,页面会抖动一下的问题。 30 | 31 | 欢迎各位提供能解决的方案和实现 demo。如果在条件允许的情况下,建议请直接使用 pro 进行改造,也欢迎直接 PR 到 pro 的仓库 32 | -------------------------------------------------------------------------------- /src/utils/axios.js: -------------------------------------------------------------------------------- 1 | const VueAxios = { 2 | vm: {}, 3 | // eslint-disable-next-line no-unused-vars 4 | install (Vue, instance) { 5 | if (this.installed) { 6 | return 7 | } 8 | this.installed = true 9 | 10 | if (!instance) { 11 | // eslint-disable-next-line no-console 12 | console.error('You have to install axios') 13 | return 14 | } 15 | 16 | Vue.axios = instance 17 | 18 | Object.defineProperties(Vue.prototype, { 19 | axios: { 20 | get: function get () { 21 | return instance 22 | } 23 | }, 24 | $http: { 25 | get: function get () { 26 | return instance 27 | } 28 | } 29 | }) 30 | } 31 | } 32 | 33 | export { 34 | VueAxios 35 | } 36 | -------------------------------------------------------------------------------- /src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ACCESS_TOKEN = 'Access-Token' 2 | export const USER_ID = 'User-ID' 3 | export const SIDEBAR_TYPE = 'SIDEBAR_TYPE' 4 | export const DEFAULT_THEME = 'DEFAULT_THEME' 5 | export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE' 6 | export const DEFAULT_COLOR = 'DEFAULT_COLOR' 7 | export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK' 8 | export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER' 9 | export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU' 10 | export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN' 11 | export const DEFAULT_CONTENT_WIDTH_TYPE = 'DEFAULT_CONTENT_WIDTH_TYPE' 12 | export const DEFAULT_MULTI_TAB = 'DEFAULT_MULTI_TAB' 13 | 14 | export const CONTENT_WIDTH_TYPE = { 15 | Fluid: 'Fluid', 16 | Fixed: 'Fixed' 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Trend/index.less: -------------------------------------------------------------------------------- 1 | @import "../index"; 2 | 3 | @trend-prefix-cls: ~"@{ant-pro-prefix}-trend"; 4 | 5 | .@{trend-prefix-cls} { 6 | display: inline-block; 7 | font-size: @font-size-base; 8 | line-height: 22px; 9 | 10 | .up, 11 | .down { 12 | margin-left: 4px; 13 | position: relative; 14 | top: 1px; 15 | 16 | i { 17 | font-size: 12px; 18 | transform: scale(0.83); 19 | } 20 | } 21 | 22 | .item-text { 23 | display: inline-block; 24 | margin-left: 8px; 25 | color: rgba(0,0,0,.85); 26 | } 27 | 28 | .up { 29 | color: @red-6; 30 | } 31 | .down { 32 | color: @green-6; 33 | top: -1px; 34 | } 35 | 36 | &.reverse-color .up { 37 | color: @green-6; 38 | } 39 | &.reverse-color .down { 40 | color: @red-6; 41 | } 42 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset=utf-8 3 | end_of_line=lf 4 | insert_final_newline=false 5 | indent_style=space 6 | indent_size=2 7 | 8 | [{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}] 9 | indent_style=space 10 | indent_size=2 11 | 12 | [{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}] 13 | indent_style=space 14 | indent_size=2 15 | 16 | [{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}] 17 | indent_style=space 18 | indent_size=2 19 | 20 | [*.svg] 21 | indent_style=space 22 | indent_size=2 23 | 24 | [*.js.map] 25 | indent_style=space 26 | indent_size=2 27 | 28 | [*.less] 29 | indent_style=space 30 | indent_size=2 31 | 32 | [*.vue] 33 | indent_style=space 34 | indent_size=2 35 | 36 | [{.analysis_options,*.yml,*.yaml}] 37 | indent_style=space 38 | indent_size=2 39 | 40 | -------------------------------------------------------------------------------- /src/components/SettingDrawer/SettingItem.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | 25 | 39 | -------------------------------------------------------------------------------- /src/layouts/IframeView.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 43 | 44 | 47 | -------------------------------------------------------------------------------- /src/components/Ellipsis/index.md: -------------------------------------------------------------------------------- 1 | # Ellipsis 文本自动省略号 2 | 3 | 文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。 4 | 5 | 6 | 7 | 引用方式: 8 | 9 | ```javascript 10 | import Ellipsis from '@/components/Ellipsis' 11 | 12 | export default { 13 | components: { 14 | Ellipsis 15 | } 16 | } 17 | ``` 18 | 19 | 20 | 21 | ## 代码演示 [demo](https://pro.loacg.com/test/home) 22 | 23 | ```html 24 | 25 | There were injuries alleged in three cases in 2015, and a 26 | fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall. 27 | 28 | ``` 29 | 30 | 31 | 32 | ## API 33 | 34 | 35 | 参数 | 说明 | 类型 | 默认值 36 | ----|------|-----|------ 37 | tooltip | 移动到文本展示完整内容的提示 | boolean | - 38 | length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | - -------------------------------------------------------------------------------- /src/views/dashboard/Analysis.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 36 | 37 | 39 | -------------------------------------------------------------------------------- /src/components/Trend/index.md: -------------------------------------------------------------------------------- 1 | # Trend 趋势标记 2 | 3 | 趋势符号,标记上升和下降趋势。通常用绿色代表“好”,红色代表“不好”,股票涨跌场景除外。 4 | 5 | 6 | 7 | 引用方式: 8 | 9 | ```javascript 10 | import Trend from '@/components/Trend' 11 | 12 | export default { 13 | components: { 14 | Trend 15 | } 16 | } 17 | ``` 18 | 19 | 20 | 21 | ## 代码演示 [demo](https://pro.loacg.com/test/home) 22 | 23 | ```html 24 | 5% 25 | ``` 26 | 或 27 | ```html 28 | 29 | 工资 30 | 5% 31 | 32 | ``` 33 | 或 34 | ```html 35 | 5% 36 | ``` 37 | 38 | 39 | ## API 40 | 41 | | 参数 | 说明 | 类型 | 默认值 | 42 | |----------|------------------------------------------|-------------|-------| 43 | | flag | 上升下降标识:`up|down` | string | - | 44 | | reverseColor | 颜色反转 | Boolean | false | 45 | 46 | -------------------------------------------------------------------------------- /src/components/SettingDrawer/themeColor.js: -------------------------------------------------------------------------------- 1 | import client from 'webpack-theme-color-replacer/client' 2 | import generate from '@ant-design/colors/lib/generate' 3 | 4 | export default { 5 | getAntdSerials (color) { 6 | // 淡化(即less的tint) 7 | const lightens = new Array(9).fill().map((t, i) => { 8 | return client.varyColor.lighten(color, i / 10) 9 | }) 10 | // colorPalette变换得到颜色值 11 | const colorPalettes = generate(color) 12 | return lightens.concat(colorPalettes) 13 | }, 14 | changeColor (newColor) { 15 | var options = { 16 | newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors` 17 | changeUrl (cssUrl) { 18 | return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path 19 | } 20 | } 21 | return client.changer.changeColor(options, Promise) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/components/FooterToolbar/index.md: -------------------------------------------------------------------------------- 1 | # FooterToolbar 底部工具栏 2 | 3 | 固定在底部的工具栏。 4 | 5 | 6 | 7 | ## 何时使用 8 | 9 | 固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。 10 | 11 | 12 | 13 | 引用方式: 14 | 15 | ```javascript 16 | import FooterToolBar from '@/components/FooterToolbar' 17 | 18 | export default { 19 | components: { 20 | FooterToolBar 21 | } 22 | } 23 | ``` 24 | 25 | 26 | 27 | ## 代码演示 28 | 29 | ```html 30 | 31 | 提交 32 | 33 | ``` 34 | 或 35 | ```html 36 | 37 | 提交 38 | 39 | ``` 40 | 41 | 42 | ## API 43 | 44 | 参数 | 说明 | 类型 | 默认值 45 | ----|------|-----|------ 46 | children (slot) | 工具栏内容,向右对齐 | - | - 47 | extra | 额外信息,向左对齐 | String, Object | - 48 | 49 | -------------------------------------------------------------------------------- /src/components/Trend/Trend.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 38 | 39 | 42 | -------------------------------------------------------------------------------- /src/utils/device.js: -------------------------------------------------------------------------------- 1 | import enquireJs from 'enquire.js' 2 | 3 | export const DEVICE_TYPE = { 4 | DESKTOP: 'desktop', 5 | TABLET: 'tablet', 6 | MOBILE: 'mobile' 7 | } 8 | 9 | export const deviceEnquire = function (callback) { 10 | const matchDesktop = { 11 | match: () => { 12 | callback && callback(DEVICE_TYPE.DESKTOP) 13 | } 14 | } 15 | 16 | const matchLablet = { 17 | match: () => { 18 | callback && callback(DEVICE_TYPE.TABLET) 19 | } 20 | } 21 | 22 | const matchMobile = { 23 | match: () => { 24 | callback && callback(DEVICE_TYPE.MOBILE) 25 | } 26 | } 27 | 28 | // screen and (max-width: 1087.99px) 29 | enquireJs 30 | .register('screen and (max-width: 576px)', matchMobile) 31 | .register('screen and (min-width: 576px) and (max-width: 1199px)', matchLablet) 32 | .register('screen and (min-width: 1200px)', matchDesktop) 33 | } 34 | -------------------------------------------------------------------------------- /src/components/NumberInfo/index.md: -------------------------------------------------------------------------------- 1 | # NumberInfo 数据文本 2 | 3 | 常用在数据卡片中,用于突出展示某个业务数据。 4 | 5 | 6 | 7 | 引用方式: 8 | 9 | ```javascript 10 | import NumberInfo from '@/components/NumberInfo' 11 | 12 | export default { 13 | components: { 14 | NumberInfo 15 | } 16 | } 17 | ``` 18 | 19 | 20 | 21 | ## 代码演示 [demo](https://pro.loacg.com/test/home) 22 | 23 | ```html 24 | 29 | ``` 30 | 31 | 32 | 33 | ## API 34 | 35 | 参数 | 说明 | 类型 | 默认值 36 | ----|------|-----|------ 37 | title | 标题 | ReactNode\|string | - 38 | subTitle | 子标题 | ReactNode\|string | - 39 | total | 总量 | ReactNode\|string | - 40 | subTotal | 子总量 | ReactNode\|string | - 41 | status | 增加状态 | 'up \| down' | - 42 | theme | 状态样式 | string | 'light' 43 | gap | 设置数字和描述之间的间距(像素)| number | 8 44 | -------------------------------------------------------------------------------- /src/layouts/RouteView.vue: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /docs/webpack-bundle-analyzer.md: -------------------------------------------------------------------------------- 1 | 先增加依赖 2 | 3 | ```bash 4 | // npm 5 | $ npm install --save-dev webpack-bundle-analyzer 6 | 7 | // or yarn 8 | $ yarn add webpack-bundle-analyzer -D 9 | ``` 10 | 11 | 配置文件 `vue.config.js` 增加 `configureWebpack.plugins` 参数 12 | 13 | ``` 14 | const path = require('path') 15 | const webpack = require('webpack') 16 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 17 | 18 | function resolve (dir) { 19 | return path.join(__dirname, dir) 20 | } 21 | 22 | // vue.config.js 23 | module.exports = { 24 | configureWebpack: { 25 | plugins: [ 26 | // Ignore all locale files of moment.js 27 | new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), 28 | // 依赖大小分析工具 29 | new BundleAnalyzerPlugin(), 30 | ] 31 | }, 32 | 33 | 34 | ... 35 | } 36 | ``` 37 | 38 | 39 | 40 | 启动 `cli` 的 `build` 命令进行项目编译,编译完成时,会自动运行一个 http://localhost:8888 的地址,完整显示了支持库依赖 -------------------------------------------------------------------------------- /src/components/IconSelector/README.md: -------------------------------------------------------------------------------- 1 | IconSelector 2 | ==== 3 | 4 | > 图标选择组件,常用于为某一个数据设定一个图标时使用 5 | > eg: 设定菜单列表时,为每个菜单设定一个图标 6 | 7 | 该组件由 [@Saraka](https://github.com/saraka-tsukai) 封装 8 | 9 | 10 | 11 | ### 使用方式 12 | 13 | ```vue 14 | 19 | 20 | 39 | ``` 40 | 41 | 42 | 43 | ### 事件 44 | 45 | 46 | | 名称 | 说明 | 类型 | 默认值 | 47 | | ------ | -------------------------- | ------ | ------ | 48 | | change | 当改变了 `icon` 选中项触发 | String | - | 49 | -------------------------------------------------------------------------------- /src/components/Charts/MiniSmoothArea.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 37 | 38 | 41 | -------------------------------------------------------------------------------- /src/api/crole.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/role' 4 | 5 | const api = { 6 | roleList: moudulePath + '/page', 7 | addRole: moudulePath 8 | } 9 | 10 | export default api 11 | 12 | export function getRoleList (parameter) { 13 | return axios({ 14 | url: api.roleList, 15 | method: 'get', 16 | params: parameter 17 | }) 18 | } 19 | 20 | export function addRole (parameter) { 21 | return axios({ 22 | url: api.addRole, 23 | method: 'post', 24 | params: parameter 25 | }) 26 | } 27 | 28 | export function editRole (roleId, parameter) { 29 | console.log('roleId', roleId) 30 | console.log('parameter', parameter) 31 | return axios({ 32 | url: moudulePath + '/' + roleId, 33 | method: 'put', 34 | params: parameter 35 | }) 36 | } 37 | 38 | export function delRole (roleId) { 39 | console.log('roleId', roleId) 40 | return axios({ 41 | url: moudulePath + '/' + roleId, 42 | method: 'delete' 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /src/components/AvatarList/Item.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 47 | -------------------------------------------------------------------------------- /src/components/GlobalFooter/GlobalFooter.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | 23 | 50 | -------------------------------------------------------------------------------- /src/config/router.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | import { UserLayout } from '@/layouts' 3 | 4 | /** 5 | * 基础路由 6 | * @type { *[] } 7 | */ 8 | export const constantRouterMap = [ 9 | { 10 | path: '/user', 11 | component: UserLayout, 12 | redirect: '/user/login', 13 | hidden: true, 14 | children: [ 15 | { 16 | path: 'login', 17 | name: 'login', 18 | component: () => import(/* webpackChunkName: "user" */ '@/views/user/Login') 19 | }, 20 | { 21 | path: 'register', 22 | name: 'register', 23 | component: () => import(/* webpackChunkName: "user" */ '@/views/user/Register') 24 | }, 25 | { 26 | path: 'register-result', 27 | name: 'registerResult', 28 | component: () => import(/* webpackChunkName: "user" */ '@/views/user/RegisterResult') 29 | } 30 | ] 31 | }, 32 | 33 | { 34 | path: '/404', 35 | hidden: true, 36 | component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404') 37 | } 38 | 39 | ] 40 | -------------------------------------------------------------------------------- /src/utils/utils.less: -------------------------------------------------------------------------------- 1 | .textOverflow() { 2 | overflow: hidden; 3 | white-space: nowrap; 4 | text-overflow: ellipsis; 5 | word-break: break-all; 6 | } 7 | 8 | .textOverflowMulti(@line: 3, @bg: #fff) { 9 | position: relative; 10 | max-height: @line * 1.5em; 11 | margin-right: -1em; 12 | padding-right: 1em; 13 | overflow: hidden; 14 | line-height: 1.5em; 15 | text-align: justify; 16 | &::before { 17 | position: absolute; 18 | right: 14px; 19 | bottom: 0; 20 | padding: 0 1px; 21 | background: @bg; 22 | content: '...'; 23 | } 24 | &::after { 25 | position: absolute; 26 | right: 14px; 27 | width: 1em; 28 | height: 1em; 29 | margin-top: 0.2em; 30 | background: white; 31 | content: ''; 32 | } 33 | } 34 | 35 | // mixins for clearfix 36 | // ------------------------ 37 | .clearfix() { 38 | zoom: 1; 39 | &::before, 40 | &::after { 41 | display: table; 42 | content: ' '; 43 | } 44 | &::after { 45 | clear: both; 46 | height: 0; 47 | font-size: 0; 48 | visibility: hidden; 49 | } 50 | } -------------------------------------------------------------------------------- /src/mock/util.js: -------------------------------------------------------------------------------- 1 | const responseBody = { 2 | message: '', 3 | timestamp: 0, 4 | data: null, 5 | status: 0 6 | } 7 | 8 | export const builder = (data, message, code = 0, headers = {}) => { 9 | responseBody.data = data 10 | if (message !== undefined && message !== null) { 11 | responseBody.message = message 12 | } 13 | if (code !== undefined && code !== 0) { 14 | responseBody.status = code 15 | responseBody._status = code 16 | } 17 | if (headers !== null && typeof headers === 'object' && Object.keys(headers).length > 0) { 18 | responseBody._headers = headers 19 | } 20 | responseBody.timestamp = new Date().getTime() 21 | return responseBody 22 | } 23 | 24 | export const getQueryParameters = (options) => { 25 | const url = options.url 26 | const search = url.split('?')[1] 27 | if (!search) { 28 | return {} 29 | } 30 | return JSON.parse('{"' + decodeURIComponent(search) 31 | .replace(/"/g, '\\"') 32 | .replace(/&/g, '","') 33 | .replace(/=/g, '":"') + '"}') 34 | } 35 | 36 | export const getBody = (options) => { 37 | return options.body && JSON.parse(options.body) 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Anan Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/components/_util/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * components util 3 | */ 4 | 5 | /** 6 | * 清理空值,对象 7 | * @param children 8 | * @returns {*[]} 9 | */ 10 | export function filterEmpty (children = []) { 11 | return children.filter(c => c.tag || (c.text && c.text.trim() !== '')) 12 | } 13 | 14 | /** 15 | * 获取字符串长度,英文字符 长度1,中文字符长度2 16 | * @param {*} str 17 | */ 18 | export const getStrFullLength = (str = '') => 19 | str.split('').reduce((pre, cur) => { 20 | const charCode = cur.charCodeAt(0) 21 | if (charCode >= 0 && charCode <= 128) { 22 | return pre + 1 23 | } 24 | return pre + 2 25 | }, 0) 26 | 27 | /** 28 | * 截取字符串,根据 maxLength 截取后返回 29 | * @param {*} str 30 | * @param {*} maxLength 31 | */ 32 | export const cutStrByFullLength = (str = '', maxLength) => { 33 | let showLength = 0 34 | return str.split('').reduce((pre, cur) => { 35 | const charCode = cur.charCodeAt(0) 36 | if (charCode >= 0 && charCode <= 128) { 37 | showLength += 1 38 | } else { 39 | showLength += 2 40 | } 41 | if (showLength <= maxLength) { 42 | return pre + cur 43 | } 44 | return pre 45 | }, '') 46 | } 47 | -------------------------------------------------------------------------------- /src/api/cuser.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/user' 4 | 5 | const api = { 6 | userList: moudulePath + '/page', 7 | addUser: moudulePath 8 | } 9 | 10 | export default api 11 | 12 | export function getUserList (parameter) { 13 | return axios({ 14 | url: api.userList, 15 | method: 'get', 16 | params: parameter 17 | }) 18 | } 19 | 20 | export function getUserInfo (userId) { 21 | return axios({ 22 | url: api.moudulePath + '/' + userId, 23 | method: 'get' 24 | }) 25 | } 26 | 27 | export function addUser (parameter) { 28 | return axios({ 29 | url: api.addUser, 30 | method: 'post', 31 | params: parameter 32 | }) 33 | } 34 | 35 | export function editUser (userId, parameter) { 36 | console.log('userId', userId) 37 | console.log('parameter', parameter) 38 | return axios({ 39 | url: moudulePath + '/' + userId, 40 | method: 'put', 41 | params: parameter 42 | }) 43 | } 44 | 45 | export function delUser (userId) { 46 | console.log('userId', userId) 47 | return axios({ 48 | url: moudulePath + '/' + userId, 49 | method: 'delete' 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /src/views/user/RegisterResult.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 47 | 48 | 51 | -------------------------------------------------------------------------------- /src/utils/permissions.js: -------------------------------------------------------------------------------- 1 | export function actionToObject (json) { 2 | try { 3 | return JSON.parse(json) 4 | } catch (e) { 5 | console.log('err', e.message) 6 | } 7 | return [] 8 | } 9 | 10 | export function convertTreeData (resources, selectable) { 11 | return resources.map(r => { 12 | return { 13 | title: r.resourceName + ' - ' + formatType(r.resourceType), 14 | key: r.resourceId, 15 | value: r.resourceId, 16 | children: r.childResources ? convertTreeData(r.childResources) : [], 17 | selectable: selectable 18 | } 19 | }) 20 | } 21 | 22 | function formatType (type) { 23 | if (type === 'G') { 24 | return '(菜单组)' 25 | } else if (type === 'M') { 26 | return '(菜单)' 27 | } else if (type === 'O') { 28 | return '(按钮)' 29 | } 30 | } 31 | 32 | export function convertCheckKeys (checkedKeys, resources) { 33 | // 仅选中所有子节点,以便渲染 34 | resources.forEach(r => { 35 | // 如果有子节点,则取子节点数据即可,没有才取当前节点 36 | if (r.childResources && r.childResources.length > 0) { 37 | convertCheckKeys(checkedKeys, r.childResources) 38 | } else { 39 | checkedKeys.push(r.resourceId) 40 | } 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /src/components/TagSelect/TagSelectOption.jsx: -------------------------------------------------------------------------------- 1 | import { Tag } from 'ant-design-vue' 2 | const { CheckableTag } = Tag 3 | 4 | export default { 5 | name: 'TagSelectOption', 6 | props: { 7 | prefixCls: { 8 | type: String, 9 | default: 'ant-pro-tag-select-option' 10 | }, 11 | value: { 12 | type: [String, Number, Object], 13 | default: '' 14 | }, 15 | checked: { 16 | type: Boolean, 17 | default: false 18 | } 19 | }, 20 | data () { 21 | return { 22 | localChecked: this.checked || false 23 | } 24 | }, 25 | watch: { 26 | 'checked' (val) { 27 | this.localChecked = val 28 | }, 29 | '$parent.items': { 30 | handler: function (val) { 31 | this.value && val.hasOwnProperty(this.value) && (this.localChecked = val[this.value]) 32 | }, 33 | deep: true 34 | } 35 | }, 36 | render () { 37 | const { $slots, value } = this 38 | const onChange = (checked) => { 39 | this.$emit('change', { value, checked }) 40 | } 41 | return ( 42 | {$slots.default} 43 | ) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/views/list/search/components/CardInfo.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 29 | 30 | 59 | -------------------------------------------------------------------------------- /src/views/list/QueryList.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 51 | -------------------------------------------------------------------------------- /src/components/tools/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /src/components/Charts/MiniBar.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 54 | 55 | 58 | -------------------------------------------------------------------------------- /src/components/Charts/MiniArea.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /src/api/manage.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const api = { 4 | user: '/user', 5 | service: '/service', 6 | permission: '/permission', 7 | permissionNoPager: '/permission/no-pager', 8 | orgTree: '/org/tree' 9 | } 10 | 11 | export default api 12 | 13 | export function getUserList (parameter) { 14 | return axios({ 15 | url: api.user, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getServiceList (parameter) { 22 | console.log('getPa', parameter) 23 | return axios({ 24 | url: api.service, 25 | method: 'get', 26 | params: parameter 27 | }) 28 | } 29 | 30 | export function getPermissions (parameter) { 31 | return axios({ 32 | url: api.permissionNoPager, 33 | method: 'get', 34 | params: parameter 35 | }) 36 | } 37 | 38 | export function getOrgTree (parameter) { 39 | return axios({ 40 | url: api.orgTree, 41 | method: 'get', 42 | params: parameter 43 | }) 44 | } 45 | 46 | // id == 0 add post 47 | // id != 0 update put 48 | export function saveService (parameter) { 49 | return axios({ 50 | url: api.service, 51 | method: parameter.id === 0 ? 'post' : 'put', 52 | data: parameter 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /src/components/NumberInfo/NumberInfo.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 51 | 52 | 55 | -------------------------------------------------------------------------------- /src/api/task.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/task' 4 | 5 | const api = { 6 | tasklogList: moudulePath + '/list', 7 | addTaskLog: moudulePath 8 | } 9 | 10 | export default api 11 | 12 | export function getTaskList (parameter) { 13 | return axios({ 14 | url: api.tasklogList, 15 | method: 'get', 16 | params: parameter 17 | }) 18 | } 19 | 20 | export function addTask (parameter) { 21 | return axios({ 22 | url: api.addTaskLog, 23 | method: 'post', 24 | params: parameter 25 | }) 26 | } 27 | 28 | export function editTask (parameter) { 29 | return axios({ 30 | url: moudulePath, 31 | method: 'put', 32 | params: parameter 33 | }) 34 | } 35 | 36 | export function delTask (jobGroup, jobName) { 37 | return axios({ 38 | url: moudulePath + '/' + jobGroup + '/' + jobName, 39 | method: 'delete' 40 | }) 41 | } 42 | 43 | export function pauseTask (jobGroup, jobName) { 44 | return axios({ 45 | url: moudulePath + '/pause/' + jobGroup + '/' + jobName, 46 | method: 'put' 47 | }) 48 | } 49 | 50 | export function resumeTask (jobGroup, jobName) { 51 | return axios({ 52 | url: moudulePath + '/resume/' + jobGroup + '/' + jobName, 53 | method: 'put' 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /src/api/ads.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/ads' 4 | 5 | const api = { 6 | adsList: moudulePath + '/page', 7 | adsAll: moudulePath + '/all', 8 | addAds: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getAdsList (parameter) { 14 | return axios({ 15 | url: api.adsList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getAdsAll (parameter) { 22 | return axios({ 23 | url: api.adsAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getAdsInfo (adsId) { 30 | return axios({ 31 | url: moudulePath + '/' + adsId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addAds (parameter) { 37 | return axios({ 38 | url: api.addAds, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editAds (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delAds (adsId) { 54 | console.log('adsId', adsId) 55 | return axios({ 56 | url: moudulePath + '/' + adsId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/media.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/media' 4 | 5 | const api = { 6 | mediaList: moudulePath + '/page', 7 | mediaAll: moudulePath + '/all', 8 | addMedia: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getMediaList (parameter) { 14 | return axios({ 15 | url: api.mediaList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getMediaAll (parameter) { 22 | return axios({ 23 | url: api.mediaAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getMediaInfo (id) { 30 | return axios({ 31 | url: moudulePath + '/' + id, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addMedia (parameter) { 37 | return axios({ 38 | url: api.addMedia, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editMedia (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delMedia (id) { 54 | console.log('id', id) 55 | return axios({ 56 | url: moudulePath + '/' + id, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/login.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/user' 4 | 5 | const api = { 6 | Login: moudulePath + '/login', 7 | Logout: moudulePath + '/logout', 8 | // get my info 9 | UserInfo: moudulePath + '/' 10 | } 11 | 12 | export default api 13 | 14 | /** 15 | * login func 16 | * parameter: { 17 | * username: '', 18 | * password: '', 19 | * remember_me: true, 20 | * captcha: '12345' 21 | * } 22 | * @param parameter 23 | * @returns {*} 24 | */ 25 | export function login (parameter) { 26 | return axios({ 27 | url: api.Login, 28 | method: 'put', 29 | params: parameter 30 | }) 31 | } 32 | 33 | export function getSmsCaptcha (parameter) { 34 | return axios({ 35 | url: api.SendSms, 36 | method: 'post', 37 | data: parameter 38 | }) 39 | } 40 | 41 | export function getInfo (userId) { 42 | return axios({ 43 | url: api.UserInfo, 44 | method: 'get' + userId 45 | }) 46 | } 47 | 48 | export function refreshUserAuthCache (userId) { 49 | return axios({ 50 | url: moudulePath + '/authcache/' + userId, 51 | method: 'put' 52 | }) 53 | } 54 | 55 | export function logout (userId) { 56 | return axios({ 57 | url: api.Logout + '/' + userId, 58 | method: 'put' 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /src/components/Editor/WangEditor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 50 | 51 | 58 | -------------------------------------------------------------------------------- /src/components/IconSelector/IconSelector.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 34 | 35 | 54 | -------------------------------------------------------------------------------- /src/components/AvatarList/index.less: -------------------------------------------------------------------------------- 1 | @import "../index"; 2 | 3 | @avatar-list-prefix-cls: ~"@{ant-pro-prefix}-avatar-list"; 4 | @avatar-list-item-prefix-cls: ~"@{ant-pro-prefix}-avatar-list-item"; 5 | 6 | .@{avatar-list-prefix-cls} { 7 | display: inline-block; 8 | 9 | ul { 10 | list-style: none; 11 | display: inline-block; 12 | padding: 0; 13 | margin: 0 0 0 8px; 14 | font-size: 0; 15 | } 16 | } 17 | 18 | .@{avatar-list-item-prefix-cls} { 19 | display: inline-block; 20 | font-size: @font-size-base; 21 | margin-left: -8px; 22 | width: @avatar-size-base; 23 | height: @avatar-size-base; 24 | 25 | :global { 26 | .ant-avatar { 27 | border: 1px solid #fff; 28 | cursor: pointer; 29 | } 30 | } 31 | 32 | &.large { 33 | width: @avatar-size-lg; 34 | height: @avatar-size-lg; 35 | } 36 | 37 | &.small { 38 | width: @avatar-size-sm; 39 | height: @avatar-size-sm; 40 | } 41 | 42 | &.mini { 43 | width: 20px; 44 | height: 20px; 45 | 46 | :global { 47 | .ant-avatar { 48 | width: 20px; 49 | height: 20px; 50 | line-height: 20px; 51 | 52 | .ant-avatar-string { 53 | font-size: 12px; 54 | line-height: 18px; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/components/Charts/TransferBar.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 65 | -------------------------------------------------------------------------------- /src/api/param.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/param' 4 | 5 | const api = { 6 | paramList: moudulePath + '/page', 7 | paramAll: moudulePath + '/all', 8 | addParam: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getParamList (parameter) { 14 | return axios({ 15 | url: api.paramList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getParamAll (parameter) { 22 | return axios({ 23 | url: api.paramAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getParamInfo (paramId) { 30 | return axios({ 31 | url: moudulePath + '/' + paramId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addParam (parameter) { 37 | return axios({ 38 | url: api.addParam, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editParam (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delParam (paramId) { 54 | console.log('paramId', paramId) 55 | return axios({ 56 | url: moudulePath + '/' + paramId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/config/defaultSettings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目默认配置项 3 | * primaryColor - 默认主题色, 如果修改颜色不生效,请清理 localStorage 4 | * navTheme - sidebar theme ['dark', 'light'] 两种主题 5 | * colorWeak - 色盲模式 6 | * layout - 整体布局方式 ['sidemenu', 'topmenu'] 两种布局 7 | * fixedHeader - 固定 Header : boolean 8 | * fixSiderbar - 固定左侧菜单栏 : boolean 9 | * autoHideHeader - 向下滚动时,隐藏 Header : boolean 10 | * contentWidth - 内容区布局: 流式 | 固定 11 | * 12 | * storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage) 13 | * 14 | */ 15 | 16 | export default { 17 | primaryColor: '#1890FF', // primary color of ant design 18 | navTheme: 'dark', // theme for nav menu 19 | layout: 'sidemenu', // nav menu position: sidemenu or topmenu 20 | contentWidth: 'Fixed', // layout of content: Fluid or Fixed, only works when layout is topmenu 21 | fixedHeader: false, // sticky header 22 | fixSiderbar: false, // sticky siderbar 23 | autoHideHeader: false, // auto hide header 24 | colorWeak: false, 25 | multiTab: false, 26 | production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true', 27 | // vue-ls options 28 | storageOptions: { 29 | namespace: 'pro__', // key prefix 30 | name: 'ls', // name variable Vue.[ls] or this.[$ls], 31 | storage: 'local' // storage name session, local, memory 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/Charts/Bar.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 63 | -------------------------------------------------------------------------------- /src/api/loginlog.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/loginLog' 4 | 5 | const api = { 6 | loginlogList: moudulePath + '/page', 7 | loginlogAll: moudulePath + '/all', 8 | addLoginLog: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getLoginLogList (parameter) { 14 | return axios({ 15 | url: api.loginlogList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getLoginLogAll (parameter) { 22 | return axios({ 23 | url: api.loginlogAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getLoginLogInfo (logId) { 30 | return axios({ 31 | url: moudulePath + '/' + logId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addLoginLog (parameter) { 37 | return axios({ 38 | url: api.addLoginLog, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editLoginLog (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delLoginLog (logId) { 54 | console.log('logId', logId) 55 | return axios({ 56 | url: moudulePath + '/' + logId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/views/result/Error.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 42 | 43 | 46 | -------------------------------------------------------------------------------- /src/api/gallery.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/gallery' 4 | 5 | const api = { 6 | galleryList: moudulePath + '/page', 7 | galleryAll: moudulePath + '/all', 8 | addGallery: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getGalleryList (parameter) { 14 | return axios({ 15 | url: api.galleryList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getGalleryAll (parameter) { 22 | return axios({ 23 | url: api.galleryAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getGalleryInfo (galleryId) { 30 | return axios({ 31 | url: moudulePath + '/' + galleryId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addGallery (parameter) { 37 | return axios({ 38 | url: api.addGallery, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editGallery (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delGallery (galleryId) { 54 | console.log('galleryId', galleryId) 55 | return axios({ 56 | url: moudulePath + '/' + galleryId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/tasklog.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/taskLog' 4 | 5 | const api = { 6 | tasklogList: moudulePath + '/range', 7 | tasklogAll: moudulePath + '/all', 8 | addTaskLog: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getTaskLogList (parameter) { 14 | return axios({ 15 | url: api.tasklogList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getTaskLogAll (parameter) { 22 | return axios({ 23 | url: api.tasklogAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getTaskLogInfo (taskLogId) { 30 | return axios({ 31 | url: moudulePath + '/' + taskLogId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addTaskLog (parameter) { 37 | return axios({ 38 | url: api.addTaskLog, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editTaskLog (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delTaskLog (taskLogId) { 54 | console.log('taskLogId', taskLogId) 55 | return axios({ 56 | url: moudulePath + '/' + taskLogId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/components/NumberInfo/index.less: -------------------------------------------------------------------------------- 1 | @import "../index"; 2 | 3 | @numberInfo-prefix-cls: ~"@{ant-pro-prefix}-number-info"; 4 | 5 | .@{numberInfo-prefix-cls} { 6 | 7 | .ant-pro-number-info-subtitle { 8 | color: @text-color-secondary; 9 | font-size: @font-size-base; 10 | height: 22px; 11 | line-height: 22px; 12 | overflow: hidden; 13 | text-overflow: ellipsis; 14 | word-break: break-all; 15 | white-space: nowrap; 16 | } 17 | 18 | .number-info-value { 19 | margin-top: 4px; 20 | font-size: 0; 21 | overflow: hidden; 22 | text-overflow: ellipsis; 23 | word-break: break-all; 24 | white-space: nowrap; 25 | 26 | & > span { 27 | color: @heading-color; 28 | display: inline-block; 29 | line-height: 32px; 30 | height: 32px; 31 | font-size: 24px; 32 | margin-right: 32px; 33 | } 34 | 35 | .sub-total { 36 | color: @text-color-secondary; 37 | font-size: @font-size-lg; 38 | vertical-align: top; 39 | margin-right: 0; 40 | i { 41 | font-size: 12px; 42 | transform: scale(0.82); 43 | margin-left: 4px; 44 | } 45 | :global { 46 | .anticon-caret-up { 47 | color: @red-6; 48 | } 49 | .anticon-caret-down { 50 | color: @green-6; 51 | } 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/api/dictdata.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/dictData' 4 | 5 | const api = { 6 | dictdataList: moudulePath + '/page', 7 | dictdataAll: moudulePath + '/all', 8 | addDictData: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getDictDataList (parameter) { 14 | return axios({ 15 | url: api.dictdataList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getDictDataAll (parameter) { 22 | return axios({ 23 | url: api.dictdataAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getDictDataInfo (dictDataId) { 30 | return axios({ 31 | url: moudulePath + '/' + dictDataId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addDictData (parameter) { 37 | return axios({ 38 | url: api.addDictData, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editDictData (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delDictData (dictDataId) { 54 | console.log('dictDataId', dictDataId) 55 | return axios({ 56 | url: moudulePath + '/' + dictDataId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/article.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/article' 4 | 5 | const api = { 6 | articleList: moudulePath + '/pages', 7 | articleAll: moudulePath + '/all', 8 | addArticle: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getArticleList (parameter) { 14 | return axios({ 15 | url: api.articleList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getArticleAll (parameter) { 22 | return axios({ 23 | url: api.articleAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getArticleInfo (articleId) { 30 | return axios({ 31 | url: moudulePath + '/' + articleId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addArticle (parameter) { 37 | return axios({ 38 | url: api.addArticle, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editArticle (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath + '/' + parameter.articleId, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delArticle (articleId) { 54 | console.log('articleId', articleId) 55 | return axios({ 56 | url: moudulePath + '/' + articleId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/dictcatalog.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/dictCatalog' 4 | 5 | const api = { 6 | dictcatalogList: moudulePath + '/page', 7 | dictcatalogAll: moudulePath + '/all', 8 | addDictCatalog: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getDictCatalogList (parameter) { 14 | return axios({ 15 | url: api.dictcatalogList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getDictCatalogAll (parameter) { 22 | return axios({ 23 | url: api.dictcatalogAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getDictCatalogInfo (dictId) { 30 | return axios({ 31 | url: moudulePath + '/' + dictId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addDictCatalog (parameter) { 37 | return axios({ 38 | url: api.addDictCatalog, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editDictCatalog (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delDictCatalog (dictId) { 54 | console.log('dictId', dictId) 55 | return axios({ 56 | url: moudulePath + '/' + dictId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/operationlog.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/operationLog' 4 | 5 | const api = { 6 | operationlogList: moudulePath + '/page', 7 | operationlogAll: moudulePath + '/all', 8 | addOperationLog: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getOperationLogList (parameter) { 14 | return axios({ 15 | url: api.operationlogList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getOperationLogAll (parameter) { 22 | return axios({ 23 | url: api.operationlogAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getOperationLogInfo (logId) { 30 | return axios({ 31 | url: moudulePath + '/' + logId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addOperationLog (parameter) { 37 | return axios({ 38 | url: api.addOperationLog, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editOperationLog (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delOperationLog (logId) { 54 | console.log('logId', logId) 55 | return axios({ 56 | url: moudulePath + '/' + logId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/systemnotice.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/systemNotice' 4 | 5 | const api = { 6 | systemnoticeList: moudulePath + '/page', 7 | systemnoticeAll: moudulePath + '/all', 8 | addSystemNotice: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getSystemNoticeList (parameter) { 14 | return axios({ 15 | url: api.systemnoticeList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getSystemNoticeAll (parameter) { 22 | return axios({ 23 | url: api.systemnoticeAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getSystemNoticeInfo (noticeId) { 30 | return axios({ 31 | url: moudulePath + '/' + noticeId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addSystemNotice (parameter) { 37 | return axios({ 38 | url: api.addSystemNotice, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editSystemNotice (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delSystemNotice (noticeId) { 54 | console.log('noticeId', noticeId) 55 | return axios({ 56 | url: moudulePath + '/' + noticeId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/userrolemapping.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/userRoleMapping' 4 | 5 | const api = { 6 | userrolemappingList: moudulePath + '/page', 7 | userrolemappingAll: moudulePath + '/all', 8 | addUserRoleMapping: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getUserRoleMappingList (parameter) { 14 | return axios({ 15 | url: api.userrolemappingList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserRoleMappingAll (parameter) { 22 | return axios({ 23 | url: api.userrolemappingAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getUserRoleMappingInfo (id) { 30 | return axios({ 31 | url: moudulePath + '/' + id, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addUserRoleMapping (parameter) { 37 | return axios({ 38 | url: api.addUserRoleMapping, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editUserRoleMapping (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delUserRoleMapping (id) { 54 | console.log('id', id) 55 | return axios({ 56 | url: moudulePath + '/' + id, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/components/tools/HeadInfo.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 32 | 33 | 68 | -------------------------------------------------------------------------------- /src/api/articlecontent.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/articleContent' 4 | 5 | const api = { 6 | articlecontentList: moudulePath + '/page', 7 | articlecontentAll: moudulePath + '/all', 8 | addArticleContent: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getArticleContentList (parameter) { 14 | return axios({ 15 | url: api.articlecontentList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getArticleContentAll (parameter) { 22 | return axios({ 23 | url: api.articlecontentAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getArticleContentInfo (contentId) { 30 | return axios({ 31 | url: moudulePath + '/' + contentId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addArticleContent (parameter) { 37 | return axios({ 38 | url: api.addArticleContent, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editArticleContent (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delArticleContent (contentId) { 54 | console.log('contentId', contentId) 55 | return axios({ 56 | url: moudulePath + '/' + contentId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/post.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/post' 4 | 5 | const api = { 6 | postList: moudulePath + '/page', 7 | postAll: moudulePath + '/all', 8 | addPost: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getPostList (parameter) { 14 | return axios({ 15 | url: api.postList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserPosts (userId) { 22 | return axios({ 23 | url: moudulePath + '/' + userId + '/list', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | export function getPostAll (parameter) { 29 | return axios({ 30 | url: api.postAll, 31 | method: 'get', 32 | params: parameter 33 | }) 34 | } 35 | 36 | export function getPostInfo (postId) { 37 | return axios({ 38 | url: moudulePath + '/' + postId, 39 | method: 'get' 40 | }) 41 | } 42 | 43 | export function addPost (parameter) { 44 | return axios({ 45 | url: api.addPost, 46 | method: 'post', 47 | params: parameter 48 | }) 49 | } 50 | 51 | export function editPost (parameter) { 52 | console.log('parameter', parameter) 53 | return axios({ 54 | url: moudulePath, 55 | method: 'put', 56 | params: parameter 57 | }) 58 | } 59 | 60 | export function delPost (postId) { 61 | console.log('postId', postId) 62 | return axios({ 63 | url: moudulePath + '/' + postId, 64 | method: 'delete' 65 | }) 66 | } 67 | -------------------------------------------------------------------------------- /src/api/userdeptmapping.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/userDeptMapping' 4 | 5 | const api = { 6 | userdeptmappingList: moudulePath + '/page', 7 | userdeptmappingAll: moudulePath + '/all', 8 | addUserDeptMapping: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getUserDeptMappingList (parameter) { 14 | return axios({ 15 | url: api.userdeptmappingList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserDeptMappingAll (parameter) { 22 | return axios({ 23 | url: api.userdeptmappingAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getUserDeptMappingInfo (mappingId) { 30 | return axios({ 31 | url: moudulePath + '/' + mappingId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addUserDeptMapping (parameter) { 37 | return axios({ 38 | url: api.addUserDeptMapping, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editUserDeptMapping (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delUserDeptMapping (mappingId) { 54 | console.log('mappingId', mappingId) 55 | return axios({ 56 | url: moudulePath + '/' + mappingId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/userpostmapping.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/userPostMapping' 4 | 5 | const api = { 6 | userpostmappingList: moudulePath + '/page', 7 | userpostmappingAll: moudulePath + '/all', 8 | addUserPostMapping: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getUserPostMappingList (parameter) { 14 | return axios({ 15 | url: api.userpostmappingList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserPostMappingAll (parameter) { 22 | return axios({ 23 | url: api.userpostmappingAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getUserPostMappingInfo (mappingId) { 30 | return axios({ 31 | url: moudulePath + '/' + mappingId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addUserPostMapping (parameter) { 37 | return axios({ 38 | url: api.addUserPostMapping, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editUserPostMapping (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delUserPostMapping (mappingId) { 54 | console.log('mappingId', mappingId) 55 | return axios({ 56 | url: moudulePath + '/' + mappingId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/roleresourcemapping.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/roleResourceMapping' 4 | 5 | const api = { 6 | roleresourcemappingList: moudulePath + '/page', 7 | roleresourcemappingAll: moudulePath + '/all', 8 | addRoleResourceMapping: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getRoleResourceMappingList (parameter) { 14 | return axios({ 15 | url: api.roleresourcemappingList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getRoleResourceMappingAll (parameter) { 22 | return axios({ 23 | url: api.roleresourcemappingAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getRoleResourceMappingInfo (id) { 30 | return axios({ 31 | url: moudulePath + '/' + id, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addRoleResourceMapping (parameter) { 37 | return axios({ 38 | url: api.addRoleResourceMapping, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editRoleResourceMapping (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delRoleResourceMapping (id) { 54 | console.log('id', id) 55 | return axios({ 56 | url: moudulePath + '/' + id, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/usergroupmapping.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/userGroupMapping' 4 | 5 | const api = { 6 | usergroupmappingList: moudulePath + '/page', 7 | usergroupmappingAll: moudulePath + '/all', 8 | addUserGroupMapping: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getUserGroupMappingList (parameter) { 14 | return axios({ 15 | url: api.usergroupmappingList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserGroupMappingAll (parameter) { 22 | return axios({ 23 | url: api.usergroupmappingAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getUserGroupMappingInfo (mappingId) { 30 | return axios({ 31 | url: moudulePath + '/' + mappingId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addUserGroupMapping (parameter) { 37 | return axios({ 38 | url: api.addUserGroupMapping, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editUserGroupMapping (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delUserGroupMapping (mappingId) { 54 | console.log('mappingId', mappingId) 55 | return axios({ 56 | url: moudulePath + '/' + mappingId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/views/form/stepForm/StepForm.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 56 | 57 | 63 | -------------------------------------------------------------------------------- /src/core/bootstrap.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import store from '@/store/' 3 | import { 4 | ACCESS_TOKEN, 5 | DEFAULT_COLOR, 6 | DEFAULT_THEME, 7 | DEFAULT_LAYOUT_MODE, 8 | DEFAULT_COLOR_WEAK, 9 | SIDEBAR_TYPE, 10 | DEFAULT_FIXED_HEADER, 11 | DEFAULT_FIXED_HEADER_HIDDEN, 12 | DEFAULT_FIXED_SIDEMENU, 13 | DEFAULT_CONTENT_WIDTH_TYPE, 14 | DEFAULT_MULTI_TAB 15 | } from '@/store/mutation-types' 16 | import config from '@/config/defaultSettings' 17 | 18 | export default function Initializer () { 19 | store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, true)) 20 | store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme)) 21 | store.commit('TOGGLE_LAYOUT_MODE', Vue.ls.get(DEFAULT_LAYOUT_MODE, config.layout)) 22 | store.commit('TOGGLE_FIXED_HEADER', Vue.ls.get(DEFAULT_FIXED_HEADER, config.fixedHeader)) 23 | store.commit('TOGGLE_FIXED_SIDERBAR', Vue.ls.get(DEFAULT_FIXED_SIDEMENU, config.fixSiderbar)) 24 | store.commit('TOGGLE_CONTENT_WIDTH', Vue.ls.get(DEFAULT_CONTENT_WIDTH_TYPE, config.contentWidth)) 25 | store.commit('TOGGLE_FIXED_HEADER_HIDDEN', Vue.ls.get(DEFAULT_FIXED_HEADER_HIDDEN, config.autoHideHeader)) 26 | store.commit('TOGGLE_WEAK', Vue.ls.get(DEFAULT_COLOR_WEAK, config.colorWeak)) 27 | store.commit('TOGGLE_COLOR', Vue.ls.get(DEFAULT_COLOR, config.primaryColor)) 28 | store.commit('TOGGLE_MULTI_TAB', Vue.ls.get(DEFAULT_MULTI_TAB, config.multiTab)) 29 | store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN)) 30 | 31 | // last step 32 | } 33 | -------------------------------------------------------------------------------- /src/components/Charts/Liquid.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 64 | 65 | 68 | -------------------------------------------------------------------------------- /src/api/resource.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/resource' 4 | 5 | const api = { 6 | resourceList: moudulePath + '/list', 7 | resourceAll: moudulePath + '/all', 8 | addResource: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getResourceList (parameter) { 14 | return axios({ 15 | url: api.resourceList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getResourceAll (parameter) { 22 | return axios({ 23 | url: api.resourceAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getResourceInfo (resourceId) { 30 | return axios({ 31 | url: moudulePath + '/' + resourceId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function bindRoleResource (roleId, parameter) { 37 | return axios({ 38 | url: moudulePath + '/bind/' + roleId, 39 | method: 'put', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function addResource (parameter) { 45 | return axios({ 46 | url: api.addResource, 47 | method: 'post', 48 | params: parameter 49 | }) 50 | } 51 | 52 | export function editResource (resourceId, parameter) { 53 | return axios({ 54 | url: moudulePath + '/' + resourceId, 55 | method: 'put', 56 | params: parameter 57 | }) 58 | } 59 | 60 | export function delResource (resourceId) { 61 | return axios({ 62 | url: moudulePath + '/' + resourceId, 63 | method: 'delete' 64 | }) 65 | } 66 | -------------------------------------------------------------------------------- /src/components/Menu/SideMenu.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 64 | -------------------------------------------------------------------------------- /src/api/usergrouprolemapping.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/userGroupRoleMapping' 4 | 5 | const api = { 6 | usergrouprolemappingList: moudulePath + '/page', 7 | usergrouprolemappingAll: moudulePath + '/all', 8 | addUserGroupRoleMapping: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getUserGroupRoleMappingList (parameter) { 14 | return axios({ 15 | url: api.usergrouprolemappingList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserGroupRoleMappingAll (parameter) { 22 | return axios({ 23 | url: api.usergrouprolemappingAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getUserGroupRoleMappingInfo (mappingId) { 30 | return axios({ 31 | url: moudulePath + '/' + mappingId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addUserGroupRoleMapping (parameter) { 37 | return axios({ 38 | url: api.addUserGroupRoleMapping, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editUserGroupRoleMapping (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delUserGroupRoleMapping (mappingId) { 54 | console.log('mappingId', mappingId) 55 | return axios({ 56 | url: moudulePath + '/' + mappingId, 57 | method: 'delete' 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /src/api/cresource.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/resource' 4 | 5 | const api = { 6 | resourceList: moudulePath + '/list', 7 | addResource: moudulePath 8 | } 9 | 10 | export default api 11 | 12 | export function getResourceList (parameter) { 13 | return axios({ 14 | url: api.resourceList, 15 | method: 'get', 16 | params: parameter 17 | }) 18 | } 19 | 20 | export function getResourceInfo (resourceId) { 21 | return axios({ 22 | url: api.moudulePath + '/' + resourceId, 23 | method: 'get' 24 | }) 25 | } 26 | 27 | export function addResource (parameter) { 28 | return axios({ 29 | url: api.addResource, 30 | method: 'post', 31 | params: parameter 32 | }) 33 | } 34 | 35 | export function editResource (resourceId, parameter) { 36 | console.log('resourceId', resourceId) 37 | console.log('parameter', parameter) 38 | return axios({ 39 | url: moudulePath + '/' + resourceId, 40 | method: 'put', 41 | params: parameter 42 | }) 43 | } 44 | 45 | export function delResource (resourceId) { 46 | console.log('resourceId', resourceId) 47 | return axios({ 48 | url: moudulePath + '/' + resourceId, 49 | method: 'delete' 50 | }) 51 | } 52 | 53 | export function getUserResources (userId) { 54 | return axios({ 55 | url: moudulePath + '/' + userId + '/list', 56 | method: 'get' 57 | }) 58 | } 59 | 60 | export function getRoleResources (roleId) { 61 | return axios({ 62 | url: moudulePath + '/role/' + roleId + '/list', 63 | method: 'get' 64 | }) 65 | } 66 | -------------------------------------------------------------------------------- /src/utils/helper/permission.js: -------------------------------------------------------------------------------- 1 | const PERMISSION_ENUM = { 2 | 'add': { key: 'add', label: '新增' }, 3 | 'delete': { key: 'delete', label: '删除' }, 4 | 'edit': { key: 'edit', label: '修改' }, 5 | 'query': { key: 'query', label: '查询' }, 6 | 'get': { key: 'get', label: '详情' }, 7 | 'enable': { key: 'enable', label: '启用' }, 8 | 'disable': { key: 'disable', label: '禁用' }, 9 | 'import': { key: 'import', label: '导入' }, 10 | 'export': { key: 'export', label: '导出' } 11 | } 12 | 13 | function plugin (Vue) { 14 | if (plugin.installed) { 15 | return 16 | } 17 | 18 | !Vue.prototype.$auth && Object.defineProperties(Vue.prototype, { 19 | $auth: { 20 | get () { 21 | const _this = this 22 | return (permissions) => { 23 | const [permission, action] = permissions.split('.') 24 | const permissionList = _this.$store.getters.resources 25 | return permissionList.find((val) => { 26 | return val.resourceKey === permission 27 | }).actionList.findIndex((val) => { 28 | return val === action 29 | }) > -1 30 | } 31 | } 32 | } 33 | }) 34 | 35 | !Vue.prototype.$enum && Object.defineProperties(Vue.prototype, { 36 | $enum: { 37 | get () { 38 | // const _this = this; 39 | return (val) => { 40 | let result = PERMISSION_ENUM 41 | val && val.split('.').forEach(v => { 42 | result = result && result[v] || null 43 | }) 44 | return result 45 | } 46 | } 47 | } 48 | }) 49 | } 50 | 51 | export default plugin 52 | -------------------------------------------------------------------------------- /src/api/role.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/role' 4 | 5 | const api = { 6 | roleList: moudulePath + '/page', 7 | roleAll: moudulePath + '/all', 8 | addRole: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getRoleList (parameter) { 14 | return axios({ 15 | url: api.roleList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserRoles (userId) { 22 | return axios({ 23 | url: moudulePath + '/' + userId + '/list', 24 | method: 'get' 25 | }) 26 | } 27 | 28 | export function getGroupRoles (groupId) { 29 | return axios({ 30 | url: moudulePath + '/group/' + groupId + '/list', 31 | method: 'get' 32 | }) 33 | } 34 | 35 | export function getRoleAll (parameter) { 36 | return axios({ 37 | url: api.roleAll, 38 | method: 'get', 39 | params: parameter 40 | }) 41 | } 42 | 43 | export function getRoleInfo (roleId) { 44 | return axios({ 45 | url: moudulePath + '/' + roleId, 46 | method: 'get' 47 | }) 48 | } 49 | 50 | export function addRole (parameter) { 51 | return axios({ 52 | url: api.addRole, 53 | method: 'post', 54 | params: parameter 55 | }) 56 | } 57 | 58 | export function editRole (parameter) { 59 | console.log('parameter', parameter) 60 | return axios({ 61 | url: moudulePath, 62 | method: 'put', 63 | params: parameter 64 | }) 65 | } 66 | 67 | export function delRole (roleId) { 68 | console.log('roleId', roleId) 69 | return axios({ 70 | url: moudulePath + '/' + roleId, 71 | method: 'delete' 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /public/loading/loading.css: -------------------------------------------------------------------------------- 1 | #preloadingAnimation{position:fixed;left:0;top:0;height:100%;width:100%;background:#ffffff;user-select:none;z-index: 9999;overflow: hidden}.lds-roller{display:inline-block;position:relative;left:50%;top:50%;transform:translate(-50%,-50%);width:64px;height:64px;}.lds-roller div{animation:lds-roller 1.2s cubic-bezier(0.5,0,0.5,1) infinite;transform-origin:32px 32px;}.lds-roller div:after{content:" ";display:block;position:absolute;width:6px;height:6px;border-radius:50%;background:#13c2c2;margin:-3px 0 0 -3px;}.lds-roller div:nth-child(1){animation-delay:-0.036s;}.lds-roller div:nth-child(1):after{top:50px;left:50px;}.lds-roller div:nth-child(2){animation-delay:-0.072s;}.lds-roller div:nth-child(2):after{top:54px;left:45px;}.lds-roller div:nth-child(3){animation-delay:-0.108s;}.lds-roller div:nth-child(3):after{top:57px;left:39px;}.lds-roller div:nth-child(4){animation-delay:-0.144s;}.lds-roller div:nth-child(4):after{top:58px;left:32px;}.lds-roller div:nth-child(5){animation-delay:-0.18s;}.lds-roller div:nth-child(5):after{top:57px;left:25px;}.lds-roller div:nth-child(6){animation-delay:-0.216s;}.lds-roller div:nth-child(6):after{top:54px;left:19px;}.lds-roller div:nth-child(7){animation-delay:-0.252s;}.lds-roller div:nth-child(7):after{top:50px;left:14px;}.lds-roller div:nth-child(8){animation-delay:-0.288s;}.lds-roller div:nth-child(8):after{top:45px;left:10px;}#preloadingAnimation .load-tips{color: #13c2c2;font-size:2rem;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin-top:80px;text-align:center;width:400px;height:64px;} @keyframes lds-roller{0%{transform:rotate(0deg);} 100%{transform:rotate(360deg);}} -------------------------------------------------------------------------------- /src/components/Charts/Radar.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 65 | 66 | 69 | -------------------------------------------------------------------------------- /src/mock/services/auth.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs2' 2 | import { builder, getBody } from '../util' 3 | 4 | const username = ['admin', 'cuser.js', 'super'] 5 | const password = ['21232f297a57a5a743894a0e4a801fc3', '8914de686ab28dc22f30d3d8e107ff6c'] // admin, ant.design 6 | 7 | const login = (options) => { 8 | const body = getBody(options) 9 | console.log('mock: body', body) 10 | if (!username.includes(body.username) || !password.includes(body.password)) { 11 | return builder({ isLogin: true }, '账户或密码错误', 401) 12 | } 13 | 14 | return builder({ 15 | 'id': Mock.mock('@guid'), 16 | 'name': Mock.mock('@name'), 17 | 'username': 'admin', 18 | 'password': '', 19 | 'avatar': 'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png', 20 | 'status': 1, 21 | 'telephone': '', 22 | 'lastLoginIp': '27.154.74.117', 23 | 'lastLoginTime': 1534837621348, 24 | 'creatorId': 'admin', 25 | 'createTime': 1497160610259, 26 | 'deleted': 0, 27 | 'roleId': 'admin', 28 | 'lang': 'zh-CN', 29 | 'token': '4291d7da9005377ec9aec4a71ea837f' 30 | }, '', 200, { 'Custom-Header': Mock.mock('@guid') }) 31 | } 32 | 33 | const logout = () => { 34 | return builder({}, '[测试接口] 注销成功') 35 | } 36 | 37 | const smsCaptcha = () => { 38 | return builder({ captcha: Mock.mock('@integer(10000, 99999)') }) 39 | } 40 | 41 | const twofactor = () => { 42 | return builder({ stepCode: Mock.mock('@integer(0, 1)') }) 43 | } 44 | 45 | Mock.mock(/\/auth\/login/, 'post', login) 46 | Mock.mock(/\/auth\/logout/, 'post', logout) 47 | Mock.mock(/\/account\/sms/, 'post', smsCaptcha) 48 | Mock.mock(/\/auth\/2step-code/, 'post', twofactor) 49 | -------------------------------------------------------------------------------- /src/api/dept.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/dept' 4 | 5 | const api = { 6 | deptList: moudulePath + '/page', 7 | deptAll: moudulePath + '/all', 8 | deptTreeList: moudulePath + '/list', 9 | addDept: moudulePath 10 | } 11 | 12 | export default api 13 | 14 | export function getDeptList (parameter) { 15 | return axios({ 16 | url: api.deptList, 17 | method: 'get', 18 | params: parameter 19 | }) 20 | } 21 | 22 | export function getDeptTreeList (parameter) { 23 | return axios({ 24 | url: api.deptTreeList, 25 | method: 'get', 26 | params: parameter 27 | }) 28 | } 29 | 30 | export function getUserDepts (userId) { 31 | return axios({ 32 | url: moudulePath + '/' + userId + '/list', 33 | method: 'get' 34 | }) 35 | } 36 | 37 | export function getDeptAll (parameter) { 38 | return axios({ 39 | url: api.deptAll, 40 | method: 'get', 41 | params: parameter 42 | }) 43 | } 44 | 45 | export function getDeptInfo (deptId) { 46 | return axios({ 47 | url: moudulePath + '/' + deptId, 48 | method: 'get' 49 | }) 50 | } 51 | 52 | export function addDept (parameter) { 53 | return axios({ 54 | url: api.addDept, 55 | method: 'post', 56 | params: parameter 57 | }) 58 | } 59 | 60 | export function editDept (parameter) { 61 | console.log('parameter', parameter) 62 | return axios({ 63 | url: moudulePath, 64 | method: 'put', 65 | params: parameter 66 | }) 67 | } 68 | 69 | export function delDept (deptId) { 70 | console.log('deptId', deptId) 71 | return axios({ 72 | url: moudulePath + '/' + deptId, 73 | method: 'delete' 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/utils/storage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Set storage 3 | * 4 | * @param name 5 | * @param content 6 | * @param maxAge 7 | */ 8 | export const setStore = (name, content, maxAge = null) => { 9 | if (!global.window || !name) { 10 | return 11 | } 12 | 13 | if (typeof content !== 'string') { 14 | content = JSON.stringify(content) 15 | } 16 | 17 | const storage = global.window.localStorage 18 | 19 | storage.setItem(name, content) 20 | if (maxAge && !isNaN(parseInt(maxAge))) { 21 | const timeout = parseInt(new Date().getTime() / 1000) 22 | storage.setItem(`${name}_expire`, timeout + maxAge) 23 | } 24 | } 25 | 26 | /** 27 | * Get storage 28 | * 29 | * @param name 30 | * @returns {*} 31 | */ 32 | export const getStore = name => { 33 | if (!global.window || !name) { 34 | return 35 | } 36 | 37 | const content = window.localStorage.getItem(name) 38 | const _expire = window.localStorage.getItem(`${name}_expire`) 39 | 40 | if (_expire) { 41 | const now = parseInt(new Date().getTime() / 1000) 42 | if (now > _expire) { 43 | return 44 | } 45 | } 46 | 47 | try { 48 | return JSON.parse(content) 49 | } catch (e) { 50 | return content 51 | } 52 | } 53 | 54 | /** 55 | * Clear storage 56 | * 57 | * @param name 58 | */ 59 | export const clearStore = name => { 60 | if (!global.window || !name) { 61 | return 62 | } 63 | 64 | window.localStorage.removeItem(name) 65 | window.localStorage.removeItem(`${name}_expire`) 66 | } 67 | 68 | /** 69 | * Clear all storage 70 | */ 71 | export const clearAll = () => { 72 | if (!global.window || !name) { 73 | return 74 | } 75 | 76 | window.localStorage.clear() 77 | } 78 | -------------------------------------------------------------------------------- /src/api/articlecategory.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/articleCategory' 4 | 5 | const api = { 6 | articlecategoryList: moudulePath + '/page', 7 | articlecategoryAll: moudulePath + '/all', 8 | articlecategoryTree: moudulePath + '/tree', 9 | addArticleCategory: moudulePath 10 | } 11 | 12 | export default api 13 | 14 | export function getArticleCategoryList (parameter) { 15 | return axios({ 16 | url: api.articlecategoryList, 17 | method: 'get', 18 | params: parameter 19 | }) 20 | } 21 | 22 | export function getArticleCategoryAll (parameter) { 23 | return axios({ 24 | url: api.articlecategoryAll, 25 | method: 'get', 26 | params: parameter 27 | }) 28 | } 29 | 30 | export function getArticlecategoryTree (parameter) { 31 | return axios({ 32 | url: api.articlecategoryTree, 33 | method: 'get', 34 | params: parameter 35 | }) 36 | } 37 | 38 | export function getArticleCategoryInfo (articleCategoryId) { 39 | return axios({ 40 | url: moudulePath + '/' + articleCategoryId, 41 | method: 'get' 42 | }) 43 | } 44 | 45 | export function addArticleCategory (parameter) { 46 | return axios({ 47 | url: api.addArticleCategory, 48 | method: 'post', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function editArticleCategory (parameter) { 54 | console.log('parameter', parameter) 55 | return axios({ 56 | url: moudulePath, 57 | method: 'put', 58 | params: parameter 59 | }) 60 | } 61 | 62 | export function delArticleCategory (articleCategoryId) { 63 | console.log('articleCategoryId', articleCategoryId) 64 | return axios({ 65 | url: moudulePath + '/' + articleCategoryId, 66 | method: 'delete' 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /src/utils/util.js: -------------------------------------------------------------------------------- 1 | export function timeFix () { 2 | const time = new Date() 3 | const hour = time.getHours() 4 | return hour < 9 ? '早上好' : hour <= 11 ? '上午好' : hour <= 13 ? '中午好' : hour < 20 ? '下午好' : '晚上好' 5 | } 6 | 7 | export function welcome () { 8 | const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 DOTA', '我猜你可能累了'] 9 | const index = Math.floor(Math.random() * arr.length) 10 | return arr[index] 11 | } 12 | 13 | /** 14 | * 触发 window.resize 15 | */ 16 | export function triggerWindowResizeEvent () { 17 | const event = document.createEvent('HTMLEvents') 18 | event.initEvent('resize', true, true) 19 | event.eventType = 'message' 20 | window.dispatchEvent(event) 21 | } 22 | 23 | export function handleScrollHeader (callback) { 24 | let timer = 0 25 | 26 | let beforeScrollTop = window.pageYOffset 27 | callback = callback || function () {} 28 | window.addEventListener( 29 | 'scroll', 30 | event => { 31 | clearTimeout(timer) 32 | timer = setTimeout(() => { 33 | let direction = 'up' 34 | const afterScrollTop = window.pageYOffset 35 | const delta = afterScrollTop - beforeScrollTop 36 | if (delta === 0) { 37 | return false 38 | } 39 | direction = delta > 0 ? 'down' : 'up' 40 | callback(direction) 41 | beforeScrollTop = afterScrollTop 42 | }, 50) 43 | }, 44 | false 45 | ) 46 | } 47 | 48 | /** 49 | * Remove loading animate 50 | * @param id parent element id or class 51 | * @param timeout 52 | */ 53 | export function removeLoadingAnimate (id = '', timeout = 1500) { 54 | if (id === '') { 55 | return 56 | } 57 | setTimeout(() => { 58 | document.body.removeChild(document.getElementById(id)) 59 | }, timeout) 60 | } 61 | -------------------------------------------------------------------------------- /src/views/list/modules/CreateForm.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 68 | -------------------------------------------------------------------------------- /src/api/user.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | import md5 from 'md5' 3 | 4 | const moudulePath = '/v1/user' 5 | 6 | const api = { 7 | userList: moudulePath + '/page', 8 | userAll: moudulePath + '/all', 9 | addUser: moudulePath, 10 | reset: moudulePath + '/reset' 11 | } 12 | 13 | export default api 14 | 15 | export function getUserList (parameter) { 16 | return axios({ 17 | url: api.userList, 18 | method: 'get', 19 | params: parameter 20 | }) 21 | } 22 | 23 | export function getUserAll (parameter) { 24 | return axios({ 25 | url: api.userAll, 26 | method: 'get', 27 | params: parameter 28 | }) 29 | } 30 | 31 | export function getUserByGroupId (groupId) { 32 | return axios({ 33 | url: moudulePath + '/group/' + groupId + '/list', 34 | method: 'get' 35 | }) 36 | } 37 | 38 | export function getUserInfo (userId) { 39 | return axios({ 40 | url: moudulePath + '/' + userId, 41 | method: 'get' 42 | }) 43 | } 44 | 45 | export function addUser (parameter) { 46 | parameter.password = md5(parameter.password) 47 | return axios({ 48 | url: api.addUser, 49 | method: 'post', 50 | params: parameter 51 | }) 52 | } 53 | 54 | export function editUser (userId, parameter) { 55 | return axios({ 56 | url: moudulePath + '/' + userId, 57 | method: 'put', 58 | params: parameter 59 | }) 60 | } 61 | 62 | export function resetPwd (parameter) { 63 | parameter.password = md5(parameter.password) 64 | return axios({ 65 | url: api.reset, 66 | method: 'put', 67 | params: parameter 68 | }) 69 | } 70 | 71 | export function delUser (userId) { 72 | console.log('userId', userId) 73 | return axios({ 74 | url: moudulePath + '/' + userId, 75 | method: 'delete' 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /src/api/usergroup.js: -------------------------------------------------------------------------------- 1 | import { axios } from '@/utils/request' 2 | 3 | const moudulePath = '/v1/userGroup' 4 | 5 | const api = { 6 | usergroupList: moudulePath + '/page', 7 | usergroupAll: moudulePath + '/all', 8 | addUserGroup: moudulePath 9 | } 10 | 11 | export default api 12 | 13 | export function getUserGroupList (parameter) { 14 | return axios({ 15 | url: api.usergroupList, 16 | method: 'get', 17 | params: parameter 18 | }) 19 | } 20 | 21 | export function getUserGroupAll (parameter) { 22 | return axios({ 23 | url: api.usergroupAll, 24 | method: 'get', 25 | params: parameter 26 | }) 27 | } 28 | 29 | export function getUserGroupInfo (groupId) { 30 | return axios({ 31 | url: moudulePath + '/' + groupId, 32 | method: 'get' 33 | }) 34 | } 35 | 36 | export function addUserGroup (parameter) { 37 | return axios({ 38 | url: api.addUserGroup, 39 | method: 'post', 40 | params: parameter 41 | }) 42 | } 43 | 44 | export function editUserGroup (parameter) { 45 | console.log('parameter', parameter) 46 | return axios({ 47 | url: moudulePath, 48 | method: 'put', 49 | params: parameter 50 | }) 51 | } 52 | 53 | export function delUserGroup (groupId) { 54 | console.log('groupId', groupId) 55 | return axios({ 56 | url: moudulePath + '/' + groupId, 57 | method: 'delete' 58 | }) 59 | } 60 | 61 | export function bindUserGroup (groupId, parameter) { 62 | return axios({ 63 | url: moudulePath + '/bind/user/' + groupId, 64 | method: 'put', 65 | params: parameter 66 | }) 67 | } 68 | 69 | export function bindRoleGroup (groupId, parameter) { 70 | return axios({ 71 | url: moudulePath + '/bind/role/' + groupId, 72 | method: 'put', 73 | params: parameter 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /src/components/Ellipsis/Ellipsis.vue: -------------------------------------------------------------------------------- 1 | 65 | -------------------------------------------------------------------------------- /src/components/Charts/MiniProgress.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 36 | 37 | 76 | -------------------------------------------------------------------------------- /src/components/Charts/RankList.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 30 | 31 | 78 | -------------------------------------------------------------------------------- /src/core/directives/action.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import store from '@/store' 3 | 4 | /** 5 | * Action 权限指令 6 | * 指令用法: 7 | * - 在需要控制 action 级别权限的组件上使用 v-action:[method] , 如下: 8 | * 添加用户 9 | * 删除用户 10 | * 修改 11 | * 12 | * - 当前用户没有权限时,组件上使用了该指令则会被隐藏 13 | * - 当后台权限跟 pro 提供的模式不同时,只需要针对这里的权限过滤进行修改即可 14 | * 15 | * @see https://github.com/sendya/ant-design-pro-vue/pull/53 16 | */ 17 | const action = Vue.directive('action', { 18 | inserted: function (el, binding, vnode) { 19 | const actionName = binding.arg 20 | const resources = store.getters.resources 21 | const elVal = vnode.context.$route.meta.permission 22 | const permissionId = elVal instanceof String && [elVal] || elVal 23 | 24 | resources.forEach(r => { 25 | checkPermission(r, el, permissionId, actionName) 26 | }) 27 | } 28 | }) 29 | 30 | function checkPermission (resource, el, permissionId, actionName) { 31 | const childResources = resource.childResources 32 | if (childResources && childResources.length > 0) { 33 | childResources.forEach(cr => { 34 | checkPermission(cr, el, permissionId, actionName) 35 | }) 36 | } 37 | 38 | // 找到对应的父级资源ID 39 | if (!permissionId.includes(resource.resourceKey)) { 40 | return 41 | } 42 | 43 | // 遍历子级资源是否具备该操作资源 44 | 45 | let hasPermission = false 46 | 47 | if (childResources && childResources.length > 0) { 48 | childResources.forEach(r => { 49 | if (r.resourceKey && r.resourceKey === actionName) { 50 | hasPermission = true 51 | } 52 | }) 53 | } 54 | 55 | if (!hasPermission) { 56 | el.parentNode && el.parentNode.removeChild(el) || (el.style.display = 'none') 57 | } 58 | } 59 | 60 | export default action 61 | -------------------------------------------------------------------------------- /src/views/account/settings/Security.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 38 | 39 | 42 | -------------------------------------------------------------------------------- /src/assets/icons/bx-analyse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Charts/Trend.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 52 | 53 | 83 | -------------------------------------------------------------------------------- /src/views/list/search/SearchLayout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 65 | 66 | 79 | -------------------------------------------------------------------------------- /src/views/form/stepForm/Step3.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 55 | 70 | -------------------------------------------------------------------------------- /src/core/lazy_lib/components_use.js: -------------------------------------------------------------------------------- 1 | 2 | /* eslint-disable */ 3 | /** 4 | * 该文件是为了按需加载,剔除掉了一些不需要的框架组件。 5 | * 减少了编译支持库包大小 6 | * 7 | * 当需要更多组件依赖时,在该文件加入即可 8 | */ 9 | import Vue from 'vue' 10 | import { 11 | LocaleProvider, 12 | Layout, 13 | Input, 14 | InputNumber, 15 | Button, 16 | Switch, 17 | Radio, 18 | Checkbox, 19 | Select, 20 | Card, 21 | Form, 22 | Row, 23 | Col, 24 | Modal, 25 | Table, 26 | Tabs, 27 | Icon, 28 | Badge, 29 | Popover, 30 | Dropdown, 31 | List, 32 | Avatar, 33 | Breadcrumb, 34 | Steps, 35 | Spin, 36 | Menu, 37 | Drawer, 38 | Tooltip, 39 | Alert, 40 | Tag, 41 | Divider, 42 | DatePicker, 43 | TimePicker, 44 | Upload, 45 | Progress, 46 | Skeleton, 47 | Popconfirm, 48 | message, 49 | notification 50 | } from 'ant-design-vue' 51 | // import VueCropper from 'vue-cropper' 52 | 53 | Vue.use(LocaleProvider) 54 | Vue.use(Layout) 55 | Vue.use(Input) 56 | Vue.use(InputNumber) 57 | Vue.use(Button) 58 | Vue.use(Switch) 59 | Vue.use(Radio) 60 | Vue.use(Checkbox) 61 | Vue.use(Select) 62 | Vue.use(Card) 63 | Vue.use(Form) 64 | Vue.use(Row) 65 | Vue.use(Col) 66 | Vue.use(Modal) 67 | Vue.use(Table) 68 | Vue.use(Tabs) 69 | Vue.use(Icon) 70 | Vue.use(Badge) 71 | Vue.use(Popover) 72 | Vue.use(Dropdown) 73 | Vue.use(List) 74 | Vue.use(Avatar) 75 | Vue.use(Breadcrumb) 76 | Vue.use(Steps) 77 | Vue.use(Spin) 78 | Vue.use(Menu) 79 | Vue.use(Drawer) 80 | Vue.use(Tooltip) 81 | Vue.use(Alert) 82 | Vue.use(Tag) 83 | Vue.use(Divider) 84 | Vue.use(DatePicker) 85 | Vue.use(TimePicker) 86 | Vue.use(Upload) 87 | Vue.use(Progress) 88 | Vue.use(Skeleton) 89 | Vue.use(Popconfirm) 90 | // Vue.use(VueCropper) 91 | Vue.use(notification) 92 | 93 | Vue.prototype.$confirm = Modal.confirm 94 | Vue.prototype.$message = message 95 | Vue.prototype.$notification = notification 96 | Vue.prototype.$info = Modal.info 97 | Vue.prototype.$success = Modal.success 98 | Vue.prototype.$error = Modal.error 99 | Vue.prototype.$warning = Modal.warning -------------------------------------------------------------------------------- /src/views/account/settings/Custom.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Xadmin 9 | 10 | 11 | 12 | 15 |
16 |
17 |
18 | 19 |
20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | // chart 2 | import Bar from '@/components/Charts/Bar' 3 | import ChartCard from '@/components/Charts/ChartCard' 4 | import Liquid from '@/components/Charts/Liquid' 5 | import MiniArea from '@/components/Charts/MiniArea' 6 | import MiniSmoothArea from '@/components/Charts/MiniSmoothArea' 7 | import MiniBar from '@/components/Charts/MiniBar' 8 | import MiniProgress from '@/components/Charts/MiniProgress' 9 | import Radar from '@/components/Charts/Radar' 10 | import RankList from '@/components/Charts/RankList' 11 | import TransferBar from '@/components/Charts/TransferBar' 12 | import TagCloud from '@/components/Charts/TagCloud' 13 | 14 | // pro components 15 | import AvatarList from '@/components/AvatarList' 16 | import CountDown from '@/components/CountDown' 17 | import Ellipsis from '@/components/Ellipsis' 18 | import FooterToolbar from '@/components/FooterToolbar' 19 | import NumberInfo from '@/components/NumberInfo' 20 | import DescriptionList from '@/components/DescriptionList' 21 | import Tree from '@/components/Tree/Tree' 22 | import Trend from '@/components/Trend' 23 | import STable from '@/components/Table' 24 | import MultiTab from '@/components/MultiTab' 25 | import Result from '@/components/Result' 26 | import IconSelector from '@/components/IconSelector' 27 | import TagSelect from '@/components/TagSelect' 28 | import ExceptionPage from '@/components/Exception' 29 | import StandardFormRow from '@/components/StandardFormRow' 30 | import ArticleListContent from '@/components/ArticleListContent' 31 | 32 | export { 33 | AvatarList, 34 | Bar, 35 | ChartCard, 36 | Liquid, 37 | MiniArea, 38 | MiniSmoothArea, 39 | MiniBar, 40 | MiniProgress, 41 | Radar, 42 | TagCloud, 43 | RankList, 44 | TransferBar, 45 | Trend, 46 | CountDown, 47 | Ellipsis, 48 | FooterToolbar, 49 | NumberInfo, 50 | DescriptionList, 51 | // 兼容写法,请勿继续使用 52 | DescriptionList as DetailList, 53 | Tree, 54 | STable, 55 | MultiTab, 56 | Result, 57 | ExceptionPage, 58 | IconSelector, 59 | TagSelect, 60 | StandardFormRow, 61 | ArticleListContent 62 | } 63 | -------------------------------------------------------------------------------- /docs/load-on-demand.md: -------------------------------------------------------------------------------- 1 | 按需加载 减小打包 2 | ==== 3 | 4 | 5 | 6 | ## 按需引入组件依赖 7 | 8 | `Ant Design Pro Vue` 默认编码工作并不支持按需引入,不过可以通过以下操作结合 [Ant Design Of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 官方文档来进行按需引入。 9 | 10 | - 增加项目按需引入依赖 11 | - 修改引入组件方式 12 | 13 | 14 | 15 | 1. 增加按需引入所需依赖 `babel-plugin-import` 16 | 并且修改文件 `babel.config.js` 17 | ```ecmascript 6 18 | module.exports = { 19 | presets: [ 20 | '@vue/app' 21 | ], 22 | plugins: [ 23 | [ "import", { 24 | "libraryName": "ant-design-vue", 25 | "libraryDirectory": "es", 26 | "style": "css" 27 | } ] 28 | ] 29 | } 30 | ``` 31 | 32 | 33 | 2. 修改引入组件方式 (注意,这只是一个例子,请完整引入你所需要的组件) 34 | 35 | 文件 `@/core/lazy_lib/component_use.js` 36 | 37 | ```javascript 38 | import Vue from 'vue' 39 | import { 40 | Input, 41 | Button, 42 | Select, 43 | Card, 44 | Form, 45 | Row, 46 | Col, 47 | Modal, 48 | Table, 49 | notification 50 | } from 'ant-design-vue' 51 | 52 | Vue.use(Input) 53 | Vue.use(Button) 54 | Vue.use(Select) 55 | Vue.use(Card) 56 | Vue.use(Form) 57 | Vue.use(Row) 58 | Vue.use(Col) 59 | Vue.use(Modal) 60 | Vue.use(Table) 61 | Vue.use(notification) 62 | 63 | Vue.prototype.$notification = notification; 64 | ``` 65 | 66 | 67 | 3. 最后在 `main.js` 中引入 `@/core/lazy_use.js` 文件即可,如下 68 | 69 | ```javascript 70 | 71 | import Vue from 'vue' 72 | import App from './App' 73 | 74 | // 引入 按需组件的统一引入文件 75 | import './core/use' 76 | 77 | import './style/index.less' 78 | 79 | 80 | Vue.config.productionTip = false 81 | 82 | new Vue({ 83 | render: h => h(App), 84 | }).$mount('#app') 85 | 86 | ``` 87 | 88 | 89 | 90 | ## 其他 减少打包大小 91 | 92 | 93 | 94 | 1. Ant Design Vue 1.2.x 版本起,采用的 ant-design 官方方案 svg Icon 组件,整个项目打包会变大很多,图标进行按需加载可参考 https://github.com/HeskeyBaozi/reduce-antd-icons-bundle-demo 95 | 2. moment 按需加载 可参考 https://github.com/jmblog/how-to-optimize-momentjs-with-webpack -------------------------------------------------------------------------------- /src/components/tools/UserMenu.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 71 | -------------------------------------------------------------------------------- /src/utils/request.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | import store from '@/store' 4 | import { 5 | VueAxios 6 | } from './axios' 7 | import notification from 'ant-design-vue/es/notification' 8 | import { 9 | ACCESS_TOKEN, 10 | USER_ID 11 | } from '@/store/mutation-types' 12 | 13 | const baseHost = 'http://10.10.10.146:21550' 14 | const uploadUrl = baseHost + '/v1/common/upload' 15 | 16 | // 创建 axios 实例 17 | const service = axios.create({ 18 | baseURL: baseHost, // api base_url 19 | timeout: 6000 // 请求超时时间 20 | }) 21 | 22 | const err = (error) => { 23 | const data = error.data 24 | 25 | if (data) { 26 | switch (data.status) { 27 | case 90000: 28 | case 90001: 29 | case 90002: 30 | case 90003: 31 | store.dispatch('ClearUser').then(() => { 32 | setTimeout(() => { 33 | window.location.reload() 34 | }, 500) 35 | }) 36 | } 37 | notification.error({ 38 | message: '操作失败', 39 | description: data.message 40 | }) 41 | } else { 42 | notification.error({ 43 | key: 'NETWORK_ERROR', 44 | message: '连接服务器失败', 45 | description: '请检查您的网络连接配置' 46 | }) 47 | } 48 | } 49 | 50 | // request interceptor 51 | service.interceptors.request.use(config => { 52 | const token = Vue.ls.get(ACCESS_TOKEN) 53 | const userId = Vue.ls.get(USER_ID) 54 | if (token) { 55 | config.headers['X-USER-TOKEN'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改 56 | } 57 | if (userId) { 58 | config.headers['X-USER-ID'] = userId 59 | } 60 | config.headers['X-SOURCE'] = 'web' 61 | return config 62 | }, err) 63 | 64 | // response interceptor 65 | service.interceptors.response.use((response) => { 66 | const data = response.data 67 | if (data && data.status === 10000) { 68 | return data 69 | } else { 70 | throw err(response) 71 | } 72 | }, err) 73 | 74 | const installer = { 75 | vm: {}, 76 | install (Vue) { 77 | Vue.use(VueAxios, service) 78 | } 79 | } 80 | 81 | export { 82 | installer as VueAxios, 83 | service as axios, 84 | uploadUrl, 85 | baseHost 86 | } 87 | -------------------------------------------------------------------------------- /public/loading/option2/loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ArticleListContent/ArticleListContent.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 47 | 48 | 90 | -------------------------------------------------------------------------------- /public/loading/option2/html_code_segment.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
-------------------------------------------------------------------------------- /src/views/account/center/page/Article.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /src/components/NoticeIcon/NoticeIcon.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 65 | 66 | 71 | 81 | -------------------------------------------------------------------------------- /src/utils/mixin.js: -------------------------------------------------------------------------------- 1 | // import Vue from 'vue' 2 | import { deviceEnquire, DEVICE_TYPE } from '@/utils/device' 3 | import { mapState } from 'vuex' 4 | 5 | // const mixinsComputed = Vue.config.optionMergeStrategies.computed 6 | // const mixinsMethods = Vue.config.optionMergeStrategies.methods 7 | 8 | const mixin = { 9 | computed: { 10 | ...mapState({ 11 | layoutMode: state => state.app.layout, 12 | navTheme: state => state.app.theme, 13 | primaryColor: state => state.app.color, 14 | colorWeak: state => state.app.weak, 15 | fixedHeader: state => state.app.fixedHeader, 16 | fixSiderbar: state => state.app.fixSiderbar, 17 | fixSidebar: state => state.app.fixSiderbar, 18 | contentWidth: state => state.app.contentWidth, 19 | autoHideHeader: state => state.app.autoHideHeader, 20 | sidebarOpened: state => state.app.sidebar, 21 | multiTab: state => state.app.multiTab 22 | }) 23 | }, 24 | methods: { 25 | isTopMenu () { 26 | return this.layoutMode === 'topmenu' 27 | }, 28 | isSideMenu () { 29 | return !this.isTopMenu() 30 | } 31 | } 32 | } 33 | 34 | const mixinDevice = { 35 | computed: { 36 | ...mapState({ 37 | device: state => state.app.device 38 | }) 39 | }, 40 | methods: { 41 | isMobile () { 42 | return this.device === DEVICE_TYPE.MOBILE 43 | }, 44 | isDesktop () { 45 | return this.device === DEVICE_TYPE.DESKTOP 46 | }, 47 | isTablet () { 48 | return this.device === DEVICE_TYPE.TABLET 49 | } 50 | } 51 | } 52 | 53 | const AppDeviceEnquire = { 54 | mounted () { 55 | const { $store } = this 56 | deviceEnquire(deviceType => { 57 | switch (deviceType) { 58 | case DEVICE_TYPE.DESKTOP: 59 | $store.commit('TOGGLE_DEVICE', 'desktop') 60 | $store.dispatch('setSidebar', true) 61 | break 62 | case DEVICE_TYPE.TABLET: 63 | $store.commit('TOGGLE_DEVICE', 'tablet') 64 | $store.dispatch('setSidebar', false) 65 | break 66 | case DEVICE_TYPE.MOBILE: 67 | default: 68 | $store.commit('TOGGLE_DEVICE', 'mobile') 69 | $store.dispatch('setSidebar', true) 70 | break 71 | } 72 | }) 73 | } 74 | } 75 | 76 | export { mixin, AppDeviceEnquire, mixinDevice } 77 | -------------------------------------------------------------------------------- /src/views/list/modules/TaskForm.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 80 | -------------------------------------------------------------------------------- /src/components/AvatarList/index.md: -------------------------------------------------------------------------------- 1 | # AvatarList 用户头像列表 2 | 3 | 4 | 一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。 5 | 6 | 7 | 8 | 引用方式: 9 | 10 | ```javascript 11 | import AvatarList from '@/components/AvatarList' 12 | const AvatarListItem = AvatarList.AvatarItem 13 | 14 | export default { 15 | components: { 16 | AvatarList, 17 | AvatarListItem 18 | } 19 | } 20 | ``` 21 | 22 | 23 | 24 | ## 代码演示 [demo](https://pro.loacg.com/test/home) 25 | 26 | ```html 27 | 28 | 29 | 30 | 31 | 32 | ``` 33 | 或 34 | ```html 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | ``` 45 | 46 | 47 | 48 | ## API 49 | 50 | ### AvatarList 51 | 52 | | 参数 | 说明 | 类型 | 默认值 | 53 | | ---------------- | -------- | ---------------------------------- | --------- | 54 | | size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` | 55 | | maxLength | 要显示的最大项目 | number | - | 56 | | excessItemsStyle | 多余的项目风格 | CSSProperties | - | 57 | 58 | ### AvatarList.Item 59 | 60 | | 参数 | 说明 | 类型 | 默认值 | 61 | | ---- | ------ | --------- | --- | 62 | | tips | 头像展示文案 | string | - | 63 | | src | 头像图片连接 | string | - | 64 | 65 | -------------------------------------------------------------------------------- /src/views/usergroup/CreateForm.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 92 | -------------------------------------------------------------------------------- /src/views/other/modules/OrgModal.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 101 | -------------------------------------------------------------------------------- /src/components/Result/Result.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 59 | 60 | 110 | -------------------------------------------------------------------------------- /src/components/CountDown/CountDown.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 99 | 100 | 103 | -------------------------------------------------------------------------------- /src/components/tools/TwoStepCaptcha.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 83 | 90 | -------------------------------------------------------------------------------- /src/views/common/CreateForm.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 96 | -------------------------------------------------------------------------------- /src/components/AvatarList/List.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 100 | -------------------------------------------------------------------------------- /src/views/usergroup/RoleConfigForm.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 102 | -------------------------------------------------------------------------------- /src/views/usergroup/UserConfigForm.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 102 | -------------------------------------------------------------------------------- /src/permission.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import router from './router' 3 | import store from './store' 4 | 5 | import NProgress from 'nprogress' // progress bar 6 | import 'nprogress/nprogress.css' // progress bar style 7 | import notification from 'ant-design-vue/es/notification' 8 | import { setDocumentTitle, domTitle } from '@/utils/domUtil' 9 | import { ACCESS_TOKEN, USER_ID } from '@/store/mutation-types' 10 | import { refreshUserAuthCache } from '@/api/login' 11 | 12 | NProgress.configure({ showSpinner: false }) // NProgress Configuration 13 | 14 | const whiteList = ['login', 'register', 'registerResult'] // no redirect whitelist 15 | 16 | router.beforeEach((to, from, next) => { 17 | const userToken = Vue.ls.get(ACCESS_TOKEN) 18 | const userId = Vue.ls.get(USER_ID) 19 | NProgress.start() // start progress bar 20 | to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`)) 21 | if (userToken && userId) { 22 | /* has token */ 23 | if (to.path === '/user/login') { 24 | next({ path: '/' }) 25 | NProgress.done() 26 | } else { 27 | // 判断当前用户是否资源列表为空,是则开始获取资源列表(即权限列表) 28 | if (store.getters.resources.length === 0) { 29 | store 30 | .dispatch('GetUserResources', userId) 31 | .then(res => { 32 | store.dispatch('GeneratorDynamicRouter', res).then(() => { 33 | // 根据roles权限生成可访问的路由表 34 | // 动态添加可访问路由表 35 | router.addRoutes(store.getters.addRouters) 36 | const redirect = decodeURIComponent(from.query.redirect || to.path) 37 | if (to.path === redirect) { 38 | // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record 39 | next({ ...to, replace: true }) 40 | } else { 41 | // 跳转到目的路由 42 | next({ path: redirect }) 43 | } 44 | }) 45 | }) 46 | .catch(() => { 47 | notification.error({ 48 | message: '错误', 49 | description: '请求用户信息失败,请重试' 50 | }) 51 | store.dispatch('Logout').then(() => { 52 | next({ path: '/user/login', query: { redirect: to.fullPath } }) 53 | }) 54 | }) 55 | // 刷新用户权限相关缓存 56 | refreshUserAuthCache(userId) 57 | } else { 58 | next() 59 | } 60 | } 61 | } else { 62 | if (whiteList.includes(to.name)) { 63 | // 在免登录白名单,直接进入 64 | next() 65 | } else { 66 | next({ path: '/user/login' }) 67 | NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it 68 | } 69 | } 70 | }) 71 | 72 | router.afterEach(() => { 73 | NProgress.done() // finish progress bar 74 | }) 75 | --------------------------------------------------------------------------------