├── .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 | [](https://www.apache.org/licenses/LICENSE-2.0.html)
4 | [](https://github.com/dingqianwen/rule-engine-front-v2/stargazers)
5 | [](https://github.com/dingqianwen/rule-engine-front-v2/fork)
6 | [](https://github.com/dingqianwen/rule-engine-front-v2/issues)
7 | [](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 |
21 |
22 | <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
23 |
24 | <% } %>
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
12 |
17 |
20 |
21 |
22 |
23 |
29 |
30 |
79 |
--------------------------------------------------------------------------------
/src/components/chart/Bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
52 |
53 |
60 |
--------------------------------------------------------------------------------
/src/components/chart/MiniArea.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
56 |
57 |
68 |
--------------------------------------------------------------------------------
/src/components/chart/MiniBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
56 |
57 |
60 |
--------------------------------------------------------------------------------
/src/components/chart/MiniProgress.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
21 |
22 |
57 |
--------------------------------------------------------------------------------
/src/components/chart/Radar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
77 |
78 |
81 |
--------------------------------------------------------------------------------
/src/components/chart/RankingList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
5 | -
6 | {{index + 1}}
7 | {{item.name}}
8 | {{item.total}}
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
60 |
--------------------------------------------------------------------------------
/src/components/chart/Trend.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{term}}
4 |
{{rate}}%
5 |
6 |
7 |
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 |
2 |
5 |
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 |
2 |
3 |
4 |
![]()
5 |
6 |
7 |
{{config[type].title}}
8 |
{{config[type].desc}}
9 |
12 |
13 |
14 |
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 |
2 |
10 |
11 |
12 |
18 |
19 |
52 |
--------------------------------------------------------------------------------
/src/components/input/IInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
67 |
--------------------------------------------------------------------------------
/src/components/menu/Contextmenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
73 |
74 |
85 |
--------------------------------------------------------------------------------
/src/components/menu/SideMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{systemName}}
7 |
8 |
9 |
10 |
11 |
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 |
2 |
3 |
27 |
28 |
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 |
2 |
3 |
6 |
{{title}}
7 |
{{description}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
24 |
65 |
--------------------------------------------------------------------------------
/src/components/setting/SettingItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
5 |
6 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 默认
9 |
10 |
11 | 中等
12 |
13 |
14 | 紧密
15 |
16 |
17 |
18 |
19 |
20 |
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 |
2 |
3 | {{title}}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
46 |
47 |
--------------------------------------------------------------------------------
/src/components/task/TaskItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{content}}
4 |
5 |
6 |
7 |
13 |
14 |
26 |
--------------------------------------------------------------------------------
/src/components/tool/AStepItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
{{title}}
7 |
8 |
9 |
10 |
11 |
12 |
47 |
48 |
60 |
--------------------------------------------------------------------------------
/src/components/tool/AvatarList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
47 |
48 |
70 |
--------------------------------------------------------------------------------
/src/components/tool/DetailList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
100 |
101 |
157 |
--------------------------------------------------------------------------------
/src/components/tool/Drawer.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
59 |
60 |
143 |
--------------------------------------------------------------------------------
/src/components/tool/FooterToolBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
18 |
31 |
--------------------------------------------------------------------------------
/src/components/tool/HeadInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
{{content}}
5 |
6 |
7 |
8 |
14 |
15 |
35 |
--------------------------------------------------------------------------------
/src/components/tool/TagSelect.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
68 |
69 |
84 |
--------------------------------------------------------------------------------
/src/components/tool/TagSelectOption.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
26 |
34 |
--------------------------------------------------------------------------------
/src/components/transition/PageToggleTransition.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
23 |
--------------------------------------------------------------------------------
/src/layouts/CommonLayout.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
20 |
21 |
43 |
--------------------------------------------------------------------------------
/src/layouts/PageView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
45 |
46 |
56 |
--------------------------------------------------------------------------------
/src/layouts/footer/PageFooter.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
23 |
24 |
49 |
--------------------------------------------------------------------------------
/src/layouts/header/HeaderAvatar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 | 个人中心
11 |
12 |
13 |
14 | 设置
15 |
16 |
17 |
18 |
19 | 退出登录
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
77 |
--------------------------------------------------------------------------------
/src/layouts/header/HeaderNotice.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
39 |
40 |
41 |
42 |
67 |
68 |
93 |
--------------------------------------------------------------------------------
/src/layouts/header/HeaderSearch.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
38 |
39 |
68 |
--------------------------------------------------------------------------------
/src/layouts/header/HeaderWorkSpace.vue:
--------------------------------------------------------------------------------
1 |
2 |
29 |
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 |
2 |
3 |
4 |
5 |
6 |
7 | {{$t('search')}}
8 |
9 |
10 |
11 |
12 |
13 |
12321
14 |
71.2
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {{$t('capita')}}
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
42 | {{text}}
43 | {{text}} %
44 |
45 |
46 |
47 |
48 |
106 |
107 |
143 |
--------------------------------------------------------------------------------
/src/pages/dashboard/analysis/RankingList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{title}}
4 |
5 | -
6 | {{index + 1}}
7 | {{item.name}}
8 | {{item.total}}
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
60 |
--------------------------------------------------------------------------------
/src/pages/dashboard/analysis/SalesData.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
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 |
2 |
3 |
4 |
5 |
19 |
20 |
22 |
--------------------------------------------------------------------------------
/src/pages/exception/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
22 |
--------------------------------------------------------------------------------
/src/pages/exception/500.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
2 |
3 |
4 |
5 | 返回
6 |
7 |
8 |
9 | {{ this.message }}
10 |
11 |
18 |
25 |
26 |
27 |
28 |
29 |
30 |
48 |
49 |
57 |
--------------------------------------------------------------------------------
/src/pages/result/Success.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 返回列表
6 | 查看项目
7 | 打印
8 |
9 |
10 |
项目名称
11 |
12 | 20180724089
13 | 曲丽丽
14 | 016-12-12 ~ 2017-12-12
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
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 |
2 |
6 |
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 |
--------------------------------------------------------------------------------