├── .env ├── .env.development ├── .env.production ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── img │ │ ├── alipay.png │ │ ├── avatar.jpg │ │ ├── logo.png │ │ ├── preview-nine.png │ │ ├── preview.png │ │ └── wechatpay.png ├── bootstrap.js ├── components │ ├── cache │ │ └── AKeepAlive.js │ ├── card │ │ └── ChartCard.vue │ ├── chart │ │ ├── Bar.vue │ │ ├── MiniArea.vue │ │ ├── MiniBar.vue │ │ ├── MiniProgress.vue │ │ ├── Radar.vue │ │ ├── RankingList.vue │ │ ├── Trend.vue │ │ └── index.less │ ├── checkbox │ │ ├── ColorCheckbox.vue │ │ ├── ImgCheckbox.vue │ │ └── index.js │ ├── exception │ │ ├── ExceptionPage.vue │ │ └── typeConfig.js │ ├── form │ │ └── FormRow.vue │ ├── input │ │ └── IInput.vue │ ├── menu │ │ ├── Contextmenu.vue │ │ ├── SideMenu.vue │ │ ├── index.less │ │ └── menu.js │ ├── page │ │ └── header │ │ │ ├── PageHeader.vue │ │ │ └── index.less │ ├── result │ │ └── Result.vue │ ├── setting │ │ ├── Setting.vue │ │ ├── SettingItem.vue │ │ └── i18n.js │ ├── table │ │ ├── StandardTable.vue │ │ ├── advance │ │ │ ├── ActionColumns.vue │ │ │ ├── ActionSize.vue │ │ │ ├── AdvanceTable.vue │ │ │ ├── SearchArea.vue │ │ │ └── index.js │ │ └── api │ │ │ └── ApiTable.vue │ ├── task │ │ ├── TaskGroup.vue │ │ └── TaskItem.vue │ ├── tool │ │ ├── AStepItem.vue │ │ ├── AvatarList.vue │ │ ├── DetailList.vue │ │ ├── Drawer.vue │ │ ├── FooterToolBar.vue │ │ ├── HeadInfo.vue │ │ ├── TagSelect.vue │ │ └── TagSelectOption.vue │ └── transition │ │ └── PageToggleTransition.vue ├── config │ ├── config.js │ ├── default │ │ ├── admin.config.js │ │ ├── animate.config.js │ │ ├── antd.config.js │ │ ├── index.js │ │ └── setting.config.js │ ├── index.js │ └── replacer │ │ ├── index.js │ │ └── resolve.config.js ├── layouts │ ├── AdminLayout.vue │ ├── BlankView.vue │ ├── CommonLayout.vue │ ├── PageLayout.vue │ ├── PageView.vue │ ├── footer │ │ └── PageFooter.vue │ ├── header │ │ ├── AdminHeader.vue │ │ ├── HeaderAvatar.vue │ │ ├── HeaderNotice.vue │ │ ├── HeaderSearch.vue │ │ ├── HeaderWorkSpace.vue │ │ └── index.less │ └── tabs │ │ ├── TabsHead.vue │ │ ├── TabsView.vue │ │ ├── i18n.js │ │ └── index.js ├── main.js ├── mock │ ├── common │ │ ├── activityData.js │ │ ├── index.js │ │ └── tableData.js │ ├── extend │ │ └── index.js │ ├── goods │ │ └── index.js │ ├── index.js │ ├── project │ │ └── index.js │ ├── user │ │ ├── current.js │ │ ├── login.js │ │ └── routes.js │ └── workplace │ │ └── index.js ├── pages │ ├── components │ │ ├── Inputparameter │ │ │ ├── InputParameter.vue │ │ │ └── index.js │ │ ├── condition │ │ │ └── ConditionModal.vue │ │ ├── function │ │ │ ├── Function.vue │ │ │ └── index.js │ │ └── variable │ │ │ ├── Variable.vue │ │ │ └── index.js │ ├── dashboard │ │ ├── analysis │ │ │ ├── Analysis.vue │ │ │ ├── Bar.vue │ │ │ ├── HotSearch.vue │ │ │ ├── RankingList.vue │ │ │ ├── SalesData.vue │ │ │ ├── i18n-search.js │ │ │ ├── i18n.js │ │ │ └── index.js │ │ └── workplace │ │ │ ├── Radar.vue │ │ │ ├── WorkPlace.vue │ │ │ ├── i18n.js │ │ │ ├── index.js │ │ │ └── index.less │ ├── exception │ │ ├── 403.vue │ │ ├── 404.vue │ │ └── 500.vue │ ├── login │ │ ├── Login.vue │ │ └── index.js │ ├── result │ │ ├── Error.vue │ │ └── Success.vue │ ├── rulemanagement │ │ └── generalrule │ │ │ ├── config │ │ │ ├── Config.vue │ │ │ ├── index.js │ │ │ └── index.less │ │ │ ├── list │ │ │ ├── GeneralRule.vue │ │ │ ├── i18n.js │ │ │ ├── index.js │ │ │ └── index.less │ │ │ ├── publish │ │ │ ├── Publish.vue │ │ │ └── index.js │ │ │ ├── router │ │ │ ├── Router.vue │ │ │ └── index.js │ │ │ └── view │ │ │ ├── View.vue │ │ │ └── index.js │ └── settings │ │ ├── personal │ │ ├── Personal.vue │ │ ├── i18n.js │ │ ├── index.js │ │ └── index.less │ │ ├── user │ │ ├── UserList.vue │ │ ├── i18n.js │ │ ├── index.js │ │ └── index.less │ │ └── workspace │ │ ├── Workspace.vue │ │ ├── i18n.js │ │ ├── index.js │ │ └── index.less ├── plugins │ ├── authority-plugin.js │ ├── i18n-extend.js │ ├── index.js │ └── tabs-page-plugin.js ├── router │ ├── async │ │ ├── config.async.js │ │ └── router.map.js │ ├── config.js │ ├── guards.js │ ├── i18n.js │ └── index.js ├── services │ ├── api.js │ ├── condition.js │ ├── conditionGroup.js │ ├── conditionGroupCondition.js │ ├── dataPermission.js │ ├── dataSource.js │ ├── function.js │ ├── generalRule.js │ ├── importExport.js │ ├── index.js │ ├── inputParameter.js │ ├── operationRecord.js │ ├── rule.js │ ├── user.js │ ├── variable.js │ ├── workplace.js │ ├── workspace.js │ └── workspaceMember.js ├── store │ ├── index.js │ └── modules │ │ ├── index.js │ │ ├── setting.js │ │ ├── user.js │ │ └── workspace.js ├── theme │ ├── antd │ │ ├── ant-menu.less │ │ ├── ant-message.less │ │ ├── ant-table.less │ │ ├── ant-time-picker.less │ │ └── index.less │ ├── default │ │ ├── color.less │ │ ├── index.less │ │ ├── nprogress.less │ │ └── style.less │ ├── index.less │ └── theme.less └── utils │ ├── Objects.js │ ├── array.js │ ├── authority-utils.js │ ├── axios-interceptors.js │ ├── clipboardUtil.js │ ├── colors.js │ ├── dateUtil.js │ ├── formatter.js │ ├── i18n.js │ ├── json.js │ ├── request.js │ ├── routerUtil.js │ ├── selectSearch.js │ ├── symbol.js │ ├── theme-color-replacer-extend.js │ ├── themeUtil.js │ ├── util.js │ └── value-type.js └── vue.config.js /.env: -------------------------------------------------------------------------------- 1 | VUE_APP_PUBLIC_PATH=/ 2 | VUE_APP_NAME="Rule Engine" 3 | VUE_APP_ROUTES_KEY=admin.routes 4 | VUE_APP_PERMISSIONS_KEY=admin.permissions 5 | VUE_APP_ROLES_KEY=admin.roles 6 | VUE_APP_USER_KEY=admin.user 7 | VUE_APP_WORKSPACE_KEY=admin.workspace 8 | VUE_APP_SETTING_KEY=admin.setting 9 | VUE_APP_TBAS_KEY=admin.tabs 10 | VUE_APP_TBAS_TITLES_KEY=admin.tabs.titles 11 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | VUE_APP_WEB_BASE_URL=http://dingqw.com:8010 2 | VUE_APP_COMPUTE_BASE_URL=http://dingqw.com:8011 3 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | VUE_APP_WEB_BASE_URL=http://ruleengine.cn:8010 2 | VUE_APP_COMPUTE_BASE_URL=http://ruleengine.cn:8011 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | /engine/ 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | /test/unit/coverage/ 9 | /test/e2e/reports/ 10 | selenium-debug.log 11 | 12 | # Editor directories and files 13 | .idea 14 | .vscode 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln 19 | 20 | package-lock.json 21 | rule-engine-front-open.iml 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📌 规则引擎前端开源版 RuleEngine 📌 2 | 3 | [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) 4 | [![GitHub Stars](https://img.shields.io/github/stars/dingqianwen/rule-engine-front-open)](https://github.com/dingqianwen/rule-engine-front-v2/stargazers) 5 | [![GitHub Forks](https://img.shields.io/github/forks/dingqianwen/rule-engine-front-open)](https://github.com/dingqianwen/rule-engine-front-v2/fork) 6 | [![GitHub issues](https://img.shields.io/github/issues/dingqianwen/rule-engine-front-open.svg)](https://github.com/dingqianwen/rule-engine-front-v2/issues) 7 | [![Percentage of issues still open](http://isitmaintained.com/badge/open/dingqianwen/rule-engine-front-open.svg)](https://github.com/dingqianwen/rule-engine-front-v2/issues "Percentage of issues still open") 8 | 9 | #### 业务逻辑实现不再依赖于代码开发,可零代码实现复杂业务逻辑。 10 | 11 | 后端代码地址:https://gitee.com/aizuda/rule-engine-open
12 | 项目展示地址:http://ruleengine.cn/ 13 | 14 | ##### 联系方式: 15 | 16 | - QQ:761945125 17 | - Email:761945125@qq.com 18 | 19 | ### 技术文档 20 | 21 | 简单使用:...
22 | 详细文档:http://ruleengine.cn/doc 23 | 24 | ### 技术栈/版本介绍: 25 | 26 | - 所涉及的相关的技术有: 27 | - Vue 28 | - Element-ui 29 | 30 | ### 项目安装(部署) 31 | 32 | Node.js 版本 : `Node.js v16.15.0` 33 | 34 | ###### 设置 npm 镜像源 35 | 36 | ```language 37 | npm config set registry https://registry.npm.taobao.org 38 | ``` 39 | 40 | ###### 下载安装 41 | 42 | ```bash 43 | ## 克隆项目源码包 44 | git clone https://github.com/dingqianwen/rule-engine-front-open 45 | 46 | ## 安装项目依赖扩展组件 47 | npm install 48 | 49 | # 启动本地开发环境 50 | npm run serve 51 | 52 | ## 生产环境构建项目 53 | npm run build 54 | 55 | ## 生产环境构建项目并查看构建报告 56 | npm run build --report 57 | ``` 58 | 59 | ###### 修改 .env 配置信息 60 | 61 | ```env 62 | #web服务的 63 | VUE_APP_WEB_BASE_URL=http://xxx.yourdomain.com 64 | #计算服务的 65 | VUE_APP_COMPUTE_BASE_URL=http://xxx.yourdomain.com:8011 66 | ``` 67 | 68 | ### 如果觉得本项目对您有任何一点帮助,请点右上角 "Star" 支持一下, 并向您的基友、同事们宣传一下吧,谢谢! 69 | 70 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV) 2 | 3 | const plugins = [] 4 | if (IS_PROD) { 5 | plugins.push('transform-remove-console') 6 | } 7 | 8 | module.exports = { 9 | presets: [ 10 | '@vue/cli-plugin-babel/preset' 11 | ], 12 | plugins 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rule-engine-front", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "dqw <761945125@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "vue-cli-service serve", 9 | "serve": "vue-cli-service serve", 10 | "build": "vue-cli-service build", 11 | "lint": "vue-cli-service lint", 12 | "deploy": "rm -rf engine;vue-cli-service build;mv dist engine;scp -r engine root@124.71.168.161:/usr/local/nginx/html" 13 | }, 14 | "dependencies": { 15 | "@antv/data-set": "^0.11.4", 16 | "animate.css": "^4.1.0", 17 | "ant-design-vue": "1.7.2", 18 | "axios": "^0.19.2", 19 | "chromedriver": "^91.0.1", 20 | "clipboard": "^2.0.6", 21 | "core-js": "^3.6.5", 22 | "date-fns": "^2.14.0", 23 | "enquire.js": "^2.1.6", 24 | "highlight.js": "^10.2.1", 25 | "js-base64": "^3.6.1", 26 | "js-cookie": "^2.2.1", 27 | "mockjs": "^1.1.0", 28 | "nprogress": "^0.2.0", 29 | "sortablejs": "^1.14.0", 30 | "viser-vue": "^2.4.8", 31 | "vue": "^2.6.11", 32 | "vue-cropper": "^0.5.6", 33 | "vue-i18n": "^8.18.2", 34 | "vue-router": "^3.3.4", 35 | "vuedraggable": "^2.23.2", 36 | "vuescroll": "^4.17.3", 37 | "vuex": "^3.4.0", 38 | "vxe-table": "^3.3.10", 39 | "xe-utils": "^3.3.1" 40 | }, 41 | "devDependencies": { 42 | "@ant-design/colors": "^4.0.1", 43 | "@vue/cli-plugin-babel": "^4.4.0", 44 | "@vue/cli-plugin-eslint": "^4.4.0", 45 | "@vue/cli-service": "^4.4.0", 46 | "@vuepress/plugin-back-to-top": "^1.5.2", 47 | "babel-eslint": "^10.1.0", 48 | "babel-plugin-transform-remove-console": "^6.9.4", 49 | "babel-polyfill": "^6.26.0", 50 | "compression-webpack-plugin": "^2.0.0", 51 | "deepmerge": "^4.2.2", 52 | "eslint": "^6.7.2", 53 | "eslint-plugin-vue": "^6.2.2", 54 | "fast-deep-equal": "^3.1.3", 55 | "gh-pages": "^3.1.0", 56 | "less-loader": "^6.1.1", 57 | "style-resources-loader": "^1.3.2", 58 | "vue-cli-plugin-style-resources-loader": "^0.1.4", 59 | "vue-template-compiler": "^2.6.11", 60 | "vuepress": "^1.5.2", 61 | "webpack-theme-color-replacer": "1.3.18", 62 | "whatwg-fetch": "^3.0.0" 63 | }, 64 | "eslintConfig": { 65 | "root": true, 66 | "env": { 67 | "node": true 68 | }, 69 | "extends": [ 70 | "plugin:vue/essential", 71 | "eslint:recommended" 72 | ], 73 | "parserOptions": { 74 | "parser": "babel-eslint" 75 | }, 76 | "rules": {} 77 | }, 78 | "browserslist": [ 79 | "> 1%", 80 | "last 2 versions", 81 | "not ie <= 10" 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= process.env.VUE_APP_NAME %> 9 | 10 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %> 11 | 12 | <% } %> 13 | 14 | 15 | 18 |
19 |
20 |
21 | 22 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %> 23 | 24 | <% } %> 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 89 | 94 | 98 | -------------------------------------------------------------------------------- /src/assets/img/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/assets/img/alipay.png -------------------------------------------------------------------------------- /src/assets/img/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/assets/img/avatar.jpg -------------------------------------------------------------------------------- /src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/assets/img/logo.png -------------------------------------------------------------------------------- /src/assets/img/preview-nine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/assets/img/preview-nine.png -------------------------------------------------------------------------------- /src/assets/img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/assets/img/preview.png -------------------------------------------------------------------------------- /src/assets/img/wechatpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/assets/img/wechatpay.png -------------------------------------------------------------------------------- /src/bootstrap.js: -------------------------------------------------------------------------------- 1 | import {loadRoutes, loadGuards, setAppOptions} from '@/utils/routerUtil' 2 | import {loadInterceptors} from '@/utils/request' 3 | import guards from '@/router/guards' 4 | import interceptors from '@/utils/axios-interceptors' 5 | 6 | /** 7 | * 启动引导方法 8 | * 应用启动时需要执行的操作放在这里 9 | * @param router 应用的路由实例 10 | * @param store 应用的 vuex.store 实例 11 | * @param i18n 应用的 vue-i18n 实例 12 | * @param i18n 应用的 message 实例 13 | */ 14 | function bootstrap({router, store, i18n, message}) { 15 | // 设置应用配置 16 | setAppOptions({router, store, i18n}) 17 | // 加载 axios 拦截器 18 | loadInterceptors(interceptors, {router, store, i18n, message}) 19 | // 加载路由 20 | loadRoutes() 21 | // 加载路由守卫 22 | loadGuards(guards, {router, store, i18n, message}) 23 | } 24 | 25 | export default bootstrap 26 | -------------------------------------------------------------------------------- /src/components/card/ChartCard.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 29 | 30 | 79 | -------------------------------------------------------------------------------- /src/components/chart/Bar.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 52 | 53 | 60 | -------------------------------------------------------------------------------- /src/components/chart/MiniArea.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 56 | 57 | 68 | -------------------------------------------------------------------------------- /src/components/chart/MiniBar.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 56 | 57 | 60 | -------------------------------------------------------------------------------- /src/components/chart/MiniProgress.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 21 | 22 | 57 | -------------------------------------------------------------------------------- /src/components/chart/Radar.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 77 | 78 | 81 | -------------------------------------------------------------------------------- /src/components/chart/RankingList.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 20 | 21 | 60 | -------------------------------------------------------------------------------- /src/components/chart/Trend.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 64 | 65 | 80 | -------------------------------------------------------------------------------- /src/components/chart/index.less: -------------------------------------------------------------------------------- 1 | .mini-chart{ 2 | position: relative; 3 | width: 100%; 4 | .chart-content{ 5 | position: absolute; 6 | bottom: -28px; 7 | width: 100%; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/checkbox/ColorCheckbox.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 144 | 145 | 158 | -------------------------------------------------------------------------------- /src/components/checkbox/index.js: -------------------------------------------------------------------------------- 1 | import ColorCheckbox from '@/components/checkbox/ColorCheckbox' 2 | import ImgCheckbox from '@/components/checkbox/ImgCheckbox' 3 | 4 | export { 5 | ColorCheckbox, 6 | ImgCheckbox 7 | } 8 | -------------------------------------------------------------------------------- /src/components/exception/ExceptionPage.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 37 | 38 | 70 | -------------------------------------------------------------------------------- /src/components/exception/typeConfig.js: -------------------------------------------------------------------------------- 1 | const config = { 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 config 20 | -------------------------------------------------------------------------------- /src/components/form/FormRow.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 18 | 19 | 52 | -------------------------------------------------------------------------------- /src/components/input/IInput.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 67 | -------------------------------------------------------------------------------- /src/components/menu/Contextmenu.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 73 | 74 | 85 | -------------------------------------------------------------------------------- /src/components/menu/SideMenu.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /src/components/menu/index.less: -------------------------------------------------------------------------------- 1 | .shadow{ 2 | box-shadow: 2px 0 6px rgba(0, 21, 41, .35); 3 | } 4 | .side-menu{ 5 | min-height: 100vh; 6 | overflow-y: auto; 7 | z-index: 10; 8 | .logo{ 9 | height: 64px; 10 | position: relative; 11 | line-height: 64px; 12 | padding-left: 24px; 13 | -webkit-transition: all .3s; 14 | transition: all .3s; 15 | overflow: hidden; 16 | background-color: @layout-trigger-background; 17 | &.light{ 18 | background-color: #fff; 19 | h1{ 20 | color: @primary-color; 21 | } 22 | } 23 | h1{ 24 | color: @menu-dark-highlight-color; 25 | font-size: 20px; 26 | margin: 0 0 0 12px; 27 | display: inline-block; 28 | vertical-align: middle; 29 | } 30 | img{ 31 | width: 32px; 32 | vertical-align: middle; 33 | } 34 | } 35 | } 36 | .menu{ 37 | padding: 16px 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/components/page/header/PageHeader.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 57 | 58 | 61 | -------------------------------------------------------------------------------- /src/components/page/header/index.less: -------------------------------------------------------------------------------- 1 | .page-header{ 2 | background: @base-bg-color; 3 | padding: 16px 24px; 4 | &.head.fixed{ 5 | margin: auto; 6 | max-width: 1400px; 7 | } 8 | .page-header-wide{ 9 | .breadcrumb{ 10 | margin-bottom: 10px; 11 | } 12 | .detail{ 13 | display: flex; 14 | .row { 15 | display: flex; 16 | flex-wrap: wrap; 17 | justify-content: space-between; 18 | } 19 | .avatar { 20 | margin:0 24px 0 0; 21 | } 22 | .main{ 23 | width: 100%; 24 | .title{ 25 | font-size: 20px; 26 | color: @title-color; 27 | margin-bottom: 16px; 28 | } 29 | .content{ 30 | display: flex; 31 | flex-wrap: wrap; 32 | color: @text-color-second; 33 | } 34 | .extra{ 35 | display: flex; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/components/result/Result.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 23 | 24 | 65 | -------------------------------------------------------------------------------- /src/components/setting/SettingItem.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /src/components/setting/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | theme: { 5 | title: '整体风格设置', 6 | light: '亮色菜单风格', 7 | dark: '暗色菜单风格', 8 | night: '深夜模式', 9 | color: '主题色' 10 | }, 11 | navigate: { 12 | title: '导航设置', 13 | side: '侧边导航', 14 | head: '顶部导航', 15 | mix: '混合导航', 16 | content: { 17 | title: '内容区域宽度', 18 | fluid: '流式', 19 | fixed: '定宽' 20 | }, 21 | fixedHeader: '固定Header', 22 | fixedSideBar: '固定侧边栏', 23 | }, 24 | other: { 25 | title: '其他设置', 26 | weekMode: '色弱模式', 27 | multiPages: '多页签模式', 28 | hideSetting: '隐藏设置抽屉' 29 | }, 30 | animate: { 31 | title: '页面切换动画', 32 | disable: '禁用动画', 33 | effect: '动画效果', 34 | direction: '动画方向' 35 | }, 36 | alert: '拷贝配置后,直接覆盖文件 src/config/config.js 中的全部内容,然后重启即可。(注意:仅会拷贝与默认配置不同的项)', 37 | copy: '拷贝配置', 38 | save: '保存配置', 39 | reset: '重置配置', 40 | }, 41 | HK: { 42 | theme: { 43 | title: '整體風格設置', 44 | light: '亮色菜單風格', 45 | dark: '暗色菜單風格', 46 | night: '深夜模式', 47 | color: '主題色' 48 | }, 49 | navigate: { 50 | title: '導航設置', 51 | side: '側邊導航', 52 | head: '頂部導航', 53 | content: { 54 | title: '內容區域寬度', 55 | fluid: '流式', 56 | fixed: '定寬' 57 | }, 58 | fixedHeader: '固定Header', 59 | fixedSideBar: '固定側邊欄', 60 | }, 61 | other: { 62 | title: '其他設置', 63 | weekMode: '色弱模式', 64 | multiPages: '多頁簽模式', 65 | hideSetting: '隱藏設置抽屜' 66 | }, 67 | animate: { 68 | title: '頁面切換動畫', 69 | disable: '禁用動畫', 70 | effect: '動畫效果', 71 | direction: '動畫方向' 72 | }, 73 | alert: '拷貝配置后,直接覆蓋文件 src/config/config.js 中的全部內容,然後重啟即可。(注意:僅會拷貝與默認配置不同的項)', 74 | copy: '拷貝配置', 75 | save: '保存配置', 76 | reset: '重置配置', 77 | }, 78 | US: { 79 | theme: { 80 | title: 'Page Style Setting', 81 | light: 'Light Style', 82 | dark: 'Dark Style', 83 | night: 'Night Style', 84 | color: 'Theme Color' 85 | }, 86 | navigate: { 87 | title: 'Navigation Mode', 88 | side: 'Side Menu Layout', 89 | head: 'Top Menu Layout', 90 | mix: 'Mix Menu Layout', 91 | content: { 92 | title: 'Content Width', 93 | fluid: 'Fluid', 94 | fixed: 'Fixed' 95 | }, 96 | fixedHeader: 'Fixed Header', 97 | fixedSideBar: 'Fixed SideBar', 98 | }, 99 | other: { 100 | title: 'Other Setting', 101 | weekMode: 'Week Mode', 102 | multiPages: 'Multi Pages', 103 | hideSetting: 'Hide Setting Drawer' 104 | }, 105 | animate: { 106 | title: 'Page Toggle Animation', 107 | disable: 'Disable', 108 | effect: 'Effect', 109 | direction: 'Direction' 110 | }, 111 | alert: 'After copying the configuration code, directly cover all contents in the file src/config/config.js, then restart the server. (Note: only items that are different from the default configuration will be copied)', 112 | copy: 'Copy Setting', 113 | save: 'Save', 114 | reset: 'Reset', 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/components/table/advance/ActionSize.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 39 | 40 | -------------------------------------------------------------------------------- /src/components/table/advance/index.js: -------------------------------------------------------------------------------- 1 | import AdvanceTable from './AdvanceTable' 2 | export default AdvanceTable -------------------------------------------------------------------------------- /src/components/table/api/ApiTable.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 46 | 47 | -------------------------------------------------------------------------------- /src/components/task/TaskItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 26 | -------------------------------------------------------------------------------- /src/components/tool/AStepItem.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 47 | 48 | 60 | -------------------------------------------------------------------------------- /src/components/tool/AvatarList.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 47 | 48 | 70 | -------------------------------------------------------------------------------- /src/components/tool/DetailList.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 100 | 101 | 157 | -------------------------------------------------------------------------------- /src/components/tool/Drawer.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 59 | 60 | 143 | -------------------------------------------------------------------------------- /src/components/tool/FooterToolBar.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /src/components/tool/HeadInfo.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | 35 | -------------------------------------------------------------------------------- /src/components/tool/TagSelect.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 68 | 69 | 84 | -------------------------------------------------------------------------------- /src/components/tool/TagSelectOption.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | 26 | 34 | -------------------------------------------------------------------------------- /src/components/transition/PageToggleTransition.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 80 | 81 | 97 | -------------------------------------------------------------------------------- /src/config/config.js: -------------------------------------------------------------------------------- 1 | // 自定义配置,参考 ./default/setting.config.js,需要自定义的属性在这里配置即可 2 | module.exports = { 3 | theme: { 4 | color: '#13c2c2', 5 | mode: 'dark', 6 | }, 7 | multiPage: true, 8 | animate: { 9 | name: 'lightSpeed', 10 | direction: 'left' 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/config/default/admin.config.js: -------------------------------------------------------------------------------- 1 | // admin 配置 2 | const ADMIN = { 3 | palettes: ['#f5222d', '#fa541c', '#fadb14', '#3eaf7c', '#13c2c2', '#1890ff', '#722ed1', '#eb2f96'], 4 | animates: require('./animate.config').preset, 5 | theme: { 6 | mode: { 7 | DARK: 'dark', 8 | LIGHT: 'light', 9 | NIGHT: 'night' 10 | } 11 | }, 12 | layout: { 13 | SIDE: 'side', 14 | HEAD: 'head' 15 | } 16 | } 17 | 18 | module.exports = ADMIN 19 | -------------------------------------------------------------------------------- /src/config/default/animate.config.js: -------------------------------------------------------------------------------- 1 | const direct_s = ['left', 'right'] 2 | const direct_1 = ['left', 'right', 'down', 'up'] 3 | const direct_1_b = ['downBig', 'upBig', 'leftBig', 'rightBig'] 4 | const direct_2 = ['topLeft', 'bottomRight', 'topRight', 'bottomLeft'] 5 | const direct_3 = ['downLeft', 'upRight', 'downRight', 'upLeft'] 6 | 7 | // animate.css 配置 8 | const ANIMATE = { 9 | preset: [ //预设动画配置 10 | {name: 'back', alias: '渐近', directions: direct_1}, 11 | {name: 'bounce', alias: '弹跳', directions: direct_1.concat('default')}, 12 | {name: 'fade', alias: '淡化', directions: direct_1.concat(direct_1_b).concat(direct_2).concat('default')}, 13 | {name: 'flip', alias: '翻转', directions: ['x', 'y']}, 14 | {name: 'lightSpeed', alias: '光速', directions: direct_s}, 15 | {name: 'rotate', alias: '旋转', directions: direct_3.concat('default')}, 16 | {name: 'roll', alias: '翻滚', directions: ['default']}, 17 | {name: 'zoom', alias: '缩放', directions: direct_1.concat('default')}, 18 | {name: 'slide', alias: '滑动', directions: direct_1}, 19 | ] 20 | } 21 | module.exports = ANIMATE 22 | -------------------------------------------------------------------------------- /src/config/default/antd.config.js: -------------------------------------------------------------------------------- 1 | // antd 配置 2 | const ANTD = { 3 | primary: { 4 | color: '#1890ff', 5 | warning: '#faad14', 6 | success: '#52c41a', 7 | error: '#f5222d', 8 | light: { 9 | menuColors: ['#000c17', '#001529', '#002140'] 10 | }, 11 | dark: { 12 | menuColors: ['#000c17', '#001529', '#002140'] 13 | }, 14 | night: { 15 | menuColors: ['#151515', '#1f1f1f', '#1e1e1e'], 16 | } 17 | }, 18 | theme: { 19 | dark: { 20 | 'layout-body-background': '#f0f2f5', 21 | 'body-background': '#fff', 22 | 'component-background': '#fff', 23 | 'heading-color': 'rgba(0, 0, 0, 0.85)', 24 | 'text-color': 'rgba(0, 0, 0, 0.65)', 25 | 'text-color-inverse': '#fff', 26 | 'text-color-secondary': 'rgba(0, 0, 0, 0.45)', 27 | 'shadow-color': 'rgba(0, 0, 0, 0.15)', 28 | 'border-color-split': '#f0f0f0', 29 | 'background-color-light': '#fafafa', 30 | 'background-color-base': '#f5f5f5', 31 | 'table-selected-row-bg': '#fafafa', 32 | 'table-expanded-row-bg': '#fbfbfb', 33 | 'checkbox-check-color': '#fff', 34 | 'disabled-color': 'rgba(0, 0, 0, 0.25)', 35 | 'menu-dark-color': 'rgba(254, 254, 254, 0.65)', 36 | 'menu-dark-highlight-color': '#fefefe', 37 | 'menu-dark-arrow-color': '#fefefe', 38 | 'btn-primary-color': '#fff', 39 | }, 40 | light: { 41 | 'layout-body-background': '#f0f2f5', 42 | 'body-background': '#fff', 43 | 'component-background': '#fff', 44 | 'heading-color': 'rgba(0, 0, 0, 0.85)', 45 | 'text-color': 'rgba(0, 0, 0, 0.65)', 46 | 'text-color-inverse': '#fff', 47 | 'text-color-secondary': 'rgba(0, 0, 0, 0.45)', 48 | 'shadow-color': 'rgba(0, 0, 0, 0.15)', 49 | 'border-color-split': '#f0f0f0', 50 | 'background-color-light': '#fafafa', 51 | 'background-color-base': '#f5f5f5', 52 | 'table-selected-row-bg': '#fafafa', 53 | 'table-expanded-row-bg': '#fbfbfb', 54 | 'checkbox-check-color': '#fff', 55 | 'disabled-color': 'rgba(0, 0, 0, 0.25)', 56 | 'menu-dark-color': 'rgba(1, 1, 1, 0.65)', 57 | 'menu-dark-highlight-color': '#fefefe', 58 | 'menu-dark-arrow-color': '#fefefe', 59 | 'btn-primary-color': '#fff', 60 | }, 61 | night: { 62 | 'layout-body-background': '#000', 63 | 'body-background': '#141414', 64 | 'component-background': '#141414', 65 | 'heading-color': 'rgba(255, 255, 255, 0.85)', 66 | 'text-color': 'rgba(255, 255, 255, 0.85)', 67 | 'text-color-inverse': '#141414', 68 | 'text-color-secondary': 'rgba(255, 255, 255, 0.45)', 69 | 'shadow-color': 'rgba(255, 255, 255, 0.15)', 70 | 'border-color-split': '#303030', 71 | 'background-color-light': '#ffffff0a', 72 | 'background-color-base': '#2a2a2a', 73 | 'table-selected-row-bg': '#ffffff0a', 74 | 'table-expanded-row-bg': '#ffffff0b', 75 | 'checkbox-check-color': '#141414', 76 | 'disabled-color': 'rgba(255, 255, 255, 0.25)', 77 | 'menu-dark-color': 'rgba(254, 254, 254, 0.65)', 78 | 'menu-dark-highlight-color': '#fefefe', 79 | 'menu-dark-arrow-color': '#fefefe', 80 | 'btn-primary-color': '#141414', 81 | } 82 | } 83 | } 84 | module.exports = ANTD 85 | -------------------------------------------------------------------------------- /src/config/default/index.js: -------------------------------------------------------------------------------- 1 | const ANTD = require('./antd.config') 2 | const ADMIN = require('./admin.config') 3 | const ANIMATE = require('./animate.config') 4 | const setting = require('./setting.config') 5 | 6 | module.exports = {ANTD, ADMIN, ANIMATE, setting} 7 | -------------------------------------------------------------------------------- /src/config/default/setting.config.js: -------------------------------------------------------------------------------- 1 | // 此配置为系统默认设置,需修改的设置项,在src/config/config.js中添加修改项即可。也可直接在此文件中修改。 2 | module.exports = { 3 | lang: 'CN', //语言,可选 CN(简体)、HK(繁体)、US(英语),也可扩展其它语言 4 | theme: { //主题 5 | color: '#1890ff', //主题色 6 | mode: 'dark', //主题模式 可选 dark、 light 和 night 7 | success: '#52c41a', //成功色 8 | warning: '#faad14', //警告色 9 | error: '#f5222f', //错误色 10 | }, 11 | layout: 'side', //导航布局,可选 side 和 head,分别为侧边导航和顶部导航 12 | fixedHeader: false, //固定头部状态栏,true:固定,false:不固定 13 | fixedSideBar: true, //固定侧边栏,true:固定,false:不固定 14 | fixedTabs: false, //固定页签头,true:固定,false:不固定 15 | pageWidth: 'fixed', //内容区域宽度,fixed:固定宽度,fluid:流式宽度 16 | weekMode: false, //色弱模式,true:开启,false:不开启 17 | multiPage: false, //多页签模式,true:开启,false:不开启 18 | cachePage: true, //是否缓存页面数据,仅多页签模式下生效,true 缓存, false 不缓存 19 | hideSetting: true, //隐藏设置抽屉,true:隐藏,false:不隐藏 20 | systemName: 'Rule Engine', //系统名称 21 | copyright: '2020-2025 规则引擎(ruleengine.cn) All Rights Reserved', //copyright 22 | // 京ICP备2020034246号-1 备案号 23 | asyncRoutes: false, //异步加载路由,true:开启,false:不开启 24 | showPageTitle: false, //是否显示页面标题(PageLayout 布局中的页面标题),true:显示,false:不显示 25 | filterMenu: true, //根据权限过滤菜单,true:过滤,false:不过滤 26 | animate: { //动画设置 27 | disabled: true, //禁用动画,true:禁用,false:启用 28 | name: 'bounce', //动画效果,支持的动画效果可参考 ./animate.config.js 29 | direction: 'left' //动画方向,切换页面时动画的方向,参考 ./animate.config.js 30 | }, 31 | footerLinks: [ //页面底部链接,{link: '链接地址', name: '名称/显示文字', icon: '图标,支持 ant design vue 图标库'} 32 | {link: 'https://gitee.com/aizuda/rule-engine-open', name: '后台源码'}, 33 | {link: 'https://github.com/dingqianwen', icon: 'github'}, 34 | {link: 'http://ruleengine.cn/doc/', name: '文档'} 35 | ], 36 | } 37 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | const deepMerge = require('deepmerge') 2 | const _config = require('./config') 3 | const {setting} = require('./default') 4 | const config = deepMerge(setting, _config) 5 | 6 | module.exports = config 7 | -------------------------------------------------------------------------------- /src/config/replacer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack-theme-color-replacer 配置 3 | * webpack-theme-color-replacer 是一个高效的主题色替换插件,可以实现系统运行时动态切换主题功能。 4 | * 但有些情景下,我们需要为 webpack-theme-color-replacer 配置一些规则,以达到我们的个性化需求的目的 5 | * 6 | * @cssResolve: css处理规则,在 webpack-theme-color-replacer 提取 需要替换主题色的 css 后,应用此规则。一般在 7 | * webpack-theme-color-replacer 默认规则无法达到我们的要求时使用。 8 | */ 9 | const cssResolve = require('./resolve.config') 10 | module.exports = {cssResolve} 11 | -------------------------------------------------------------------------------- /src/config/replacer/resolve.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * webpack-theme-color-replacer 插件的 resolve 配置 3 | * 为特定的 css 选择器(selector)配置 resolve 规则。 4 | * 5 | * key 为 css selector 值或合法的正则表达式字符串 6 | * 当 key 设置 css selector 值时,会匹配对应的 css 7 | * 当 key 设置为正则表达式时,会匹配所有满足此正则表达式的的 css 8 | * 9 | * value 可以设置为 boolean 值 false 或 一个对象 10 | * 当 value 为 false 时,则会忽略此 css,即此 css 不纳入 webpack-theme-color-replacer 管理 11 | * 当 value 为 对象时,会调用该对象的 resolve 函数,并传入 cssText(原始的 css文本) 和 cssObj(css对象)参数; resolve函数应该返 12 | * 回一个处理后的、合法的 css字符串(包含 selector) 13 | * 注意: value 不能设置为 true 14 | */ 15 | const cssResolve = { 16 | '.ant-checkbox-checked .ant-checkbox-inner::after': { 17 | resolve(cssText, cssObj) { 18 | cssObj.rules.push('border-top:0', 'border-left:0') 19 | return cssObj.toText() 20 | } 21 | }, 22 | '.ant-tree-checkbox-checked .ant-tree-checkbox-inner::after': { 23 | resolve(cssText, cssObj) { 24 | cssObj.rules.push('border-top:0', 'border-left:0') 25 | return cssObj.toText() 26 | } 27 | }, 28 | '.ant-checkbox-checked .ant-checkbox-inner:after': { 29 | resolve(cssText, cssObj) { 30 | cssObj.rules.push('border-top:0', 'border-left:0') 31 | return cssObj.toText() 32 | } 33 | }, 34 | '.ant-tree-checkbox-checked .ant-tree-checkbox-inner:after': { 35 | resolve(cssText, cssObj) { 36 | cssObj.rules.push('border-top:0', 'border-left:0') 37 | return cssObj.toText() 38 | } 39 | }, 40 | '.ant-menu-dark .ant-menu-inline.ant-menu-sub': { 41 | resolve(cssText, cssObj) { 42 | cssObj.rules = cssObj.rules.filter(rule => rule.indexOf('box-shadow') == -1) 43 | return cssObj.toText() 44 | } 45 | }, 46 | '.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu:hover,.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-submenu-selected': { 47 | resolve(cssText, cssObj) { 48 | cssObj.selector = cssObj.selector.replace(/.ant-menu-horizontal/g, '.ant-menu-horizontal:not(.ant-menu-dark)') 49 | return cssObj.toText() 50 | } 51 | }, 52 | '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover': { 53 | resolve(cssText, cssObj) { 54 | cssObj.selector = cssObj.selector.replace(/.ant-menu-horizontal/g, '.ant-menu-horizontal:not(.ant-menu-dark)') 55 | return cssObj.toText() 56 | } 57 | }, 58 | '.ant-layout-sider': { 59 | resolve(cssText, cssObj) { 60 | cssObj.selector = '.ant-layout-sider-dark' 61 | return cssObj.toText() 62 | } 63 | }, 64 | '/keyframes/': false 65 | } 66 | 67 | module.exports = cssResolve 68 | -------------------------------------------------------------------------------- /src/layouts/BlankView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/layouts/CommonLayout.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | 21 | 43 | -------------------------------------------------------------------------------- /src/layouts/PageView.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 45 | 46 | 56 | -------------------------------------------------------------------------------- /src/layouts/footer/PageFooter.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 23 | 24 | 49 | -------------------------------------------------------------------------------- /src/layouts/header/HeaderAvatar.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 54 | 55 | 77 | -------------------------------------------------------------------------------- /src/layouts/header/HeaderNotice.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 67 | 68 | 93 | -------------------------------------------------------------------------------- /src/layouts/header/HeaderSearch.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 38 | 39 | 68 | -------------------------------------------------------------------------------- /src/layouts/header/HeaderWorkSpace.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 126 | 127 | 135 | -------------------------------------------------------------------------------- /src/layouts/header/index.less: -------------------------------------------------------------------------------- 1 | .admin-header{ 2 | padding: 0; 3 | z-index: 2; 4 | box-shadow: @shadow-down; 5 | position: relative; 6 | background: @base-bg-color; 7 | .head-menu{ 8 | height: 64px; 9 | line-height: 64px; 10 | vertical-align: middle; 11 | box-shadow: none; 12 | } 13 | &.dark{ 14 | background: @header-bg-color-dark; 15 | color: white; 16 | } 17 | &.night{ 18 | .head-menu{ 19 | background: @base-bg-color; 20 | } 21 | } 22 | .admin-header-wide{ 23 | padding-left: 24px; 24 | &.head.fixed{ 25 | max-width: 1400px; 26 | margin: auto; 27 | padding-left: 0; 28 | } 29 | &.side{ 30 | padding-right: 12px; 31 | } 32 | .logo { 33 | height: 64px; 34 | line-height: 58px; 35 | vertical-align: top; 36 | display: inline-block; 37 | padding: 0 12px 0 24px; 38 | cursor: pointer; 39 | font-size: 20px; 40 | color: inherit; 41 | &.pc{ 42 | padding: 0 12px 0 0; 43 | } 44 | img { 45 | vertical-align: middle; 46 | } 47 | h1{ 48 | color: inherit; 49 | display: inline-block; 50 | font-size: 16px; 51 | } 52 | } 53 | .trigger { 54 | font-size: 20px; 55 | line-height: 64px; 56 | padding: 0 24px; 57 | cursor: pointer; 58 | transition: color .3s; 59 | &:hover{ 60 | color: @primary-color; 61 | } 62 | } 63 | .admin-header-menu{ 64 | display: inline-block; 65 | } 66 | .admin-header-right{ 67 | float: right; 68 | display: flex; 69 | color: inherit; 70 | .header-item{ 71 | color: inherit; 72 | padding: 0 12px; 73 | cursor: pointer; 74 | align-self: center; 75 | a{ 76 | color: inherit; 77 | i{ 78 | font-size: 16px; 79 | } 80 | } 81 | } 82 | each(@theme-list, { 83 | &.@{value} .header-item{ 84 | &:hover{ 85 | @class: ~'hover-bg-color-@{value}'; 86 | background-color: @@class; 87 | } 88 | } 89 | }) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/layouts/tabs/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | closeLeft: '关闭左侧', 5 | closeRight: '关闭右侧', 6 | closeOthers: '关闭其它', 7 | refresh: '刷新页面', 8 | warn: '这是最后一页,不能再关闭了', 9 | }, 10 | HK: { 11 | closeLeft: '關閉左側', 12 | closeRight: '關閉右側', 13 | closeOthers: '關閉其它', 14 | refresh: '刷新頁面', 15 | warn: '這是最後一頁,不能再關閉了', 16 | }, 17 | US: { 18 | closeLeft: 'close left', 19 | closeRight: 'close right', 20 | closeOthers: 'close others', 21 | refresh: 'refresh the page', 22 | warn: 'This is the last page, you can\'t close it', 23 | }, 24 | } 25 | } -------------------------------------------------------------------------------- /src/layouts/tabs/index.js: -------------------------------------------------------------------------------- 1 | import TabsView from './TabsView' 2 | export default TabsView 3 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import {initRouter} from './router' 4 | import './theme/index.less' 5 | import Antd from 'ant-design-vue' 6 | import Viser from 'viser-vue' 7 | import '@/mock' 8 | import store from './store' 9 | import 'animate.css/source/animate.css' 10 | import Plugins from '@/plugins' 11 | import {initI18n} from '@/utils/i18n' 12 | import bootstrap from '@/bootstrap' 13 | import 'moment/locale/zh-cn' 14 | import VueCropper from 'vue-cropper' 15 | import vueScroll from "vuescroll";//引入vuescroll 16 | import "vuescroll/dist/vuescroll.css";//引入vuescroll样式 17 | import 'xe-utils' 18 | import VXETable from 'vxe-table' 19 | import 'vxe-table/lib/style.css' 20 | 21 | const router = initRouter(store.state.setting.asyncRoutes) 22 | const i18n = initI18n('CN', 'US') 23 | 24 | Vue.use(Antd) 25 | Vue.config.productionTip = false 26 | Vue.use(Viser) 27 | Vue.use(Plugins) 28 | Vue.use(VueCropper) 29 | Vue.use(vueScroll, { 30 | ops: {}, // 在这里设置全局默认配置 31 | name: 'vue-scroll' // 在这里自定义组件名字,默认是vueScroll 32 | });//使用 33 | 34 | Vue.use(VXETable) 35 | bootstrap({router, store, i18n, message: Vue.prototype.$message}) 36 | 37 | let vueMain = new Vue({ 38 | router, 39 | store, 40 | i18n, 41 | render: h => h(App), 42 | }).$mount('#app') 43 | 44 | export default vueMain 45 | -------------------------------------------------------------------------------- /src/mock/common/activityData.js: -------------------------------------------------------------------------------- 1 | import {users, groups} from './index' 2 | 3 | const events = [ 4 | { 5 | type: 0, 6 | event: '八月迭代' 7 | }, 8 | { 9 | type: 1, 10 | event: '留言' 11 | }, 12 | { 13 | type: 2, 14 | event: '项目进展' 15 | } 16 | ] 17 | 18 | const activities = users.map((user, index) => { 19 | return { 20 | user: Object.assign({}, user, {group: groups[user.groupId]}), 21 | activity: events[index % events.length], 22 | template: '' 23 | } 24 | }) 25 | 26 | const templates = [ 27 | (user, activity) => { return `${user.name} 在 ${user.group} 新建项目 ${activity.event}` }, 28 | (user, activity) => { return `${user.name} 在 ${user.group} 发布了 ${activity.event}` }, 29 | (user, activity) => { return `${user.name} 将 ${activity.event} 更新至已发布状态` } 30 | ] 31 | 32 | export {activities, templates} 33 | -------------------------------------------------------------------------------- /src/mock/common/index.js: -------------------------------------------------------------------------------- 1 | const avatars = [ 2 | 'https://gw.alipayobjects.com/zos/rmsportal/cnrhVkzwxjPwAaCfPbdc.png', 3 | 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png', 4 | 'https://gw.alipayobjects.com/zos/rmsportal/gaOngJwsRYRaVAuXXcmB.png', 5 | 'https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png', 6 | 'https://gw.alipayobjects.com/zos/rmsportal/ubnKSIfAJTxIgXOKlciN.png', 7 | 'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png' 8 | ] 9 | 10 | const positions = [ 11 | { 12 | CN: 'Java工程师 | 蚂蚁金服-计算服务事业群-微信平台部', 13 | HK: 'Java工程師 | 螞蟻金服-計算服務事業群-微信平台部', 14 | US: 'Java engineer | Ant financial - Computing services business group - WeChat platform division' 15 | },{ 16 | CN: '前端工程师 | 蚂蚁金服-计算服务事业群-VUE平台', 17 | HK: '前端工程師 | 螞蟻金服-計算服務事業群-VUE平台', 18 | US: 'Front-end engineer | Ant Financial - Computing services business group - VUE platform' 19 | },{ 20 | CN: '前端工程师 | 蚂蚁金服-计算服务事业群-REACT平台', 21 | HK: '前端工程師 | 螞蟻金服-計算服務事業群-REACT平台', 22 | US: 'Front-end engineer | Ant Financial - Computing services business group - REACT platform' 23 | },{ 24 | CN: '产品分析师 | 蚂蚁金服-计算服务事业群-IOS平台部', 25 | HK: '產品分析師 | 螞蟻金服-計算服務事業群-IOS平台部', 26 | US: 'Product analyst | Ant Financial - Computing services business group - IOS platform division' 27 | } 28 | ] 29 | 30 | const sayings = [ 31 | '那是一种内在的东西,他们到达不了,也无法触及的', 32 | '希望是一个好东西,也许是最好的,好东西是不会消亡的', 33 | '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', 34 | '那时候我只会想自己想要什么,从不想自己拥有什么' 35 | ] 36 | 37 | const logos = [ 38 | 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png', 39 | 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png', 40 | 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png', 41 | 'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png', 42 | 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png' 43 | ] 44 | 45 | const admins = ['ICZER', 'JACK', 'LUIS', 'DAVID'] 46 | 47 | const groups = ['高逼格设计天团', '中二少女团', '科学搬砖组', '骗你学计算机', '程序员日常'] 48 | 49 | const users = [ 50 | { 51 | name: '曲丽丽', 52 | avatar: avatars[0], 53 | groupId: 0 54 | }, 55 | { 56 | name: '付晓晓', 57 | avatar: avatars[1], 58 | groupId: 0 59 | }, 60 | { 61 | name: '林东东', 62 | avatar: avatars[2], 63 | groupId: 1 64 | }, 65 | { 66 | name: '周星星', 67 | avatar: avatars[3], 68 | groupId: 2 69 | }, 70 | { 71 | name: '朱偏右', 72 | avatar: avatars[4], 73 | groupId: 3 74 | }, 75 | { 76 | name: '勒个', 77 | avatar: avatars[5], 78 | groupId: 4 79 | } 80 | ] 81 | 82 | const teams = groups.map((item, index) => { 83 | return { 84 | name: item, 85 | avatar: avatars[index] 86 | } 87 | }) 88 | 89 | export {logos, sayings, positions, avatars, admins, groups, users, teams} 90 | -------------------------------------------------------------------------------- /src/mock/common/tableData.js: -------------------------------------------------------------------------------- 1 | const operation1 = [ 2 | { 3 | key: 'op1', 4 | type: '订购关系生效', 5 | name: '曲丽丽', 6 | status: 'agree', 7 | updatedAt: '2017-10-03 19:23:12', 8 | memo: '-' 9 | }, 10 | { 11 | key: 'op2', 12 | type: '财务复审', 13 | name: '付小小', 14 | status: 'reject', 15 | updatedAt: '2017-10-03 19:23:12', 16 | memo: '不通过原因' 17 | }, 18 | { 19 | key: 'op3', 20 | type: '部门初审', 21 | name: '周毛毛', 22 | status: 'agree', 23 | updatedAt: '2017-10-03 19:23:12', 24 | memo: '-' 25 | }, 26 | { 27 | key: 'op4', 28 | type: '提交订单', 29 | name: '林东东', 30 | status: 'agree', 31 | updatedAt: '2017-10-03 19:23:12', 32 | memo: '很棒' 33 | }, 34 | { 35 | key: 'op5', 36 | type: '创建订单', 37 | name: '汗牙牙', 38 | status: 'agree', 39 | updatedAt: '2017-10-03 19:23:12', 40 | memo: '-' 41 | } 42 | ] 43 | 44 | const operation2 = [ 45 | { 46 | key: 'op2', 47 | type: '财务复审', 48 | name: '付小小', 49 | status: 'reject', 50 | updatedAt: '2017-10-03 19:23:12', 51 | memo: '不通过原因' 52 | }, 53 | { 54 | key: 'op3', 55 | type: '部门初审', 56 | name: '周毛毛', 57 | status: 'agree', 58 | updatedAt: '2017-10-03 19:23:12', 59 | memo: '-' 60 | }, 61 | { 62 | key: 'op4', 63 | type: '提交订单', 64 | name: '林东东', 65 | status: 'agree', 66 | updatedAt: '2017-10-03 19:23:12', 67 | memo: '很棒' 68 | } 69 | ] 70 | 71 | const operation3 = [ 72 | { 73 | key: 'op2', 74 | type: '财务复审', 75 | name: '付小小', 76 | status: 'reject', 77 | updatedAt: '2017-10-03 19:23:12', 78 | memo: '不通过原因' 79 | }, 80 | { 81 | key: 'op3', 82 | type: '部门初审', 83 | name: '周毛毛', 84 | status: 'agree', 85 | updatedAt: '2017-10-03 19:23:12', 86 | memo: '-' 87 | } 88 | ] 89 | 90 | const operationColumns = [ 91 | { 92 | title: '操作类型', 93 | dataIndex: 'type', 94 | key: 'type' 95 | }, 96 | { 97 | title: '操作人', 98 | dataIndex: 'name', 99 | key: 'name' 100 | }, 101 | { 102 | title: '执行结果', 103 | dataIndex: 'status', 104 | key: 'status' 105 | }, 106 | { 107 | title: '操作时间', 108 | dataIndex: 'updatedAt', 109 | key: 'updatedAt' 110 | }, 111 | { 112 | title: '备注', 113 | dataIndex: 'memo', 114 | key: 'memo' 115 | } 116 | ] 117 | 118 | export {operation1, operation2, operation3, operationColumns} 119 | -------------------------------------------------------------------------------- /src/mock/extend/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import {logos, sayings, positions, avatars, admins} from '../common' 3 | 4 | const Random = Mock.Random 5 | 6 | const timeList = [ 7 | { 8 | CN: '早上好', 9 | HK: '早晨啊', 10 | US: 'Good morning', 11 | },{ 12 | CN: '上午好', 13 | HK: '上午好', 14 | US: 'Good morning', 15 | },{ 16 | CN: '中午好', 17 | HK: '中午好', 18 | US: 'Good afternoon', 19 | },{ 20 | CN: '下午好', 21 | HK: '下午好', 22 | US: 'Good afternoon', 23 | },{ 24 | CN: '晚上好', 25 | HK: '晚上好', 26 | US: 'Good evening', 27 | } 28 | ] 29 | 30 | const welcomeMessages = [ 31 | { 32 | CN: '休息一会儿吧', 33 | HK: '休息一會兒吧', 34 | US: 'you may need a break', 35 | }, 36 | { 37 | CN: '准备吃什么呢', 38 | HK: '準備吃什麼呢', 39 | US: 'what are you going to eat', 40 | }, 41 | { 42 | CN: '要不要打一把 DOTA', 43 | HK: '要不要打一把 DOTA', 44 | US: 'how about a game of DOTA', 45 | }, 46 | { 47 | CN: '我猜你可能累了', 48 | HK: '我猜你可能累了', 49 | US: 'i guess you might be tired', 50 | } 51 | ] 52 | 53 | const goods = ['运动鞋', '短裤', 'T恤', '七分裤', '风衣', '寸衫'] 54 | 55 | Random.extend({ 56 | admin () { 57 | return this.pick(admins) 58 | }, 59 | welcome () { 60 | return this.pick(welcomeMessages) 61 | }, 62 | timeFix () { 63 | const time = new Date() 64 | const hour = time.getHours() 65 | return hour < 9 66 | ? timeList[0] : (hour <= 11 ? timeList[1] : (hour <= 13 ? timeList[2] : (hour <= 20 ? timeList[3] : timeList[4]))) 67 | }, 68 | avatar () { 69 | return this.pick(avatars) 70 | }, 71 | position () { 72 | return this.pick(positions) 73 | }, 74 | goods () { 75 | return this.pick(goods) 76 | }, 77 | saying () { 78 | return this.pick(sayings) 79 | }, 80 | logo () { 81 | return this.pick(logos) 82 | } 83 | }) 84 | -------------------------------------------------------------------------------- /src/mock/goods/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import '@/mock/extend' 3 | import {parseUrlParams} from '@/utils/request' 4 | 5 | const current = new Date().getTime() 6 | 7 | const goodsList = Mock.mock({ 8 | 'list|100': [{ 9 | 'id|+1': 0, 10 | 'name': '@GOODS', 11 | 'orderId': `${current}-@integer(1,100)`, 12 | 'status|1-4': 1, 13 | 'send': '@BOOLEAN', 14 | 'sendTime': '@DATETIME', 15 | 'orderDate': '@DATE', 16 | 'auditTime': '@TIME' 17 | }] 18 | }) 19 | 20 | Mock.mock(RegExp(`/api/goods` + '.*'),'get', ({url}) => { 21 | const params = parseUrlParams(decodeURI(url)) 22 | let {page, pageSize} = params 23 | page = eval(page) - 1 || 0 24 | pageSize = eval(pageSize) || 10 25 | delete params.page 26 | delete params.pageSize 27 | let result = goodsList.list.filter(item => { 28 | for (let [key, value] of Object.entries(params)) { 29 | if (item[key] != value) { 30 | return false 31 | } 32 | } 33 | return true 34 | }) 35 | const total = result.length 36 | if ((page) * pageSize > total) { 37 | result = [] 38 | } else { 39 | result = result.slice(page * pageSize, (page + 1) * pageSize) 40 | } 41 | return { 42 | code: 0, 43 | message: 'success', 44 | data: { 45 | page: page + 1, 46 | pageSize, 47 | total, 48 | list: result 49 | } 50 | } 51 | }) 52 | 53 | const columnsConfig = [ 54 | { 55 | title: '商品名称', 56 | dataIndex: 'name', 57 | searchAble: true 58 | }, 59 | { 60 | title: '订单号', 61 | dataIndex: 'orderId' 62 | }, 63 | { 64 | searchAble: true, 65 | dataIndex: 'status', 66 | dataType: 'select', 67 | slots: {title: 'statusTitle'}, 68 | scopedSlots: {customRender: 'status'}, 69 | search: { 70 | selectOptions: [ 71 | {title: '已下单', value: 1}, 72 | {title: '已付款', value: 2}, 73 | {title: '已审核', value: 3}, 74 | // {title: '已发货', value: 4} 75 | ] 76 | } 77 | }, 78 | { 79 | title: '发货', 80 | searchAble: true, 81 | dataIndex: 'send', 82 | dataType: 'boolean', 83 | scopedSlots: {customRender: 'send'} 84 | }, 85 | { 86 | title: '发货时间', 87 | dataIndex: 'sendTime', 88 | dataType: 'datetime' 89 | }, 90 | { 91 | title: '下单日期', 92 | searchAble: true, 93 | dataIndex: 'orderDate', 94 | dataType: 'date', 95 | visible: false 96 | }, 97 | { 98 | title: '审核时间', 99 | dataIndex: 'auditTime', 100 | dataType: 'time', 101 | }, 102 | ] 103 | 104 | Mock.mock(`${process.env.VUE_APP_WEB_BASE_URL}/columns`, 'get', () => { 105 | return columnsConfig 106 | }) 107 | -------------------------------------------------------------------------------- /src/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import '@/mock/user/current' 3 | import '@/mock/project' 4 | import '@/mock/user/login' 5 | import '@/mock/workplace' 6 | import '@/mock/user/routes' 7 | import '@/mock/goods' 8 | 9 | // 设置全局延时 10 | Mock.setup({ 11 | timeout: '200-400' 12 | }) 13 | -------------------------------------------------------------------------------- /src/mock/project/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import '@/mock/extend' 3 | 4 | const projectArr = Mock.mock({ 5 | 'list|6': [ 6 | { 7 | logo: '@LOGO', 8 | desc: '@SAYING' 9 | } 10 | ] 11 | }).list 12 | 13 | Mock.mock('/project', 'get', () => { 14 | return projectArr 15 | }) 16 | -------------------------------------------------------------------------------- /src/mock/user/current.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import '@/mock/extend' 3 | 4 | const welcome = Mock.mock({ 5 | timeFix: '@TIMEFIX', 6 | message: '@WELCOME' 7 | }) 8 | 9 | Mock.mock('/user/welcome', 'get', () => { 10 | return welcome 11 | }) 12 | -------------------------------------------------------------------------------- /src/mock/user/login.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import '@/mock/extend' 3 | 4 | const user = Mock.mock({ 5 | name: '@ADMIN', 6 | avatar: '@AVATAR', 7 | address: '@CITY', 8 | position: '@POSITION' 9 | }) 10 | Mock.mock(`${process.env.VUE_APP_WEB_BASE_URL}/login`, 'post', ({body}) => { 11 | let result = {data: {}} 12 | const {name, password} = JSON.parse(body) 13 | 14 | let success = false 15 | 16 | if (name === 'admin' && password === '888888') { 17 | success = true 18 | result.data.permissions = [{id: 'queryForm', operation: ['add', 'edit']}] 19 | result.data.roles = [{id: 'admin', operation: ['add', 'edit', 'delete']}] 20 | } else if (name === 'test' || password === '888888') { 21 | success = true 22 | result.data.permissions = [{id: 'queryForm', operation: ['add', 'edit']}] 23 | result.data.roles = [{id: 'test', operation: ['add', 'edit', 'delete']}] 24 | } else { 25 | success = false 26 | } 27 | 28 | if (success) { 29 | result.code = 200 30 | result.message = Mock.mock('@TIMEFIX').CN + ',欢迎回来' 31 | result.data.user = user 32 | result.data.token = 'Authorization:' + Math.random() 33 | result.data.expireAt = new Date(new Date().getTime() + 30 * 60 * 1000) 34 | } else { 35 | result.code = -1 36 | result.message = '账户名或密码错误(admin/888888 or test/888888)' 37 | } 38 | return result 39 | }) 40 | -------------------------------------------------------------------------------- /src/mock/user/routes.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | 3 | Mock.mock(`/api/routes`, 'get', () => { 4 | let result = {} 5 | result.code = 200 6 | result.data = [{ 7 | router: 'root', 8 | children: [ 9 | { 10 | router: 'dashboard', 11 | children: ['workplace', 'analysis'], 12 | }, 13 | { 14 | router: 'form', 15 | children: ['basicForm', 'stepForm', 'advanceForm'] 16 | }, 17 | { 18 | router: 'basicForm', 19 | name: '验权表单', 20 | icon: 'file-excel', 21 | authority: 'queryForm' 22 | }, 23 | { 24 | router: 'antdv', 25 | path: 'antdv', 26 | name: 'Ant Design Vue', 27 | icon: 'ant-design', 28 | link: 'https://www.antdv.com/docs/vue/introduce-cn/' 29 | }, 30 | { 31 | router: 'document', 32 | path: 'document', 33 | name: '使用文档', 34 | icon: 'file-word', 35 | link: 'https://iczer.gitee.io/vue-antd-admin-docs/' 36 | } 37 | ] 38 | }] 39 | return result 40 | }) 41 | -------------------------------------------------------------------------------- /src/mock/workplace/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import {activities, templates} from '../common/activityData' 3 | import {teams} from '../../mock/common' 4 | 5 | activities.forEach(item => { 6 | item.template = templates[item.activity.type](item.user, item.activity) 7 | }) 8 | 9 | Mock.mock('/work/activity', 'get', () => { 10 | return activities 11 | }) 12 | 13 | Mock.mock('/work/team', 'get', () => { 14 | return teams 15 | }) 16 | -------------------------------------------------------------------------------- /src/pages/components/Inputparameter/index.js: -------------------------------------------------------------------------------- 1 | import InputParameter from './InputParameter' 2 | export default InputParameter 3 | -------------------------------------------------------------------------------- /src/pages/components/function/index.js: -------------------------------------------------------------------------------- 1 | import Function from './Function' 2 | export default Function 3 | -------------------------------------------------------------------------------- /src/pages/components/variable/index.js: -------------------------------------------------------------------------------- 1 | import Variable from './Variable' 2 | export default Variable 3 | -------------------------------------------------------------------------------- /src/pages/dashboard/analysis/HotSearch.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 106 | 107 | 143 | -------------------------------------------------------------------------------- /src/pages/dashboard/analysis/RankingList.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 20 | 21 | 60 | -------------------------------------------------------------------------------- /src/pages/dashboard/analysis/SalesData.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /src/pages/dashboard/analysis/i18n-search.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | search: '搜索用户数', 5 | capita: '人均搜索次数', 6 | rank: '排名', 7 | keyword: '搜索关键词', 8 | count: '用户数', 9 | range: '周涨幅', 10 | introduce: '指标说明' 11 | }, 12 | HK: { 13 | search: '搜索用戶數', 14 | capita: '人均搜索次數', 15 | rank: '排名', 16 | keyword: '搜索關鍵詞', 17 | count: '用戶數', 18 | range: '周漲幅', 19 | introduce: '指標說明' 20 | }, 21 | US: { 22 | search: 'Search Users', 23 | capita: 'Per Capita Search', 24 | rank: 'Rank', 25 | keyword: 'Keyword', 26 | users: 'Users', 27 | range: 'Weekly Range', 28 | introduce: 'Introduce' 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/pages/dashboard/analysis/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | introduce: '指标说明', 5 | totalSales: '总销售额', 6 | visits: '访问量', 7 | payments: '支付笔数', 8 | operating: '运营活动效果', 9 | wow: '同周比', 10 | dod: '日环比', 11 | sales: '销售额', 12 | daily: '日均', 13 | day: '今日', 14 | week: '本周', 15 | month: '本月', 16 | year: '本年', 17 | search: '热门搜索', 18 | proportion: '销售额占比', 19 | conversion: '转化率', 20 | trend: '趋势', 21 | ranking: '排行榜', 22 | all: '全渠道', 23 | online: '线上', 24 | stores: '门店', 25 | }, 26 | HK: { 27 | introduce: '指標說明', 28 | totalSales: '總銷售額', 29 | visits: '訪問量', 30 | payments: '支付筆數', 31 | operating: '運營活動效果', 32 | wow: '通周比', 33 | dod: '日環比', 34 | sales: '銷售額', 35 | daily: '日均', 36 | day: '今日', 37 | week: '本週', 38 | month: '本月', 39 | year: '本年', 40 | search: '熱門搜索', 41 | proportion: '銷售額佔比', 42 | conversion: '轉化率', 43 | trend: '趨勢', 44 | ranking: '排行榜', 45 | all: '全渠道', 46 | online: '線上', 47 | stores: '門店', 48 | }, 49 | US: { 50 | introduce: 'Introduce', 51 | totalSales: 'Total Sales', 52 | visits: 'Visits', 53 | payments: 'Payments', 54 | operating: 'Operational Effect', 55 | wow: 'WoW Change', 56 | dod: 'DoD Change', 57 | sales: 'Sales', 58 | daily: 'Daily', 59 | day: 'All Day', 60 | week: 'All Week', 61 | month: 'All Month', 62 | year: 'All Year', 63 | search: 'Hot Search', 64 | proportion: 'The Proportion Of Sales', 65 | conversion: 'Conversion Rate', 66 | trend: 'Trend', 67 | ranking: 'Ranking', 68 | all: 'All', 69 | online: 'Online', 70 | stores: 'Stores', 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/pages/dashboard/analysis/index.js: -------------------------------------------------------------------------------- 1 | import Analysis from './Analysis' 2 | export default Analysis 3 | -------------------------------------------------------------------------------- /src/pages/dashboard/workplace/Radar.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 81 | 82 | 85 | -------------------------------------------------------------------------------- /src/pages/dashboard/workplace/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | project: '项目数', 5 | ranking: '团队排名', 6 | visit: '项目访问', 7 | progress: '进行中的项目', 8 | all: '全部项目', 9 | access: '快速开始/便捷导航', 10 | dynamic: '动态', 11 | degree: '指数', 12 | team: '团队', 13 | add: '添加' 14 | }, 15 | HK: { 16 | project: '項目數', 17 | ranking: '團隊排名', 18 | visit: '項目訪問', 19 | progress: '進行中的項目', 20 | all: '全部項目', 21 | access: '快速開始/便捷導航', 22 | dynamic: '動態', 23 | degree: '指數', 24 | team: '團隊', 25 | add: '添加' 26 | }, 27 | US: { 28 | project: 'Project', 29 | ranking: 'Ranking', 30 | visit: 'Visit', 31 | progress: 'Projects in progress', 32 | all: 'All projects', 33 | access: 'Quick start / Easy navigation', 34 | dynamic: 'Dynamic', 35 | degree: 'degree', 36 | team: 'Team', 37 | add: 'Add' 38 | }, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/pages/dashboard/workplace/index.js: -------------------------------------------------------------------------------- 1 | import WorkPlace from './WorkPlace' 2 | export default WorkPlace 3 | -------------------------------------------------------------------------------- /src/pages/dashboard/workplace/index.less: -------------------------------------------------------------------------------- 1 | .project-list { 2 | .card-title { 3 | span{ 4 | vertical-align: middle; 5 | &:last-child{ 6 | margin-left: 0px; 7 | } 8 | } 9 | } 10 | .project-item { 11 | display: flex; 12 | justify-content: space-between; 13 | margin-top: 8px; 14 | overflow: hidden; 15 | font-size: 12px; 16 | color: inherit; 17 | .group{ 18 | color: @text-color; 19 | flex: 1 1 0; 20 | &:hover { 21 | color: @primary-color; 22 | } 23 | } 24 | .datetime { 25 | color: @text-color-second; 26 | flex: 0 0 auto; 27 | } 28 | } 29 | .ant-card-meta-description { 30 | height: 44px; 31 | line-height: 22px; 32 | overflow: hidden; 33 | } 34 | } 35 | .item-group{ 36 | padding: 20px 0 8px 24px; 37 | font-size: 0; 38 | a{ 39 | color: inherit; 40 | display: inline-block; 41 | font-size: 14px; 42 | margin-bottom: 13px; 43 | width: 25%; 44 | } 45 | } 46 | .members { 47 | a { 48 | display: block; 49 | margin: 12px 0; 50 | color: @text-color; 51 | &:hover { 52 | color: @primary-color; 53 | } 54 | .member { 55 | vertical-align: middle; 56 | margin-left: 12px; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/pages/exception/403.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 22 | -------------------------------------------------------------------------------- /src/pages/exception/404.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 22 | -------------------------------------------------------------------------------- /src/pages/exception/500.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | 20 | 22 | -------------------------------------------------------------------------------- /src/pages/login/index.js: -------------------------------------------------------------------------------- 1 | import Login from './Login' 2 | export default Login 3 | -------------------------------------------------------------------------------- /src/pages/result/Error.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 48 | 49 | 57 | -------------------------------------------------------------------------------- /src/pages/result/Success.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 63 | 64 | 77 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/config/index.js: -------------------------------------------------------------------------------- 1 | import Config from './Config' 2 | export default Config 3 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/config/index.less: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/list/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | ruleName:'规则名称' 5 | }, 6 | HK: { 7 | ruleName:'規則名稱' 8 | }, 9 | US: { 10 | ruleName:'RuleName' 11 | }, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/list/index.js: -------------------------------------------------------------------------------- 1 | import GeneralRule from './GeneralRule' 2 | export default GeneralRule 3 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/list/index.less: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/publish/index.js: -------------------------------------------------------------------------------- 1 | import Publish from './Publish' 2 | 3 | export default Publish 4 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/router/Router.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 68 | 69 | 72 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/router/index.js: -------------------------------------------------------------------------------- 1 | import Router from './Router' 2 | 3 | export default Router 4 | -------------------------------------------------------------------------------- /src/pages/rulemanagement/generalrule/view/index.js: -------------------------------------------------------------------------------- 1 | import View from './View' 2 | 3 | export default View 4 | -------------------------------------------------------------------------------- /src/pages/settings/personal/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | 5 | }, 6 | HK: { 7 | 8 | }, 9 | US: { 10 | 11 | }, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/settings/personal/index.js: -------------------------------------------------------------------------------- 1 | import Personal from './Personal' 2 | export default Personal 3 | -------------------------------------------------------------------------------- /src/pages/settings/personal/index.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/pages/settings/personal/index.less -------------------------------------------------------------------------------- /src/pages/settings/user/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | 5 | }, 6 | HK: { 7 | 8 | }, 9 | US: { 10 | 11 | }, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/settings/user/index.js: -------------------------------------------------------------------------------- 1 | import UserList from './UserList' 2 | export default UserList 3 | -------------------------------------------------------------------------------- /src/pages/settings/user/index.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/pages/settings/user/index.less -------------------------------------------------------------------------------- /src/pages/settings/workspace/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | 5 | }, 6 | HK: { 7 | 8 | }, 9 | US: { 10 | 11 | }, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/settings/workspace/index.js: -------------------------------------------------------------------------------- 1 | import Workspace from './Workspace' 2 | export default Workspace 3 | -------------------------------------------------------------------------------- /src/pages/settings/workspace/index.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rule-engine/rule-engine-front-open/71de541de4f6214959b5721e6f25fee231c213e8/src/pages/settings/workspace/index.less -------------------------------------------------------------------------------- /src/plugins/i18n-extend.js: -------------------------------------------------------------------------------- 1 | // 语句模式 2 | const MODE = { 3 | STATEMENTS: 's', //语句模式 4 | PHRASAL: 'p', //词组模式 5 | } 6 | 7 | const VueI18nPlugin = { 8 | install: function (Vue) { 9 | Vue.mixin({ 10 | methods: { 11 | $ta(syntaxKey, mode) { 12 | let _mode = mode || MODE.STATEMENTS 13 | let keys = syntaxKey.split('|') 14 | let _this = this 15 | let locale = this.$i18n.locale 16 | let message = '' 17 | let splitter = locale == 'US' ? ' ' : '' 18 | // 拼接 message 19 | keys.forEach(key => { 20 | message += _this.$t(key) + splitter 21 | }) 22 | // 英文环境语句模式下,转换单词大小写 23 | if (keys.length > 0 && _mode == MODE.STATEMENTS && locale == 'US') { 24 | message = message.charAt(0).toUpperCase() + message.toLowerCase().substring(1) 25 | } 26 | return message 27 | } 28 | } 29 | }) 30 | } 31 | } 32 | export default VueI18nPlugin 33 | -------------------------------------------------------------------------------- /src/plugins/index.js: -------------------------------------------------------------------------------- 1 | import VueI18nPlugin from './i18n-extend' 2 | import AuthorityPlugin from './authority-plugin' 3 | import TabsPagePlugin from './tabs-page-plugin' 4 | 5 | const Plugins = { 6 | install: function (Vue) { 7 | Vue.use(VueI18nPlugin) 8 | Vue.use(AuthorityPlugin) 9 | Vue.use(TabsPagePlugin) 10 | } 11 | } 12 | export default Plugins 13 | -------------------------------------------------------------------------------- /src/plugins/tabs-page-plugin.js: -------------------------------------------------------------------------------- 1 | const TabsPagePlugin = { 2 | install(Vue) { 3 | Vue.mixin({ 4 | methods: { 5 | $closePage(closeRoute, nextRoute) { 6 | const event = new CustomEvent('page:close', {detail:{closeRoute, nextRoute}}) 7 | window.dispatchEvent(event) 8 | }, 9 | $refreshPage(route) { 10 | const path = typeof route === 'object' ? route.path : route 11 | const event = new CustomEvent('page:refresh', {detail:{pageKey: path}}) 12 | window.dispatchEvent(event) 13 | }, 14 | $openPage(route, title) { 15 | this.$setPageTitle(route, title) 16 | this.$router.push(route) 17 | }, 18 | $setPageTitle(route, title) { 19 | if (title) { 20 | let path = typeof route === 'object' ? route.path : route 21 | path = path && path.split('?')[0] 22 | this.$store.commit('setting/setCustomTitle', {path, title}) 23 | } 24 | } 25 | }, 26 | computed: { 27 | customTitle() { 28 | const customTitles = this.$store.state.setting.customTitles 29 | const path = this.$route.path.split('?')[0] 30 | const custom = customTitles.find(item => item.path === path) 31 | return custom && custom.title 32 | } 33 | } 34 | }) 35 | } 36 | } 37 | 38 | export default TabsPagePlugin 39 | -------------------------------------------------------------------------------- /src/router/async/config.async.js: -------------------------------------------------------------------------------- 1 | import routerMap from './router.map' 2 | import {parseRoutes} from '@/utils/routerUtil' 3 | 4 | // 异步路由配置 5 | const routesConfig = [ 6 | 'login', 7 | 'root', 8 | { 9 | router: 'exp404', 10 | path: '*', 11 | name: '404' 12 | }, 13 | { 14 | router: 'exp403', 15 | path: '/403', 16 | name: '403' 17 | } 18 | ] 19 | 20 | const options = { 21 | routes: parseRoutes(routesConfig, routerMap) 22 | } 23 | 24 | export default options 25 | -------------------------------------------------------------------------------- /src/router/async/router.map.js: -------------------------------------------------------------------------------- 1 | // 视图组件 2 | const view = { 3 | tabs: () => import('@/layouts/tabs'), 4 | blank: () => import('@/layouts/BlankView'), 5 | page: () => import('@/layouts/PageView') 6 | } 7 | 8 | // 路由组件注册 9 | const routerMap = { 10 | login: { 11 | authority: '*', 12 | path: '/login', 13 | component: () => import('@/pages/login') 14 | }, 15 | root: { 16 | path: '/', 17 | name: '首页', 18 | redirect: '/login', 19 | component: view.tabs 20 | }, 21 | dashboard: { 22 | name: '控制台', 23 | component: view.blank 24 | }, 25 | workplace: { 26 | name: '工作台', 27 | component: () => import('@/pages/dashboard/workplace') 28 | }, 29 | analysis: { 30 | name: '监控', 31 | component: () => import('@/pages/dashboard/analysis') 32 | }, 33 | ruleManagement: { 34 | name: '规则管理', 35 | component: view.blank 36 | }, 37 | generalRuleList: { 38 | path: '/generalRuleList', 39 | name: 'generalRuleList', 40 | component: () => import('@/pages/rulemanagement/generalrule/list'), 41 | }, 42 | form: { 43 | name: '表单页', 44 | icon: 'form', 45 | component: view.page 46 | }, 47 | list: { 48 | name: '列表页', 49 | icon: 'table', 50 | component: view.page 51 | }, 52 | details: { 53 | name: '详情页', 54 | icon: 'profile', 55 | component: view.blank 56 | }, 57 | result: { 58 | name: '结果页', 59 | icon: 'check-circle-o', 60 | component: view.page 61 | }, 62 | success: { 63 | name: '成功', 64 | component: () => import('@/pages/result/Success') 65 | }, 66 | error: { 67 | name: '失败', 68 | component: () => import('@/pages/result/Error') 69 | }, 70 | exception: { 71 | name: '异常页', 72 | icon: 'warning', 73 | component: view.blank 74 | }, 75 | exp403: { 76 | authority: '*', 77 | name: 'exp403', 78 | path: '403', 79 | component: () => import('@/pages/exception/403') 80 | }, 81 | exp404: { 82 | name: 'exp404', 83 | path: '404', 84 | component: () => import('@/pages/exception/404') 85 | }, 86 | exp500: { 87 | name: 'exp500', 88 | path: '500', 89 | component: () => import('@/pages/exception/500') 90 | }, 91 | components: { 92 | name: '小组件', 93 | icon: 'appstore-o', 94 | component: view.page 95 | }, 96 | } 97 | export default routerMap 98 | 99 | -------------------------------------------------------------------------------- /src/router/guards.js: -------------------------------------------------------------------------------- 1 | import {hasAuthority} from '@/utils/authority-utils' 2 | import {loginIgnore} from '@/router/index' 3 | import {checkAuthorization} from '@/utils/request' 4 | import NProgress from 'nprogress' 5 | 6 | NProgress.configure({ showSpinner: false }) 7 | 8 | /** 9 | * 进度条开始 10 | * @param to 11 | * @param form 12 | * @param next 13 | */ 14 | const progressStart = (to, from, next) => { 15 | // start progress bar 16 | if (!NProgress.isStarted()) { 17 | NProgress.start() 18 | } 19 | next() 20 | } 21 | 22 | /** 23 | * 登录守卫 24 | * @param to 25 | * @param form 26 | * @param next 27 | * @param options 28 | */ 29 | const loginGuard = (to, from, next, options) => { 30 | const {message} = options 31 | if (!loginIgnore.includes(to) && !checkAuthorization()) { 32 | message.warning('登录已失效,请重新登录') 33 | next({path: '/login'}) 34 | } else { 35 | next() 36 | } 37 | } 38 | 39 | /** 40 | * 权限守卫 41 | * @param to 42 | * @param form 43 | * @param next 44 | * @param options 45 | */ 46 | const authorityGuard = (to, from, next, options) => { 47 | const {store, message} = options 48 | const permissions = store.getters['user/permissions'] 49 | const roles = store.getters['user/roles'] 50 | if (!hasAuthority(to, permissions, roles)) { 51 | message.warning(`对不起,您无权访问页面: ${to.fullPath},请联系管理员`) 52 | next({path: '/403'}) 53 | // NProgress.done() 54 | } else { 55 | next() 56 | } 57 | } 58 | 59 | /** 60 | * 混合导航模式下一级菜单跳转重定向 61 | * @param to 62 | * @param from 63 | * @param next 64 | * @param options 65 | * @returns {*} 66 | */ 67 | const redirectGuard = (to, from, next, options) => { 68 | const {store} = options 69 | const getFirstChild = (routes) => { 70 | const route = routes[0] 71 | if (!route.children || route.children.length === 0) { 72 | return route 73 | } 74 | return getFirstChild(route.children) 75 | } 76 | if (store.state.setting.layout === 'mix') { 77 | const firstMenu = store.getters['setting/firstMenu'] 78 | if (firstMenu.find(item => item.fullPath === to.fullPath)) { 79 | store.commit('setting/setActivatedFirst', to.fullPath) 80 | const subMenu = store.getters['setting/subMenu'] 81 | if (subMenu.length > 0) { 82 | const redirect = getFirstChild(subMenu) 83 | return next({path: redirect.fullPath}) 84 | } 85 | } 86 | } 87 | next() 88 | } 89 | 90 | /** 91 | * 进度条结束 92 | * @param to 93 | * @param form 94 | * @param options 95 | */ 96 | const progressDone = () => { 97 | // finish progress bar 98 | NProgress.done() 99 | } 100 | 101 | export default { 102 | beforeEach: [progressStart, loginGuard, authorityGuard, redirectGuard], 103 | afterEach: [progressDone] 104 | } 105 | -------------------------------------------------------------------------------- /src/router/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | messages: { 3 | CN: { 4 | home: {name: '首页'}, 5 | }, 6 | US: { 7 | home: {name: 'home'}, 8 | }, 9 | HK: { 10 | home: {name: '首頁'}, 11 | dashboard: { 12 | name: 'Dashboard', 13 | workplace: {name: '工作台'}, 14 | analysis: {name: '分析頁'} 15 | }, 16 | form: { 17 | name: '表單頁', 18 | basic: {name: '基礎表單'}, 19 | step: {name: '分步表單'}, 20 | advance: {name: '分步表單'} 21 | }, 22 | list: { 23 | name: '列表頁', 24 | query: {name: '查詢表格'}, 25 | primary: {name: '標準列表'}, 26 | card: {name: '卡片列表'}, 27 | search: { 28 | name: '搜索列表', 29 | article: {name: '文章'}, 30 | application: {name: '應用'}, 31 | project: {name: '項目'} 32 | } 33 | }, 34 | details: { 35 | name: '詳情頁', 36 | basic: {name: '基礎詳情頁'}, 37 | advance: {name: '高級詳情頁'} 38 | }, 39 | result: { 40 | name: '結果頁', 41 | success: {name: '成功'}, 42 | error: {name: '失敗'} 43 | }, 44 | exception: { 45 | name: '異常頁', 46 | 404: {name: '404'}, 47 | 403: {name: '403'}, 48 | 500: {name: '500'} 49 | }, 50 | components: { 51 | name: '小組件', 52 | taskCard: {name: '任務卡片'}, 53 | palette: {name: '顏色複選框'} 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import {formatRoutes} from '@/utils/routerUtil' 4 | 5 | Vue.use(Router) 6 | 7 | // 不需要登录拦截的路由配置 8 | const loginIgnore = { 9 | names: ['404', '403'], //根据路由名称匹配 10 | paths: ['/login'], //根据路由fullPath匹配 11 | /** 12 | * 判断路由是否包含在该配置中 13 | * @param route vue-router 的 route 对象 14 | * @returns {boolean} 15 | */ 16 | includes(route) { 17 | return this.names.includes(route.name) || this.paths.includes(route.path) 18 | } 19 | } 20 | 21 | /** 22 | * 初始化路由实例 23 | * @param isAsync 是否异步路由模式 24 | * @returns {VueRouter} 25 | */ 26 | function initRouter(isAsync) { 27 | const options = isAsync ? require('./async/config.async').default : require('./config').default 28 | formatRoutes(options.routes) 29 | return new Router(options) 30 | } 31 | // 解决vue-router在3.0版本以上重复点菜单报错问题 32 | const originalPush = Router.prototype.push 33 | Router.prototype.push = function push(location) { 34 | return originalPush.call(this, location).catch(err => err) 35 | } 36 | export {loginIgnore, initRouter} 37 | export default class router { 38 | } 39 | -------------------------------------------------------------------------------- /src/services/condition.js: -------------------------------------------------------------------------------- 1 | import {condition} from '@/services/api' 2 | import {METHOD, request} from '@/utils/request' 3 | 4 | export async function updateCondition(param) { 5 | return request(condition.UPDATE_CONDITION, METHOD.POST, param) 6 | } 7 | 8 | export async function addCondition(param) { 9 | return request(condition.ADD, METHOD.POST, param) 10 | } -------------------------------------------------------------------------------- /src/services/conditionGroup.js: -------------------------------------------------------------------------------- 1 | import {conditionGroup} from '@/services/api' 2 | import {METHOD, request} from '@/utils/request' 3 | 4 | export async function saveOrUpdate(param) { 5 | return request(conditionGroup.SAVE_OR_UPDATE, METHOD.POST, param) 6 | } 7 | 8 | export async function deleteConditionGroup(param) { 9 | return request(conditionGroup.DELETE_CONDITION_GROUP, METHOD.POST, param) 10 | } 11 | 12 | 13 | export async function conditionGroupRearrange(param) { 14 | return request(conditionGroup.REARRANGE, METHOD.POST, param) 15 | } 16 | 17 | export default { 18 | saveOrUpdate 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/services/conditionGroupCondition.js: -------------------------------------------------------------------------------- 1 | import {conditionGroupCondition} from '@/services/api' 2 | import {METHOD, request} from '@/utils/request' 3 | 4 | 5 | export async function saveConditionAndBindGroup(param) { 6 | return request(conditionGroupCondition.SAVE_CONDITION_AND_BIND_GROUP, METHOD.POST, param) 7 | } 8 | 9 | /** 10 | * 删除条件 11 | * @param param 12 | */ 13 | export async function deleteCondition(param) { 14 | return request(conditionGroupCondition.DELETE_CONDITION, METHOD.POST, param) 15 | } 16 | /** 17 | * 交换顺序 18 | * @param param 19 | * @returns {Promise>} 20 | */ 21 | export async function switchOrder(param) { 22 | return request(conditionGroupCondition.SWITCH_ORDER, METHOD.POST, param) 23 | } 24 | 25 | export async function rearrange(param) { 26 | return request(conditionGroupCondition.REARRANGE, METHOD.POST, param) 27 | } -------------------------------------------------------------------------------- /src/services/dataPermission.js: -------------------------------------------------------------------------------- 1 | import {dataPermission} from '@/services/api' 2 | import {request, METHOD} from '@/utils/request' 3 | 4 | export async function dataPermissionList(query) { 5 | return request(dataPermission.LIST, METHOD.POST, query) 6 | } 7 | export async function update(query) { 8 | return request(dataPermission.UPDATE, METHOD.POST, query) 9 | } 10 | 11 | export default { 12 | dataPermissionList,update 13 | } 14 | -------------------------------------------------------------------------------- /src/services/dataSource.js: -------------------------------------------------------------------------------- 1 | import {GOODS, GOODS_COLUMNS} from './api' 2 | import {METHOD, request} from '@/utils/request' 3 | 4 | export async function goodsList(params) { 5 | return request(GOODS, METHOD.GET, params) 6 | } 7 | 8 | export async function goodsColumns() { 9 | return request(GOODS_COLUMNS, METHOD.GET) 10 | } 11 | 12 | export default {goodsList, goodsColumns} -------------------------------------------------------------------------------- /src/services/function.js: -------------------------------------------------------------------------------- 1 | import {myfunction} from '@/services/api' 2 | import {METHOD, request} from '@/utils/request' 3 | 4 | 5 | export async function functionList(param) { 6 | return request(myfunction.LIST, METHOD.POST, param) 7 | } 8 | 9 | export async function selectFunctionById(param) { 10 | return request(myfunction.SELECT_FUNCTION_BY_ID, METHOD.POST, param) 11 | } 12 | 13 | 14 | export async function runFunction(param) { 15 | return request(myfunction.RUN, METHOD.POST, param) 16 | } 17 | 18 | export default { 19 | functionList 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/services/generalRule.js: -------------------------------------------------------------------------------- 1 | import {generalRule} from '@/services/api' 2 | import {request, METHOD} from '@/utils/request' 3 | 4 | /** 5 | * 验证规则code 6 | * @param query 7 | * @returns {Promise>} 8 | */ 9 | export async function verifyRuleCode(query) { 10 | return request(generalRule.VERIFY_RULE_CODE, METHOD.POST, query) 11 | } 12 | 13 | export async function list(query) { 14 | return request(generalRule.LIST, METHOD.POST, query) 15 | } 16 | 17 | export async function deleteGeneralRule(query) { 18 | return request(generalRule.DELETE, METHOD.POST, query) 19 | } 20 | 21 | //保存规则定义 22 | export async function addGeneralRule(param) { 23 | return request(generalRule.ADD, METHOD.POST, param) 24 | } 25 | 26 | //更新规则定义 27 | export async function updateGeneralRuleDefinition(param) { 28 | return request(generalRule.UPDATE_DEFINITION, METHOD.POST, param) 29 | } 30 | 31 | 32 | export async function getRuleConfig(query) { 33 | return request(generalRule.GET_RULE_CONFIG, METHOD.POST, query) 34 | } 35 | 36 | 37 | export async function getRuleDefinition(query) { 38 | return request(generalRule.GET_RULE_DEFINITION, METHOD.POST, query) 39 | } 40 | 41 | 42 | export async function generationRelease(query) { 43 | return request(generalRule.GENERATION_RELEASE, METHOD.POST, query) 44 | } 45 | 46 | export async function runTest(query) { 47 | return request(generalRule.RUN_TEST, METHOD.POST, query) 48 | } 49 | 50 | 51 | export async function viewGeneralRule(query) { 52 | return request(generalRule.VIEW, METHOD.POST, query) 53 | } 54 | 55 | export async function saveDefaultAction(query) { 56 | return request(generalRule.SAVE_DEFAULT_ACTION, METHOD.POST, query) 57 | } 58 | 59 | export async function defaultActionSwitch(query) { 60 | return request(generalRule.DEFAULT_ACTION_SWITCH, METHOD.POST, query) 61 | } 62 | 63 | export async function generalRulePublish(query) { 64 | return request(generalRule.PUBLISH, METHOD.POST, query) 65 | } 66 | 67 | export async function generalRuleDownloadList(query) { 68 | return request(generalRule.DOWNLOAD_LIST, METHOD.POST, query) 69 | } 70 | 71 | export async function showHistoryVersionList(query) { 72 | return request(generalRule.SHOW_HISTORY_VERSION_LIST, METHOD.POST, query) 73 | } 74 | 75 | export async function deleteHistoricalRules(query) { 76 | return request(generalRule.DELETE_HISTORICAL_RULES, METHOD.POST, query) 77 | } 78 | 79 | export async function goBack(query) { 80 | return request(generalRule.GO_BACK, METHOD.POST, query) 81 | } 82 | 83 | 84 | export async function referenceableList(query) { 85 | return request(generalRule.REFERENCEABLE_LIST, METHOD.POST, query) 86 | } 87 | 88 | export default { 89 | list, 90 | } 91 | -------------------------------------------------------------------------------- /src/services/importExport.js: -------------------------------------------------------------------------------- 1 | import {METHOD, request} from "@/utils/request"; 2 | import {importExport} from "@/services/api"; 3 | 4 | 5 | export function exportData(query) { 6 | request(importExport.EXPORT, METHOD.POST, query).then(res => { 7 | const blob = new Blob([JSON.stringify(JSON.parse(res.data.data.data), null, 4)]); 8 | const downloadElement = document.createElement("a"); 9 | const href = window.URL.createObjectURL(blob); 10 | downloadElement.href = href; 11 | let suffix; 12 | if (query.dataType === 0) { 13 | suffix = '.r'; 14 | } else if (query.dataType === 1) { 15 | suffix = '.rs'; 16 | } else if (query.dataType === 2) { 17 | suffix = '.dt'; 18 | } 19 | downloadElement.download = decodeURIComponent(res.data.data.code + suffix); 20 | document.body.appendChild(downloadElement); 21 | downloadElement.click(); 22 | document.body.removeChild(downloadElement); 23 | window.URL.revokeObjectURL(href); 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /src/services/index.js: -------------------------------------------------------------------------------- 1 | import userService from './user' 2 | import dataSource from './dataSource' 3 | 4 | export { 5 | userService, 6 | dataSource 7 | } 8 | -------------------------------------------------------------------------------- /src/services/inputParameter.js: -------------------------------------------------------------------------------- 1 | import {request, METHOD} from '@/utils/request' 2 | import {inputParameter} from "@/services/api"; 3 | 4 | /** 5 | * 保存规则参数 6 | * @param param 7 | */ 8 | export async function addInputParameter(param) { 9 | return request(inputParameter.ADD, METHOD.POST, param) 10 | } 11 | 12 | /** 13 | * 验证code是否存在 14 | * @param param 15 | * @returns {Promise>} 16 | */ 17 | export async function verifyInputParameterCode(param) { 18 | return request(inputParameter.VERIFY_INOUT_PARAMETER_CODE, METHOD.POST, param) 19 | } 20 | 21 | /** 22 | * 获取参数列表 23 | * @param query 24 | */ 25 | export async function listInputParameter(query) { 26 | return request(inputParameter.LIST, METHOD.POST, query) 27 | } 28 | 29 | /** 30 | * 根据id查询 31 | * @param query 32 | */ 33 | export async function get(query) { 34 | return request(inputParameter.GET, METHOD.POST, query) 35 | } 36 | 37 | /** 38 | * 根据id更新 39 | * @param query 40 | * @constructor 41 | */ 42 | export async function update(query) { 43 | return request(inputParameter.UPDATE, METHOD.POST, query) 44 | } 45 | 46 | /** 47 | * 根据id删除 48 | * @param query 49 | * @constructor 50 | */ 51 | export async function deleteById(query) { 52 | return request(inputParameter.DELETE, METHOD.POST, query) 53 | } 54 | -------------------------------------------------------------------------------- /src/services/operationRecord.js: -------------------------------------------------------------------------------- 1 | import {request, METHOD} from '@/utils/request' 2 | import {operationRecord} from "@/services/api"; 3 | 4 | 5 | export async function operationRecordList(param) { 6 | return request(operationRecord.OPERATION_RECORD, METHOD.POST, param) 7 | } 8 | -------------------------------------------------------------------------------- /src/services/rule.js: -------------------------------------------------------------------------------- 1 | import {METHOD, request} from "@/utils/request"; 2 | import {rule} from "@/services/api"; 3 | 4 | 5 | export async function saveRuleAndBindRuleSet(query) { 6 | return request(rule.SAVE_RULE_AND_BIND_RULE_SET, METHOD.POST, query) 7 | } 8 | 9 | export async function ruleSetRuleRearrange(param) { 10 | return request(rule.REARRANGE, METHOD.POST, param) 11 | } 12 | 13 | export async function deleteRuleSetRule(param) { 14 | return request(rule.DELETE_RULE_SET_RULE, METHOD.POST, param) 15 | } 16 | 17 | export async function saveAction(query) { 18 | return request(rule.SAVE_ACTION, METHOD.POST, query) 19 | } 20 | 21 | export async function saveOrUpdateRule(query) { 22 | return request(rule.SAVE_OR_ACTION, METHOD.POST, query) 23 | } 24 | -------------------------------------------------------------------------------- /src/services/user.js: -------------------------------------------------------------------------------- 1 | import {user, ROUTES} from '@/services/api' 2 | import {request, METHOD, removeAuthorization} from '@/utils/request' 3 | 4 | /** 5 | * 登录服务 6 | * @param username 账户名 7 | * @param password 账户密码 8 | */ 9 | export async function login(username, password) { 10 | return request(user.LOGIN, METHOD.POST, { 11 | username: username, 12 | password: password 13 | }) 14 | } 15 | 16 | /** 17 | * 获取用户信息 18 | */ 19 | export async function getUserInfo() { 20 | return request(user.GET_USER_INFO, METHOD.POST) 21 | } 22 | 23 | /** 24 | * 检查用户名是否可用 25 | * @param param 26 | * @returns {Promise>} 27 | */ 28 | export async function verifyUserName(param) { 29 | return request(user.VERIFY_USER_NAME, METHOD.POST, param) 30 | } 31 | 32 | /** 33 | * 检查邮箱是否可用 34 | * @param param 35 | * @returns {Promise>} 36 | */ 37 | export async function verifyckEmail(param) { 38 | return request(user.VERIFY_EMAIL, METHOD.POST, param) 39 | } 40 | export async function userList(param) { 41 | return request(user.LIST, METHOD.POST, param) 42 | } 43 | 44 | export async function addUser(param) { 45 | return request(user.ADD_USER, METHOD.POST, param) 46 | } 47 | 48 | export async function deleteUser(param) { 49 | return request(user.DELETE_USER, METHOD.POST, param) 50 | } 51 | 52 | export async function updateUserInfo(param) { 53 | return request(user.UPDATE_USER_INFO, METHOD.POST, param) 54 | } 55 | 56 | export async function selectUserById(param) { 57 | return request(user.SELECT_USER_BY_ID, METHOD.POST, param) 58 | } 59 | 60 | export async function uploadAvatar(param) { 61 | return request(user.UPLOADAVATAR, METHOD.POST, param) 62 | } 63 | 64 | export async function getRoutesConfig() { 65 | return request(ROUTES, METHOD.GET) 66 | } 67 | 68 | /** 69 | * 退出登录 70 | */ 71 | export function logout(context) { 72 | localStorage.removeItem(process.env.VUE_APP_ROUTES_KEY) 73 | localStorage.removeItem(process.env.VUE_APP_PERMISSIONS_KEY) 74 | localStorage.removeItem(process.env.VUE_APP_ROLES_KEY) 75 | localStorage.removeItem(process.env.VUE_APP_WORKSPACE_KEY) 76 | removeAuthorization(); 77 | context.$router.push('/login') 78 | } 79 | 80 | export default { 81 | login, 82 | logout, 83 | getRoutesConfig, 84 | userList 85 | } 86 | -------------------------------------------------------------------------------- /src/services/variable.js: -------------------------------------------------------------------------------- 1 | import {request, METHOD} from '@/utils/request' 2 | import {variable} from "@/services/api"; 3 | 4 | /** 5 | * 保存规则变量 6 | * @param param 7 | */ 8 | export async function addVariable(param) { 9 | return request(variable.ADD, METHOD.POST, param) 10 | } 11 | 12 | /** 13 | * 验证变量名字是否存在 14 | * @param param 15 | */ 16 | export async function verifyVariableName(param) { 17 | return request(variable.VERIFY_VARIABLE_NAME, METHOD.POST, param) 18 | } 19 | 20 | /** 21 | * 获取变量列表 22 | * @param query 23 | */ 24 | export async function listVariable(query) { 25 | return request(variable.LIST, METHOD.POST, query) 26 | } 27 | 28 | /** 29 | * 根据id查询 30 | * @param query 31 | */ 32 | export async function get(query) { 33 | return request(variable.GET, METHOD.POST, query) 34 | } 35 | 36 | /** 37 | * 根据id更新 38 | * @param query 39 | * @constructor 40 | */ 41 | export async function updateVariable(query) { 42 | return request(variable.UPDATE, METHOD.POST, query) 43 | } 44 | 45 | /** 46 | * 根据id删除 47 | * @param query 48 | * @constructor 49 | */ 50 | export async function deleteById(query) { 51 | return request(variable.DELETE, METHOD.POST, query) 52 | } 53 | 54 | export default { 55 | updateVariable, 56 | deleteById, 57 | get, 58 | listVariable, 59 | addVariable, 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/services/workplace.js: -------------------------------------------------------------------------------- 1 | import {request, METHOD} from '@/utils/request' 2 | import {workplace} from "@/services/api"; 3 | 4 | 5 | export async function projectInProgress(param) { 6 | return request(workplace.PROJECT_IN_PROGRESS, METHOD.POST, param) 7 | } 8 | 9 | 10 | export async function headInfo(param) { 11 | return request(workplace.HEAD_INFO, METHOD.POST, param) 12 | } 13 | 14 | 15 | export async function numberOfCreationsRanking(param) { 16 | return request(workplace.NUMBER_OF_CREATIONS_RANKING, METHOD.POST, param) 17 | } 18 | -------------------------------------------------------------------------------- /src/services/workspace.js: -------------------------------------------------------------------------------- 1 | import {workspace} from '@/services/api' 2 | import {request, METHOD} from '@/utils/request' 3 | 4 | /** 5 | * 获取工作空间列表 6 | */ 7 | export async function list(query) { 8 | return request(workspace.LIST, METHOD.POST, query) 9 | } 10 | 11 | /** 12 | * 切换工作空间 13 | */ 14 | export async function change(param) { 15 | return request(workspace.CHANGE, METHOD.POST, param) 16 | } 17 | 18 | /** 19 | * 获取当前工作空间 20 | */ 21 | export async function currentWorkspace(query) { 22 | return request(workspace.CURRENT_WORKSPACE, METHOD.POST, query) 23 | } 24 | 25 | /** 26 | * @Description: 根据id获取工作空间信息 27 | **/ 28 | export async function selectWorkSpaceById(query) { 29 | return request(workspace.SELECT_WORKSPACE_BY_ID, METHOD.POST, query) 30 | } 31 | 32 | /** 33 | * 检查工作空间code 34 | * @param query 35 | * @returns {Promise>} 36 | */ 37 | export async function verifyWorkspaceCode(query) { 38 | return request(workspace.VERIFY_WORKSPACE_CODE, METHOD.POST, query) 39 | } 40 | 41 | export async function add(query) { 42 | return request(workspace.ADD, METHOD.POST, query) 43 | } 44 | 45 | export async function edit(query) { 46 | return request(workspace.EDIT, METHOD.POST, query) 47 | } 48 | 49 | export async function deleteWorkspace(query) { 50 | return request(workspace.DELETE_WORKSPACE, METHOD.POST, query) 51 | } 52 | 53 | export async function accessKey(query) { 54 | return request(workspace.ACCESS_KEY, METHOD.POST, query) 55 | } 56 | 57 | export async function updateAccessKey(query) { 58 | return request(workspace.UPDATE_ACCESS_KEY, METHOD.POST, query) 59 | } 60 | 61 | 62 | export default { 63 | list, 64 | change, 65 | currentWorkspace, 66 | deleteWorkspace, 67 | accessKey, 68 | updateAccessKey, 69 | selectWorkSpaceById 70 | } 71 | -------------------------------------------------------------------------------- /src/services/workspaceMember.js: -------------------------------------------------------------------------------- 1 | import {workspaceMember} from '@/services/api' 2 | import {request, METHOD} from '@/utils/request' 3 | 4 | /** 5 | * 获取工作空间成员列表 6 | */ 7 | export async function memberList(query) { 8 | return request(workspaceMember.LIST, METHOD.POST, query) 9 | } 10 | 11 | export async function bindMember(query) { 12 | return request(workspaceMember.BIND_MEMBER, METHOD.POST, query) 13 | } 14 | 15 | export async function optionalPersonnel(query) { 16 | return request(workspaceMember.OPTIONAL_PERSONNEL, METHOD.POST, query) 17 | } 18 | 19 | export async function deleteMember(query) { 20 | return request(workspaceMember.DELETE_MEMBER, METHOD.POST, query) 21 | } 22 | 23 | 24 | export async function permissionTransferApi(query) { 25 | return request(workspaceMember.PERMISSION_TRANSFER, METHOD.POST, query) 26 | } 27 | 28 | export default { 29 | memberList 30 | } 31 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import modules from './modules' 4 | 5 | Vue.use(Vuex) 6 | const store = new Vuex.Store({modules},) 7 | 8 | export default store 9 | -------------------------------------------------------------------------------- /src/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import user from './user' 2 | import setting from './setting' 3 | import workspace from "./workspace"; 4 | 5 | export default {user, setting,workspace} 6 | -------------------------------------------------------------------------------- /src/store/modules/setting.js: -------------------------------------------------------------------------------- 1 | import config from '@/config' 2 | import {ADMIN} from '@/config/default' 3 | import {formatFullPath} from '@/utils/i18n' 4 | import {filterMenu} from '@/utils/authority-utils' 5 | import {getLocalSetting} from '@/utils/themeUtil' 6 | import deepClone from 'lodash.clonedeep' 7 | 8 | const localSetting = getLocalSetting(true) 9 | const customTitlesStr = sessionStorage.getItem(process.env.VUE_APP_TBAS_TITLES_KEY) 10 | const customTitles = (customTitlesStr && JSON.parse(customTitlesStr)) || [] 11 | 12 | export default { 13 | namespaced: true, 14 | state: { 15 | isMobile: false, 16 | animates: ADMIN.animates, 17 | palettes: ADMIN.palettes, 18 | pageMinHeight: 0, 19 | menuData: [], 20 | activatedFirst: undefined, 21 | lang:'CN', 22 | customTitles, 23 | ...config, 24 | ...localSetting 25 | }, 26 | getters: { 27 | menuData(state, getters, rootState) { 28 | if (state.filterMenu) { 29 | const {permissions, roles} = rootState.user 30 | return filterMenu(deepClone(state.menuData), permissions, roles) 31 | } 32 | return state.menuData 33 | }, 34 | firstMenu(state, getters) { 35 | const {menuData} = getters 36 | if (menuData.length > 0 && !menuData[0].fullPath) { 37 | formatFullPath(menuData) 38 | } 39 | return menuData.map(item => { 40 | const menuItem = {...item} 41 | delete menuItem.children 42 | return menuItem 43 | }) 44 | }, 45 | subMenu(state) { 46 | const {menuData, activatedFirst} = state 47 | if (menuData.length > 0 && !menuData[0].fullPath) { 48 | formatFullPath(menuData) 49 | } 50 | const current = menuData.find(menu => menu.fullPath === activatedFirst) 51 | return current && current.children || [] 52 | } 53 | }, 54 | mutations: { 55 | setDevice (state, isMobile) { 56 | state.isMobile = isMobile 57 | }, 58 | setTheme (state, theme) { 59 | state.theme = theme 60 | }, 61 | setLayout (state, layout) { 62 | state.layout = layout 63 | }, 64 | setMultiPage (state, multiPage) { 65 | state.multiPage = multiPage 66 | }, 67 | setAnimate (state, animate) { 68 | state.animate = animate 69 | }, 70 | setWeekMode(state, weekMode) { 71 | state.weekMode = weekMode 72 | }, 73 | setFixedHeader(state, fixedHeader) { 74 | state.fixedHeader = fixedHeader 75 | }, 76 | setFixedSideBar(state, fixedSideBar) { 77 | state.fixedSideBar = fixedSideBar 78 | }, 79 | setLang(state, lang) { 80 | state.lang = lang 81 | }, 82 | setHideSetting(state, hideSetting) { 83 | state.hideSetting = hideSetting 84 | }, 85 | correctPageMinHeight(state, minHeight) { 86 | state.pageMinHeight += minHeight 87 | }, 88 | setMenuData(state, menuData) { 89 | state.menuData = menuData 90 | }, 91 | setAsyncRoutes(state, asyncRoutes) { 92 | state.asyncRoutes = asyncRoutes 93 | }, 94 | setPageWidth(state, pageWidth) { 95 | state.pageWidth = pageWidth 96 | }, 97 | setActivatedFirst(state, activatedFirst) { 98 | state.activatedFirst = activatedFirst 99 | }, 100 | setFixedTabs(state, fixedTabs) { 101 | state.fixedTabs = fixedTabs 102 | }, 103 | setCustomTitle(state, {path, title}) { 104 | if (title) { 105 | const obj = state.customTitles.find(item => item.path === path) 106 | if (obj) { 107 | obj.title = title 108 | } else { 109 | state.customTitles.push({path, title}) 110 | } 111 | sessionStorage.setItem(process.env.VUE_APP_TBAS_TITLES_KEY, JSON.stringify(state.customTitles)) 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | export default { 2 | namespaced: true, 3 | state: { 4 | user: { 5 | // 用户ID 6 | id: 0, 7 | // 用户昵称 8 | username: 'admin', 9 | // 性别 10 | sex: 0, 11 | // 个性签名 12 | signature: undefined, 13 | // 个性头像 14 | avatar: require("@/assets/img/avatar.jpg"), 15 | // 当前登录状态 16 | loginStatus: false, 17 | email: undefined, 18 | phone: undefined, 19 | //是否为管理员 20 | isAdmin: false, 21 | position: '北京市xxx' 22 | }, 23 | permissions: null, 24 | roles: null, 25 | routesConfig: null 26 | }, 27 | getters: { 28 | isAdmin: (getters) => { 29 | return getters.user.isAdmin 30 | }, 31 | user: state => { 32 | if (!state.user) { 33 | try { 34 | const user = localStorage.getItem(process.env.VUE_APP_USER_KEY) 35 | state.user = JSON.parse(user) 36 | } catch (e) { 37 | console.error(e) 38 | } 39 | } 40 | return state.user 41 | }, 42 | permissions: state => { 43 | if (!state.permissions) { 44 | try { 45 | const permissions = localStorage.getItem(process.env.VUE_APP_PERMISSIONS_KEY) 46 | state.permissions = JSON.parse(permissions) 47 | state.permissions = state.permissions ? state.permissions : [] 48 | } catch (e) { 49 | console.error(e.message) 50 | } 51 | } 52 | return state.permissions 53 | }, 54 | roles: state => { 55 | if (!state.roles) { 56 | try { 57 | const roles = localStorage.getItem(process.env.VUE_APP_ROLES_KEY) 58 | state.roles = JSON.parse(roles) 59 | state.roles = state.roles ? state.roles : [] 60 | } catch (e) { 61 | console.error(e.message) 62 | } 63 | } 64 | return state.roles 65 | }, 66 | routesConfig: state => { 67 | if (!state.routesConfig) { 68 | try { 69 | const routesConfig = localStorage.getItem(process.env.VUE_APP_ROUTES_KEY) 70 | state.routesConfig = JSON.parse(routesConfig) 71 | state.routesConfig = state.routesConfig ? state.routesConfig : [] 72 | } catch (e) { 73 | console.error(e.message) 74 | } 75 | } 76 | return state.routesConfig 77 | } 78 | }, 79 | mutations: { 80 | setUser: (state, user) => { 81 | state.user = user 82 | localStorage.setItem(process.env.VUE_APP_USER_KEY, JSON.stringify(user)) 83 | }, 84 | setPermissions(state, permissions) { 85 | state.permissions = permissions 86 | localStorage.setItem(process.env.VUE_APP_PERMISSIONS_KEY, JSON.stringify(permissions)) 87 | }, 88 | setRoles(state, roles) { 89 | state.roles = roles 90 | localStorage.setItem(process.env.VUE_APP_ROLES_KEY, JSON.stringify(roles)) 91 | }, 92 | setRoutesConfig(state, routesConfig) { 93 | state.routesConfig = routesConfig 94 | localStorage.setItem(process.env.VUE_APP_ROUTES_KEY, JSON.stringify(routesConfig)) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/store/modules/workspace.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | namespaced: true, 4 | state: { 5 | currentWorkSpace: { 6 | id:undefined, 7 | name:undefined, 8 | code:undefined, 9 | isAdmin:undefined 10 | } 11 | }, 12 | getters: { 13 | isAdmin: (getters) => { 14 | return getters.currentWorkSpace.isAdmin 15 | }, 16 | currentWorkSpace: state => { 17 | if (!state.currentWorkSpace) { 18 | try { 19 | const workspace = localStorage.getItem(process.env.VUE_APP_WORKSPACE_KEY) 20 | state.workspace = JSON.parse(workspace) 21 | } catch (e) { 22 | console.error(e) 23 | } 24 | } 25 | return state.currentWorkSpace 26 | } 27 | }, 28 | mutations: { 29 | setWorkSpace: (state, currentWorkSpace) => { 30 | state.currentWorkSpace = currentWorkSpace 31 | localStorage.setItem(process.env.VUE_APP_WORKSPACE_KEY, JSON.stringify(currentWorkSpace)) 32 | } 33 | }, 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/theme/antd/ant-menu.less: -------------------------------------------------------------------------------- 1 | .ant-menu-inline-collapsed-tooltip a{ 2 | color: @text-color-inverse; 3 | } -------------------------------------------------------------------------------- /src/theme/antd/ant-message.less: -------------------------------------------------------------------------------- 1 | .ant-message{ 2 | z-index: 1100; 3 | } 4 | -------------------------------------------------------------------------------- /src/theme/antd/ant-table.less: -------------------------------------------------------------------------------- 1 | 2 | .ant-table-thead{ 3 | tr{ 4 | th{ 5 | &.ant-table-column-has-actions{ 6 | &.ant-table-column-has-sorters:hover{ 7 | background-color: @background-color-base; 8 | } 9 | &.ant-table-column-has-filters{ 10 | &:hover{ 11 | .anticon-filter, .anticon-filter:hover{ 12 | background-color: @background-color-base; 13 | } 14 | } 15 | .anticon-filter.ant-table-filter-open{ 16 | background-color: @background-color-base; 17 | } 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/theme/antd/ant-time-picker.less: -------------------------------------------------------------------------------- 1 | .ant-time-picker-panel-input{ 2 | background-color: @component-background; 3 | } 4 | -------------------------------------------------------------------------------- /src/theme/antd/index.less: -------------------------------------------------------------------------------- 1 | @import "ant-time-picker"; 2 | @import "ant-message"; 3 | @import "ant-table"; 4 | @import "ant-menu"; -------------------------------------------------------------------------------- /src/theme/default/color.less: -------------------------------------------------------------------------------- 1 | @import '~ant-design-vue/lib/style/themes/default'; 2 | 3 | @gray-1: #ffffff; 4 | @gray-2: #fafafa; 5 | @gray-3: #f5f5f5; 6 | @gray-4: #f0f0f0; 7 | @gray-5: #d9d9d9; 8 | @gray-6: #bfbfbf; 9 | @gray-7: #8c8c8c; 10 | @gray-8: #595959; 11 | @gray-9: #434343; 12 | @gray-10: #262626; 13 | @gray-11: #1f1f1f; 14 | @gray-12: #141414; 15 | @gray-13: #000000; 16 | 17 | @primary-color: @primary-color; 18 | @success-color: @success-color; 19 | @warning-color: @warning-color; 20 | @error-color: @warning-color; 21 | 22 | @title-color: @heading-color; 23 | @text-color: @text-color; 24 | @text-color-second: @text-color-secondary; 25 | 26 | @layout-bg-color: @layout-body-background; 27 | @base-bg-color: @body-background; 28 | @hover-bg-color: rgba(0, 0, 0, 0.025); 29 | @border-color: @border-color-split; 30 | @shadow-color: @shadow-color; 31 | 32 | @text-color-inverse: @text-color-inverse; 33 | @hover-bg-color-light: @hover-bg-color; 34 | @hover-bg-color-dark: @primary-7; 35 | @hover-bg-color-night: rgba(255, 255, 255, 0.025); 36 | @header-bg-color-dark: @layout-header-background; 37 | 38 | @shadow-down: @shadow-1-down; 39 | @shadow-up: @shadow-1-up; 40 | @shadow-left: @shadow-1-left; 41 | @shadow-right: @shadow-1-right; 42 | 43 | @theme-list: light, dark, night; 44 | -------------------------------------------------------------------------------- /src/theme/default/index.less: -------------------------------------------------------------------------------- 1 | @import "color"; 2 | @import "style"; 3 | @import "nprogress"; 4 | -------------------------------------------------------------------------------- /src/theme/default/nprogress.less: -------------------------------------------------------------------------------- 1 | @import '~ant-design-vue/lib/style/themes/default'; 2 | 3 | /* Make clicks pass-through */ 4 | #nprogress { 5 | pointer-events: none; 6 | } 7 | 8 | #nprogress .bar { 9 | background: @primary-color; 10 | 11 | position: fixed; 12 | z-index: 1031; 13 | top: 0; 14 | left: 0; 15 | 16 | width: 100%; 17 | height: 2px; 18 | } 19 | 20 | /* Fancy blur effect */ 21 | #nprogress .peg { 22 | display: block; 23 | position: absolute; 24 | right: 0px; 25 | width: 100px; 26 | height: 100%; 27 | box-shadow: 0 0 10px @primary-color, 0 0 5px @primary-color; 28 | opacity: 1.0; 29 | 30 | -webkit-transform: rotate(3deg) translate(0px, -4px); 31 | -ms-transform: rotate(3deg) translate(0px, -4px); 32 | transform: rotate(3deg) translate(0px, -4px); 33 | } 34 | 35 | /* Remove these to get rid of the spinner */ 36 | #nprogress .spinner { 37 | display: block; 38 | position: fixed; 39 | z-index: 1031; 40 | top: 15px; 41 | right: 15px; 42 | } 43 | 44 | #nprogress .spinner-icon { 45 | width: 18px; 46 | height: 18px; 47 | box-sizing: border-box; 48 | 49 | border: solid 2px transparent; 50 | border-top-color: @primary-color; 51 | border-left-color: @primary-color; 52 | border-radius: 50%; 53 | 54 | -webkit-animation: nprogress-spinner 400ms linear infinite; 55 | animation: nprogress-spinner 400ms linear infinite; 56 | } 57 | 58 | .nprogress-custom-parent { 59 | overflow: hidden; 60 | position: relative; 61 | } 62 | 63 | .nprogress-custom-parent #nprogress .spinner, 64 | .nprogress-custom-parent #nprogress .bar { 65 | position: absolute; 66 | } 67 | 68 | @-webkit-keyframes nprogress-spinner { 69 | 0% { -webkit-transform: rotate(0deg); } 70 | 100% { -webkit-transform: rotate(360deg); } 71 | } 72 | @keyframes nprogress-spinner { 73 | 0% { transform: rotate(0deg); } 74 | 100% { transform: rotate(360deg); } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/theme/default/style.less: -------------------------------------------------------------------------------- 1 | .week-mode{ 2 | overflow: hidden; 3 | filter: invert(80%); 4 | } 5 | .beauty-scroll{ 6 | scrollbar-color: @primary-color @primary-2; 7 | scrollbar-width: thin; 8 | -ms-overflow-style:none; 9 | position: relative; 10 | &::-webkit-scrollbar{ 11 | width: 3px; 12 | height: 1px; 13 | } 14 | &::-webkit-scrollbar-thumb { 15 | border-radius: 3px; 16 | background: @primary-color; 17 | } 18 | &::-webkit-scrollbar-track { 19 | -webkit-box-shadow: inset 0 0 1px rgba(0,0,0,0); 20 | border-radius: 3px; 21 | background: @primary-3; 22 | } 23 | } 24 | .split-right{ 25 | &:not(:last-child) { 26 | border-right: 1px solid rgba(98, 98, 98, 0.2); 27 | } 28 | } 29 | .disabled{ 30 | cursor: not-allowed; 31 | color: @disabled-color; 32 | pointer-events: none; 33 | } 34 | -------------------------------------------------------------------------------- /src/theme/index.less: -------------------------------------------------------------------------------- 1 | @import '~ant-design-vue/dist/antd.less'; 2 | @import "default/index"; 3 | @import "antd/index"; 4 | -------------------------------------------------------------------------------- /src/theme/theme.less: -------------------------------------------------------------------------------- 1 | @import "default/index"; 2 | -------------------------------------------------------------------------------- /src/utils/Objects.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 给对象注入属性 3 | * @param keys 属性key数组, 如 keys = ['config', 'path'] , 则会给对象注入 object.config.path 的属性 4 | * @param value 属性值 5 | * @returns {Object} 6 | */ 7 | Object.defineProperty(Object.prototype, 'assignProps', { 8 | writable: false, 9 | enumerable: false, 10 | configurable: true, 11 | value: function (keys, value) { 12 | let props = this 13 | for (let i = 0; i < keys.length; i++) { 14 | let key = keys[i] 15 | if (i === keys.length - 1) { 16 | props[key] = value 17 | } else { 18 | props[key] = props[key] === undefined ? {} : props[key] 19 | props = props[key] 20 | } 21 | } 22 | return this 23 | } 24 | }) 25 | -------------------------------------------------------------------------------- /src/utils/array.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 深拷贝 4 | * 5 | * @param source Array/Object 对象/数组 6 | */ 7 | export function deepClone(source) { 8 | const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象 9 | for (let keys in source) { // 遍历目标 10 | if (source.hasOwnProperty(keys)) { 11 | if (source[keys] && typeof source[keys] === 'object') { // 如果值是对象,就递归一下 12 | targetObj[keys] = source[keys].constructor === Array ? [] : {}; 13 | targetObj[keys] = deepClone(source[keys]); 14 | } else { // 如果不是,就直接赋值 15 | targetObj[keys] = source[keys]; 16 | } 17 | } 18 | } 19 | return targetObj; 20 | } 21 | -------------------------------------------------------------------------------- /src/utils/authority-utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 判断是否有路由的权限 3 | * @param authority 路由权限配置 4 | * @param permissions 用户权限集合 5 | * @returns {boolean|*} 6 | */ 7 | function hasPermission(authority, permissions) { 8 | let required = '*' 9 | if (typeof authority === 'string') { 10 | required = authority 11 | } else if (typeof authority === 'object') { 12 | required = authority.permission 13 | } 14 | return required === '*' || (permissions && permissions.findIndex(item => item === required || item.id === required) !== -1) 15 | } 16 | 17 | /** 18 | * 判断是否有路由需要的角色 19 | * @param authority 路由权限配置 20 | * @param roles 用户角色集合 21 | */ 22 | function hasRole(authority, roles) { 23 | let required = undefined 24 | if (typeof authority === 'object') { 25 | required = authority.role 26 | } 27 | return authority === '*' || hasAnyRole(required, roles) 28 | } 29 | 30 | /** 31 | * 判断是否有需要的任意一个角色 32 | * @param required {String | Array[String]} 需要的角色,可以是单个角色或者一个角色数组 33 | * @param roles 拥有的角色 34 | * @returns {boolean} 35 | */ 36 | function hasAnyRole(required, roles) { 37 | if (!required) { 38 | return false 39 | } else if(Array.isArray(required)) { 40 | return roles.findIndex(role => { 41 | return required.findIndex(item => item === role || item === role.id) !== -1 42 | }) !== -1 43 | } else { 44 | return roles.findIndex(role => role === required || role.id === required) !== -1 45 | } 46 | } 47 | 48 | /** 49 | * 路由权限校验 50 | * @param route 路由 51 | * @param permissions 用户权限集合 52 | * @param roles 用户角色集合 53 | * @returns {boolean} 54 | */ 55 | function hasAuthority(route, permissions, roles) { 56 | const authorities = [...route.meta.pAuthorities, route.meta.authority] 57 | for (let authority of authorities) { 58 | if (!hasPermission(authority, permissions) && !hasRole(authority, roles)) { 59 | return false 60 | } 61 | } 62 | return true 63 | } 64 | 65 | /** 66 | * 根据权限配置过滤菜单数据 67 | * @param menuData 68 | * @param permissions 69 | * @param roles 70 | */ 71 | function filterMenu(menuData, permissions, roles) { 72 | return menuData.filter(menu => { 73 | if (menu.meta && menu.meta.invisible === undefined) { 74 | if (!hasAuthority(menu, permissions, roles)) { 75 | return false 76 | } 77 | } 78 | if (menu.children && menu.children.length > 0) { 79 | menu.children = filterMenu(menu.children, permissions, roles) 80 | } 81 | return true 82 | }) 83 | } 84 | 85 | export {filterMenu, hasAuthority} 86 | -------------------------------------------------------------------------------- /src/utils/clipboardUtil.js: -------------------------------------------------------------------------------- 1 | import Clipboard from 'clipboard'; 2 | import Vue from 'vue' 3 | 4 | export function copy(e, code) { 5 | const clipboard = new Clipboard(e.target, { 6 | // 点击copy按钮,直接通过text直接返回复印的内容 7 | text: () => code 8 | }); 9 | clipboard.on('success', () => { 10 | Vue.prototype.$message.success('复制成功'); 11 | clipboard.off('error'); 12 | clipboard.off('success'); 13 | clipboard.destroy() 14 | }); 15 | clipboard.on('error', (e) => { 16 | console.log(e); 17 | Vue.prototype.$message.warn('该浏览器不支持此方式复制'); 18 | clipboard.off('error'); 19 | clipboard.off('success'); 20 | clipboard.destroy() 21 | }); 22 | clipboard.onClick(e) 23 | } -------------------------------------------------------------------------------- /src/utils/colors.js: -------------------------------------------------------------------------------- 1 | const varyColor = require('webpack-theme-color-replacer/client/varyColor') 2 | const {generate} = require('@ant-design/colors') 3 | const {ADMIN, ANTD} = require('../config/default') 4 | const Config = require('../config') 5 | 6 | const themeMode = ADMIN.theme.mode 7 | 8 | // 获取 ant design 色系 9 | function getAntdColors(color, mode) { 10 | let options = mode && (mode == themeMode.NIGHT) ? {theme: 'dark'} : undefined 11 | return generate(color, options) 12 | } 13 | 14 | // 获取功能性颜色 15 | function getFunctionalColors(mode) { 16 | let options = mode && (mode == themeMode.NIGHT) ? {theme: 'dark'} : undefined 17 | let {success, warning, error} = ANTD.primary 18 | const {success: s1, warning: w1, error: e1} = Config.theme 19 | success = success && s1 20 | warning = success && w1 21 | error = success && e1 22 | const successColors = generate(success, options) 23 | const warningColors = generate(warning, options) 24 | const errorColors = generate(error, options) 25 | return { 26 | success: successColors, 27 | warning: warningColors, 28 | error: errorColors 29 | } 30 | } 31 | 32 | // 获取菜单色系 33 | function getMenuColors(color, mode) { 34 | if (mode == themeMode.NIGHT) { 35 | return ANTD.primary.night.menuColors 36 | } else if (color == ANTD.primary.color) { 37 | return ANTD.primary.dark.menuColors 38 | } else { 39 | return [varyColor.darken(color, 0.93), varyColor.darken(color, 0.83), varyColor.darken(color, 0.73)] 40 | } 41 | } 42 | 43 | // 获取主题模式切换色系 44 | function getThemeToggleColors(color, mode) { 45 | //主色系 46 | const mainColors = getAntdColors(color, mode) 47 | const primary = mainColors[5] 48 | //辅助色系,因为 antd 目前没针对夜间模式设计,所以增加辅助色系以保证夜间模式的正常切换 49 | const subColors = getAntdColors(primary, themeMode.LIGHT) 50 | //菜单色系 51 | const menuColors = getMenuColors(color, mode) 52 | //内容色系(包含背景色、文字颜色等) 53 | const themeCfg = ANTD.theme[mode] 54 | let contentColors = Object.keys(themeCfg) 55 | .map(key => themeCfg[key]) 56 | .map(color => isHex(color) ? color : toNum3(color).join(',')) 57 | // 内容色去重 58 | contentColors = [...new Set(contentColors)] 59 | // rgb 格式的主题色 60 | let rgbColors = [toNum3(primary).join(',')] 61 | let functionalColors = getFunctionalColors(mode) 62 | return {primary, mainColors, subColors, menuColors, contentColors, rgbColors, functionalColors} 63 | } 64 | 65 | function toNum3(color) { 66 | if (isHex(color)) { 67 | return varyColor.toNum3(color) 68 | } 69 | let colorStr = '' 70 | if (isRgb(color)) { 71 | colorStr = color.slice(5, color.length) 72 | } else if (isRgba(color)) { 73 | colorStr = color.slice(6, color.lastIndexOf(',')) 74 | } 75 | let rgb = colorStr.split(',') 76 | const r = parseInt(rgb[0]) 77 | const g = parseInt(rgb[1]) 78 | const b = parseInt(rgb[2]) 79 | return [r, g, b] 80 | } 81 | 82 | function isHex(color) { 83 | return color.length >= 4 && color[0] == '#' 84 | } 85 | 86 | function isRgb(color) { 87 | return color.length >= 10 && color.slice(0, 3) == 'rgb' 88 | } 89 | 90 | function isRgba(color) { 91 | return color.length >= 13 && color.slice(0, 4) == 'rgba' 92 | } 93 | 94 | module.exports = { 95 | isHex, 96 | isRgb, 97 | isRgba, 98 | toNum3, 99 | getAntdColors, 100 | getMenuColors, 101 | getThemeToggleColors, 102 | getFunctionalColors 103 | } 104 | -------------------------------------------------------------------------------- /src/utils/dateUtil.js: -------------------------------------------------------------------------------- 1 | export function showtime(time) { 2 | let date = 3 | typeof time === "number" 4 | ? new Date(time) 5 | : new Date((time || "").replace(/-/g, "/")); 6 | let diff = (new Date().getTime() - date.getTime()) / 1000; 7 | let dayDiff = Math.floor(diff / 86400); 8 | 9 | let isValidDate = 10 | Object.prototype.toString.call(date) === "[object Date]" && 11 | !isNaN(date.getTime()); 12 | 13 | if (!isValidDate) { 14 | window.console.error("不是有效日期格式"); 15 | } 16 | const formatDate = function (date) { 17 | let today = new Date(date); 18 | let year = today.getFullYear(); 19 | let month = ("0" + (today.getMonth() + 1)).slice(-2); 20 | let day = ("0" + today.getDate()).slice(-2); 21 | let hour = today.getHours(); 22 | let minute = today.getMinutes(); 23 | let second = today.getSeconds(); 24 | return `${year}-${month}-${day} ${hour}:${minute}:${second}`; 25 | }; 26 | 27 | if (isNaN(dayDiff) || dayDiff < 0 || dayDiff >= 31) { 28 | return formatDate(date); 29 | } 30 | return ( 31 | (dayDiff === 0 && 32 | ((diff < 60 && "刚刚") || 33 | (diff < 120 && "1分钟前") || 34 | (diff < 3600 && Math.floor(diff / 60) + "分钟前") || 35 | (diff < 7200 && "1小时前") || 36 | (diff < 86400 && Math.floor(diff / 3600) + "小时前"))) || 37 | (dayDiff === 1 && "昨天") || 38 | (dayDiff < 7 && dayDiff + "天前") || 39 | (dayDiff < 31 && Math.ceil(dayDiff / 7) + "周前") 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /src/utils/formatter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 把对象按照 js配置文件的格式进行格式化 3 | * @param obj 格式化的对象 4 | * @param dep 层级,此项无需传值 5 | * @returns {string} 6 | */ 7 | function formatConfig(obj, dep) { 8 | dep = dep || 1 9 | const LN = '\n', TAB = ' ' 10 | let indent = '' 11 | for (let i = 0; i < dep; i++) { 12 | indent += TAB 13 | } 14 | let isArray = false, arrayLastIsObj = false 15 | let str = '', prefix = '{', subfix = '}' 16 | if (Array.isArray(obj)) { 17 | isArray = true 18 | prefix = '[' 19 | subfix = ']' 20 | str = obj.map((item, index) => { 21 | let format = '' 22 | if (typeof item == 'function') { 23 | // 24 | } else if (typeof item == 'object') { 25 | arrayLastIsObj = true 26 | format = `${LN}${indent}${formatConfig(item,dep + 1)},` 27 | } else if ((typeof item == 'number' && !isNaN(item)) || typeof item == 'boolean') { 28 | format = `${item},` 29 | } else if (typeof item == 'string') { 30 | format = `'${item}',` 31 | } 32 | if (index == obj.length - 1) { 33 | format = format.substring(0, format.length - 1) 34 | } else { 35 | arrayLastIsObj = false 36 | } 37 | return format 38 | }).join('') 39 | } else if (typeof obj != 'function' && typeof obj == 'object') { 40 | str = Object.keys(obj).map((key, index, keys) => { 41 | const val = obj[key] 42 | let format = '' 43 | if (typeof val == 'function') { 44 | // 45 | } else if (typeof val == 'object') { 46 | format = `${LN}${indent}${key}: ${formatConfig(val,dep + 1)},` 47 | } else if ((typeof val == 'number' && !isNaN(val)) || typeof val == 'boolean') { 48 | format = `${LN}${indent}${key}: ${val},` 49 | } else if (typeof val == 'string') { 50 | format = `${LN}${indent}${key}: '${val}',` 51 | } 52 | if (index == keys.length - 1) { 53 | format = format.substring(0, format.length - 1) 54 | } 55 | return format 56 | }).join('') 57 | } 58 | const len = TAB.length 59 | if (indent.length >= len) { 60 | indent = indent.substring(0, indent.length - len) 61 | } 62 | if (!isArray || arrayLastIsObj) { 63 | subfix = LN + indent +subfix 64 | } 65 | return`${prefix}${str}${subfix}` 66 | } 67 | 68 | module.exports = {formatConfig} 69 | -------------------------------------------------------------------------------- /src/utils/i18n.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | import routesI18n from '@/router/i18n' 4 | import './Objects' 5 | import {getI18nKey} from '@/utils/routerUtil' 6 | 7 | /** 8 | * 创建 i18n 配置 9 | * @param locale 本地化语言 10 | * @param fallback 回退语言 11 | * @returns {VueI18n} 12 | */ 13 | function initI18n(locale, fallback) { 14 | Vue.use(VueI18n) 15 | let i18nOptions = { 16 | locale, 17 | fallbackLocale: fallback, 18 | silentFallbackWarn: true, 19 | } 20 | return new VueI18n(i18nOptions) 21 | } 22 | 23 | /** 24 | * 根据 router options 配置生成 国际化语言 25 | * @param lang 26 | * @param routes 27 | * @param valueKey 28 | * @returns {*} 29 | */ 30 | function generateI18n(lang, routes, valueKey) { 31 | routes.forEach(route => { 32 | let keys = getI18nKey(route.fullPath).split('.') 33 | let value = valueKey === 'path' ? route[valueKey].split('/').filter(item => !item.startsWith(':') && item != '').join('.') : route[valueKey] 34 | lang.assignProps(keys, value) 35 | if (route.children) { 36 | generateI18n(lang, route.children, valueKey) 37 | } 38 | }) 39 | return lang 40 | } 41 | 42 | /** 43 | * 格式化 router.options.routes,生成 fullPath 44 | * @param routes 45 | * @param parentPath 46 | */ 47 | function formatFullPath(routes, parentPath = '') { 48 | routes.forEach(route => { 49 | let isFullPath = route.path.substring(0, 1) === '/' 50 | route.fullPath = isFullPath ? route.path : (parentPath === '/' ? parentPath + route.path : parentPath + '/' + route.path) 51 | if (route.children) { 52 | formatFullPath(route.children, route.fullPath) 53 | } 54 | }) 55 | } 56 | 57 | /** 58 | * 从路由提取国际化数据 59 | * @param i18n 60 | * @param routes 61 | */ 62 | function mergeI18nFromRoutes(i18n, routes) { 63 | formatFullPath(routes) 64 | const CN = generateI18n(new Object(), routes, 'name') 65 | const US = generateI18n(new Object(), routes, 'path') 66 | i18n.mergeLocaleMessage('CN', CN) 67 | i18n.mergeLocaleMessage('US', US) 68 | const messages = routesI18n.messages 69 | Object.keys(messages).forEach(lang => { 70 | i18n.mergeLocaleMessage(lang, messages[lang]) 71 | }) 72 | } 73 | 74 | export { 75 | initI18n, 76 | mergeI18nFromRoutes, 77 | formatFullPath 78 | } 79 | -------------------------------------------------------------------------------- /src/utils/json.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 设置默认值 4 | * 5 | * @param obj 6 | * @param defaultValue 不传默认值undefined 7 | * @returns {*[]|*} 8 | */ 9 | export function setDefaultValue(obj, defaultValue) { 10 | const newObj = obj ? obj.constructor === Array ? [] : {} : defaultValue; 11 | // constructor 属性返回对创建此对象的数组函数的引用。创建相同类型的空数据 12 | if (typeof obj !== 'object') { 13 | return; 14 | } else { 15 | for (const i in obj) { 16 | if (typeof obj[i] === 'object') {//判断对象的这条属性是否为对象 17 | newObj[i] = setDefaultValue(obj[i]);//若是对象进行嵌套调用 18 | } else { 19 | newObj[i] = defaultValue; 20 | } 21 | } 22 | } 23 | return newObj; 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/selectSearch.js: -------------------------------------------------------------------------------- 1 | import {listInputParameter} from '@/services/inputParameter' 2 | import {listVariable} from '@/services/variable' 3 | import {functionList} from '@/services/function' 4 | import {referenceableList} from '@/services/generalRule' 5 | 6 | let timeout; 7 | let currentValue; 8 | 9 | export function selectSearch(param, callback, type) { 10 | if (timeout) { 11 | clearTimeout(timeout); 12 | timeout = null; 13 | } 14 | currentValue = param.value; 15 | 16 | function fake() { 17 | let requestData = { 18 | page: { 19 | pageSize: 10, 20 | pageIndex: 1 21 | }, 22 | query: param, 23 | orders: [] 24 | }; 25 | if (type === 0) { 26 | listInputParameter(requestData).then(res => { 27 | if (currentValue === param.value) { 28 | if (res.data.data) { 29 | callback(res.data.data.rows); 30 | } else { 31 | callback([]); 32 | } 33 | } 34 | }); 35 | } else if (type === 1) { 36 | listVariable(requestData).then(res => { 37 | if (currentValue === param.value) { 38 | if (res.data.data) { 39 | callback(res.data.data.rows); 40 | } else { 41 | callback([]); 42 | } 43 | } 44 | }); 45 | } else if (type === 3) { 46 | functionList(requestData).then(res => { 47 | if (currentValue === param.value) { 48 | if (res.data.data) { 49 | callback(res.data.data.rows); 50 | } else { 51 | callback([]); 52 | } 53 | } 54 | }); 55 | } else if (type === 10) { 56 | referenceableList(requestData).then(res => { 57 | if (currentValue === param.value) { 58 | if (res.data.data) { 59 | callback(res.data.data.rows); 60 | } else { 61 | callback([]); 62 | } 63 | } 64 | }); 65 | } 66 | } 67 | 68 | timeout = setTimeout(fake, 300); 69 | } 70 | -------------------------------------------------------------------------------- /src/utils/symbol.js: -------------------------------------------------------------------------------- 1 | 2 | export function getSymbolExplanation(name) { 3 | switch (name) { 4 | case "EQ": 5 | return "等于"; 6 | case "NE": 7 | return "不等于"; 8 | case "GT": 9 | return "大于"; 10 | case "LT": 11 | return "小于"; 12 | case "GE": 13 | return "大于等于"; 14 | case "LE": 15 | return "小于等于"; 16 | case "CONTAIN": 17 | return "包含"; 18 | case "NOT_CONTAIN": 19 | return "不包含"; 20 | case "IN": 21 | return "在"; 22 | case "NOT_IN": 23 | return "不在"; 24 | case "STARTS_WITH": 25 | return "以..开始"; 26 | case "ENDS_WITH": 27 | return "以..结束"; 28 | } 29 | } 30 | 31 | export function getSymbolByValueType(valueType) { 32 | switch (valueType) { 33 | case "STRING": 34 | return [{"explanation": "等于", "name": "EQ", "symbol": "=="}, { 35 | "explanation": "不等于", 36 | "name": "NE", 37 | "symbol": "!=" 38 | }, {"explanation": "包含", "name": "CONTAIN", "symbol": "contain"}, { 39 | "explanation": "以..结束", 40 | "name": "ENDS_WITH", 41 | "symbol": "ends with" 42 | }, {"explanation": "以..开始", "name": "STARTS_WITH", "symbol": "starts with"}]; 43 | case "BOOLEAN": 44 | return [{"explanation": "等于", "name": "EQ", "symbol": "=="}, { 45 | "explanation": "不等于", 46 | "name": "NE", 47 | "symbol": "!=" 48 | }]; 49 | case "NUMBER": 50 | return [{"explanation": "大于", "name": "GT", "symbol": ">"}, { 51 | "explanation": "小于", 52 | "name": "LT", 53 | "symbol": "<" 54 | }, {"explanation": "等于", "name": "EQ", "symbol": "=="}, { 55 | "explanation": "不等于", 56 | "name": "NE", 57 | "symbol": "!=" 58 | }, {"explanation": "大于等于", "name": "GE", "symbol": ">="}, { 59 | "explanation": "小于等于", 60 | "name": "LE", 61 | "symbol": "<=" 62 | }]; 63 | case "COLLECTION": 64 | return [{"explanation": "等于", "name": "EQ", "symbol": "=="}, { 65 | "explanation": "在", 66 | "name": "IN", 67 | "symbol": "in" 68 | }, {"explanation": "不在", "name": "NOT_IN", "symbol": "not in"}, { 69 | "explanation": "包含", 70 | "name": "CONTAIN", 71 | "symbol": "contain" 72 | }, {"explanation": "不包含", "name": "NOT_CONTAIN", "symbol": "not contain"}]; 73 | case "DATE": 74 | return [{"explanation": "大于", "name": "GT", "symbol": ">"}, { 75 | "explanation": "小于", 76 | "name": "LT", 77 | "symbol": "<" 78 | }, {"explanation": "等于", "name": "EQ", "symbol": "=="}, { 79 | "explanation": "不等于", 80 | "name": "NE", 81 | "symbol": "!=" 82 | }, {"explanation": "大于等于", "name": "GE", "symbol": ">="}, { 83 | "explanation": "小于等于", 84 | "name": "LE", 85 | "symbol": "<=" 86 | }]; 87 | } 88 | } -------------------------------------------------------------------------------- /src/utils/theme-color-replacer-extend.js: -------------------------------------------------------------------------------- 1 | const {cssResolve} = require('../config/replacer') 2 | // 修正 webpack-theme-color-replacer 插件提取的 css 结果 3 | function resolveCss(output, srcArr) { 4 | let regExps = [] 5 | // 提取 resolve 配置中所有的正则配置 6 | Object.keys(cssResolve).forEach(key => { 7 | let isRegExp = false 8 | let reg = {} 9 | try { 10 | reg = eval(key) 11 | isRegExp = reg instanceof RegExp 12 | } catch (e) { 13 | isRegExp = false 14 | } 15 | if (isRegExp) { 16 | regExps.push([reg, cssResolve[key]]) 17 | } 18 | }) 19 | 20 | // 去重 21 | srcArr = dropDuplicate(srcArr) 22 | 23 | // 处理 css 24 | let outArr = [] 25 | srcArr.forEach(text => { 26 | // 转换为 css 对象 27 | let cssObj = parseCssObj(text) 28 | // 根据selector匹配配置,匹配成功,则按配置处理 css 29 | if (cssResolve[cssObj.selector] != undefined) { 30 | let cfg = cssResolve[cssObj.selector] 31 | if (cfg) { 32 | outArr.push(cfg.resolve(text, cssObj)) 33 | } 34 | } else { 35 | let cssText = '' 36 | // 匹配不成功,则测试是否有匹配的正则配置,有则按正则对应的配置处理 37 | for (let regExp of regExps) { 38 | if (regExp[0].test(cssObj.selector)) { 39 | let cssCfg = regExp[1] 40 | cssText = cssCfg ? cssCfg.resolve(text, cssObj) : '' 41 | break 42 | } 43 | // 未匹配到正则,则设置 cssText 为默认的 css(即不处理) 44 | cssText = text 45 | } 46 | if (cssText != '') { 47 | outArr.push(cssText) 48 | } 49 | } 50 | }) 51 | output = outArr.join('\n') 52 | return output 53 | } 54 | 55 | // 数组去重 56 | function dropDuplicate(arr) { 57 | let map = {} 58 | let r = [] 59 | for (let s of arr) { 60 | if (!map[s]) { 61 | r.push(s) 62 | map[s] = 1 63 | } 64 | } 65 | return r 66 | } 67 | 68 | /** 69 | * 从字符串解析 css 对象 70 | * @param cssText 71 | * @returns {{ 72 | * name: String, 73 | * rules: Array[String], 74 | * toText: function 75 | * }} 76 | */ 77 | function parseCssObj(cssText) { 78 | let css = {} 79 | const ruleIndex = cssText.indexOf('{') 80 | css.selector = cssText.substring(0, ruleIndex) 81 | const ruleBody = cssText.substring(ruleIndex + 1, cssText.length - 1) 82 | const rules = ruleBody.split(';') 83 | css.rules = rules 84 | css.toText = function () { 85 | let body = '' 86 | this.rules.forEach(item => {body += item + ';'}) 87 | return `${this.selector}{${body}}` 88 | } 89 | return css 90 | } 91 | 92 | module.exports = {resolveCss} 93 | -------------------------------------------------------------------------------- /src/utils/themeUtil.js: -------------------------------------------------------------------------------- 1 | const client = require('webpack-theme-color-replacer/client') 2 | const {theme} = require('../config') 3 | const {getMenuColors, getAntdColors, getThemeToggleColors, getFunctionalColors} = require('../utils/colors') 4 | const {ANTD} = require('../config/default') 5 | 6 | function getThemeColors(color, $theme) { 7 | const _color = color || theme.color 8 | const mode = $theme || theme.mode 9 | const replaceColors = getThemeToggleColors(_color, mode) 10 | const themeColors = [ 11 | ...replaceColors.mainColors, 12 | ...replaceColors.subColors, 13 | ...replaceColors.menuColors, 14 | ...replaceColors.contentColors, 15 | ...replaceColors.rgbColors, 16 | ...replaceColors.functionalColors.success, 17 | ...replaceColors.functionalColors.warning, 18 | ...replaceColors.functionalColors.error, 19 | ] 20 | return themeColors 21 | } 22 | 23 | function changeThemeColor(newColor, $theme) { 24 | let promise = client.changer.changeColor({newColors: getThemeColors(newColor, $theme)}) 25 | return promise 26 | } 27 | 28 | function modifyVars(color) { 29 | let _color = color || theme.color 30 | const palettes = getAntdColors(_color, theme.mode) 31 | const menuColors = getMenuColors(_color, theme.mode) 32 | const {success, warning, error} = getFunctionalColors(theme.mode) 33 | const primary = palettes[5] 34 | return { 35 | 'primary-color': primary, 36 | 'primary-1': palettes[0], 37 | 'primary-2': palettes[1], 38 | 'primary-3': palettes[2], 39 | 'primary-4': palettes[3], 40 | 'primary-5': palettes[4], 41 | 'primary-6': palettes[5], 42 | 'primary-7': palettes[6], 43 | 'primary-8': palettes[7], 44 | 'primary-9': palettes[8], 45 | 'primary-10': palettes[9], 46 | 'info-color': primary, 47 | 'success-color': success[5], 48 | 'warning-color': warning[5], 49 | 'error-color': error[5], 50 | 'alert-info-bg-color': palettes[0], 51 | 'alert-info-border-color': palettes[2], 52 | 'alert-success-bg-color': success[0], 53 | 'alert-success-border-color': success[2], 54 | 'alert-warning-bg-color': warning[0], 55 | 'alert-warning-border-color': warning[2], 56 | 'alert-error-bg-color': error[0], 57 | 'alert-error-border-color': error[2], 58 | 'processing-color': primary, 59 | 'menu-dark-submenu-bg': menuColors[0], 60 | 'layout-header-background': menuColors[1], 61 | 'layout-trigger-background': menuColors[2], 62 | 'btn-danger-bg': error[4], 63 | 'btn-danger-border': error[4], 64 | ...ANTD.theme[theme.mode] 65 | } 66 | } 67 | 68 | function loadLocalTheme(localSetting) { 69 | if (localSetting && localSetting.theme) { 70 | let {color, mode} = localSetting.theme 71 | color = color || theme.color 72 | mode = mode || theme.mode 73 | changeThemeColor(color, mode) 74 | } 75 | } 76 | 77 | /** 78 | * 获取本地保存的配置 79 | * @param load {boolean} 是否加载配置中的主题 80 | * @returns {Object} 81 | */ 82 | function getLocalSetting(loadTheme) { 83 | let localSetting = {} 84 | try { 85 | const localSettingStr = localStorage.getItem(process.env.VUE_APP_SETTING_KEY) 86 | localSetting = JSON.parse(localSettingStr) 87 | } catch (e) { 88 | console.error(e) 89 | } 90 | if (loadTheme) { 91 | loadLocalTheme(localSetting) 92 | } 93 | return localSetting 94 | } 95 | 96 | module.exports = { 97 | getThemeColors, 98 | changeThemeColor, 99 | modifyVars, 100 | loadLocalTheme, 101 | getLocalSetting 102 | } 103 | -------------------------------------------------------------------------------- /src/utils/util.js: -------------------------------------------------------------------------------- 1 | import enquireJs from 'enquire.js' 2 | 3 | export function isDef(v) { 4 | return v !== undefined && v !== null 5 | } 6 | 7 | /** 8 | * Remove an item from an array. 9 | */ 10 | export function remove(arr, item) { 11 | if (arr.length) { 12 | const index = arr.indexOf(item) 13 | if (index > -1) { 14 | return arr.splice(index, 1) 15 | } 16 | } 17 | } 18 | 19 | export function isEmail(str) { 20 | return /^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/.test(str); 21 | } 22 | 23 | export function isRegExp(v) { 24 | return _toString.call(v) === '[object RegExp]' 25 | } 26 | 27 | export function enquireScreen(call) { 28 | const handler = { 29 | match: function () { 30 | call && call(true) 31 | }, 32 | unmatch: function () { 33 | call && call(false) 34 | } 35 | } 36 | enquireJs.register('only screen and (max-width: 767.99px)', handler) 37 | } 38 | 39 | const _toString = Object.prototype.toString 40 | -------------------------------------------------------------------------------- /src/utils/value-type.js: -------------------------------------------------------------------------------- 1 | function getValueTypeName(valueType) { 2 | switch (valueType) { 3 | case 'STRING': 4 | return '字符串' 5 | case 'NUMBER': 6 | return '数值' 7 | case 'COLLECTION': 8 | return '集合' 9 | case 'BOOLEAN': 10 | return '布尔' 11 | case 'DATE': 12 | return '日期' 13 | case 'FUNCTION': 14 | return '函数' 15 | case 'UNKNOWN': 16 | return '未知' //返回值不确定 17 | default: 18 | return valueType; 19 | } 20 | } 21 | 22 | function getTypeName(v) { 23 | switch (v.type) { 24 | case 0: 25 | return "参数"; 26 | case 1: 27 | if (v.variableType === 2) { 28 | return "固定值变量"; 29 | } else if (v.variableType === 3) { 30 | return "函数变量"; 31 | } 32 | return "表达式变量"; 33 | case 2: 34 | return "固定值"; 35 | case 3: 36 | return "函数"; 37 | case 4: 38 | return "表达式"; 39 | case 10: 40 | return "普通规则"; 41 | default: 42 | return v.type; 43 | } 44 | } 45 | 46 | 47 | function valueType(v) { 48 | if (v.type === 0) { 49 | return 'PARAMETER'; 50 | } 51 | if (v.type === 1) { 52 | return 'VARIABLE'; 53 | } 54 | if (v.type === 10) { 55 | return 'GENERAL_RULE'; 56 | } 57 | if (v.valueType) { 58 | return v.valueType; 59 | } 60 | return undefined; 61 | } 62 | 63 | 64 | export {getValueTypeName, getTypeName, valueType} 65 | --------------------------------------------------------------------------------