├── .babelrc ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .lintstagedrc ├── .travis.yml ├── LICENSE ├── _config.yml ├── app ├── apis │ ├── __mocks__ │ │ └── manage.js │ ├── common.js │ └── manage.js ├── client.js ├── components │ ├── draw │ │ ├── README.md │ │ ├── __mocks__ │ │ │ └── draw.js │ │ ├── draw.js │ │ ├── draw.less │ │ └── draw2.0.js │ ├── logo │ │ ├── logo.css │ │ └── logo.js │ └── tableList │ │ └── tableList.js ├── configs │ ├── __mocks__ │ │ └── ajax.js │ ├── ajax.js │ ├── common.js │ ├── config.js │ ├── regular.config.js │ ├── router.config.js │ └── socket.js ├── images │ ├── default.png │ ├── icon │ │ └── menu │ │ │ ├── default.png │ │ │ ├── icon_duty.png │ │ │ ├── icon_pgmb.png │ │ │ ├── icon_pgmx.png │ │ │ ├── icon_statistics.png │ │ │ ├── icon_xtxg.png │ │ │ ├── moduleManage.png │ │ │ ├── roleManage.png │ │ │ └── userManage.png │ ├── login.png │ ├── logo.png │ ├── navcontrol.png │ ├── photo_default.jpg │ ├── user.jpg │ └── user.png ├── index.html ├── middleware │ ├── configureStore.js │ ├── history.js │ ├── index.js │ ├── logger.js │ └── router.js ├── mocks │ ├── apis │ │ ├── base │ │ │ ├── index.js │ │ │ ├── login.js │ │ │ ├── logout.js │ │ │ ├── menu.js │ │ │ └── staff.js │ │ ├── fail.js │ │ ├── success.js │ │ ├── sys │ │ │ ├── moduleManage │ │ │ │ ├── fetchModuleDetail.js │ │ │ │ ├── fetchModuleList.js │ │ │ │ └── index.js │ │ │ ├── roleManage │ │ │ │ ├── fetchButtonList.js │ │ │ │ ├── fetchModuleListInRole.js │ │ │ │ ├── fetchRoleDetail.js │ │ │ │ ├── fetchTreeList.js │ │ │ │ └── index.js │ │ │ └── userManage │ │ │ │ ├── fetchRoleList.js │ │ │ │ ├── fetchUserDepttList.js │ │ │ │ ├── fetchUserDetail.js │ │ │ │ ├── fetchUserList.js │ │ │ │ └── index.js │ │ └── tableList.js │ ├── http.js │ ├── interfaceFilter.js │ └── interfaceMap.js ├── pages │ ├── base │ │ ├── app.js │ │ ├── app │ │ │ ├── header.js │ │ │ ├── leftNav.js │ │ │ ├── modal │ │ │ │ ├── editPassword.js │ │ │ │ └── userInfo.js │ │ │ └── tabList.js │ │ ├── developing.js │ │ ├── example.js │ │ ├── index.js │ │ ├── login.js │ │ ├── notfound.js │ │ ├── socket.js │ │ └── socketReceive.js │ ├── example.js │ ├── menu │ │ ├── echarts.js │ │ ├── editor.js │ │ └── index.js │ └── set │ │ ├── index.js │ │ ├── moduleManage │ │ ├── index.js │ │ ├── modal │ │ │ ├── addButtonModal.js │ │ │ ├── buttonModal.js │ │ │ └── moduleAdd.js │ │ └── moduleList.js │ │ ├── roleManage │ │ ├── index.js │ │ ├── modal │ │ │ ├── buttonModal.js │ │ │ └── roleAdd.js │ │ ├── peopleTreeList.js │ │ ├── roleCheckbox.js │ │ ├── roleList.js │ │ └── roleModuleList.js │ │ └── userManage │ │ ├── index.js │ │ ├── modal │ │ ├── addPolice.js │ │ └── selectRole.js │ │ └── treeList.js ├── redux │ ├── actions │ │ ├── common.js │ │ └── tabList.js │ └── reducers │ │ ├── common.js │ │ ├── index.js │ │ └── tabList.js ├── resource │ └── iconfont │ │ ├── iconfont.eot │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff └── styles │ ├── RichEditor.less │ ├── base.less │ ├── login.less │ ├── personalCenter.less │ ├── set.less │ └── theme.less ├── package-lock.json ├── package.json ├── postcss.config.js ├── readme.md ├── scripts ├── webpack.base.config.js ├── webpack.dev.config.js ├── webpack.dll.config.js ├── webpack.prod.config.js └── webpack.testing.config.js └── test ├── Enzyme.js └── setCenter └── sys ├── moduleManage ├── index.spec.js ├── module │ ├── addButtonModal.spec.js │ ├── addmodal.spec.js │ └── buttonModal.spec.js └── moduleList.spec.js ├── roleManage ├── index.spec.js ├── modal │ ├── buttonModal.spec.js │ └── roleAdd.spec.js ├── roleCheckbox.spec.js └── roleModuleList.spec.js └── userManage ├── index.spec.js └── modal └── addPolice.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env",{ 4 | "useBuiltIns": "usage", 5 | "targets": { 6 | "chrome": "49", 7 | "ie": "11" 8 | }, 9 | "corejs": 2 10 | }], 11 | "@babel/preset-react" 12 | ], 13 | "plugins": [ 14 | ["@babel/plugin-transform-runtime",{ 15 | "absoluteRuntime": false, 16 | "corejs": 2, 17 | "helpers": true, 18 | "regenerator": true, 19 | "useESModules": false 20 | }], 21 | [ 22 | "@babel/plugin-proposal-decorators", 23 | { 24 | "legacy": true 25 | } 26 | ], 27 | "@babel/plugin-proposal-class-properties", 28 | // "transform-decorators-legacy", 29 | // "@babel/plugin-syntax-dynamic-import", 30 | ["import", { 31 | "libraryName": "antd", 32 | "libraryDirectory": "es", 33 | "style": true // `style: true` 会加载 less 文件 34 | }] 35 | ] 36 | } -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | references: 4 | container_config: &container_config 5 | docker: 6 | - image: circleci/node:8 7 | working_directory: ~/react 8 | 9 | attach_workspace: &attach_workspace 10 | attach_workspace: 11 | at: ~/react 12 | 13 | react_16: &react_16 14 | environment: 15 | REACT: 16 16 | 17 | workflow: &workflow 18 | jobs: 19 | - setup: 20 | filters: 21 | branches: 22 | ignore: gh-pages 23 | # - testing: 24 | # requires: 25 | # - setup 26 | - lint: 27 | requires: 28 | - setup 29 | 30 | 31 | jobs: 32 | setup: 33 | <<: *container_config 34 | steps: 35 | - checkout 36 | - run: node -v 37 | - run: npm -v 38 | - run: npm install 39 | - run: npm run dll 40 | - run: 41 | command: | 42 | set +eo 43 | npm ls 44 | true 45 | - persist_to_workspace: 46 | root: ~/react 47 | paths: 48 | - node_modules 49 | 50 | # testing: 51 | # <<: *container_config 52 | # steps: 53 | # - checkout 54 | # - *attach_workspace 55 | # - run: npm run testing 56 | # - run: node ./scripts/webpack.testing.config.js 57 | # - persist_to_workspace: 58 | # root: ~/react 59 | # paths: 60 | # - dist 61 | 62 | 63 | lint: 64 | <<: *container_config 65 | steps: 66 | - checkout 67 | - *attach_workspace 68 | - run: npm run lint 69 | 70 | workflows: 71 | version: 2 72 | build_test: 73 | <<: *workflow 74 | nightly: 75 | <<: *workflow 76 | triggers: 77 | - schedule: 78 | cron: "0 0 * * *" 79 | filters: 80 | branches: 81 | only: 82 | - master 83 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # /node_modules/* and /bower_components/* ignored by default 2 | 3 | /* 4 | !app 5 | 6 | /test 7 | 8 | /app/components/draw/__mocks__/draw.js 9 | 10 | /app/configs/__mocks__/ajax.js 11 | /app/resource 12 | 13 | # app/configs 14 | # app/components 15 | # app/pages -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "es6": true 7 | }, 8 | "settings": { 9 | "import/core-modules": [ 10 | "components", 11 | "actions", 12 | "api", 13 | "reducers", 14 | "utils", 15 | "constants" 16 | ] 17 | }, 18 | "parser": "babel-eslint", 19 | "parserOptions": { 20 | "ecmaFeatures": { 21 | "jsx": true, 22 | "experimentalObjectRestSpread": true 23 | } 24 | }, 25 | "rules": { 26 | "linebreak-style": "off", 27 | "func-names": 0, 28 | "max-len": [ 29 | "warn", 30 | 200, 31 | 4, 32 | { 33 | "comments": 150 34 | } 35 | ], 36 | "indent": [ 37 | "error", 38 | 2, 39 | { 40 | "SwitchCase": 1 41 | } 42 | ], 43 | "react/jsx-indent": [ 44 | 2, 45 | 2 46 | ], 47 | "semi": 0, 48 | "react/sort-comp": 0, 49 | "react/prop-types": 0, 50 | "react/prefer-es6-class": 0, 51 | "react/prefer-stateless-function": 0, 52 | "react/jsx-first-prop-new-line": 0, 53 | "react/jsx-filename-extension": 0, 54 | "no-return-assign": 0, 55 | "react/no-multi-comp": 0, 56 | "array-callback-return": 0, 57 | "no-underscore-dangle": 0, 58 | "no-bitwise": [ 59 | "error", 60 | { 61 | "allow": [ 62 | "~" 63 | ] 64 | } 65 | ], 66 | "no-plusplus": 1, 67 | "no-unused-expressions": [ 68 | "warn", 69 | { 70 | "allowShortCircuit": true, 71 | "allowTernary": true 72 | } 73 | ], 74 | "import/no-unresolved": 0, 75 | "import/no-extraneous-dependencies": 0, 76 | "jsx-a11y/no-static-element-interactions": 0, 77 | "jsx-a11y/img-has-alt": 0, 78 | "no-unused-vars": [ 79 | "warn", 80 | { 81 | "vars": "all", 82 | "args": "none" 83 | } 84 | ], 85 | "react/no-unused-state": [ 86 | "warn" 87 | ], 88 | "no-param-reassign": [ 89 | "error", 90 | { 91 | "props": false 92 | } 93 | ], 94 | "object-shorthand": 0, 95 | "jsx-a11y/anchor-is-valid": 0, 96 | "react/no-array-index-key": 0, 97 | "jsx-a11y/click-events-have-key-events": 0, 98 | "import/extensions": 0, 99 | "no-debugger": "off", 100 | "react/jsx-closing-tag-location": 0, 101 | "import/prefer-default-export": 0, 102 | "react/forbid-prop-types": 1, 103 | "class-methods-use-this": 0, 104 | "consistent-return": 1, 105 | "import/first": 1, 106 | "no-console":"off", 107 | "prefer-destructuring": [ 108 | "warn" 109 | ], 110 | "object-curly-newline": [ 111 | "error", 112 | { 113 | "minProperties": 5, 114 | "consistent": true, 115 | "multiline":true 116 | } 117 | ] 118 | }, 119 | "plugins": [ 120 | "jsx-a11y" 121 | ] 122 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js eol=lf 2 | *.json eol=lf 3 | *.jsx eol=lf 4 | *.ts eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # vscode 7 | jsconfig.json 8 | dist 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # Compiled binary addons (http://nodejs.org/api/addons.html) 32 | build/Release 33 | 34 | # Dependency directories 35 | node_modules 36 | jspm_packages 37 | 38 | # Optional npm cache directory 39 | .npm 40 | 41 | # Optional REPL history 42 | .node_repl_history 43 | 44 | #mac 45 | .DS_Store 46 | 47 | #vscode 48 | .vscode 49 | /.idea/ 50 | 51 | #eslint 52 | .eslintcache 53 | 54 | #cashe 55 | .cache 56 | 57 | #app/components/condition1.0 58 | 59 | #don't upload node_modules.rar 60 | node_modules.rar 61 | 62 | #don't upload react.rar 63 | react.rar 64 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "linters": { 3 | "app/**/*.js": [ 4 | "npm run lint", 5 | "git add" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '9' 4 | cache: 5 | directories: 6 | - node_modules 7 | 8 | install: 9 | - npm install 10 | 11 | script: 'true' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present, dupi, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /app/apis/__mocks__/manage.js: -------------------------------------------------------------------------------- 1 | 2 | import { createApi } from '@ajax' 3 | import { mockURL, path } from '@configs/config' 4 | 5 | const prefix = 'usercenter' 6 | const option = { baseURL: mockURL } 7 | // 模块管理 8 | export const fetchModuleList = createApi(`${path}/${prefix}/resource/list`, option) // 获取模块列表 9 | export const fetchModuleDelete = createApi(`${path}/${prefix}/resource/delete`, option) // 删除模块 10 | export const fetchModuleDetail = createApi(`${path}/${prefix}/resource/detail`, option) // 获取模块详情 11 | export const fetchChangeModuleStatus = createApi(`${path}/${prefix}/resource/updateStatus`, option) // 修改模块显隐状态 12 | export const fetchModuleUpdateDetail = createApi(`${path}/${prefix}/resource/update`, option) // 修改模块详情 13 | export const fetchModuleAdd = createApi(`${path}/${prefix}/resource/save`, option) // 新增模块 14 | export const fetchButtonList = createApi(`${path}/${prefix}/resource/button/list`, 'fetchButtonList') // 按钮权限列表 15 | 16 | // 角色管理 17 | export const fetchRoleList = createApi(`${path}/${prefix}/role/list`, 'fetchRoleList') // 角色列表 18 | export const fetchRoleAdd = createApi(`${path}/${prefix}/role/save`, option) // 保存角色 19 | export const fetchRoleUpdate = createApi(`${path}/${prefix}/role/update`, option) // 角色编辑 20 | export const fetchRoleDetail = createApi(`${path}/${prefix}/role/detail`, option) // 已选择的菜单以及按钮 21 | export const fetchRoleDelete = createApi(`${path}/${prefix}/role/delete`, option) // 删除角色 22 | export const fetchModuleListInRole = createApi(`${path}/${prefix}/role/resList`, 'fetchModuleListInRole') // 已选择的模块 23 | export const fetchUpdateRoleRes = createApi(`${path}/${prefix}/role/updateRes`, option) // 更新已选择的模块 24 | 25 | export const fetchRoleDeletePeople = createApi(`${path}/${prefix}/user/removeRole`, option) 26 | export const fetchUpdateButton = createApi(`${path}/${prefix}/role/updateButton`, option) 27 | export const fetchTreeList = createApi(`${path}/${prefix}/role/resTree`, 'fetchTreeList') 28 | // 用户管理 29 | export const fetchUserDepttList = createApi(`${path}/${prefix}/dept/list`, 'fetchUserDepttList') // 获取用户管理左侧分类列表 30 | export const fetchUserList = createApi(`${path}/${prefix}/user/list`, 'fetchUserList') // 获取用户列表 31 | export const fetchUserDetail = createApi(`${path}/${prefix}/user/detail`, option) // 获取用户详情 32 | export const fetchUserDetailUpdate = createApi(`${path}/${prefix}/user/update`, option) // 修改用户详情 33 | export const fetchUserAdd = createApi(`${path}/${prefix}/user/save`, option) // 新增用户 34 | export const synUser = createApi(`${path}/${prefix}/user/synUser`, option) // 同步用户 35 | export const fetchUserSetRole = createApi(`${path}/${prefix}/user/updateRole`, option) // 修改用户角色 36 | export const fetchUserDelete = createApi(`${path}/${prefix}/user/delete`, option) // 删除用户 37 | export const fetchChangeUserStatus = createApi(`${path}/${prefix}/user/updateStatus`, option) // 设置用户是否冻结状态 38 | -------------------------------------------------------------------------------- /app/apis/common.js: -------------------------------------------------------------------------------- 1 | 2 | import { createApi } from '@ajax' 3 | import { mockURL, /* baseURL, */ path } from '@config' 4 | 5 | const prefix = 'usercenter' 6 | const option = { baseURL: mockURL } 7 | 8 | export const login = createApi(`${path}/${prefix}/login`, option) // 登陆 9 | export const logout = createApi(`${path}/${prefix}/logout`, option) // 登出 10 | export const loginByTicket = createApi(`${path}/${prefix}/loginByTicket`, option) // 通过ticket登陆 11 | export const loginByKey = createApi(`${path}/service/pagerservice/checkKey`, option) // 通过key进入项目 12 | export const staff = createApi(`${path}/${prefix}/user/userInfo`, option) // 用户信息 13 | export const synUser = createApi(`${path}/${prefix}/user/synUser`, option)// 同步用户 14 | export const menu = createApi(`${path}/${prefix}/user/userMenu`, option) // 获取菜单 15 | export const getLevel = createApi(`${path}/${prefix}/user/getLevel`, option) // 当前用户的等级 16 | export const getBtns = createApi(`${path}/${prefix}/resource/listByPid`, option) // 获取菜单id 17 | export const getAllRetrieval = createApi(`${path}/data/sys/retrieval/queryAllRetrievald`) // 获取gForm2.0头部搜索 18 | -------------------------------------------------------------------------------- /app/apis/manage.js: -------------------------------------------------------------------------------- 1 | 2 | import { createApi } from '@ajax' 3 | import { mockURL, /* baseURL, */ path } from '@config' 4 | 5 | const prefix = 'usercenter' 6 | const option = { baseURL: mockURL } 7 | 8 | // 模块管理 9 | export const fetchModuleList = createApi(`${path}/${prefix}/resource/list`, option) // 获取模块列表 10 | export const fetchModuleDelete = createApi(`${path}/${prefix}/resource/delete`, option) // 删除模块 11 | export const fetchModuleDetail = createApi(`${path}/${prefix}/resource/detail`, option) // 获取模块详情 12 | export const fetchChangeModuleStatus = createApi(`${path}/${prefix}/resource/updateStatus`, option) // 修改模块显隐状态 13 | export const fetchModuleUpdateDetail = createApi(`${path}/${prefix}/resource/update`, option) // 修改模块详情 14 | export const fetchModuleAdd = createApi(`${path}/${prefix}/resource/save`, option) // 新增模块 15 | export const fetchButtonList = createApi(`${path}/${prefix}/resource/button/list`, option) // 按钮权限列表 16 | 17 | // 角色管理 18 | export const fetchRoleList = createApi(`${path}/${prefix}/role/list`, option) // 角色列表 19 | export const fetchRoleAdd = createApi(`${path}/${prefix}/role/save`, option) // 保存角色 20 | export const fetchRoleUpdate = createApi(`${path}/${prefix}/role/update`, option) // 角色编辑 21 | export const fetchRoleDetail = createApi(`${path}/${prefix}/role/detail`, option) // 已选择的菜单以及按钮 22 | export const fetchRoleDelete = createApi(`${path}/${prefix}/role/delete`, option) // 删除角色 23 | export const fetchModuleListInRole = createApi(`${path}/${prefix}/role/resList`, option) // 已选择的模块 24 | export const fetchUpdateRoleRes = createApi(`${path}/${prefix}/role/updateRes`, option) // 更新已选择的模块 25 | 26 | export const fetchRoleDeletePeople = createApi(`${path}/${prefix}/user/removeRole`, option) 27 | export const fetchUpdateButton = createApi(`${path}/${prefix}/role/updateButton`, option) 28 | export const fetchTreeList = createApi(`${path}/${prefix}/role/resTree`, option) 29 | // 用户管理 30 | export const fetchUserDepttList = createApi(`${path}/${prefix}/dept/list`, option) // 获取用户管理左侧分类列表 31 | export const fetchUserList = createApi(`${path}/${prefix}/user/list`, option) // 获取用户列表 32 | export const fetchUserDetail = createApi(`${path}/${prefix}/user/detail`, option) // 获取用户详情 33 | export const fetchUserDetailUpdate = createApi(`${path}/${prefix}/user/update`, option) // 修改用户详情 34 | export const fetchUserAdd = createApi(`${path}/${prefix}/user/save`, option) // 新增用户 35 | export const synUser = createApi(`${path}/${prefix}/user/synUser`, option) // 同步用户 36 | export const fetchUserSetRole = createApi(`${path}/${prefix}/user/updateRole`, option) // 修改用户角色 37 | export const fetchUserDelete = createApi(`${path}/${prefix}/user/delete`, option) // 删除用户 38 | export const fetchChangeUserStatus = createApi(`${path}/${prefix}/user/updateStatus`, option) // 设置用户是否冻结状态 39 | -------------------------------------------------------------------------------- /app/client.js: -------------------------------------------------------------------------------- 1 | // import '@babel/polyfill' 2 | import React from 'react' 3 | import ReactDOM from 'react-dom' 4 | import { Provider } from 'react-redux' 5 | import { hot } from 'react-hot-loader/root' 6 | import '@config' 7 | import Routes from '@configs/router.config' 8 | import configure from '@middleware/configureStore' 9 | 10 | const HotRoutes = hot(Routes) 11 | const store = configure({ }) 12 | ReactDOM.render( 13 | 14 | 15 | , 16 | document.getElementById('root'), 17 | ) 18 | -------------------------------------------------------------------------------- /app/components/draw/README.md: -------------------------------------------------------------------------------- 1 | ## drawde(抽屉组件) 2 | #### props 3 | | 属性名 | 类型 | 默认值 | 是否必填 | 描述 | 4 | | -------- | ----------------- | ------ | ---- | ------------------------------- | 5 | | visible | String | 无 | 是 | 组件是否显示 | 6 | | title | String | '标题' | 否 | 抽屉标题 | 7 | | footer | String\|ReactNode | 无 | 否 | 组件底部内容 | 8 | | onCancel | Function | 无 | 是 | 关闭组件的回调方法,将组件设置的visible设置为false | 9 | | size | String | 'base' | 否 | 组件的大小,有sm,base,lg共3个值 | 10 | 11 | #### 调用示例 12 | 13 | ```javascript 14 | { 15 | this.state.drawVisible ? 16 | this.setState({ drawVisible: false })} 21 | size="lg" 22 | > 23 |
111
24 |
25 | : null 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /app/components/draw/draw2.0.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 韩卿 3 | * @Date: 2017-08-20 16:07:21 4 | * @Last Modified by: dupi 5 | * @Last Modified time: 2018-10-22 17:10:34 6 | */ 7 | 8 | 9 | import React, { Component } from 'react' 10 | import ReactDOM from 'react-dom' 11 | import PropTypes from 'prop-types'; 12 | // import configure from '../../store/configureStore' 13 | 14 | import './draw.less' 15 | 16 | // const store = configure({ config: global.$GLOBALCONFIG }) 17 | 18 | // 声明组件 并对外输出 19 | export default class Drawer extends Component { 20 | // 初始化页面常量 绑定事件方法 21 | constructor(props, context) { 22 | super(props, context) 23 | this.state = { 24 | // activeTab: 'pop' , 25 | drawTrasformClass: '', 26 | maskTrasformClass: '', 27 | drawerSizeClass: 'modal-base', 28 | // drawerSizeClassList: ['modal-base', 'modal-sm', 'modal-lg'], 29 | } 30 | } 31 | 32 | componentWillMount() { 33 | const { 34 | size = 'default', 35 | } = this.props 36 | this.getDrawerSize(size) 37 | this.setTrasformClass() 38 | } 39 | 40 | 41 | // 组件已经加载到dom中 42 | componentDidMount() { 43 | const { 44 | visible = true, 45 | } = this.props 46 | if (visible) { 47 | this.initDrawer() 48 | } 49 | } 50 | 51 | // 监测visible属性, 52 | componentWillReceiveProps(nextProps) { 53 | /* const { 54 | visible = true, 55 | } = this.props 56 | console.log(visible) 57 | console.log(nextProps) 58 | if (visible || nextProps.visible) { 59 | this.initDrawer() 60 | } else { 61 | this.removeDrawer() 62 | } */ 63 | } 64 | 65 | componentDidUpdate() { 66 | this.renderDrawer() 67 | } 68 | 69 | componentWillUnmount() { 70 | // ut(() => { 71 | ReactDOM.unmountComponentAtNode(this.popup) 72 | // }, 300) 73 | } 74 | 75 | // 初始化抽屉 76 | initDrawer = () => { 77 | this.popup = document.createElement('div') 78 | this.popup.setAttribute('class', 'drawers') 79 | this.renderDrawer() 80 | document.body.appendChild(this.popup) 81 | this.setTrasformClass() 82 | } 83 | 84 | // 抽屉添加动画效果class的设置 85 | setTrasformClass = () => { 86 | const { 87 | visible = true, 88 | } = this.props 89 | if (visible) { 90 | this.setState({ 91 | drawTrasformClass: 'draw-enter', 92 | maskTrasformClass: 'mask-enter', 93 | }, () => 94 | setTimeout(() => { 95 | this.setState({ 96 | drawTrasformClass: '', 97 | maskTrasformClass: '', 98 | }) 99 | }, 300)) 100 | } 101 | } 102 | 103 | // 移除弹窗 104 | removeDrawer = () => { 105 | this.setState({ 106 | drawTrasformClass: 'draw-leave', 107 | maskTrasformClass: 'mask-leave', 108 | }, () => 109 | setTimeout(() => { 110 | this.setState({ 111 | drawTrasformClass: '', 112 | maskTrasformClass: '', 113 | }) 114 | document.body.removeChild(this.popup) 115 | ReactDOM.unmountComponentAtNode(this.popup) 116 | 117 | this.props.onCancel() 118 | }, 200)) 119 | } 120 | 121 | // 判断抽屉的尺寸class 122 | getDrawerSize = (size) => { 123 | switch (size) { 124 | case 'sm': 125 | this.setState({ 126 | drawerSizeClass: 'drawer-sm', 127 | }) 128 | break 129 | case 'lg': 130 | this.setState({ 131 | drawerSizeClass: 'drawer-lg', 132 | }) 133 | break 134 | default: 135 | this.setState({ 136 | drawerSizeClass: 'drawer-base', 137 | }) 138 | break 139 | } 140 | } 141 | 142 | // 将弹窗内容插入到指定dom中 143 | renderDrawer() { 144 | const { 145 | title = '标题', 146 | footer = null, 147 | } = this.props 148 | const { 149 | drawTrasformClass, 150 | maskTrasformClass, 151 | drawerSizeClass, 152 | } = this.state 153 | 154 | ReactDOM.render( 155 |
156 |
this.removeDrawer()} /> 157 |
158 |
159 |
160 | 163 |
164 |
{title}
165 |
166 | 167 | {this.props.children} 168 | 169 |
170 | {footer} 171 |
172 |
173 |
174 |
175 |
, 176 | this.popup, 177 | ) 178 | } 179 | 180 | render() { 181 | return null 182 | } 183 | } 184 | 185 | Drawer.contextTypes = { 186 | form: PropTypes.object, 187 | vertical: PropTypes.bool, 188 | store: PropTypes.object, 189 | }; 190 | 191 | class AntModalBody extends Component { 192 | getChildContext() { 193 | return { form: this.props.context.form, vertical: this.props.context.vertical, store: this.props.context.store } 194 | } 195 | render() { 196 | return ( 197 |
198 | {this.props.children} 199 |
200 | ) 201 | } 202 | } 203 | 204 | AntModalBody.childContextTypes = { 205 | form: PropTypes.object, 206 | vertical: PropTypes.string, 207 | store: PropTypes.object, 208 | } 209 | -------------------------------------------------------------------------------- /app/components/logo/logo.css: -------------------------------------------------------------------------------- 1 | .logo-gather-demo-edit-wrapper { 2 | position: absolute; 3 | bottom: 0; 4 | width: 100%; 5 | background: #f1f1f1; 6 | padding: 0 5%; 7 | line-height: 45px; 8 | } 9 | 10 | .logo-gather-demo-edit-wrapper ul { 11 | display: block; 12 | width: 100%; 13 | overflow: hidden; 14 | } 15 | 16 | .logo-gather-demo-edit-wrapper ul li:first-child { 17 | margin-left: 0; 18 | } 19 | 20 | .logo-gather-demo-edit-wrapper ul li { 21 | float: left; 22 | vertical-align: middle; 23 | margin: 0 5px; 24 | } 25 | 26 | .logo-gather-demo-wrapper { 27 | position: absolute; 28 | z-index: 10; 29 | top: 0; 30 | /*margin:0 auto;*/ 31 | left: 0; 32 | background: transparent; 33 | overflow: hidden; 34 | height: 100%; 35 | width: 100%; 36 | } 37 | 38 | .logo-gather-demo-wrapper .point-wrapper { 39 | position: absolute; 40 | } 41 | 42 | .logo-gather-demo-wrapper .point { 43 | border-radius: 100%; 44 | } 45 | 46 | .logo-gather-demo-wrapper .right-side { 47 | width: 1038px; 48 | height: 280px; 49 | position: absolute; 50 | right: 0; 51 | top: -60px; 52 | bottom: 0; 53 | left: 0; 54 | margin: auto; 55 | } 56 | 57 | .logo-gather-demo-wrapper .right-side * { 58 | pointer-events: none; 59 | } 60 | 61 | @media screen and (max-width: 414px) { 62 | .exhibition-details-demo { 63 | overflow: hidden; 64 | } 65 | 66 | .logo-gather-demo-edit-wrapper { 67 | transform: translateY(100%); 68 | transition: transform .45s ease-in-out; 69 | } 70 | 71 | .logo-gather-demo-edit-wrapper.open{ 72 | transform: translateY(0); 73 | } 74 | 75 | .logo-gather-demo-edit-wrapper .anticon-down{ 76 | transition: transform .45s ease-in-out; 77 | } 78 | 79 | .logo-gather-demo-edit-wrapper.open .anticon-down{ 80 | transform: rotate(180deg); 81 | } 82 | 83 | .logo-gather-demo-edit-wrapper > div { 84 | width: 90%; 85 | line-height: 24px !important; 86 | margin-bottom: 5px; 87 | } 88 | 89 | .exhibition-details-demo .edit-button{ 90 | position: absolute; 91 | top: -20px; 92 | width: 30px; 93 | height: 20px; 94 | border-radius: 30px 30px 0 0; 95 | background: #f1f1f1; 96 | text-align: center; 97 | left: 0; 98 | right: 0; 99 | margin: auto; 100 | box-shadow: 0 -5px 5px rgba(0, 0, 0, 0.15); 101 | } 102 | 103 | .logo-gather-demo-edit-wrapper ul { 104 | margin: 5px auto; 105 | } 106 | 107 | .phone-float-none { 108 | clear: both; 109 | margin-left: 0 !important; 110 | } 111 | 112 | .none { 113 | display: none; 114 | } 115 | 116 | } -------------------------------------------------------------------------------- /app/components/logo/logo.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | // import ReactDOM from 'react-dom' 3 | import { connect } from 'react-redux' 4 | import TweenOne from 'rc-tween-one' 5 | import ticker from 'rc-tween-one/lib/ticker' 6 | import PropTypes from 'prop-types' 7 | import logo from '@images/login.png' 8 | import './logo.css' 9 | 10 | @connect((state, props) => ({ 11 | config: state.config, 12 | })) 13 | 14 | export default class app extends Component { 15 | static propTypes = { 16 | image: PropTypes.string, 17 | w: PropTypes.number, 18 | h: PropTypes.number, 19 | pixSize: PropTypes.number, 20 | pointSizeMin: PropTypes.number, 21 | }; 22 | 23 | static defaultProps = { 24 | image: logo, 25 | // className: 'logo-gather-demo', 26 | w: 1038, 27 | h: 280, 28 | pixSize: 20, 29 | pointSizeMin: 8, 30 | }; 31 | 32 | constructor(props) { 33 | super(props); 34 | this.state = {}; 35 | this.interval = null; 36 | this.gather = true; 37 | this.intervalTime = 9000; 38 | } 39 | 40 | componentDidMount() { 41 | // this.dom = ReactDOM.findDOMNode(this) 42 | this.dom = this.componentDom 43 | this.createPointData(); 44 | } 45 | 46 | componentWillUnmount() { 47 | ticker.clear(this.interval) 48 | this.interval = null 49 | } 50 | 51 | onMouseEnter = () => { 52 | // !this.gather && this.updateTweenData(); 53 | if (!this.gather) { 54 | this.updateTweenData(); 55 | } 56 | this.componentWillUnmount(); 57 | }; 58 | 59 | onMouseLeave = () => { 60 | // this.gather && this.updateTweenData(); 61 | if (this.gather) { 62 | this.updateTweenData(); 63 | } 64 | this.interval = ticker.interval(this.updateTweenData, this.intervalTime); 65 | }; 66 | 67 | setDataToDom(data, w, h) { 68 | this.pointArray = []; 69 | const number = this.props.pixSize; 70 | for (let i = 0; i < w; i += number) { 71 | for (let j = 0; j < h; j += number) { 72 | if (data[((i + (j * w)) * 4) + 3] > 150) { 73 | this.pointArray.push({ x: i, y: j }); 74 | } 75 | } 76 | } 77 | const children = []; 78 | this.pointArray.forEach((item, i) => { 79 | const r = (Math.random() * this.props.pointSizeMin) + this.props.pointSizeMin; 80 | const b = (Math.random() * 0.4) + 0.1; 81 | children.push( 82 | 100 | ); 101 | }); 102 | this.setState({ 103 | children, 104 | boxAnim: { opacity: 0, type: 'from', duration: 800 }, 105 | }, () => { 106 | this.interval = ticker.interval(this.updateTweenData, this.intervalTime); 107 | }); 108 | } 109 | 110 | createPointData = () => { 111 | const { w, h } = this.props; 112 | const canvas = document.getElementById('canvas'); 113 | const ctx = canvas.getContext('2d'); 114 | ctx.clearRect(0, 0, w, h); 115 | canvas.width = this.props.w; 116 | canvas.height = h; 117 | const img = new Image(); 118 | img.onload = () => { 119 | ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h); 120 | const { data } = ctx.getImageData(0, 0, w, h); 121 | this.setDataToDom(data, w, h); 122 | this.dom.removeChild(canvas); 123 | }; 124 | img.crossOrigin = 'anonymous'; 125 | img.src = this.props.image; 126 | }; 127 | 128 | gatherData = () => { 129 | const children = this.state.children && this.state.children.map(item => 130 | React.cloneElement(item, { 131 | animation: { 132 | x: 0, 133 | y: 0, 134 | opacity: 1, 135 | scale: 1, 136 | delay: Math.random() * 500, 137 | duration: 800, 138 | ease: 'easeInOutQuint', 139 | }, 140 | })); 141 | this.setState({ children }); 142 | }; 143 | 144 | disperseData = () => { 145 | const rect = this.dom.getBoundingClientRect(); 146 | const sideRect = this.sideBox.getBoundingClientRect(); 147 | const sideTop = sideRect.top - rect.top; 148 | const sideLeft = sideRect.left - rect.left; 149 | const children = this.state.children.map(item => 150 | React.cloneElement(item, { 151 | animation: { 152 | x: (Math.random() * rect.width) - sideLeft - item.props.style.left, 153 | y: (Math.random() * rect.height) - sideTop - item.props.style.top, 154 | opacity: (Math.random() * 0.4) + 0.1, 155 | scale: (Math.random() * 2.4) + 0.1, 156 | duration: (Math.random() * 500) + 500, 157 | ease: 'easeInOutQuint', 158 | }, 159 | })); 160 | 161 | this.setState({ 162 | children, 163 | }); 164 | }; 165 | 166 | updateTweenData = () => { 167 | // this.dom = ReactDOM.findDOMNode(this); 168 | this.dom = this.componentDom 169 | // this.sideBox = ReactDOM.findDOMNode(this.sideBoxComp); 170 | this.sideBox = document.querySelector('.right-side'); 171 | ((this.gather && this.disperseData) || this.gatherData)(); 172 | this.gather = !this.gather; 173 | }; 174 | 175 | render() { 176 | return (
this.componentDom = c}> 177 | 178 | { 184 | this.sideBoxComp = c; 185 | }} 186 | > 187 | {this.state.children} 188 | 189 |
); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /app/components/tableList/tableList.js: -------------------------------------------------------------------------------- 1 | /* 2 | 如果要使用不回行的table,那么就要设置table的className为nowrap,并且不能对td设置特定的宽度,且scroll={{ y: true, x: true }}的X值必须为true 3 | */ 4 | 5 | import React, { Component } from 'react' 6 | import { Table, Pagination } from 'antd' 7 | 8 | export default class TableList extends Component { 9 | componentDidMount() { 10 | this.tableWidthAdaptive() 11 | } 12 | 13 | componentWillUnmount() { 14 | clearInterval(this.t) 15 | } 16 | 17 | // 动态计算td的宽度 18 | tableWidthAdaptive = () => { 19 | if (this.props.className && this.props.className.indexOf('nowrap') > -1) { 20 | this.t = setInterval(() => { // 通过定时器循环的方式,看看真实节点是否加载到dom中了 21 | const tds = document.querySelector('.ant-table-row') && document.querySelector('.ant-table-row').querySelectorAll('td') 22 | const ths = document.querySelectorAll('.ant-table-header th') 23 | if (tds && tds.length) { 24 | clearInterval(this.t) 25 | for (let i = 0; i < tds.length; i += 1) { 26 | const tdw = tds[i].offsetWidth 27 | const thw = ths[i].offsetWidth 28 | const w = (tdw > thw) ? tdw : thw 29 | tds[i].style.minWidth = `${w}px` 30 | ths[i].style.minWidth = `${w}px` 31 | } 32 | } 33 | }, 100) 34 | } 35 | } 36 | 37 | render() { 38 | const { 39 | currentPage, 40 | pageSize, 41 | totalCount, 42 | onShowSizeChange, 43 | onChange, 44 | columns, 45 | } = this.props 46 | const hasMultiHead = columns.filter(one => !!one.children).length > 0 47 | return ( 48 |
49 | 56 | { currentPage ? 57 | `共 ${_totalCount} 条`} 64 | current={currentPage || 1} 65 | pageSize={pageSize || 10} 66 | {...this.props} 67 | /> : null 68 | } 69 | 70 | ) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/configs/__mocks__/ajax.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import fetchUserList from '../../mocks/apis/sys/userManage/fetchUserList'; 3 | import fetchUserDepttList from '../../mocks/apis/sys/userManage/fetchUserDepttList'; 4 | import fetchButtonList from '../../mocks/apis/sys/roleManage/fetchButtonList'; 5 | import fetchRoleList from '../../mocks/apis/sys/userManage/fetchRoleList'; 6 | import fetchTreeList from '../../mocks/apis/sys/roleManage/fetchTreeList'; 7 | import fetchModuleListInRole from '../../mocks/apis/sys/roleManage/fetchModuleListInRole'; 8 | 9 | // 创建发起api的启动器 10 | export const createApi = function (api, type) { 11 | fetchUserList.data.totalCount = null; 12 | if (type == 'fetchUserList') { 13 | return backState(fetchUserList); 14 | } 15 | if (type == 'fetchUserDepttList') { 16 | return backState(fetchUserDepttList); 17 | } 18 | if (type == 'fetchButtonList') { 19 | return backState(fetchButtonList); 20 | } 21 | if (type == 'fetchRoleList') { 22 | return backState(fetchRoleList); 23 | } 24 | if (type == 'fetchTreeList') { 25 | return backState(fetchTreeList); 26 | } 27 | fetchModuleListInRole.data.list[0].status = true; 28 | if (type == 'fetchModuleListInRole') { 29 | return backState(fetchModuleListInRole); 30 | } 31 | const param = { 32 | data: { 33 | list: [], 34 | }, 35 | msg: '操作成功', 36 | status: 1, 37 | }; 38 | return backState(param); 39 | }; 40 | function backState(param) { 41 | return (data, callback, callback2) => { 42 | callback(param); 43 | if (callback2) { 44 | callback2(param); 45 | } 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /app/configs/common.js: -------------------------------------------------------------------------------- 1 | 2 | import { hashHistory } from 'react-router' 3 | import { message } from 'antd' 4 | import { loginByTicket, staff, login as loginApi, getBtns } from '@apis/common' 5 | 6 | export function parseQueryString(url) { 7 | const obj = {} 8 | if (url.indexOf('?') !== -1) { 9 | const str = url.split('?')[1] 10 | const strs = str.split('&') 11 | strs.map((item, i) => { 12 | const arr = strs[i].split('=') 13 | /* eslint-disable */ 14 | obj[arr[0]] = arr[1] 15 | }) 16 | } 17 | return obj 18 | } 19 | 20 | /* --------------验证ticket并获取用户信息和菜单信息 --------------*/ 21 | const _fetchLoginByTicket = async ticket => new Promise((resolve) => { 22 | loginByTicket({ ticket }, (response) => { 23 | resolve(response.data) 24 | }, (response) => { 25 | const obj = parseQueryString(window.location.href) 26 | console.log(obj) 27 | if (obj.ticket || obj.mode) { 28 | message.info('登录过期或服务不可用') 29 | } else { 30 | hashHistory.replace('/login') 31 | } 32 | }) 33 | }) 34 | 35 | const _fetchStaff = () => new Promise((resolve) => { 36 | staff({}, (res) => { 37 | const { data } = res 38 | sessionStorage.setItem('userinfo', JSON.stringify(data)) 39 | resolve() 40 | }) 41 | }) 42 | 43 | /* eslint-disable no-use-before-define */ 44 | export const isHasCurrentMenu = (allMenu, pathname) => compare(allMenu, pathname) 45 | /* eslint-enable no-use-before-define */ 46 | 47 | 48 | const _fetchNav = pathname => new Promise((resolve) => { 49 | // try { 50 | // if (JSON.parse(sessionStorage.getItem('menu')).length > 0) { 51 | // resolve() 52 | // return 53 | // } 54 | // } catch (e) { e } 55 | nav({}, (response) => { 56 | const { list } = response.data 57 | if (list.length === 0) { 58 | message.info('该账户没有任何菜单权限,请联系管理员') 59 | hashHistory.replace('/login') 60 | // this.setState({ loading: false }) 61 | return 62 | } 63 | sessionStorage.setItem('menu', JSON.stringify(list)) 64 | // TODO:添加完菜单权限后,需要增加以下代码 65 | // if (pathname !== '/' && !isHasCurrentMenu(list, pathname)) { 66 | // if (process.env.NODE_ENV === 'production') { 67 | // hashHistory.replace('/') 68 | // } 69 | // } 70 | resolve() 71 | }) 72 | }) 73 | 74 | /* 不管是否含有ticket参数都会在顶层组件中调用 */ 75 | export const validateTickit = async function validateTickit({ query, pathname }, callback) { 76 | const { ticket } = query 77 | if (ticket) { 78 | const loginInfo = await _fetchLoginByTicket(ticket) 79 | sessionStorage.setItem('token', loginInfo.token) 80 | // sessionStorage.setItem('isLeftNavMini', false) 81 | } else { 82 | /** 83 | * 仅存在于以下两种情况: 84 | * 1. 未登录,退出到登录页面进行登录操作,在登录时获取菜单并存到sessionStorage中,再进行页面跳转,执行此代码时只需要请求staff信息 85 | * 2. 登录过,刷新页面后执行此代码,认为上次登录时已经获取过菜单并已存到sessionStorage中,所以只需要请求staff信息 86 | * (FIXME:网速缓慢的情况下,可能存在登录token拿到后,菜单数据返回前,直接输入url访问页面的情况,所以会导致获取不到菜单) 87 | */ 88 | // await _fetchStaff() 89 | // if (typeof callback === 'function')callback() 90 | /* 91 | _fetchStaff() 92 | _fetchNav(callback) 93 | */ 94 | } 95 | 96 | const _a = _fetchStaff() 97 | const _b = _fetchNav(pathname) 98 | await _a 99 | await _b 100 | if (typeof callback === 'function') callback() 101 | } 102 | /* -----------------------------------------------------------------------------*/ 103 | 104 | /* -------------- 存储当前页面的菜单id到sessionStorage的menuId属性上 --------------*/ 105 | // 比较方法 106 | function compare(children, pathname) { 107 | for (let i = 0; i < children.length; i += 1) { 108 | const item = children[i] 109 | /* eslint-disable no-useless-escape */ 110 | const _resKey = `${item.resKey.replace(/[\$\.\?\+\^\[\]\(\)\{\}\|\\\/]/g, '\\$&').replace(/\*\*/g, '[\\w|\\W]+').replace(/\*/g, '[^\\/]+')}$` 111 | /* eslint-enable no-useless-escape */ 112 | if (new RegExp(_resKey).test(pathname)) { 113 | sessionStorage.setItem('menuId', item.id) 114 | return true 115 | } else if (item.children) { 116 | if (compare(item.children, pathname)) return true 117 | } 118 | } 119 | return false 120 | } 121 | 122 | // 获取菜单id 123 | export const getMenuId = (navs, pathname) => { 124 | if (navs && navs.length > 0) { 125 | compare(navs, pathname) 126 | } 127 | } 128 | /* -----------------------------------------------------------------------------*/ 129 | 130 | /* ------------------------- 登陆 -------------------------*/ 131 | export const login = (params, success, failure) => { 132 | loginApi(params, (response) => { 133 | sessionStorage.setItem('token', response.data.token) 134 | localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage)) 135 | // _fetchNav().then(() => { success() }) 136 | if (typeof success === 'function') success(response) 137 | }, (response) => { 138 | if (typeof failure === 'function') failure(response) 139 | }) 140 | } 141 | /* -------------------------------------------------------*/ 142 | 143 | // 获取按钮 144 | export const fetchBtns = (component, cb) => { 145 | getBtns({ id: sessionStorage.getItem('menuId') }, (res) => { 146 | const result = {} 147 | res.data.list.map((item) => { 148 | result[item.resKey] = true 149 | }) 150 | typeof (cb) === 'function' ? cb(result) : '' 151 | }) 152 | } 153 | 154 | // 进入路由的判断 155 | export const isLogin = (nextState, replaceState) => { 156 | if (nextState.location.query && nextState.location.query.ticket) { // 如果url自带ticket 157 | sessionStorage.setItem('token', 'ticket') 158 | } 159 | if (nextState.location.query && nextState.location.query.key) { // 如果url自带key 160 | sessionStorage.setItem('token', 'key') 161 | } 162 | const token = sessionStorage.getItem('token') 163 | if (!token) { // 没有token,那就返回首页 164 | replaceState('/login') 165 | } 166 | } 167 | 168 | 169 | // 异步请求需要走redux的方式 170 | export const createAjaxAction = (createdApi, startAction, endAction) => (request = {}, resolve, reject, config) => (dispatch) => { 171 | if (startAction) dispatch(startAction({ req: request, res: {} })) 172 | const _resolve = (response) => { 173 | if (endAction) dispatch(endAction({ req: request, res: response })) 174 | if (resolve) resolve(response) 175 | } 176 | return createdApi(request, _resolve, reject, config) 177 | } 178 | -------------------------------------------------------------------------------- /app/configs/config.js: -------------------------------------------------------------------------------- 1 | 2 | export const set = 'set$' 3 | export const brandName = 'React' // slogan 4 | 5 | // 开发环境默认配置 6 | let _serverIp = 'http://192.168.1.222' 7 | let _port = '1111' 8 | let _baseURL = `${_serverIp}:${_port}` 9 | let _mockURL = 'http://localhost:1111/' 10 | 11 | if (process.env.NODE_ENV === 'testing') { // 测试环境 12 | _mockURL = 'http://localhost:1111/' 13 | _port = '1111' 14 | _baseURL = `${_serverIp}:${_port}` 15 | } 16 | if (process.env.NODE_ENV === 'production') { // 发布环境 17 | _port = '1111' 18 | _serverIp = 'http://192.168.1.123' 19 | _baseURL = `${_serverIp}:${_port}` 20 | } 21 | 22 | export const serverIp = _serverIp 23 | export const path = '/mock' 24 | export const timeout = '15000' // 接口超时限制(ms) 25 | export const baseURL = _baseURL 26 | export const mockURL = _mockURL 27 | -------------------------------------------------------------------------------- /app/configs/regular.config.js: -------------------------------------------------------------------------------- 1 | // 常用的正则规则 2 | // eslint-disable-next-line 3 | export const regExpConfig = { 4 | IDcard: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/, // 身份证 5 | mobile: /^1([3|4|5|7|8|])\d{9}$/, // 手机号码 6 | telephone: /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/, // 固定电话 7 | num: /^[0-9]*$/, // 数字 8 | phoneNo: /(^1([3|4|5|7|8|])\d{9}$)|(^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$)/, // 电话或者手机 9 | policeNo: /^[0-9A-Za-z]{4,10}$/, // 账号4-10位数字或字母组成 10 | pwd: /^[0-9A-Za-z]{6,16}$/, // 密码由6-16位数字或者字母组成 11 | isNumAlpha: /^[0-9A-Za-z]*$/, // 字母或数字 12 | isAlpha: /^[a-zA-Z]*$/, // 是否字母 13 | isNumAlphaCn: /^[0-9a-zA-Z\u4E00-\uFA29]*$/, // 是否数字或字母或汉字 14 | isPostCode: /^[\d-]*$/i, // 是否邮编 15 | isNumAlphaUline: /^[0-9a-zA-Z_]*$/, // 是否数字、字母或下划线 16 | isNumAndThanZero: /^([1-9]\d*(\.\d+)?|0)$/, // 是否为整数且大于0/^[1-9]\d*(\.\d+)?$/ 17 | isNormalEncode: /^(\w||[\u4e00-\u9fa5]){0,}$/, // 是否为非特殊字符(包括数字字母下划线中文) 18 | isTableName: /^[a-zA-Z][A-Za-z0-9#$_-]{0,29}$/, // 表名 19 | isInt: /^-?\d+$/, // 整数 20 | isTableOtherName: /^[\u4e00-\u9fa5]{0,20}$/, // 别名 21 | // isText_30: /^(\W|\w{1,2}){0,15}$/, // 正则 22 | // isText_20: /^(\W|\w{1,2}){0,10}$/, // 正则 23 | isText_30: /^(\W|\w{1}){0,30}$/, // 匹配30个字符,字符可以使字母、数字、下划线、非字母,一个汉字算1个字符 24 | isText_50: /^(\W|\w{1}){0,50}$/, // 匹配50个字符,字符可以使字母、数字、下划线、非字母,一个汉字算1个字符 25 | isText_20: /^(\W|\w{1}){0,20}$/, // 匹配20个字符,字符可以使字母、数字、下划线、非字母,一个汉字算1个字符 26 | isText_100: /^(\W|\w{1}){0,100}$/, // 匹配100个字符,字符可以使字母、数字、下划线、非字母,一个汉字算1个字符 27 | isText_250: /^(\W|\w{1}){0,250}$/, // 匹配250个字符,字符可以使字母、数字、下划线、非字母,一个汉字算1个字符 28 | isNotChina: /^[^\u4e00-\u9fa5]{0,}$/, // 不为中文 IDcard: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/, // 身份证 29 | IDcardAndAdmin: /^(([1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X))|(admin))$/, // 身份证或者是admin账号 30 | IDcardTrim: /^\s*(([1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3})|([1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X))|(admin))\s*$/, // 身份证 31 | num1: /^[1-9]*$/, // 数字 32 | companyNO: /^qqb_[0-9a-zA-Z_]{1,}$/, // 公司人员账号 33 | imgType: /image\/(png|jpg|jpeg|gif)$/, // 上传图片类型 34 | isChina: /^[\u4e00-\u9fa5]{2,8}$/, 35 | isNozeroNumber: /^\+?[1-9]\d*$/, // 大于零的正整数 36 | float: /^\d+(\.?|(\.\d+)?)$/, // 匹配正整数或者小数 或者0.这个特殊值 37 | } 38 | 39 | -------------------------------------------------------------------------------- /app/configs/router.config.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Router, Route, IndexRoute, hashHistory/* , Redirect */ } from 'react-router' 3 | import { isLogin } from '@configs/common' 4 | import { set } from '@config' 5 | 6 | import * as base from '@pages/base' // 基础 7 | import * as sysSet from '@pages/set' // 设置中心-系统设置 8 | import * as menu from '@pages/menu' // 菜单 9 | 10 | export default () => ( 11 | 12 | 13 | 14 | 15 | {/* */} 16 | {/** *菜单 开始 */} 17 | 18 | 19 | {/** *菜单 结束 */} 20 | {/** *系统设置 开始 */} 21 | 22 | 23 | 24 | {/** *系统设置 结束 */} 25 | 26 | 27 | 28 | 29 | ) 30 | -------------------------------------------------------------------------------- /app/configs/socket.js: -------------------------------------------------------------------------------- 1 | import io from 'socket.io-client'; 2 | // import queryString from 'query-string'; 3 | 4 | // const parsed = queryString.parse(window.location.search); 5 | 6 | class Socket { 7 | constructor(ua = 'control', disable = false) { 8 | this.uid = this.random(); 9 | // this.group = parsed.group || 'prod'; 10 | this.disable = disable; 11 | this.socket = io('http://47.102.198.102:8080/', { 12 | transports: ['websocket'], 13 | query: { 14 | ua, 15 | group: 'prod', 16 | }, 17 | }); 18 | this.isSpeaker = false; 19 | this.speakerHandlers = []; 20 | 21 | this.socket.on('room', ({ speaker }) => { 22 | this.isSpeaker = speaker === this.socket.id; 23 | this.speakerHandlers.forEach((cb) => { 24 | if (typeof cb === 'function') { 25 | cb(this.isSpeaker); 26 | } 27 | }); 28 | }); 29 | } 30 | 31 | random = () => Date.now() + Math.random(); 32 | 33 | registerSpeakerHandler = (callback) => { 34 | this.unregisterSpeakerHandler(callback); 35 | this.speakerHandlers.push(callback); 36 | }; 37 | 38 | unregisterSpeakerHandler = (callback) => { 39 | let i = -1; 40 | this.speakerHandlers.some((cb, index) => { 41 | if (cb === callback) { 42 | i = index; 43 | return true; 44 | } 45 | return false; 46 | }); 47 | if (i >= 0) { 48 | this.speakerHandlers.splice(i, 1); 49 | } 50 | }; 51 | 52 | dispatch = (data) => { 53 | // if (!this.isSpeaker && !data.speaker) { 54 | // return Promise.resolve(); 55 | // } 56 | 57 | data.uid = this.uid; 58 | data.timestamp = this.random(); 59 | this.socket.emit('dispatch', data); 60 | if (data.speaker) { 61 | return new Promise((resolve, reject) => { 62 | this.registerSpeakerHandler((r) => { 63 | if (r) { 64 | resolve(); 65 | } else { 66 | reject(); 67 | } 68 | }); 69 | }); 70 | } 71 | return new Promise((resolve) => { 72 | const callback = (res) => { 73 | if (this.uid === res.uid && res.timestamp === data.timestamp) { 74 | this.socket.off('dispatch', callback); 75 | resolve(); 76 | } 77 | }; 78 | this.socket.on('dispatch', callback); 79 | }); 80 | }; 81 | 82 | sent = (data, force) => { 83 | if (!this.isSpeaker && !force) { 84 | return; 85 | } 86 | data.uid = this.uid; 87 | data.group = this.group; 88 | this.socket.emit('msg', data); 89 | }; 90 | 91 | on = (name, call) => { 92 | if (!this.disable) { 93 | this.socket.on(name, call); 94 | } 95 | }; 96 | 97 | close = () => { 98 | this.socket.close(); 99 | }; 100 | 101 | send = (data) => { 102 | this.dispatch({ 103 | source: 'control', 104 | targets: ['control'], 105 | type: 'dispatch', 106 | payload: data, 107 | }) 108 | } 109 | } 110 | 111 | const socket = new Socket('control', window.location.pathname === '/console'); 112 | export const MsgSocket = Socket; 113 | 114 | export default socket; 115 | -------------------------------------------------------------------------------- /app/images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/default.png -------------------------------------------------------------------------------- /app/images/icon/menu/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/default.png -------------------------------------------------------------------------------- /app/images/icon/menu/icon_duty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/icon_duty.png -------------------------------------------------------------------------------- /app/images/icon/menu/icon_pgmb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/icon_pgmb.png -------------------------------------------------------------------------------- /app/images/icon/menu/icon_pgmx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/icon_pgmx.png -------------------------------------------------------------------------------- /app/images/icon/menu/icon_statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/icon_statistics.png -------------------------------------------------------------------------------- /app/images/icon/menu/icon_xtxg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/icon_xtxg.png -------------------------------------------------------------------------------- /app/images/icon/menu/moduleManage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/moduleManage.png -------------------------------------------------------------------------------- /app/images/icon/menu/roleManage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/roleManage.png -------------------------------------------------------------------------------- /app/images/icon/menu/userManage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/icon/menu/userManage.png -------------------------------------------------------------------------------- /app/images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/login.png -------------------------------------------------------------------------------- /app/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/logo.png -------------------------------------------------------------------------------- /app/images/navcontrol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/navcontrol.png -------------------------------------------------------------------------------- /app/images/photo_default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/photo_default.jpg -------------------------------------------------------------------------------- /app/images/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/user.jpg -------------------------------------------------------------------------------- /app/images/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/images/user.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React 6 | 7 | 8 |
9 | <% for(var i = 0; i < htmlWebpackPlugin.options.dlls.length;i++){%> 10 | 11 | <%}%> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/middleware/configureStore.js: -------------------------------------------------------------------------------- 1 | 2 | import { createStore, applyMiddleware } from 'redux' 3 | import thunkMiddleware from 'redux-thunk' 4 | import rootReducer from '@reducers' 5 | import { logger, /* router, */ reduxRouterMiddleware } from './index' 6 | 7 | const nextReducer = require('@reducers') 8 | 9 | export default function configure(initialState) { 10 | // console.log('initialState', initialState) 11 | const create = window.devToolsExtension 12 | ? window.devToolsExtension()(createStore) 13 | : createStore 14 | 15 | const createStoreWithMiddleware = applyMiddleware( 16 | reduxRouterMiddleware, 17 | thunkMiddleware, 18 | logger, 19 | // router, 20 | )(create) 21 | 22 | const store = createStoreWithMiddleware(rootReducer, initialState) 23 | 24 | if (module.hot) { 25 | module.hot.accept('@reducers', () => { 26 | store.replaceReducer(nextReducer) 27 | }) 28 | } 29 | 30 | return store 31 | } 32 | -------------------------------------------------------------------------------- /app/middleware/history.js: -------------------------------------------------------------------------------- 1 | import { useRouterHistory } from 'react-router' 2 | import createHashHistory from 'history/lib/createHashHistory' 3 | 4 | // export default useRouterHistory(createHashHistory)() 5 | const history = useRouterHistory(createHashHistory)({}) 6 | export default history 7 | -------------------------------------------------------------------------------- /app/middleware/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { routerMiddleware } from 'react-router-redux' 3 | import logger from './logger' 4 | import history from './history' 5 | // import router from './router' 6 | 7 | const reduxRouterMiddleware = routerMiddleware(history) 8 | 9 | export { 10 | reduxRouterMiddleware, 11 | logger, 12 | // router, 13 | } 14 | -------------------------------------------------------------------------------- /app/middleware/logger.js: -------------------------------------------------------------------------------- 1 | 2 | /* eslint-disable */ 3 | export default store => next => (action) => { 4 | // console.log(action) 5 | return next(action) 6 | } 7 | -------------------------------------------------------------------------------- /app/middleware/router.js: -------------------------------------------------------------------------------- 1 | import { browserHistory } from 'react-router' 2 | import { routerMiddleware } from 'react-router-redux' 3 | 4 | export default routerMiddleware(browserHistory) 5 | -------------------------------------------------------------------------------- /app/mocks/apis/base/index.js: -------------------------------------------------------------------------------- 1 | const login = require('./login') 2 | const logout = require('./logout') 3 | const staff = require('./staff') 4 | const menu = require('./menu') 5 | 6 | module.exports = { login, logout, staff, menu } 7 | -------------------------------------------------------------------------------- /app/mocks/apis/base/login.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | data: { 3 | ticket: 'ticket', 4 | token: '1111', 5 | }, 6 | msg: '操作成功', 7 | status: 1, 8 | } 9 | -------------------------------------------------------------------------------- /app/mocks/apis/base/logout.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | }, 5 | msg: '退出成功!', 6 | status: 1, 7 | } 8 | -------------------------------------------------------------------------------- /app/mocks/apis/base/menu.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | list: [ 5 | 6 | { 7 | id: 10063, 8 | resName: '概览', 9 | resKey: 'desk$/index', 10 | resIcon: 'pgmb', 11 | }, 12 | // { 13 | // id: 10064, 14 | // resName: 'socket接收', 15 | // resKey: 'socketReceive', 16 | // resIcon: 'pgmb', 17 | // }, 18 | { 19 | id: 600110233, 20 | resName: '图表', 21 | resKey: 'echarts', 22 | resIcon: 'statistics', 23 | }, 24 | { 25 | id: 100631, 26 | resName: '编辑器', 27 | resKey: 'editor', 28 | resIcon: 'duty', 29 | }, 30 | 31 | { 32 | id: 10062, 33 | resName: '设置中心', 34 | children: [ 35 | { 36 | id: 10108, 37 | resName: '用户管理', 38 | resKey: 'set$/userManage', 39 | resIcon: 'userManage', 40 | }, 41 | { 42 | id: 10109, 43 | resName: '角色管理', 44 | resKey: 'set$/roleManage', 45 | resIcon: 'roleManage', 46 | }, 47 | { 48 | id: 10110, 49 | resName: '权限管理', 50 | resKey: 'set$/moduleManage', 51 | resIcon: 'moduleManage', 52 | }, 53 | ], 54 | resKey: 'set$', 55 | resIcon: 'xtxg', 56 | }, 57 | ], 58 | }, 59 | msg: '操作成功', 60 | status: 1, 61 | } 62 | -------------------------------------------------------------------------------- /app/mocks/apis/base/staff.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | id: 1, 5 | username: 'admin', 6 | password: '121212', 7 | chineseName: '管理员', 8 | idcardNo: '000000000000000000', 9 | policeCode: '000000', 10 | deptCode: '370200000000', 11 | gender: 1, 12 | email: 'abc@abc.com', 13 | phoneNo: '15100000005', 14 | duty: '超级管理员', 15 | address: 'address', 16 | remark: 'remarl', 17 | type: 0, 18 | status: 0, 19 | roles: [ 20 | { 21 | id: 1, 22 | roleName: '超级管理员', 23 | resources: [], 24 | }, 25 | ], 26 | deptName: '杭州市', 27 | ticket: '.2XxGlEuidOmAoYIdSo6pQIlGbQSh83U7p4eJsoTO-70', 28 | gxdwdm: '370200000000', 29 | deptLevel: '1', 30 | defaultDeptCode: '370200000000', 31 | defaultXzqhCode: '370200', 32 | }, 33 | msg: '操作成功', 34 | status: 1, 35 | } 36 | -------------------------------------------------------------------------------- /app/mocks/apis/fail.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | 5 | }, 6 | msg: '操作失败', 7 | status: 0, 8 | } 9 | -------------------------------------------------------------------------------- /app/mocks/apis/success.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | 5 | }, 6 | msg: '操作成功', 7 | status: 1, 8 | } 9 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/moduleManage/fetchModuleDetail.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | id: 2, 5 | resName: '基础信息', 6 | resType: 1, 7 | resModule: 'inedx', 8 | resKey: 'menu2', 9 | resIcon: 'null', 10 | sort: 1, 11 | status: 0, 12 | }, 13 | msg: '操作成功', 14 | status: 1, 15 | } 16 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/moduleManage/fetchModuleList.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | list: [ 5 | { 6 | id: 10060, 7 | resName: '工作台', 8 | children: [ 9 | { 10 | id: 10063, 11 | resName: '概览', 12 | resKey: 'desk$/index', 13 | resIcon: 'cleanAccess', 14 | }, 15 | ], 16 | resKey: 'desk$', 17 | resIcon: 'home', 18 | }, 19 | { 20 | id: 10062, 21 | resName: '设置中心', 22 | children: [ 23 | { 24 | id: 10108, 25 | resName: '用户管理', 26 | resKey: 'set$/userManage', 27 | resIcon: 'userManage', 28 | }, 29 | { 30 | id: 10109, 31 | resName: '角色管理', 32 | resKey: 'set$/roleManage', 33 | resIcon: 'roleManage', 34 | }, 35 | { 36 | id: 10110, 37 | resName: '权限管理', 38 | resKey: 'set$/moduleManage', 39 | resIcon: 'unitCount', 40 | }, 41 | ], 42 | resKey: 'set$', 43 | resIcon: 'set', 44 | }, 45 | ], 46 | }, 47 | msg: '操作成功', 48 | status: 1, 49 | } 50 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/moduleManage/index.js: -------------------------------------------------------------------------------- 1 | const fetchModuleList = require('./fetchModuleList') 2 | const fetchModuleDelete = require('../../success') 3 | const fetchModuleDetail = require('./fetchModuleDetail') 4 | const fetchChangeModuleStatus = require('../../success') 5 | const fetchModuleUpdateDetail = require('../../success') 6 | const fetchModuleAdd = require('../../success') 7 | 8 | 9 | module.exports = { 10 | fetchModuleList, 11 | fetchModuleDelete, 12 | fetchModuleDetail, 13 | fetchChangeModuleStatus, 14 | fetchModuleUpdateDetail, 15 | fetchModuleAdd, 16 | } 17 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/roleManage/fetchButtonList.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | list: [ 5 | { 6 | id: 134, 7 | resName: '新增附属区苑', 8 | resType: 3, 9 | parentId: 4, 10 | roleEntities: [], 11 | resKey: 'gardenAdd', 12 | sort: 0, 13 | status: 0, 14 | }, 15 | { 16 | id: 137, 17 | resName: '新增附属区苑1', 18 | resType: 3, 19 | parentId: 4, 20 | roleEntities: [], 21 | resKey: 'gardenAdd', 22 | sort: 0, 23 | status: 0, 24 | }, 25 | ], 26 | }, 27 | msg: '操作成功', 28 | status: 1, 29 | } 30 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/roleManage/fetchModuleListInRole.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | data: { 3 | list: [ 4 | { 5 | id: 10060, 6 | resName: '工作台', 7 | children: [ 8 | { 9 | id: 10063, 10 | resName: '概览', 11 | resKey: 'desk$/index', 12 | resIcon: 'cleanAccess', 13 | resType: 1, 14 | status: 0, 15 | parentId: 10060, 16 | }, 17 | ], 18 | resKey: 'desk$', 19 | resIcon: 'home', 20 | resType: 1, 21 | status: 0, 22 | }, 23 | { 24 | id: 10062, 25 | resName: '设置中心', 26 | children: [ 27 | { 28 | id: 10108, 29 | resName: '用户管理', 30 | resKey: 'set$/userManage', 31 | resIcon: 'userManage', 32 | parentId: 10062, 33 | children: [ 34 | { 35 | id: 11003, 36 | resName: '看看', 37 | resKey: 'desk$/index', 38 | resIcon: 'cleanAccess', 39 | parentId: 10108, 40 | children: [ 41 | { 42 | id: 11004, 43 | resName: '测试', 44 | resKey: 'desk$/index', 45 | resIcon: 'cleanAccess', 46 | parentId: 11003, 47 | }, 48 | ], 49 | }, 50 | ], 51 | }, 52 | { 53 | id: 10109, 54 | resName: '角色管理', 55 | resKey: 'set$/roleManage', 56 | resIcon: 'roleManage', 57 | parentId: 10062, 58 | }, 59 | { 60 | id: 10110, 61 | resName: '权限管理', 62 | resKey: 'set$/moduleManage', 63 | resIcon: 'unitCount', 64 | parentId: 10062, 65 | }, 66 | ], 67 | resKey: 'set$', 68 | resIcon: 'set', 69 | resType: 1, 70 | status: 0, 71 | }, 72 | ], 73 | }, 74 | msg: '', 75 | errorCode: '', 76 | status: 1, 77 | }; 78 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/roleManage/fetchRoleDetail.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | id: 2, 5 | roleName: '超级管理员', 6 | sort: 0, 7 | type: 0, 8 | resourceIds: [ 9 | 10060, 10 | 10063, 11 | 10062, 12 | 10108, 13 | 10109, 14 | 10110, 15 | ], 16 | }, 17 | msg: '操作成功', 18 | errorCode: '', 19 | status: 1, 20 | } 21 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/roleManage/fetchTreeList.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | data: { 3 | list: [ 4 | { 5 | id: 10060, 6 | resName: '工作台', 7 | children: [ 8 | { 9 | id: 10063, 10 | resName: '概览', 11 | resKey: 'desk$/index', 12 | resIcon: 'cleanAccess', 13 | parentId: 10060, 14 | }, 15 | ], 16 | resKey: 'desk$', 17 | resIcon: 'home', 18 | }, 19 | { 20 | id: 10062, 21 | resName: '设置中心', 22 | children: [ 23 | { 24 | id: 10108, 25 | resName: '用户管理', 26 | resKey: 'set$/userManage', 27 | resIcon: 'userManage', 28 | parentId: 10062, 29 | buttons: [ 30 | { 31 | id: 432, 32 | resName: '上传照片', 33 | resType: 3, 34 | parentId: 427, 35 | resKey: 'upload', 36 | status: 0, 37 | }, 38 | { 39 | id: 433, 40 | resName: '查看照片', 41 | resType: 3, 42 | parentId: 427, 43 | resKey: 'view', 44 | status: 0, 45 | }, 46 | { 47 | id: 434, 48 | resName: '删除照片', 49 | resType: 3, 50 | parentId: 427, 51 | resKey: 'delete', 52 | status: 0, 53 | }, 54 | ], 55 | }, 56 | { 57 | id: 10109, 58 | resName: '角色管理', 59 | resKey: 'set$/roleManage', 60 | resIcon: 'roleManage', 61 | parentId: 10062, 62 | }, 63 | { 64 | id: 10110, 65 | resName: '权限管理', 66 | resKey: 'set$/moduleManage', 67 | resIcon: 'unitCount', 68 | parentId: 10062, 69 | }, 70 | ], 71 | resKey: 'set$', 72 | resIcon: 'set', 73 | }, 74 | ], 75 | }, 76 | msg: '', 77 | errorCode: '', 78 | status: 1, 79 | }; 80 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/roleManage/index.js: -------------------------------------------------------------------------------- 1 | const fetchRoleAdd = require('../../success') 2 | const fetchRoleUpdate = require('../../success') 3 | const fetchRoleDelete = require('../../success') 4 | const fetchUpdateRoleRes = require('../../success') 5 | const fetchTreeList = require('./fetchTreeList') 6 | const fetchModuleListInRole = require('./fetchModuleListInRole') 7 | const fetchRoleDetail = require('./fetchRoleDetail') 8 | const fetchButtonList = require('./fetchButtonList') 9 | const fetchRoleDeletePeople = require('../../success') 10 | const fetchUpdateButton = require('../../success') 11 | 12 | 13 | module.exports = { 14 | fetchRoleAdd, 15 | fetchRoleUpdate, 16 | fetchRoleDelete, 17 | fetchUpdateRoleRes, 18 | fetchTreeList, 19 | fetchModuleListInRole, 20 | fetchRoleDetail, 21 | fetchButtonList, 22 | fetchRoleDeletePeople, 23 | fetchUpdateButton, 24 | } 25 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/userManage/fetchRoleList.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | list: [ 5 | { 6 | id: 1, 7 | roleName: '超级管理员', 8 | sort: 0, 9 | type: 0, 10 | resources: [], 11 | }, 12 | { 13 | id: 10080, 14 | roleName: '开发账号', 15 | sort: 2, 16 | resources: [], 17 | }, 18 | { 19 | id: 10060, 20 | roleName: '测试', 21 | sort: 3, 22 | resources: [], 23 | }, 24 | { 25 | id: 10100, 26 | roleName: '演示账号', 27 | sort: 3, 28 | resources: [], 29 | }, 30 | ], 31 | }, 32 | msg: '', 33 | errorCode: '', 34 | status: 1, 35 | } 36 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/userManage/fetchUserDepttList.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | list: [ 5 | { 6 | id: '1', 7 | children: [ 8 | { 9 | id: '10416', 10 | parentCode: '370200000000', 11 | children: [ 12 | { 13 | id: '10541', 14 | parentCode: '370202000000', 15 | deptName: '文一路', 16 | deptCode: '370202140000', 17 | }, 18 | { 19 | id: '10401', 20 | parentCode: '370202000000', 21 | deptName: '文二路', 22 | deptCode: '370202150000', 23 | }, 24 | { 25 | id: '10398', 26 | parentCode: '370202000000', 27 | children: [ 28 | { 29 | id: '10628', 30 | parentCode: '370202230000', 31 | deptName: '文三路', 32 | deptCode: '370202230001', 33 | }, 34 | { 35 | id: '10629', 36 | parentCode: '370202230000', 37 | deptName: '文晖路', 38 | deptCode: '370202230002', 39 | }, 40 | ], 41 | deptName: '古翠路', 42 | deptCode: '370202230000', 43 | }, 44 | { 45 | id: '10537', 46 | parentCode: '370202000000', 47 | deptName: '丰潭路', 48 | deptCode: '370202240000', 49 | }, 50 | ], 51 | deptName: '下城区', 52 | deptCode: '370202000000', 53 | }, 54 | ], 55 | deptName: '杭州市', 56 | deptCode: '370200000000', 57 | }, 58 | ], 59 | }, 60 | msg: '', 61 | errorCode: '', 62 | status: 1, 63 | } 64 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/userManage/fetchUserDetail.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | id: 10240, 5 | username: 'tgramxs', 6 | password: '123456', 7 | chineseName: '销售部', 8 | idcardNo: '332527198010230505', 9 | deptCode: '370200000000', 10 | phoneNo: '18969784568', 11 | status: 0, 12 | roleIds: [ 13 | 10100, 14 | ], 15 | gxdwdm: '370200000000', 16 | }, 17 | msg: '', 18 | errorCode: '', 19 | status: 1, 20 | } 21 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/userManage/fetchUserList.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | pageSize: 10, 5 | pageNo: 1, 6 | totalCount: 10, 7 | list: [ 8 | { 9 | id: 10240, 10 | username: 'tgramxs', 11 | password: '123456', 12 | chineseName: '销售部', 13 | idcardNo: '332527198010230505', 14 | deptCode: '370200000000', 15 | phoneNo: '18969784568', 16 | status: 0, 17 | roles: [ 18 | { 19 | id: 10100, 20 | roleName: '演示账号', 21 | resources: [], 22 | }, 23 | ], 24 | gxdwdm: '370200000000', 25 | }, 26 | { 27 | id: 10198, 28 | username: 'qingdaosj', 29 | password: '888888', 30 | chineseName: '市局', 31 | idcardNo: '412722196302151222', 32 | deptCode: '370200000000', 33 | phoneNo: '15236985623', 34 | status: 1, 35 | roles: [ 36 | { 37 | id: 1, 38 | roleName: '超级管理员', 39 | resources: [], 40 | }, 41 | ], 42 | gxdwdm: '370200000000', 43 | }, 44 | { 45 | id: 10184, 46 | username: 'sjsjsj', 47 | password: '888888', 48 | chineseName: '测试sj', 49 | idcardNo: '332623196801254521', 50 | deptCode: '370200000000', 51 | phoneNo: '15821456854', 52 | type: 0, 53 | status: 1, 54 | roles: [ 55 | { 56 | id: 1, 57 | roleName: '超级管理员', 58 | resources: [], 59 | }, 60 | ], 61 | gxdwdm: '370200000000', 62 | }, 63 | { 64 | id: 10180, 65 | username: 'sj666', 66 | password: '888888', 67 | chineseName: 'sj-admin', 68 | idcardNo: '612527199310150000', 69 | deptCode: '370200000000', 70 | phoneNo: '15522223333', 71 | type: 0, 72 | status: 0, 73 | roles: [ 74 | { 75 | id: 1, 76 | roleName: '超级管理员', 77 | resources: [], 78 | }, 79 | ], 80 | gxdwdm: '370200000000', 81 | }, 82 | { 83 | id: 10178, 84 | username: 'zhlsj1', 85 | password: '888888', 86 | chineseName: 'zhlsj1', 87 | idcardNo: '330881187609090044', 88 | deptCode: '370200000000', 89 | phoneNo: '13200000000', 90 | type: 0, 91 | status: 0, 92 | roles: [ 93 | { 94 | id: 1, 95 | roleName: '超级管理员', 96 | resources: [], 97 | }, 98 | ], 99 | gxdwdm: '370200000000', 100 | }, 101 | { 102 | id: 10177, 103 | username: 'zhlsj', 104 | password: '888888', 105 | chineseName: 'zhlsj', 106 | idcardNo: '330881187609090033', 107 | deptCode: '370200000000', 108 | phoneNo: '15600000000', 109 | type: 0, 110 | status: 0, 111 | roles: [ 112 | { 113 | id: 1, 114 | roleName: '超级管理员', 115 | resources: [], 116 | }, 117 | ], 118 | gxdwdm: '370200000000', 119 | }, 120 | { 121 | id: 2, 122 | username: '111111', 123 | password: '111111', 124 | chineseName: '管理员', 125 | idcardNo: '000000000000000001', 126 | policeCode: '000000', 127 | deptCode: '370200000000', 128 | gender: 1, 129 | email: 'abc@abc.com', 130 | phoneNo: '15100000000', 131 | type: 0, 132 | status: 0, 133 | gxdwdm: '370200000000', 134 | }, 135 | ], 136 | totalPage: 1, 137 | }, 138 | msg: '', 139 | errorCode: '', 140 | status: 1, 141 | } 142 | -------------------------------------------------------------------------------- /app/mocks/apis/sys/userManage/index.js: -------------------------------------------------------------------------------- 1 | const fetchUserDepttList = require('./fetchUserDepttList') 2 | const fetchRoleList = require('./fetchRoleList') 3 | const fetchUserList = require('./fetchUserList') 4 | const fetchUserDetail = require('./fetchUserDetail') 5 | const fetchUserDetailUpdate = require('../../success') 6 | const fetchUserAdd = require('../../success') 7 | const fetchUserDelete = require('../../success') 8 | const fetchUserSetRole = require('../../success') 9 | const fetchChangeUserStatus = require('../../success') 10 | const synUser = require('../../success') 11 | 12 | 13 | module.exports = { 14 | fetchUserDepttList, 15 | fetchRoleList, 16 | fetchUserList, 17 | fetchUserDetail, 18 | fetchUserDetailUpdate, 19 | fetchUserAdd, 20 | fetchUserDelete, 21 | fetchUserSetRole, 22 | fetchChangeUserStatus, 23 | synUser, 24 | } 25 | -------------------------------------------------------------------------------- /app/mocks/apis/tableList.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | data: { 4 | totalCount: 100, 5 | currentPage: 1, 6 | pageSize: 10, 7 | 'list|10': [ 8 | { 9 | 'id|+1': 1, 10 | 'status|1': [1, 2, 3], 11 | 'name|1': ['特朗普', '奥巴马', '老布什'], 12 | }, 13 | ], 14 | }, 15 | msg: '', 16 | errorCode: '', 17 | status: 1, 18 | } 19 | -------------------------------------------------------------------------------- /app/mocks/http.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | const _map = require('./interfaceMap') 3 | const _filter = require('./interfaceFilter') 4 | const Mock = require('mockjs') 5 | 6 | http.createServer((req, res) => { 7 | res.writeHead(200, { 8 | 'Content-Type': 'application/json;charset=utf-8', 9 | 'Access-Control-Allow-Origin': req.headers.origin, 10 | 'Access-Control-Allow-Methods': '*', 11 | 'Access-Control-Allow-Headers': '*', 12 | 'Access-Control-Allow-Credentials': true, 13 | 'Cache-Control': 'no-cache,no-store', // clear cache 14 | }) 15 | if (req.method === 'OPTIONS') { 16 | res.end(null) 17 | } 18 | if (req.method === 'POST') { 19 | let postData = '' 20 | req.addListener('data', dataBuffer => postData += dataBuffer) 21 | req.addListener('end', () => { 22 | console.log('url=>', req.url) 23 | postData = JSON.parse(postData) 24 | const originData = _map[req.url] 25 | ? Mock.mock(_map[req.url]) 26 | : '' 27 | const data = typeof (_filter[req.url]) === 'function' 28 | ? _filter[req.url](originData, postData) 29 | : originData 30 | // const data = originData 31 | setTimeout(() => { 32 | res.end(JSON.stringify(data)) 33 | }, parseInt(((Math.random() - 0.5) + 1) * 500, 10)) // 随机数 34 | }) 35 | } 36 | }).listen(1111) 37 | console.log('listening port 1111') 38 | -------------------------------------------------------------------------------- /app/mocks/interfaceFilter.js: -------------------------------------------------------------------------------- 1 | const suffix = '.json' 2 | const prefix = '/kjdsj' 3 | 4 | module.exports = { 5 | [`${prefix}/dataManage/buildingAddress/fetchHouseCheckList${suffix}`]: function (mockData, request) { 6 | let jd = 120.000000000001 7 | let wd = 36.26404109130858 8 | mockData.data.list = mockData.data.list.map((one) => { 9 | jd += 0.001 10 | wd += 0.0000000001 11 | return Object.assign({}, one, { jd: String(jd), wd: String(wd), jwd: `${jd},${wd}` }) 12 | }) 13 | return mockData 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /app/mocks/interfaceMap.js: -------------------------------------------------------------------------------- 1 | 2 | const path = '/mock' 3 | 4 | // #region 5 | const base = require('./apis/base') // 基础的接口 6 | const userManage = require('./apis/sys/userManage') // 用户管理 7 | const roleManage = require('./apis/sys/roleManage') // 角色管理 8 | const moduleManage = require('./apis/sys/moduleManage') // 模块管理 9 | // #endregion 10 | 11 | module.exports = { 12 | // #region 收起所有 13 | 14 | // #region 公用 15 | [`${path}/usercenter/login`]: base.login, // 登录 16 | [`${path}/usercenter/user/userMenu`]: base.menu, // 菜单 17 | [`${path}/usercenter/user/userInfo`]: base.staff, // 用户信息 18 | [`${path}/usercenter/logout`]: base.logout, // 退出 19 | // #endregion 20 | 21 | // #region 用户管理 22 | [`${path}/usercenter/role/list`]: userManage.fetchRoleList, // 角色列表 23 | [`${path}/usercenter/dept/list`]: userManage.fetchUserDepttList, // 部门列表 24 | [`${path}/usercenter/user/list`]: userManage.fetchUserList, // 用户列表 25 | [`${path}/usercenter/user/detail`]: userManage.fetchUserDetail, // 获取用户详情 26 | [`${path}/usercenter/user/update`]: userManage.fetchUserDetailUpdate, // 修改用户详情 27 | [`${path}/usercenter/user/save`]: userManage.fetchUserAdd, // 新增用户 28 | [`${path}/usercenter/user/synUser`]: userManage.synUser, // 新增用户 29 | [`${path}/usercenter/user/updateRole`]: userManage.fetchUserSetRole, // 修改用户角色 30 | [`${path}/usercenter/user/delete`]: userManage.fetchUserDelete, // 删除用户 31 | [`${path}/usercenter/user/updateStatus`]: userManage.fetchChangeUserStatus, // 设置用户是否冻结状态 32 | // #endregion 33 | 34 | // #region 角色管理 35 | [`${path}/usercenter/role/save`]: roleManage.fetchRoleAdd, // 保存角色 36 | [`${path}/usercenter/role/delete`]: roleManage.fetchRoleDelete, // 删除角色 37 | [`${path}/usercenter/role/update`]: roleManage.fetchRoleUpdate, // 角色编辑 38 | [`${path}/usercenter/role/resTree`]: roleManage.fetchTreeList, // 角色列表 39 | [`${path}/usercenter/role/resList`]: roleManage.fetchModuleListInRole, // 已选择的模块 40 | [`${path}/usercenter/role/detail`]: roleManage.fetchRoleDetail, // 已选择的菜单以及按钮 41 | [`${path}/usercenter/resource/button/list`]: roleManage.fetchButtonList, // 模块的按钮列表 42 | [`${path}/usercenter/user/removeRole`]: roleManage.fetchRoleDeletePeople, // 删除用户 43 | [`${path}/usercenter/role/updateButton`]: roleManage.fetchUpdateButton, // 更新按钮 44 | [`${path}/usercenter/role/updateRes`]: roleManage.fetchUpdateRoleRes, // 更新已选择模块 45 | // #endregion 46 | 47 | // #region 模块管理 48 | [`${path}/usercenter/resource/list`]: moduleManage.fetchModuleList, // 获取模块列表 49 | [`${path}/usercenter/resource/delete`]: moduleManage.fetchModuleDelete, // 删除模块 50 | [`${path}/usercenter/resource/detail`]: moduleManage.fetchModuleDetail, // 获取模块详情 51 | [`${path}/usercenter/resource/updateStatus`]: moduleManage.fetchChangeModuleStatus, // 修改模块显隐状态 52 | [`${path}/usercenter/resource/update`]: moduleManage.fetchModuleUpdateDetail, // 修改模块详情 53 | [`${path}/usercenter/resource/save`]: moduleManage.fetchModuleAdd, // 新增模块 54 | // #endregion 55 | 56 | // #endregion 57 | } 58 | -------------------------------------------------------------------------------- /app/pages/base/app/leftNav.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { hashHistory/* , Link */ } from 'react-router' 4 | // import { routerActions } from 'react-router-redux' 5 | import { Menu, Spin } from 'antd' 6 | // import { updateTabList } from '@actions/tabList' 7 | import { clearGformCache2 } from '@actions/common' 8 | 9 | const { SubMenu } = Menu 10 | 11 | @connect((state, props) => ({ 12 | config: state.config, 13 | })) 14 | export default class LeftNav extends Component { 15 | constructor(props, context) { 16 | super(props, context) 17 | 18 | // const { pathname } = props.location 19 | this.state = { 20 | // current: pathname, 21 | openKeys: [], 22 | menuStyle: false, 23 | rootSubmenuKeys: [], 24 | menu: JSON.parse(sessionStorage.getItem('leftNav')) || [], 25 | } 26 | } 27 | 28 | componentDidMount() { 29 | this.init() 30 | } 31 | 32 | componentWillReceiveProps(nextProps) { 33 | if (this.props.location.pathname !== nextProps.location.pathname) { 34 | this.openKeys(nextProps.location.pathname) 35 | } 36 | } 37 | 38 | init = () => { 39 | this.openKeys(this.props.location.pathname) 40 | const { menu } = this.state 41 | const arr = [] 42 | menu.map((item, index) => { 43 | arr.push(`sub${index + 1}`) 44 | }) 45 | this.setState({ rootSubmenuKeys: arr }) 46 | } 47 | 48 | // 确认当前要打开的菜单 49 | openKeys = (pathname) => { 50 | /* 51 | **计算要打开的以及菜单 52 | */ 53 | const { menu } = this.state 54 | const curPath = `${pathname.split('$')[0]}`.replace('/', '') 55 | if (curPath === '') { // 如果是默认首页,那么就不用往下计算了 56 | this.setState({ 57 | openKeys: ['sub1'], 58 | }) 59 | return 60 | } 61 | let count = 0 62 | 63 | // 定义一个标签语句 64 | // eslint-disable-next-line 65 | jumpOut1: 66 | for (let i = 0; i < menu.length; i += 1) { 67 | const item = menu[i] 68 | count += 1 69 | if (item.resKey && curPath === item.resKey.split('$')[0].replace('/', '')) { 70 | // eslint-disable-next-line 71 | break jumpOut1 72 | } else if (item.children && item.children.length > 0) { 73 | // eslint-disable-next-line 74 | jumpOut2: 75 | for (let j = 0; j < item.children.length; j += 1) { 76 | const record = item.children[j] 77 | if (item.resKey && curPath === record.resKey.split('$')[0].replace('/', '')) { 78 | // eslint-disable-next-line 79 | break jumpOut1 80 | } 81 | } 82 | } 83 | } 84 | this.setState({ 85 | openKeys: [`sub${count - 1}`], 86 | }) 87 | } 88 | 89 | // 菜单点击事件 90 | _handleClick = (e) => { 91 | this.props.dispatch(clearGformCache2({})) 92 | hashHistory.push(`/${e.key}`) 93 | } 94 | 95 | onOpenChange = (openKeys) => { 96 | const latestOpenKey = openKeys.find(key => this.state.openKeys.indexOf(key) === -1); 97 | if (this.state.rootSubmenuKeys.indexOf(latestOpenKey) === -1) { 98 | this.setState({ openKeys }); 99 | } else { 100 | this.setState({ 101 | openKeys: latestOpenKey ? [latestOpenKey] : [], 102 | }) 103 | } 104 | } 105 | 106 | // 左侧菜单切换显示模式 107 | navMini = () => { 108 | this.setState({ 109 | menuStyle: !this.state.menuStyle, 110 | }, () => { 111 | this.props.leftNavMode(this.state.menuStyle) 112 | }) 113 | } 114 | 115 | // 二级菜单的生成 116 | renderLeftNav = (options) => { 117 | const { menu } = this.state 118 | return menu.map((item, index) => { 119 | if (!item.children || item.children.length === 0) { 120 | return ( 121 | 122 | 123 | {item.resName} 124 | 125 | ) 126 | } 127 | const key = `sub${index}` 128 | return ( 129 | 132 | 133 | {item.resName} 134 | 135 | } 136 | > 137 | { 138 | item.children.map((child, _index) => 139 | ( 140 | 141 | 142 | {child.resName} 143 | 144 | )) 145 | } 146 | 147 | ) 148 | }) 149 | } 150 | 151 | // 左侧菜单高亮的控制 152 | leftMenuHighLight = () => { 153 | const { pathname } = this.props.location 154 | // console.log(pathname) 155 | let selectedKeys = [pathname.replace('/', '')] 156 | if (pathname === '/' || pathname.indexOf('desk$/index') > -1) { 157 | selectedKeys = ['desk$/index'] 158 | } 159 | return selectedKeys 160 | } 161 | 162 | render() { 163 | const { openKeys, menuStyle } = this.state 164 | return ( 165 |
166 | 184 |
185 | ) 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /app/pages/base/app/modal/editPassword.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { Button, Form, Input, /* Select, */ Modal, Row, Col, message } from 'antd' 4 | import { regExpConfig } from '@reg' 5 | import md5 from 'md5' 6 | import { 7 | fetchPassword, 8 | } from '@actions/common' 9 | 10 | const FormItem = Form.Item 11 | // const Option = Select.Option 12 | 13 | // 连接公用常量、后端返回的数据方法 并放置在props里面调用 14 | @connect((state, props) => ({ 15 | config: state.config, 16 | })) 17 | 18 | @Form.create({}) 19 | 20 | export default class index extends Component { 21 | constructor(props) { 22 | super(props) 23 | this.state = { 24 | confirmDirty: false, 25 | } 26 | this.handleSubmit = this.handleSubmit.bind(this) 27 | this.checkConfirm = this.checkConfirm.bind(this) 28 | this.checkPassword = this.checkPassword.bind(this) 29 | } 30 | 31 | 32 | // 组件已经加载到dom中 33 | componentDidMount() { 34 | 35 | } 36 | 37 | // 提交表单数据 38 | handleSubmit(e) { 39 | e.preventDefault() 40 | this.props.form.validateFields((errors, fieldsValue) => { 41 | if (errors) { 42 | return 43 | } 44 | 45 | if (fieldsValue.password) { 46 | // if (process.env.NODE_ENV === 'production') { 47 | // fieldsValue.password = fieldsValue.password 48 | // } else { 49 | fieldsValue.password = md5(fieldsValue.password) 50 | // } 51 | } 52 | const values = { 53 | oldPwd: fieldsValue.oldPwd ? fieldsValue.oldPwd : '', 54 | password: fieldsValue.password ? fieldsValue.password : '', 55 | }; 56 | this.submitLoading = true 57 | this.props.dispatch(fetchPassword({ 58 | ...values, 59 | }, (res) => { 60 | message.success(res.msg) 61 | this.submitLoading = false 62 | this.setState({}) 63 | this.props.onCancel() 64 | }, (res) => { 65 | message.warning(res.msg) 66 | this.props.form.setFields({ oldPwd: '', password: '', confirm: '' }) 67 | this.submitLoading = false 68 | this.setState({}) 69 | })) 70 | 71 | // this.props.form.resetFields() 72 | }); 73 | } 74 | 75 | checkPassword = (rule, value, callback) => { 76 | const { form } = this.props 77 | if (value && value !== form.getFieldValue('password')) { 78 | callback('两次输入的密码不一致') 79 | } else { 80 | callback() 81 | } 82 | } 83 | 84 | checkConfirm = (rule, value, callback) => { 85 | const { form } = this.props 86 | if (value && this.state.confirmDirty) { 87 | form.validateFields(['confirm'], { force: true }) 88 | } 89 | callback() 90 | } 91 | 92 | // 弹窗的footer 93 | renderFooter() { 94 | return ( 95 |
96 | 97 | 98 |
99 | ) 100 | } 101 | 102 | render() { 103 | // const { imageUrl } = this.state 104 | const { getFieldDecorator } = this.props.form 105 | const formItemLayout = { 106 | labelCol: { span: 6 }, 107 | wrapperCol: { span: 12 }, 108 | hasFeedback: true, 109 | } 110 | return ( 111 | 118 |
119 |
120 | 121 |
122 | 123 | {getFieldDecorator('oldPwd', { 124 | rules: [ 125 | { required: true, message: '请输入密码!' }, 126 | { pattern: regExpConfig.pwd, message: '请输入6-16位数字或者字母!' }, 127 | { validator: this.checkConfirm }, 128 | ], 129 | // validateTrigger: 'onBlur', 130 | })()} 131 | 132 | 133 | 134 | 135 | 136 | 137 | {getFieldDecorator('password', { 138 | rules: [ 139 | { required: true, message: '请输入密码!' }, 140 | { pattern: regExpConfig.pwd, message: '请输入6-16位数字或者字母!' }, 141 | { validator: this.checkConfirm }, 142 | ], 143 | // validateTrigger: 'onBlur', 144 | })()} 145 | 146 | 147 | 148 | 149 | 150 | 151 | {getFieldDecorator('confirm', { 152 | rules: [ 153 | { required: true, message: '请输入密码!' }, 154 | { pattern: regExpConfig.pwd, message: '请输入6-16位数字或者字母!' }, 155 | { validator: this.checkPassword }, 156 | ], 157 | // validateTrigger: 'onBlur', 158 | })()} 159 | 160 | 161 | 162 | 163 | 164 | 165 | ) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/pages/base/app/tabList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { bindActionCreators } from 'redux' 3 | import { connect } from 'react-redux' 4 | import { routerActions } from 'react-router-redux' 5 | import { is } from 'immutable' 6 | import { Tabs } from 'antd' 7 | import { updateTabChecked, deleteTabFromList } from '@actions/tabList' 8 | 9 | const { TabPane } = Tabs 10 | 11 | @connect( 12 | (state, props) => ({ tabList: state.tabListResult }), 13 | dispatch => ({ 14 | actions: bindActionCreators(routerActions, dispatch), 15 | dispatch: dispatch, 16 | }), 17 | ) 18 | export default class TabList extends Component { 19 | constructor(props) { 20 | super(props) 21 | this.onChange = this.onChange.bind(this); 22 | this.onEdit = this.onEdit.bind(this); 23 | } 24 | componentDidMount() { 25 | // console.log('this.props', this.props); 26 | } 27 | onChange(activeKey) { 28 | const { actions } = this.props; 29 | this.props.dispatch(updateTabChecked({ activeKey: activeKey })) 30 | actions.push(activeKey) 31 | } 32 | onEdit(targetKey, action) { 33 | this[action](targetKey); 34 | } 35 | remove(targetKey) { 36 | const { actions, tabList } = this.props; 37 | let delIndex 38 | let activeKey 39 | 40 | if (targetKey === tabList.activeKey) { 41 | tabList.list.map((tab, index) => { 42 | // eslint-disable-next-line 43 | tab.key === targetKey ? delIndex = index : null; 44 | }); 45 | // eslint-disable-next-line no-nested-ternary 46 | activeKey = tabList.list[delIndex + 1] ? 47 | tabList.list[delIndex + 1].key : (tabList.list[delIndex - 1] ? 48 | tabList.list[delIndex - 1].key : ''); 49 | actions.push(activeKey); 50 | } 51 | this.props.dispatch(deleteTabFromList({ targetKey: targetKey })); 52 | } 53 | shouldComponentUpdate(nextProps, nextState) { 54 | const thisProps = this.props || {}; 55 | 56 | if (Object.keys(thisProps).length !== Object.keys(nextProps).length) { 57 | return true; 58 | } 59 | // eslint-disable-next-line no-restricted-syntax 60 | for (const key in nextProps) { 61 | if (thisProps[key] !== nextProps[key] || !is(thisProps[key], nextProps[key])) { 62 | return true; 63 | } 64 | } 65 | return false; 66 | } 67 | render() { 68 | const { tabList } = this.props 69 | return ( 70 | 77 | { 78 | tabList.list.map(tab => 79 | {tab.content}) 80 | } 81 | 82 | ) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/pages/base/developing.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Progress } from 'antd' 3 | 4 | // 声明组件 并对外输出 5 | export default class developing extends Component { 6 | // 初始化页面常量 绑定事件方法 7 | constructor(props) { 8 | super(props) 9 | this.state = { 10 | // activeTab: 'pop' , 11 | } 12 | } 13 | 14 | 15 | // 组件已经加载到dom中 16 | componentDidMount() { 17 | 18 | } 19 | 20 | 21 | render() { 22 | return ( 23 |
24 | '即将上线,敬请期待...'} 28 | width={200} 29 | status="active" 30 | /> 31 |
32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/pages/base/example.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | // import PropTypes from 'prop-types' 3 | import { Button } from 'antd' 4 | // import {connect} from 'react-redux' 5 | // import {} from '@actions/xxx' 6 | // import Socket from '@configs/socket' 7 | 8 | // @connect((storeState)=>({})) 9 | 10 | export default class app extends Component { 11 | static defaultProps = { 12 | } 13 | 14 | static propTypes = { 15 | } 16 | 17 | constructor(props) { 18 | super(props) 19 | this.state = {} 20 | } 21 | 22 | componentDidMount() { } 23 | 24 | // #region vscode 1.17的收缩代码块功能 业务代码 25 | 26 | 27 | // #endregion 28 | 29 | // 发送socket数据 30 | onClickSend = () => { 31 | // Socket.send({ type: 'receive/hello3', data: { name: 'dupi' } }) 32 | } 33 | 34 | render() { 35 | return ( 36 |
37 | 示范页面 38 |
39 | 40 |
41 |
42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/pages/base/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import developing from './developing' 4 | import example from './example' 5 | import login from './login' 6 | import notfound from './notfound' 7 | import app from './app' 8 | // import socketReceive from './socketReceive' 9 | 10 | export { developing, example, /* socketReceive, */ login, notfound, app } 11 | -------------------------------------------------------------------------------- /app/pages/base/notfound.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Link, hashHistory } from 'react-router' 3 | import { Progress, Button } from 'antd' 4 | 5 | // 声明组件 并对外输出 6 | export default class notfound extends Component { 7 | // 初始化页面常量 绑定事件方法 8 | constructor(props) { 9 | super(props) 10 | this.state = { 11 | // activeTab: 'pop' , 12 | } 13 | } 14 | 15 | render() { 16 | return ( 17 |
18 | '404'} 22 | width={200} 23 | status="active" 24 | /> 25 | 26 |
27 |

跳转至首页

28 |

跳转至登陆页

29 | 30 |
31 |
32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/pages/base/socket.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: hy 3 | * @Date: 2019-05-24 14:46:23 4 | * @Last Modified by: dupi 5 | * @Last Modified time: 2019-09-19 14:19:56 6 | */ 7 | 8 | // socket on 9 | 10 | import React, { Component } from 'react' 11 | import socket from '@configs/socket' 12 | import { socketReceive } from '@actions/common' 13 | import { connect } from 'react-redux' 14 | 15 | @connect(() => ({})) 16 | export default class SocketOn extends Component { 17 | componentDidMount() { 18 | console.log('socket didmount') 19 | this.init() 20 | } 21 | 22 | init = () => { 23 | const callback = (res) => { 24 | this.props.dispatch(socketReceive(res)) 25 | }; 26 | socket.on('dispatch', callback); 27 | } 28 | 29 | render() { 30 | return null 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/pages/base/socketReceive.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | // import PropTypes from 'prop-types' 3 | import { Button } from 'antd' 4 | import { connect } from 'react-redux' 5 | // import {} from '@actions/xxx' 6 | // import Socket from '@configs/socket' 7 | 8 | @connect(store => ({ 9 | // socketCollection: store.socketCollection, 10 | })) 11 | 12 | export default class app extends Component { 13 | static defaultProps = { 14 | } 15 | 16 | static propTypes = { 17 | } 18 | 19 | constructor(props) { 20 | super(props) 21 | this.state = {} 22 | } 23 | 24 | componentDidMount() { } 25 | 26 | // #region vscode 1.17的收缩代码块功能 业务代码 27 | 28 | 29 | // #endregion 30 | 31 | // 发送socket数据 32 | onClickSend = () => { 33 | // Socket.dispatch({ type: 'receive/hello2' }) 34 | } 35 | 36 | render() { 37 | // const { socketCollection = {} } = this.props 38 | return ( 39 |
40 | socket receive 页面示例 41 |
42 |
收到数据:
43 |
44 |             
45 |               {
46 |                 // JSON.stringify(socketCollection, null, 2)
47 |               }
48 |             
49 |           
50 |
51 |
52 | ) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/pages/example.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | // import PropTypes from 'prop-types' 3 | import { } from 'antd' 4 | // import {connect} from 'react-redux' 5 | // import {} from '@actions/xxx' 6 | 7 | // @connect((storeState)=>({})) 8 | 9 | export default class app extends Component { 10 | static defaultProps={ 11 | } 12 | 13 | static propTypes = { 14 | } 15 | 16 | constructor(props) { 17 | super(props) 18 | this.state = {} 19 | } 20 | 21 | componentDidMount() {} 22 | 23 | // #region vscode 1.17的收缩代码块功能 业务代码 24 | 25 | 26 | // #endregion 27 | 28 | render() { 29 | return ( 30 |
31 | 示范页面excample 32 |
33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/pages/menu/editor.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { connect } from 'react-redux' 4 | import { Editor, EditorState, RichUtils } from 'draft-js' 5 | import 'draft-js/dist/Draft.css' 6 | import '@styles/RichEditor.less' 7 | 8 | // Custom overrides for "code" style. 9 | const styleMap = { 10 | CODE: { 11 | backgroundColor: 'rgba(0, 0, 0, 0.05)', 12 | fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace', 13 | fontSize: 16, 14 | padding: 2, 15 | }, 16 | } 17 | 18 | function getBlockStyle(block) { 19 | switch (block.getType()) { 20 | case 'blockquote': return 'RichEditor-blockquote'; 21 | default: return null; 22 | } 23 | } 24 | 25 | @connect((state, props) => ({ 26 | config: state.config, 27 | })) 28 | export default class app extends Component { 29 | constructor(props) { 30 | super(props); 31 | this.state = { editorState: EditorState.createEmpty() }; 32 | 33 | this.focus = () => this.editor.focus() 34 | this.onChange = editorState => this.setState({ editorState }); 35 | 36 | this.handleKeyCommand = this._handleKeyCommand.bind(this); 37 | this.onTab = this._onTab.bind(this); 38 | this.toggleBlockType = this._toggleBlockType.bind(this); 39 | this.toggleInlineStyle = this._toggleInlineStyle.bind(this); 40 | } 41 | 42 | _handleKeyCommand(command, editorState) { 43 | const newState = RichUtils.handleKeyCommand(editorState, command); 44 | if (newState) { 45 | this.onChange(newState); 46 | return true; 47 | } 48 | return false; 49 | } 50 | 51 | _onTab(e) { 52 | const maxDepth = 4; 53 | this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth)); 54 | } 55 | 56 | _toggleBlockType(blockType) { 57 | this.onChange(RichUtils.toggleBlockType( 58 | this.state.editorState, 59 | blockType, 60 | )); 61 | } 62 | 63 | _toggleInlineStyle(inlineStyle) { 64 | this.onChange(RichUtils.toggleInlineStyle( 65 | this.state.editorState, 66 | inlineStyle, 67 | )); 68 | } 69 | 70 | render() { 71 | const { editorState } = this.state; 72 | 73 | // If the user changes block type before entering any text, we can 74 | // either style the placeholder or hide it. Let's just hide it now. 75 | let className = 'RichEditor-editor'; 76 | const contentState = editorState.getCurrentContent(); 77 | if (!contentState.hasText()) { 78 | if (contentState.getBlockMap().first().getType() !== 'unstyled') { 79 | className += ' RichEditor-hidePlaceholder'; 80 | } 81 | } 82 | 83 | return ( 84 |
85 | 89 | 93 |
94 | { this.editor = c }} 104 | spellCheck 105 | /> 106 |
107 |
108 | ); 109 | } 110 | } 111 | 112 | 113 | class StyleButton extends React.Component { 114 | constructor() { 115 | super(); 116 | this.onToggle = (e) => { 117 | e.preventDefault(); 118 | this.props.onToggle(this.props.style); 119 | }; 120 | } 121 | 122 | render() { 123 | let className = 'RichEditor-styleButton'; 124 | if (this.props.active) { 125 | className += ' RichEditor-activeButton'; 126 | } 127 | 128 | return ( 129 | 130 | {this.props.label} 131 | 132 | ); 133 | } 134 | } 135 | 136 | const BLOCK_TYPES = [ 137 | { label: 'H1', style: 'header-one' }, 138 | { label: 'H2', style: 'header-two' }, 139 | { label: 'H3', style: 'header-three' }, 140 | { label: 'H4', style: 'header-four' }, 141 | { label: 'H5', style: 'header-five' }, 142 | { label: 'H6', style: 'header-six' }, 143 | { label: 'Blockquote', style: 'blockquote' }, 144 | { label: 'UL', style: 'unordered-list-item' }, 145 | { label: 'OL', style: 'ordered-list-item' }, 146 | { label: 'Code Block', style: 'code-block' }, 147 | ]; 148 | 149 | const BlockStyleControls = (props) => { 150 | const { editorState } = props; 151 | const selection = editorState.getSelection(); 152 | const blockType = editorState 153 | .getCurrentContent() 154 | .getBlockForKey(selection.getStartKey()) 155 | .getType(); 156 | 157 | return ( 158 |
159 | {BLOCK_TYPES.map(type => 160 | ())} 167 |
168 | ); 169 | }; 170 | 171 | const INLINE_STYLES = [ 172 | { label: 'Bold', style: 'BOLD' }, 173 | { label: 'Italic', style: 'ITALIC' }, 174 | { label: 'Underline', style: 'UNDERLINE' }, 175 | { label: 'Monospace', style: 'CODE' }, 176 | ]; 177 | 178 | const InlineStyleControls = (props) => { 179 | const currentStyle = props.editorState.getCurrentInlineStyle(); 180 | return ( 181 |
182 | {INLINE_STYLES.map(type => 183 | ())} 190 |
191 | ); 192 | }; 193 | -------------------------------------------------------------------------------- /app/pages/menu/index.js: -------------------------------------------------------------------------------- 1 | 2 | import echarts from './echarts' 3 | import editor from './editor' 4 | 5 | export { 6 | echarts, editor, 7 | } 8 | -------------------------------------------------------------------------------- /app/pages/set/index.js: -------------------------------------------------------------------------------- 1 | 2 | import '@styles/set.less' 3 | import userManage from './userManage' 4 | import roleManage from './roleManage' 5 | import moduleManage from './moduleManage' 6 | 7 | export { userManage, roleManage, moduleManage } 8 | -------------------------------------------------------------------------------- /app/pages/set/moduleManage/modal/addButtonModal.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Button, Form, Input } from 'antd'; 3 | import { connect } from 'react-redux'; 4 | import { regExpConfig } from '@reg'; 5 | import Drawer from '@components/draw/draw'; 6 | 7 | const FormItem = Form.Item; 8 | 9 | 10 | // @connect((state, props) => ({ 11 | // config: state.config 12 | // })) 13 | @Form.create() 14 | 15 | // 声明组件 并对外输出 16 | export default class Pop extends Component { 17 | // 初始化页面常量 绑定事件方法 18 | constructor(props) { 19 | super(props); 20 | this.state = {}; 21 | this.handleSubmit = this.handleSubmit.bind(this); 22 | } 23 | 24 | componentWillMount() { 25 | this.props.form.resetFields(); 26 | } 27 | 28 | // 组件已经加载到dom中 29 | componentDidMount() {} 30 | 31 | handleSubmit(e) { 32 | e.preventDefault(); 33 | this.props.form.validateFields((errors, values) => { 34 | if (errors) { 35 | return; 36 | } 37 | values.resType = 3; 38 | if (this.props.state === 'edit') { 39 | values.id = this.props.buttonEditData.id; 40 | } 41 | this.props.handleAdd(values); 42 | }); 43 | } 44 | 45 | footer() { 46 | const { onCancel } = this.props; 47 | return ( 48 |
49 | 52 | 53 |
54 | ); 55 | } 56 | 57 | render() { 58 | const { visible, onCancel, title, buttonEditData } = this.props; 59 | const { getFieldDecorator } = this.props.form; 60 | const formItemLayout = { 61 | labelCol: { span: 5 }, 62 | wrapperCol: { span: 17 }, 63 | }; 64 | return ( 65 | 72 |
73 |
78 | {/* 79 | {getFieldDecorator('parentId', { 80 | initialValue: this.props.pid || '', 81 | })( 82 | 83 | )} 84 | */} 85 | 86 | {getFieldDecorator('resName', { 87 | rules: [{ required: true, message: '请输入按钮名称' }], 88 | initialValue: buttonEditData.resName || '', 89 | })()} 90 | 91 | 92 | {getFieldDecorator('sort', { 93 | rules: [ 94 | { required: true, message: '请输入排序数字' }, 95 | { pattern: regExpConfig.num, message: '请输入数字' }, 96 | ], 97 | initialValue: `${buttonEditData.sort || '0'}`, 98 | })()} 99 | 100 | {/* 101 | {getFieldDecorator('resModule', { 102 | rules: [ 103 | { required: true, message: '请输入模块名称' }, 104 | ], 105 | initialValue: buttonEditData.resModule || '', 106 | })( 107 | 108 | )} 109 | */} 110 | 111 | {getFieldDecorator('resKey', { 112 | rules: [{ required: true, message: '请输入关键字' }], 113 | initialValue: `${buttonEditData.resKey || ''}`, 114 | })()} 115 | 116 | {/* 117 | {getFieldDecorator('resIcon', { 118 | rules: [ 119 | { 120 | required: true, message: '请输入图标名称', 121 | }, 122 | { pattern: regExpConfig.isNumAlpha, message: '图标名称格式不正确' }, 123 | ], 124 | initialValue: `${this.props.values.resIcon || ''}`, 125 | })( 126 | 127 | )} 128 | 129 | 130 | {getFieldDecorator('resType', { 131 | rules: [ 132 | { required: true, message: '请选择类型' }, 133 | ], 134 | initialValue: `${this.props.values.resType || ''}`, 135 | })( 136 | 141 | )} 142 | */} 143 | 144 |
145 |
146 | ); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/pages/set/moduleManage/modal/buttonModal.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { connect } from 'react-redux' 4 | import { Button, message, Badge, Popconfirm } from 'antd' 5 | import TableList from '@tableList' 6 | import Drawer from '@components/draw/draw' 7 | import { 8 | // fetchButtonList, 9 | fetchModuleDelete, 10 | fetchChangeModuleStatus, 11 | } from '@apis/manage' 12 | 13 | // 连接公用常量、后端返回的数据方法 并放置在props里面调用 14 | // @connect((state, props) => ({ 15 | // config: state.config, 16 | // })) 17 | 18 | // 声明组件 并对外输出 19 | export default class pop extends Component { 20 | // 初始化页面常量 绑定事件方法 21 | constructor(props) { 22 | super(props) 23 | this.state = { 24 | // selectedRowKeys: [], 25 | // loading: false, 26 | // dataSource: [], 27 | } 28 | this.deleteButton = this.deleteButton.bind(this) 29 | } 30 | 31 | componentWillMount() { 32 | // this.getList() 33 | } 34 | 35 | // 组件已经加载到dom中 36 | componentDidMount() {} 37 | 38 | componentWillReceiveProps(nextProps) { 39 | // this.getList() 40 | } 41 | 42 | // 删除 43 | deleteButton = (id) => { 44 | fetchModuleDelete({ id: id }, (result) => { 45 | message.success(result.msg) 46 | this.props.updateList() 47 | }) 48 | } 49 | 50 | // 上线下线 51 | showOrHide=(id, val) => { 52 | fetchChangeModuleStatus({ id: id, status: val }, (result) => { 53 | this.props.updateList() 54 | }) 55 | } 56 | 57 | column() { 58 | const self = this 59 | const { editButton } = self.props 60 | const configArr = [ 61 | { 62 | title: '按钮名称', 63 | dataIndex: 'resName', 64 | key: 'resName', 65 | width: '40%', 66 | }, 67 | { 68 | title: '状态', 69 | dataIndex: 'status', 70 | key: 'status', 71 | width: '20%', 72 | render: (text, record, index) => { 73 | if (text === 1) { 74 | return 75 | } 76 | return 77 | }, 78 | }, 79 | { 80 | title: '操作', 81 | dataIndex: 'caozuo', 82 | key: 'caozuo', 83 | width: '40%', 84 | render: (text, record, index) => ( 85 | 86 | self.showOrHide(record.id, `${record.status}`)} 89 | > 90 | {record.status !== 1 ? '下线' : '上线'} 91 | 92 | 93 | editButton(record)}>修改 94 | 95 | self.deleteButton(record.id)}> 96 | 删除 97 | 98 | 99 | ), 100 | }, 101 | ] 102 | return configArr 103 | } 104 | 105 | footer() { 106 | const { addButton } = this.props 107 | return ( 108 |
109 | 110 |
111 | ) 112 | } 113 | 114 | render() { 115 | const { 116 | visible, cancelButton, listLoading, dataSource, 117 | } = this.props 118 | // const { dataSource } = this.state 119 | return ( 120 | 128 |
129 | 135 |
136 |
137 | ) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/pages/set/moduleManage/modal/moduleAdd.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { connect } from 'react-redux' 4 | import { Button, Form, Input, message } from 'antd' 5 | import { regExpConfig } from '@reg' 6 | import Drawer from '@components/draw/draw' 7 | import { 8 | fetchModuleUpdateDetail, 9 | fetchModuleAdd, 10 | } from '@apis/manage' 11 | 12 | const FormItem = Form.Item 13 | 14 | // 连接公用常量、后端返回的数据方法 并放置在props里面调用 15 | // @connect((state, props) => ({ 16 | // config: state.config, 17 | // })) 18 | 19 | @Form.create({}) 20 | 21 | export default class Index extends Component { 22 | constructor(props) { 23 | super(props) 24 | this.state = { 25 | loading: false, 26 | // isFirst: this.props.isFirst, 27 | } 28 | } 29 | 30 | // 组件已经加载到dom中 31 | componentDidMount() { 32 | this.props.form.resetFields() 33 | } 34 | 35 | upDateValue = () => { 36 | if (this.props.pid) { 37 | this.props.form.setFieldsValue({ 38 | parentid: this.props.pid, 39 | }) 40 | } 41 | } 42 | 43 | handleSubmit = (e) => { 44 | e.preventDefault(); 45 | this.props.form.validateFields((errors, values) => { 46 | if (errors) { 47 | return; 48 | } 49 | values.resType = 1 50 | this.setState({ loading: true }) 51 | if (this.props.type === 'modify') { 52 | fetchModuleUpdateDetail({ ...values, id: this.props.itemId }, (result) => { 53 | message.success(result.msg) 54 | this.setState({ loading: false }, () => { 55 | this.props.handleOk() 56 | }) 57 | // this.props.form.resetFields() 58 | }) 59 | } else { 60 | fetchModuleAdd(values, (result) => { 61 | message.success(result.msg) 62 | this.setState({ loading: false }, () => { 63 | this.props.handleOk() 64 | }) 65 | // this.props.form.resetFields() 66 | }) 67 | } 68 | }); 69 | } 70 | 71 | footer() { 72 | const { loading } = this.state 73 | return ( 74 |
75 | 76 | 77 |
78 | ) 79 | } 80 | 81 | render() { 82 | const { 83 | visible, onCancel, title, 84 | } = this.props 85 | const { getFieldDecorator } = this.props.form; 86 | const formItemLayout = { 87 | labelCol: { span: 5 }, 88 | wrapperCol: { span: 17 }, 89 | } 90 | return ( 91 | 98 |
99 |
100 | 101 | {getFieldDecorator('parentId', { 102 | initialValue: this.props.pid || '', 103 | })()} 104 | 105 | 106 | {getFieldDecorator('resName', { 107 | rules: [ 108 | { required: true, message: '请输入菜单名称' }, 109 | ], 110 | initialValue: this.props.values.resName || '', 111 | })()} 112 | 113 | 114 | {getFieldDecorator('sort', { 115 | rules: [ 116 | { required: true, message: '请输入排序数字' }, 117 | { pattern: regExpConfig.num, message: '请输入数字' }, 118 | ], 119 | initialValue: `${this.props.values.sort || '0'}`, 120 | })()} 121 | 122 | 123 | {getFieldDecorator('resModule', { 124 | rules: [ 125 | { required: true, message: '请输入模块名称' }, 126 | ], 127 | initialValue: this.props.values.resModule || '', 128 | })()} 129 | 130 | 131 | {getFieldDecorator('resKey', { 132 | rules: [ 133 | { required: true, message: '请输入关键字' }, 134 | ], 135 | initialValue: `${this.props.values.resKey || ''}`, 136 | })()} 137 | 138 | 139 | {getFieldDecorator('resIcon', { 140 | rules: [ 141 | { 142 | required: true, message: '请输入图标名称', 143 | }, 144 | { pattern: regExpConfig.isNumAlpha, message: '图标名称格式不正确' }, 145 | ], 146 | initialValue: `${this.props.values.resIcon || ''}`, 147 | })()} 148 | 149 | {/* 150 | {getFieldDecorator('resType', { 151 | rules: [ 152 | { required: true, message: '请选择类型' }, 153 | ], 154 | initialValue: `${this.props.values.resType || ''}`, 155 | })( 156 | 161 | )} 162 | */} 163 | 164 |
165 |
166 | ) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/pages/set/moduleManage/moduleList.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import React, { Component } from 'react' 4 | import { Table, Popconfirm } from 'antd' 5 | 6 | export default class ModuleList extends Component { 7 | constructor(props) { 8 | super(props) 9 | this.state = {} 10 | } 11 | 12 | renderColumn() { 13 | const { 14 | onDelete, onModify, onUpdataStatus, onAddNode, buttonList, 15 | } = this.props 16 | return [ 17 | { 18 | title: '功能', 19 | dataIndex: 'resName', 20 | width: '40%', 21 | key: 'resName', 22 | render: function (text, record, index) { 23 | return ( 24 | {text} 25 | ) 26 | }, 27 | }, 28 | { 29 | title: '操作', 30 | width: '40%', 31 | key: 'operation', 32 | render: (text, record, index) => ( 33 | 34 | onAddNode(record.id)}>新增 35 | 36 | onModify(record.id, record.parentid)}>修改 37 | { 38 | text.children && text.children.length > 0 ? 39 | null : 40 | 41 | 42 | onDelete(record.id)}> 43 | 删除 44 | 45 | 46 | } 47 | { 48 | record.resName !== '模块管理' ? ( 49 | 50 | 51 | onUpdataStatus(text.id, `${text.status ? 0 : 1}`)}> 52 | {text.status ? '显示模块' : '隐藏模块'} 53 | 54 | ) : null 55 | } 56 | 57 | buttonList(record.id, record.parentid)}>按钮权限 58 | 59 | ), 60 | }, 61 | { 62 | title: '状态', 63 | width: '20%', 64 | render: function (text, record, index) { 65 | return ( 66 | record.resName !== '模块管理' ? ( 67 | {record.status ? 未上线 : 已上线} 68 | ) : 已上线 69 | ) 70 | }, 71 | }, 72 | ] 73 | } 74 | 75 | render() { 76 | const { dataSource, loading/* , scroll */ } = this.props 77 | return ( 78 |
79 |
89 | 90 | ) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/pages/set/roleManage/modal/buttonModal.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { Button, Spin, Row, Col } from 'antd' 4 | import Drawer from '@components/draw/draw' 5 | import { 6 | fetchButtonList, 7 | fetchChangeModuleStatus, 8 | } from '@apis/manage' 9 | 10 | // 声明组件 并对外输出 11 | export default class pop extends Component { 12 | // 初始化页面常量 绑定事件方法 13 | constructor(props) { 14 | super(props) 15 | this.state = { 16 | selectedRowKeys: [], 17 | loading: false, 18 | dataSource: [], 19 | } 20 | this.change = this.change.bind(this) 21 | this.saveChecked = this.saveChecked.bind(this) 22 | this.selectChecked = this.selectChecked.bind(this) 23 | } 24 | 25 | componentWillMount() { 26 | this.state.selectedRowKeys = this.props.checkedIdArr[this.props.itemId] || [] 27 | this.getList() 28 | } 29 | 30 | getList() { 31 | this.setState({ 32 | loading: true, 33 | }, () => { 34 | fetchButtonList({ id: this.props.itemId }, (result) => { 35 | const data = result.data.list 36 | const dataSource = [] 37 | data.map((item) => { 38 | if (item.status === 0) { 39 | const { selectedRowKeys } = this.state 40 | selectedRowKeys.map((key) => { 41 | if (item.id === key) { 42 | item.checked = true 43 | } 44 | }) 45 | dataSource.push(item) 46 | } 47 | }) 48 | this.setState({ 49 | loading: false, 50 | dataSource: dataSource, 51 | }) 52 | }) 53 | }) 54 | } 55 | 56 | // componentWillReceiveProps(nextProps) { 57 | // this.getList() 58 | // } 59 | 60 | // 上线下线 61 | // showOrHide(id, val) { 62 | // fetchChangeModuleStatus({ id: id, status: val }, (result) => { 63 | // this.getList() 64 | // }) 65 | // } 66 | 67 | selectChecked() { 68 | // const checkedArr = [] 69 | this.state.dataSource.map((item) => { 70 | item.checked = true 71 | // checkedArr.push(item.id) 72 | }) 73 | this.setState({}) 74 | // this.props.saveChecked(checkedArr) 75 | } 76 | 77 | saveChecked() { 78 | // const { selectedRowKeys } = this.state 79 | // if (selectedRowKeys.length === 0) { 80 | // message.info('请选择可供用户使用的按钮权限') 81 | // return 82 | // } 83 | const checkedArr = [] 84 | this.state.dataSource.map((item) => { 85 | if (item.checked) { 86 | checkedArr.push(item.id) 87 | } 88 | }) 89 | this.props.saveChecked(checkedArr) 90 | } 91 | 92 | footer() { 93 | const { cancelButton } = this.props 94 | return ( 95 |
96 | 97 | 98 | 99 |
100 | ) 101 | } 102 | 103 | change(id, index) { 104 | const data = this.state.dataSource[index] 105 | data.checked = !data.checked 106 | this.setState({}) 107 | } 108 | 109 | render() { 110 | const { visible, cancelButton, title } = this.props 111 | const { loading, dataSource } = this.state 112 | return ( 113 | 120 | 121 |
122 | 123 | {dataSource.map((arr, i) => 124 | (
125 | 132 | ))} 133 | 134 | 135 | 136 | 137 | ) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /app/pages/set/roleManage/modal/roleAdd.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import React, { Component } from 'react' 4 | import { Button, Form, Input, /* Modal, */ Select, message } from 'antd' 5 | import { regExpConfig } from '@reg' 6 | import Drawer from '@components/draw/draw' 7 | import { 8 | fetchRoleAdd, 9 | fetchRoleUpdate, 10 | } from '@apis/manage' 11 | 12 | const FormItem = Form.Item 13 | const { Option } = Select 14 | 15 | 16 | @Form.create({}) 17 | 18 | export default class Index extends Component { 19 | constructor(props) { 20 | super(props) 21 | this.state = { 22 | loading: false, 23 | } 24 | this.handleSubmit = this.handleSubmit.bind(this) 25 | } 26 | 27 | componentDidMount() { 28 | this.props.form.resetFields() 29 | this.props.form.setFieldsValue({ 30 | roleName: this.props.value.roleName, 31 | sort: `${this.props.value.sort}`, 32 | tjFlag: this.props.value.tjFlag !== undefined ? String(this.props.value.tjFlag) : '1', 33 | }) 34 | } 35 | 36 | handleSubmit(e) { 37 | e.preventDefault(); 38 | this.props.form.validateFields((errors, values) => { 39 | if (errors) { 40 | return; 41 | } 42 | this.setState({ loading: true }) 43 | if (this.props.type === 'modify') { 44 | fetchRoleUpdate({ ...values, id: this.props.modifyId }, (res) => { 45 | message.success(res.msg) 46 | this.props.handleOk(false) 47 | }) 48 | } else { 49 | fetchRoleAdd(values, (res) => { 50 | message.success(res.msg) 51 | this.props.handleOk(false) 52 | }) 53 | } 54 | this.setState({ loading: false }) 55 | }); 56 | } 57 | 58 | footer() { 59 | const { loading } = this.state 60 | return ( 61 |
62 | 63 | 64 |
65 | ) 66 | } 67 | 68 | render() { 69 | const { 70 | visible, onCancel, title, 71 | } = this.props 72 | const { getFieldDecorator } = this.props.form 73 | const formItemLayout = { 74 | labelCol: { span: 5 }, 75 | wrapperCol: { span: 17 }, 76 | } 77 | return ( 78 | 85 |
86 |
87 | 88 | {getFieldDecorator('roleName', { 89 | rules: [ 90 | { required: true, message: '请输入角色名称' }, 91 | // { pattern: regExpConfig.isNormalEncode, message: '请输入非特殊字符' }, 92 | ], 93 | })()} 94 | 95 | 96 | {getFieldDecorator('sort', { 97 | rules: [ 98 | { required: true, message: '请输入排序数字' }, 99 | { pattern: regExpConfig.num, message: '请输入数字' }, 100 | ], 101 | })()} 102 | 103 | 104 | {getFieldDecorator('tjFlag', { 105 | initialValue: '1', 106 | rules: [ 107 | { required: true, message: '请选择是否统计' }, 108 | ], 109 | })()} 113 | 114 | 115 | 116 |
117 |
118 | ) 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /app/pages/set/roleManage/peopleTreeList.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import TableList from '@tableList' 4 | 5 | export default class app extends Component { 6 | constructor(props) { 7 | super(props); 8 | this.state = {} 9 | } 10 | 11 | componentWillMount() {} 12 | 13 | componentDidMount() { 14 | } 15 | 16 | // #region 收缩业务代码功能 17 | 18 | columns() { 19 | return ( 20 | [{ 21 | title: '功能', 22 | dataIndex: 'resName', 23 | key: 'resName', 24 | width: '30%', 25 | }, { 26 | title: '已选模块', 27 | dataIndex: 'checkedArr', 28 | key: 'checkedArr', 29 | width: '40%', 30 | }] 31 | ) 32 | } 33 | 34 | // #endregion 35 | 36 | render() { 37 | const { 38 | dataSource, 39 | } = this.props 40 | return ( 41 |
42 | 49 |
50 | ) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/pages/set/roleManage/roleCheckbox.js: -------------------------------------------------------------------------------- 1 | import { Checkbox } from 'antd'; 2 | import React from 'react'; 3 | 4 | class RoleCheckbox extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | isChecked: false, 9 | }; 10 | this.onChange = this.onChange.bind(this); 11 | } 12 | 13 | componentWillMount() { 14 | this.setState({ 15 | isChecked: this.props.defaultChecked, 16 | }); 17 | } 18 | 19 | componentWillReceiveProps(nextProps) { 20 | if (this.props.defaultChecked !== nextProps.defaultChecked) { 21 | this.setState({ 22 | isChecked: nextProps.defaultChecked, 23 | }); 24 | } 25 | } 26 | 27 | // #region 收缩业务代码功能 28 | 29 | onChange(e) { 30 | const item = this.props.checkItem; 31 | this.setState({ 32 | isChecked: e.target.checked, 33 | }); 34 | this.props.onChecked(item, e.target.checked); 35 | } 36 | 37 | // #endregion 38 | 39 | render() { 40 | return ( 41 | 46 | {this.state.isChecked ? '已开通' : '未开通'} 47 | 48 | ); 49 | } 50 | } 51 | export default RoleCheckbox; 52 | -------------------------------------------------------------------------------- /app/pages/set/roleManage/roleList.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { Icon, Popconfirm } from 'antd' 4 | 5 | export default class app extends Component { 6 | constructor(props) { 7 | super(props) 8 | this.state = { 9 | currentId: '', 10 | } 11 | } 12 | 13 | componentWillMount() { 14 | if (this.props.roles.length > 0) { 15 | this.setState({ 16 | currentId: this.props.roles[0].id || 0, 17 | }) 18 | } 19 | } 20 | 21 | componentDidMount() { 22 | 23 | } 24 | 25 | componentWillReceiveProps(nextProps) { 26 | if (this.state.currentId === '' && nextProps.roles.length > 0) { 27 | this.setState({ 28 | currentId: nextProps.roles[0].id || 0, 29 | }) 30 | } 31 | } 32 | 33 | // #region 收缩业务代码功能 34 | 35 | // 角色名点击 36 | roleNameClick = (roleid, roleType) => { 37 | this.setState({ currentId: roleid }) 38 | this.props.onCurrentIndex(roleid, roleType) 39 | } 40 | 41 | // 改变选中li的样式 42 | checkTitleId = id => 43 | // console.log(id) 44 | (id === this.state.currentId ? 'active cell-layout' : 'cell-layout') 45 | 46 | 47 | // 角色修改 48 | roleModify = (info) => { 49 | this.props.onRoleModify(info) 50 | } 51 | 52 | // 角色删除 53 | onDelete = (info) => { 54 | this.state.currentId = '' 55 | this.props.handleRoleDelete(info) 56 | } 57 | 58 | // render roleNodes 59 | renderRoleNodes = () => { 60 | const { roles, btnRights } = this.props 61 | return roles.map((item, index) => 62 | (
  • 63 | this.roleNameClick(item.id, item.type)}>{item.roleName} 64 | 65 | { 66 | btnRights.edit ? 67 | this.roleModify(item.id)} /> : null 68 | } 69 | { 70 | btnRights.deleteRole ? 71 | this.onDelete(item.id)}> 72 | 73 | 74 | : null 75 | } 76 | 77 |
  • )) 78 | } 79 | 80 | // #endregion 81 | 82 | render() { 83 | return ( 84 |
      85 | {this.renderRoleNodes()} 86 |
    87 | ) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/pages/set/userManage/modal/selectRole.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { Radio, Button, Modal, message } from 'antd' 4 | import { fetchUserSetRole } from '@apis/manage' 5 | 6 | const RadioGroup = Radio.Group; 7 | const RadioButton = Radio.Button; 8 | 9 | export default class roleSelect extends Component { 10 | constructor(props) { 11 | super(props) 12 | this.state = { 13 | loading: false, 14 | checkedValues: '', 15 | } 16 | this.handleSubmit = this.handleSubmit.bind(this) 17 | this.onChange = this.onChange.bind(this) 18 | } 19 | 20 | componentWillMount() { 21 | this.setState({ checkedValues: this.props.values.roleid }) 22 | } 23 | 24 | componentDidMount() { 25 | 26 | } 27 | 28 | onChange(e) { 29 | this.setState({ checkedValues: e.target.value }) 30 | } 31 | 32 | handleSubmit() { 33 | this.setState({ loading: true }) 34 | this.props.dispatch(fetchUserSetRole({ 35 | roleid: this.state.checkedValues, 36 | id: this.props.currPeopleId, 37 | }, (res) => { 38 | message.success(res.msg) 39 | this.setState({ loading: false }) 40 | this.props.handleOkRole() 41 | })) 42 | } 43 | 44 | footer() { 45 | return ( 46 |
    47 | 48 | 49 |
    50 | ) 51 | } 52 | 53 | render() { 54 | const { select, values, visible, onCancel } = this.props 55 | const selectNodes = select.map((item, index) => 56 | {item.name} ) 57 | return ( 58 | 65 |
    66 | 67 | {selectNodes} 68 | 69 |
    70 |
    71 | ) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/pages/set/userManage/treeList.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react' 3 | import { Tree } from 'antd' 4 | 5 | const { TreeNode } = Tree 6 | 7 | export default class TreeList extends Component { 8 | constructor(props) { 9 | super(props) 10 | this.state = { 11 | // expandedKeys: ['123'], 12 | defaultExpandedKeys: ['123'], 13 | deptCode: props.curDeptCode, 14 | } 15 | this.handleOnSelect = this.handleOnSelect.bind(this) 16 | } 17 | 18 | componentDidMount() { 19 | 20 | } 21 | 22 | componentWillReceiveProps(nextProps) { 23 | if (nextProps.curDeptCode !== this.props.curDeptCode) { 24 | this.setState({ deptCode: nextProps.curDeptCode }) 25 | } 26 | } 27 | 28 | 29 | // 展开事件 30 | onExpand = (expandedKeys) => { 31 | this.setState({ expandedKeys }) 32 | } 33 | 34 | // 选中事件 35 | handleOnSelect(info, Nodes) { 36 | if (Nodes && Nodes.selectedNodes[0] && Nodes.selectedNodes[0].props && Nodes.selectedNodes[0].props.title) { 37 | const { title } = Nodes.selectedNodes[0].props 38 | this.props.onSelect(info, title) 39 | } else { 40 | this.props.onSelect() 41 | } 42 | } 43 | 44 | render() { 45 | const { trees } = this.props 46 | const loop = (data = []) => data.map((item) => { 47 | if (item.children && item.children.length) { 48 | return {loop(item.children)} 49 | } 50 | return 51 | }) 52 | const treeNodes = loop(trees) 53 | 54 | return ( 55 |
    56 | 62 | {treeNodes} 63 | 64 |
    65 | ) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/redux/actions/common.js: -------------------------------------------------------------------------------- 1 | 2 | import { createAction } from 'redux-actions' 3 | import * as common from '@apis/common' 4 | import { createAjaxAction } from '@configs/common' 5 | 6 | 7 | // login 登陆 8 | export const requestLogin = createAction('request login') 9 | export const recevieLogin = createAction('receive login') 10 | export const login = createAjaxAction(common.login, requestLogin, recevieLogin) 11 | 12 | // gFormCache gfor2.0m的缓存 13 | export const setGformCache2 = createAction('set gform cache2') 14 | export const clearGformCache2 = createAction('clear gform cache2') 15 | 16 | // socket receive 17 | // export const socketReceive = createAction('socketReceive') 18 | -------------------------------------------------------------------------------- /app/redux/actions/tabList.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions' 2 | 3 | export const requestTabList = createAction('request tab list') 4 | export const updateTabList = createAction('update tab list') 5 | export const updateTabChecked = createAction('update tab checked') 6 | export const deleteTabFromList = createAction('delete tab from list'); 7 | -------------------------------------------------------------------------------- /app/redux/reducers/common.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | 3 | // 登陆返回结果 4 | const loginState = () => ({}) 5 | export const loginResponse = handleActions({ 6 | 'request login'(state, action) { 7 | return { ...state, loading: true } 8 | }, 9 | 'receive login'(state, action) { 10 | // eslint-disable-next-line no-unused-vars 11 | const { req, res } = action.payload 12 | return { data: res, loading: false } 13 | }, 14 | }, loginState()) 15 | 16 | 17 | // gForm2.0缓存 18 | const cache2 = () => ({}) 19 | export const gFormCache2 = handleActions({ 20 | 'set gform cache2'(state, action) { 21 | const { cacheKey, cacheContent } = action.payload 22 | if (cacheKey === undefined) { 23 | throw new Error('cacheKey不能是undefined') 24 | } 25 | if (cacheContent === undefined) { 26 | throw new Error('cacheContent不能是undefined') 27 | } 28 | state[cacheKey] = { ...state[cacheKey], ...cacheContent } 29 | return { ...state } 30 | }, 31 | 'clear gform cache2'(state, action) { 32 | return cache2() 33 | }, 34 | }, cache2()) 35 | 36 | 37 | // gForm2.0头部搜索类别 38 | const allRetrievalState = { 39 | list: [], 40 | } 41 | export const allRetrievalResult = handleActions({ 42 | 'request all retrieval'(state, action) { 43 | return { ...state, loading: true } 44 | }, 45 | 'receive all retrieval'(state, action) { 46 | // eslint-disable-next-line no-unused-vars 47 | const { req, res } = action.payload 48 | return { ...res.data, loading: false } 49 | }, 50 | }, allRetrievalState) 51 | 52 | 53 | // socket相关操作 54 | /* export const socketCollection = handleActions({ 55 | 'socketReceive'(state, action) { 56 | // eslint-disable-next-line no-unused-vars 57 | const data = action.payload 58 | return { data } 59 | }, 60 | }, {}) */ 61 | -------------------------------------------------------------------------------- /app/redux/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { routerReducer as routing } from 'react-router-redux' 2 | import { combineReducers } from 'redux' 3 | 4 | import * as tabList from './tabList' 5 | import * as common from './common' 6 | 7 | const rootReducer = combineReducers({ 8 | routing, 9 | config: (state = {}) => state, 10 | ...tabList, 11 | ...common, 12 | }) 13 | 14 | export default rootReducer 15 | -------------------------------------------------------------------------------- /app/redux/reducers/tabList.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | 3 | const tabList = JSON.parse(sessionStorage.getItem('tabList')) 4 | 5 | const initialState = { 6 | list: tabList ? tabList.list : [], 7 | activeKey: tabList ? tabList.activeKey : '', 8 | } 9 | 10 | const tabListResult = handleActions({ 11 | 'request tab list'(state, action) { 12 | return { ...state, loading: false } 13 | }, 14 | 'update tab list'(state, action) { 15 | const data = action.payload 16 | const findList = state.list.find(tab => tab.key === data.key) 17 | const list = findList === undefined ? [...state.list, data] : state.list 18 | sessionStorage.setItem('tabList', JSON.stringify({ list, activeKey: data.key, loading: false })) 19 | return { list, activeKey: data.key, loading: false } 20 | }, 21 | 'update tab checked'(state, action) { 22 | const { activeKey } = action.payload; 23 | sessionStorage.setItem('tabList', JSON.stringify({ ...state, activeKey, loading: false })) 24 | return { ...state, activeKey, loading: false } 25 | }, 26 | 'delete tab from list'(state, action) { 27 | const { targetKey } = action.payload 28 | const list = [] 29 | let delIndex = 0 30 | let { activeKey } = state 31 | state.list.map((tab, index) => { 32 | tab.key === targetKey ? delIndex = index : list.push(tab) 33 | }) 34 | if (state.activeKey === targetKey) { 35 | // eslint-disable-next-line no-nested-ternary 36 | activeKey = list[delIndex] ? list[delIndex].key : 37 | (list[delIndex - 1] ? list[delIndex - 1].key : '') 38 | } 39 | sessionStorage.setItem('tabList', JSON.stringify({ list, activeKey, loading: false })) 40 | return { list, activeKey, loading: false } 41 | }, 42 | }, initialState) 43 | 44 | export { tabListResult as default } 45 | -------------------------------------------------------------------------------- /app/resource/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/resource/iconfont/iconfont.eot -------------------------------------------------------------------------------- /app/resource/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/resource/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /app/resource/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webtopcoder/react_duxian/ff78ec236fe39fb59835141477240842d04494dc/app/resource/iconfont/iconfont.woff -------------------------------------------------------------------------------- /app/styles/RichEditor.less: -------------------------------------------------------------------------------- 1 | .flexcolumn{ flex:1; display: flex; flex-direction: column;} 2 | 3 | .RichEditor-root { .flexcolumn; 4 | background: #fff; 5 | border: 1px solid #ddd; 6 | font-family: 'Georgia', serif; 7 | font-size: 14px; 8 | padding: 16px; 9 | // overflow: auto; 10 | } 11 | 12 | .RichEditor-editor {.flexcolumn; 13 | border-top: 1px solid #ddd; 14 | cursor: text; 15 | font-size: 16px; 16 | margin-top: 10px; 17 | } 18 | 19 | .DraftEditor-root{.flexcolumn; overflow-y: auto; overflow-x: hidden;} 20 | 21 | .RichEditor-editor .public-DraftEditorPlaceholder-root, 22 | .RichEditor-editor .public-DraftEditor-content { 23 | margin: 0 -15px -15px; 24 | padding: 15px; 25 | } 26 | 27 | .RichEditor-editor .public-DraftEditor-content { 28 | min-height: 100px; 29 | } 30 | 31 | .RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root { 32 | display: none; 33 | } 34 | 35 | .RichEditor-editor .RichEditor-blockquote { 36 | border-left: 5px solid #eee; 37 | color: #666; 38 | font-family: 'Hoefler Text', 'Georgia', serif; 39 | font-style: italic; 40 | margin: 16px 0; 41 | padding: 10px 20px; 42 | } 43 | 44 | .RichEditor-editor .public-DraftStyleDefault-pre { 45 | background-color: rgba(0, 0, 0, 0.05); 46 | font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace; 47 | font-size: 16px; 48 | padding: 20px; 49 | } 50 | 51 | .RichEditor-controls { 52 | font-family: 'Helvetica', sans-serif; 53 | font-size: 14px; 54 | margin-bottom: 5px; 55 | user-select: none; 56 | } 57 | 58 | .RichEditor-styleButton { 59 | color: #999; 60 | cursor: pointer; 61 | margin-right: 16px; 62 | padding: 2px 0; 63 | display: inline-block; 64 | } 65 | 66 | .RichEditor-activeButton { 67 | color: #5890ff; 68 | } 69 | -------------------------------------------------------------------------------- /app/styles/login.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | @import './theme.less'; 4 | 5 | .flexcolumn{display: flex; flex:1; flex-direction: column;} 6 | 7 | .root{height: 100%; 8 | .login-container{.flexcolumn;height: 100%; /* background: url(../images/bg.jpg) no-repeat 0 0; */ background-size: cover; 9 | .extraLink{ position: absolute; z-index: 999; right: @space-big; top: @space-big; display: none; 10 | a{ color: #eee; margin-left: @space-big; font-size: 16px; 11 | &:hover{color: #fff;} 12 | } 13 | } 14 | .login-header{flex: 3;background: #2d333e;color: #fff;display: flex;align-items: center;justify-content: center;font-size: 36px;letter-spacing: 10px; position: relative; 15 | .slogan{ position: absolute; z-index: 1000; bottom: 40px; margin-top: -10px; width: 100%; left: 0; 16 | div{ width: 100%; text-align: center; } 17 | .title{ font-size: 50px; 18 | .en{ display: block; font-size: 20px;} 19 | } 20 | .logo{height: 54px;margin-right: 10px;vertical-align: middle;margin-bottom: 8px;} 21 | } 22 | } 23 | .login-main{flex:3;display: flex;flex-direction: column;justify-content: center; 24 | 25 | .ant-row{ 26 | .ant-col-8{ 27 | .ant-form-item{display: flex;flex-direction: column;align-items: center; 28 | .ant-form-item-control-wrapper{width: 60%; 29 | .ant-form-item-control {text-align: right; 30 | .ant-form-explain{text-align: left;} 31 | .ant-input-group-wrapper{width: 100%; 32 | .ant-input-group-addon{font-size: 16px;color:#000;} 33 | } 34 | .ant-btn{width: 100%;} 35 | >a{color:@text-color-bold;font-weight: bold;} 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | .login-footer{flex: 1;display: flex;align-items: center;justify-content: center;color: @text-color-secondary;flex-direction:column;font-size: 14px; display: none; 43 | a{align-self: flex-end;margin-right: 5%;color:@text-color-bold;font-weight: bold;} 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/styles/personalCenter.less: -------------------------------------------------------------------------------- 1 | @import './theme.less'; 2 | .changePswWrap{position: relative; 3 | .changePsw{margin: 0px auto;background: #42485B;border-radius: 2px;position: absolute;z-index: 2;width: 100%;left: 0;top: -57px;cursor: pointer; 4 | .changePsw_title{padding: 16px;font-size:16px;color: #c0c0c0;border-bottom: 1px solid #565861; 5 | } 6 | .changePsw_title+form{margin-top:26px; 7 | .ant-input{background-color: rgba(255,255,255,0.66);border-radius:2px;color: #4A4A4A; 8 | &:focus{box-shadow: none;} 9 | } 10 | } 11 | .changePsw_btngroup{text-align: right;padding-bottom: 16px; 12 | button{ 13 | margin-right:26px; 14 | } 15 | } 16 | .changePsw_btn{background: #42485B!important;border:none!important;} 17 | } 18 | } 19 | .changePsw_in{ 20 | background: #42485B; 21 | font-size: 16px; 22 | .enter{ 23 | cursor: pointer; 24 | color: #008fe3; 25 | font-style: normal; 26 | } 27 | } -------------------------------------------------------------------------------- /app/styles/set.less: -------------------------------------------------------------------------------- 1 | @import './theme.less'; 2 | .flexcolumn{display: flex; flex:1; flex-direction: column;} 3 | .page-usermanage{ 4 | .page-header{flex: initial;/* margin-top: @space-big */;/* margin-left:@space-big; */ } 5 | .page-content .ant-pagination { padding-bottom: @space-big * 2; right: @space-big * 2;} 6 | .page-content{flex: auto; 7 | .table-content{margin-top:0;} 8 | } 9 | .page-body{ border:@border-split; flex-direction: row;} 10 | .page-title{border-bottom: @border-split;} 11 | .page-body-main{.flexcolumn;} 12 | .ant-layout-sider-children{.flexcolumn; height: 100%; 13 | .ant-spin-nested-loading{.flexcolumn; 14 | .ant-spin-container{.flexcolumn; 15 | .page-title{border-right: @border-split;} 16 | .treeside{ .flexcolumn;margin-bottom: 0;background: @component-background; border-right: @border-split; padding:@space-big;overflow: auto; 17 | > div{.flexcolumn; } 18 | .ant-tree-switcher-noop{ display: none;} 19 | .ant-tree {max-width: 190px; 20 | li { margin: 0; position: relative; padding: 1px 0; 21 | .ant-tree-node-content-wrapper{ width: 100%; padding:7.5px 5px; margin-left: 2px; font-size: 13px; color: #4A4A4A; 22 | &:hover { background-color: rgba(90, 141, 239, 0.12); 23 | .right-icon { display: block; } 24 | } 25 | } 26 | .ant-tree-child-tree{ position: relative; } 27 | .ant-tree-child-tree li:after{ 28 | content: ''; position: absolute; left: -13px; top: -18px; bottom: 17px; border-left: 1px solid @border-color-split; 29 | } 30 | .ant-tree-child-tree li:before{ 31 | content: ''; position: absolute; left: -12px; top: 18px; width: 12px; border-top: 1px solid @border-color-split; 32 | } 33 | .ant-tree-switcher.ant-tree-switcher_close, 34 | .ant-tree-switcher.ant-tree-switcher_open { 35 | cursor: pointer; display: inline-block; width: 12px; height: 12px; text-align: center; background: #fff; z-index: 9; position: relative; 36 | } 37 | } 38 | .right-icon { float: right; margin-right: 20px; display: none; 39 | i { margin-left: @space-base; color: @blue; 40 | &:hover { color: @blue; } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | .ant-layout-content{.flexcolumn;} 49 | } 50 | 51 | // 角色管理 52 | .page-rolemanage{ 53 | .page-footer{margin: 0 -@space-big;} 54 | .roleModuleList{ 55 | tr{ 56 | td:first-child{ text-align: left; padding-left: @space-base;; 57 | span{ white-space: nowrap;} 58 | } 59 | } 60 | } 61 | .page-content{ 62 | .ant-spin-nested-loading{.flexcolumn; 63 | .ant-spin-container{.flexcolumn;} 64 | } 65 | } 66 | .ant-layout-content{.flexcolumn; 67 | .color-red{color:@red;} 68 | .color-green{color:@green;} 69 | .table-checkbox{display: inline-block;} 70 | } 71 | .ant-layout-sider-children{.flexcolumn; padding:@space-big; border-right: @border-split; 72 | .ant-input-group-addon{ cursor: pointer;} 73 | .ant-spin-nested-loading{.flexcolumn; 74 | .ant-spin-container{.flexcolumn; 75 | .treeside{ .flexcolumn;margin-bottom: 0;background: @component-background; border-right: 0; padding:0;overflow: auto; 76 | .ant-tree li{border: 0;} 77 | .roleslist {overflow-y: auto; overflow-x: hidden; 78 | .title{ padding-bottom: @space-base; display: block; color: @text-color-bold; font-size: @font-size-lg; border-bottom: @border-base; margin:@space-base 0 0 @space-sm;} 79 | li{ padding:@space-sm 0 @space-sm @space-base; text-align: left; position: relative; line-height: @line-height-normal; display: flex; 80 | a{ color: @text-color-bold;} 81 | .name{ display: block; flex:1} 82 | &:hover{ background: @hover-background; 83 | .icons{ 84 | display: inline-block; 85 | } 86 | } 87 | } 88 | .icons{display: none; top: @space-normal; right:@space-sm; white-space: nowrap; 89 | i{ padding: @space-sm; color: #fff; margin-right: @space-sm; color: @text-color; 90 | &:hover{color: @blue;} 91 | } 92 | } 93 | .active{background: @hover-background;} 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } 100 | 101 | // 模块管理 102 | .page-modulemanage{ 103 | .ant-table-body{ 104 | .ant-table-tbody{ 105 | tr{ 106 | td:first-child{ text-align: left; padding-left: 12%; 107 | span{ white-space: nowrap;} 108 | } 109 | } 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /app/styles/theme.less: -------------------------------------------------------------------------------- 1 | // reset antd 2 | @input-height-base : 28px; 3 | @input-height-lg : 28px; 4 | @btn-height-base : 28px; 5 | @pagination-item-size : 28px; 6 | @font-size-base : 12px; 7 | // 全局常用颜色的定义 8 | @icon-url : "../resource/iconfont/iconfont"; 9 | @white : #fff; // 白色 10 | @green : #69b721;//绿色 11 | @red : #ff0000;//红色 12 | @blue : #5a8def;//蓝色 13 | @yellow : #eca42b;//黄色 14 | @gray : #b2b2b2;//灰色色 15 | @orange : #ee860b; // 橙色 16 | 17 | // 全局按钮的颜色 主要用来重置antd的主题 18 | @primary-color : #4da9ec; 19 | @info-color : @primary-color; 20 | @success-color : @green; 21 | @error-color : @red; 22 | @highlight-color : @red; 23 | @warning-color : @yellow; 24 | 25 | // 全局默认字体颜色、二级标题颜色、背景颜色、 26 | @body-background : #fff; // 默认背景白色 用来重置antd的默认样式 27 | @background-color-base : #f8f9fd; // 灰白背景的颜色 接近白色 28 | @background-color-content : #e7ebee; // 灰白背景的颜色 更加灰 29 | @background-color-hover : rgba(90,141,239,0.2); // 元素hover的背景颜色 30 | @background-color-active : rgba(90,141,239,0.2); // 元素active的背景颜色 31 | @component-background : #fff; // 常用组件背景颜色 主要是重置antd默认样式 32 | @title-background : #f6f8fc; // 常用标题的淡蓝色背景色 33 | @hover-background : rgba(90, 141, 239, 0.2); // 常用标题的淡蓝色背景色 34 | @navbar-background : #373D41; // 左侧导航背景颜色 35 | @nav-background : #42485B; // 左侧导航背景颜色 36 | @nav-item-background : #333745; // 左侧导航打开项背景色 37 | 38 | // 全局字体定义 39 | @font-family : 'Helvetica Neue For Number,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif'; 40 | @code-family : Consolas, Menlo, Courier, monospace; 41 | 42 | // 全局文字颜色 43 | @text-color-bold : #333; 44 | @text-color : #666; 45 | @text-color-secondary : #999; 46 | 47 | // 全局字体大小 48 | @font-size-base : 12px; 49 | @font-size-lg : 14px; 50 | @font-size-hg : 18px; 51 | 52 | // 全局圆角的定义 53 | @border-radius-base : 2px; 54 | @border-radius-sm : 2px; 55 | 56 | // 边框颜色以及圆角 57 | @border-color-base : #dfe4ea; // 常见灰色边框颜色的定义 58 | @border-color-split : #dfe4ea; // 常见淡蓝色边框颜色的定义 59 | @border-color-dark : #777C8D; // 常见淡蓝色边框颜色的定义 60 | @border-lightBlack : 1px solid #565c6d; // 常见弹框里的边框颜色 61 | @border-base : 1px solid @border-color-base; // 常见灰色边框线的简写方式 62 | @border-split : 1px solid @border-color-split; // 常见淡蓝色边框线的简写方式 63 | @border-split-dashed : 1px dashed @border-color-split; // 常见淡蓝色边框线的简写方式 64 | @border-dark : 1px solid @border-color-dark; // 常见淡蓝色边框线的简写方式 65 | 66 | 67 | // 全局常用行高的定义 68 | @line-height-sm : 28px; 69 | @line-height-normal : 30px; 70 | @line-height-base : 1.5; 71 | @line-height-big : 30px; 72 | @line-height-lg : 36px; 73 | @line-height-hg : 40px; 74 | 75 | // 全局所有的padding或者margin的常用间隔 76 | @space-sm : 4px; 77 | @space-base : 8px; 78 | @space-middle : 12px; 79 | @space-normal : 14px; 80 | @space-big : 16px; 81 | @space-lg : 24px; 82 | @space-hg : 32px; 83 | 84 | @scroll-width : 14px; // 全局滚动条的宽度 85 | 86 | // 全局结构宽度高度的定义 87 | @g-left-width-base : 142px; 88 | @g-left-width-mini : 50px; 89 | @g-middle-width : 280px; 90 | @g-header-height : 64px; 91 | @g-nav-height : 44px; 92 | 93 | @g-header-bg-color : #233344; 94 | @g-title-bg-color : #ebf5fd; 95 | @form-header-color : #fafdff; 96 | 97 | // 网站自定义的icon前缀 98 | @qqbicon-prefix : qqbicon; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-admin", 3 | "version": "0.1.0", 4 | "description": "a react develop stack for pc management system", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/duxianwei520/react" 8 | }, 9 | "private": true, 10 | "scripts": { 11 | "start": "concurrently \"npm run dev\" \"npm run mock\"", 12 | "dev": "webpack-dev-server --config ./scripts/webpack.dev.config.js", 13 | "testing": "webpack --config ./scripts/webpack.testing.config.js", 14 | "build": "cross-env NODE_ENV=production webpack --config ./scripts/webpack.prod.config.js", 15 | "lint": "eslint ./ --cache --fix --ignore-pattern .gitignore", 16 | "test": "jest --coverage", 17 | "mock": "nodemon --watch app/mocks/ app/mocks/http.js", 18 | "precommit": "lint-staged", 19 | "preCommitInit": "node ./node_modules/husky/lib/installer/bin.js install", 20 | "test:report": "jest --coverage --coverageReporters=text-lcov | coveralls", 21 | "dll": "webpack --config ./scripts/webpack.dll.config.js" 22 | }, 23 | "husky": { 24 | "hooks": { 25 | "pre-commit": "lint-staged" 26 | } 27 | }, 28 | "author": "duxianwei", 29 | "contributors": [ 30 | { 31 | "name": "HanQ" 32 | }, 33 | { 34 | "name": "Huxiaoyu" 35 | }, 36 | { 37 | "name": "jinxedjkldsa" 38 | }, 39 | { 40 | "name": "FengYangLiu" 41 | } 42 | ], 43 | "jest": { 44 | "moduleFileExtensions": [ 45 | "js", 46 | "jsx" 47 | ], 48 | "testEnvironment": "jsdom", 49 | "moduleNameMapper": { 50 | "\\.(css|less)$": "identity-obj-proxy", 51 | "^@apis(.*)$": "/app/apis$1", 52 | "^@configs(.*)$": "/app/configs$1", 53 | "^@ajax(.*)$": "/app/configs/ajax.js", 54 | "^@config(.*)$": "/app/configs/config.js", 55 | "^@reg(.*)$": "/app/configs/regular.config.js", 56 | "^@components(.*)$": "/app/components$1", 57 | "^@tableList(.*)$": "/app/components/tableList/tableList.js", 58 | "^@redux/actions(.*)$": "/app/redux/actions$1", 59 | "^@images(.*)$": "/app/images$1" 60 | }, 61 | "transform": { 62 | "^.+\\.js$": "babel-jest" 63 | }, 64 | "collectCoverageFrom": [ 65 | "**/*.{js,jsx}", 66 | "!**/coverage/**", 67 | "!**/scripts/**", 68 | "!**/reducers/**", 69 | "!**/actions/**", 70 | "!**/base/**", 71 | "!**/apis/**", 72 | "!**/mocks/**", 73 | "!**/middleware/**", 74 | "!**/components/**", 75 | "!**/menu/**", 76 | "!**/configs/**", 77 | "!**/store.js", 78 | "!**/provider.jsx", 79 | "!**/example.js", 80 | "!**/client.js", 81 | "!**/webpack.config.js", 82 | "!**/selectRole.js", 83 | "!**/setCenter/index.js", 84 | "!**/dist/**" 85 | ], 86 | "coverageThreshold": { 87 | "global": { 88 | "branches": 50, 89 | "functions": 50, 90 | "lines": 50, 91 | "statements": 50 92 | } 93 | } 94 | }, 95 | "devDependencies": { 96 | "@babel/plugin-proposal-class-properties": "^7.7.0", 97 | "@babel/plugin-proposal-decorators": "^7.7.0", 98 | "@babel/plugin-transform-runtime": "^7.6.2", 99 | "@babel/preset-env": "^7.7.1", 100 | "@babel/preset-react": "^7.7.0", 101 | "add-asset-html-webpack-plugin": "^3.1.3", 102 | "autoprefixer": "^9.7.2", 103 | "babel-eslint": "~8.2.1", 104 | "babel-jest": "^23.6.0", 105 | "babel-loader": "^8.0.6", 106 | "babel-plugin-import": "^1.12.2", 107 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", 108 | "babel-plugin-transform-runtime": "~6.23.0", 109 | "clean-webpack-plugin": "^3.0.0", 110 | "concurrently": "^4.0.1", 111 | "copy-webpack-plugin": "^4.2.3", 112 | "coveralls": "^3.0.0", 113 | "cross-env": "^5.1.4", 114 | "css-loader": "^3.2.0", 115 | "dll-link-webpack-plugin": "^3.2.1", 116 | "enzyme": "^3.7.0", 117 | "eslint": "~4.15.0", 118 | "eslint-config-airbnb": "~16.1.0", 119 | "eslint-plugin-babel": "~4.1.2", 120 | "eslint-plugin-import": "~2.8.0", 121 | "eslint-plugin-jsx-a11y": "~6.0.3", 122 | "eslint-plugin-react": "~7.5.1", 123 | "file-loader": "^4.2.0", 124 | "happypack": "^5.0.0", 125 | "html-webpack-plugin": "^3.2.0", 126 | "http-proxy": "~1.16.2", 127 | "jest": "^23.6.0", 128 | "jsdom": "^12.2.0", 129 | "less": "~2.7.1", 130 | "less-loader": "^4.0.6", 131 | "mini-css-extract-plugin": "^0.8.0", 132 | "mockjs": "^1.0.1-beta3", 133 | "nodemon": "^2.0.7", 134 | "optimize-css-assets-webpack-plugin": "^5.0.3", 135 | "postcss-loader": "^3.0.0", 136 | "react-addons-test-utils": "~15.6.2", 137 | "sinon": "~4.1.6", 138 | "socket.io": "2.0.4", 139 | "style-loader": "^0.19.1", 140 | "terser-webpack-plugin": "^2.2.1", 141 | "url-loader": "^2.2.0", 142 | "webpack": "^4.41.2", 143 | "webpack-bundle-analyzer": "^3.6.0", 144 | "webpack-cli": "^3.3.10", 145 | "webpack-dev-server": "^3.9.0", 146 | "webpack-merge": "^4.1.1", 147 | "webpack-parallel-uglify-plugin": "^1.1.2" 148 | }, 149 | "dependencies": { 150 | "@babel/core": "^7.7.2", 151 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 152 | "@babel/polyfill": "^7.7.0", 153 | "@babel/runtime": "^7.7.2", 154 | "@babel/runtime-corejs2": "^7.7.2", 155 | "@hot-loader/react-dom": "^16.11.0", 156 | "antd": "^3.25.2", 157 | "axios": "^0.19.0", 158 | "benz-amr-recorder": "^1.0.9", 159 | "clipboard": "^2.0.4", 160 | "core-js": "^2.6.10", 161 | "crypto-js": "^3.1.9-1", 162 | "draft-js": "^0.10.3", 163 | "echarts": "^4.5.0", 164 | "enzyme-adapter-react-16": "^1.6", 165 | "esri-loader": "0.3.1", 166 | "husky": "^1.1.2", 167 | "identity-obj-proxy": "^3.0.0", 168 | "immutable": "~3.8.1", 169 | "lint-staged": "^7.3.0", 170 | "md5": "^2.2.1", 171 | "prop-types": "^15.7.2", 172 | "rc-queue-anim": "^1.4.1", 173 | "rc-tween-one": "~1.7.3", 174 | "react": "^16.12.0", 175 | "react-copy-to-clipboard": "~5.0.1", 176 | "react-dom": "^16.5.2", 177 | "react-hot-loader": "^4.12.18", 178 | "react-redux": "~5.0.6", 179 | "react-router": "3.2.0", 180 | "react-router-redux": "~4.0.5", 181 | "redux": "~3.7.2", 182 | "redux-actions": "~2.2.1", 183 | "redux-mock-store": "^1.5.3", 184 | "redux-thunk": "~2.2.0", 185 | "require": "^2.4.20", 186 | "socket.io-client": "^2.2.0" 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer') 4 | ], 5 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![CircleCI branch](https://img.shields.io/circleci/project/github/duxianwei520/react/master.svg?style=flat-square)](https://circleci.com/gh/duxianwei520/react) 2 | [![GitHub forks](https://img.shields.io/github/forks/duxianwei520/react.svg)](https://github.com/duxianwei520/react/network) 3 | [![GitHub stars](https://img.shields.io/github/stars/duxianwei520/react.svg)](https://github.com/duxianwei520/react/stargazers) 4 | [![GitHub issues](https://img.shields.io/github/issues/duxianwei520/react.svg)](https://github.com/duxianwei520/react/issues) 5 | [![GitHub license](https://img.shields.io/github/license/duxianwei520/react.svg)](https://github.com/duxianwei520/react/blob/master/LICENSE) 6 | [![Coverage Status](https://coveralls.io/repos/github/duxianwei520/react/badge.svg)](https://coveralls.io/github/duxianwei520/react) 7 | 8 | ## 项目技术栈 9 | 10 | node10.15.3 + react@16.12.0 + redux@3.7.2 + react-router@3.2.0 + webpack@4.41.2 + axios@0.19.0 + less@2.7.1 + antd@3.25.2 11 | 12 | ## 交流 13 | QQ群:159697743 14 | 15 | ## 项目运行 16 | 17 | 18 | ``` 19 | git clone --depth 1 https://github.com/duxianwei520/react.git 20 | 21 | cd react (进入项目) 22 | 23 | npm install (安装依赖包) 24 | 25 | npm start (启动服务) 26 | 27 | ``` 28 | 29 | ### 如果有小伙伴因为网络原因npm包下载不下来,那么可以最好挂在一个vpn之类的去下载,cnpm不靠谱,不推荐使用 30 | 31 | 32 | ## screenshots 33 | 34 | 35 | ### login 36 | 37 | 38 | 39 | ### echart 40 | 41 | 42 | 43 | 44 | ### set center 45 | 46 | 47 | 48 | 49 | ### webpack bundle analysis 50 | 51 | 52 | 53 | ### build dist folder 54 | 55 | 56 | 57 | 58 | 最后的构建命令 59 | ``` 60 | npm run build (正式环境的打包部署) 61 | npm run testing (测试环境的打包部署命令,可以根据具体需求自行配置修改) 62 | 63 | ``` 64 | 65 | 服务端返回的数据格式也是标准的json,如下所示 66 | 67 | ``` 68 | { 69 | data: { 70 | totalCount: 100, 71 | currentPage: 1, 72 | pageSize: 10, 73 | 'list': [ 74 | ], 75 | }, 76 | msg: '', 77 | status: 1, 78 | } 79 | 80 | ``` 81 | 所有异步请求返回都会经过configs里面的ajax.js做处理,如果请求没有任何问题,那status返回值是1; 82 | 如果请求错误,比如说参数错误或者其他报错之类的,那status返回值就是0; 83 | 如果status值是-1,表示登录超时,那么就会跳出登录。 84 | 这些参数都可以根据实际情况进行调整,报错或者成功的提示信息放在msg里面返回。 85 | 当前项目集成了完整的用户管理、角色管理、模块管理等基本的权限管理功能,小伙伴们一定要同时启动npm run mock才可以看到噢 86 | 87 | 这个react的项目我有在跟nodejs的express框架配合做接口的开发,可以不靠后端输出数据库真实的数据,仓库地址在 88 | 89 | ``` 90 | https://github.com/duxianwei520/express 91 | 92 | ``` 93 | 还有一个原生的nodejs版本的,仓库库地址是 94 | 95 | ``` 96 | https://github.com/duxianwei520/node 97 | 98 | ``` 99 | 基本功能差不多,目前实现了注册登录以及获取用户信息等3个接口的真实api 100 | 101 | 102 | ## 说明 103 | 104 | > 如有问题请直接在 Issues 中提,或者您发现问题并有非常好的解决方案,欢迎 PR 👍 105 | 106 | ### 大部分人项目启动不起来的原因,绝大部分的情况都是npm依赖包安装的时候有些依赖包没有下载完全,当前的demo肯定是可以跑起来的 107 | 108 | ### 取消http请求示例: 109 | ``` 110 | import axios from 'axios' 111 | const axiosHandle = axios.CancelToken.source() 112 | 113 | login(){ 114 | this.props.dispatch(fetchLogin(values, (res) => {},(error)=>{},axiosHandle) 115 | 取消请求的操作 116 | setTimeout(() => { 117 | axiosHandle.cancel('手动取消。') 118 | }, 3000) 119 | } 120 | 121 | ``` 122 | 123 | 124 | ## 功能一览 125 | - [√] 登录,以及登录权限控制 126 | - [√] 项目公用npm模块dll化 127 | - [√] redux完整示范 128 | - [√] mockjs模拟后端返回接口 129 | - [√] axios异步请求跨域的设置 130 | - [√] 实时的webpack包大小预览,方便优化 131 | - [√] draftjs编辑器 132 | 133 | 134 | 135 | ## License 136 | 137 | [MIT](https://github.com/duxianwei520/react/blob/master/LICENSE) 138 | 139 | 140 | ## 交流 141 | 想跟其他的使用react的小伙伴们交流的话,可以加入我创建的reactQQ群:159697743 -------------------------------------------------------------------------------- /scripts/webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | 2 | const path = require('path') 3 | const webpack = require('webpack') 4 | const merge = require('webpack-merge') 5 | const webpackConfigBase = require('./webpack.base.config') 6 | const HtmlWebpackPlugin = require('html-webpack-plugin') 7 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 8 | const os = require('os') 9 | let selfIp 10 | try { 11 | // selfIp = os.networkInterfaces()['WLAN'][1].address 12 | selfIp = getIpAddress() 13 | } catch (e) { 14 | selfIp = 'localhost' 15 | } 16 | 17 | const PORT = 8888 18 | // 精确的获取本机ip地址 19 | function getIpAddress () { 20 | const interfaces = require('os').networkInterfaces 21 | for (let devName in interfaces) { 22 | const iface = interfaces[devName] 23 | for (let i = 0; i < iface.length; i += 1) { 24 | let alias = iface[i] 25 | if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) { 26 | return alias.address 27 | } 28 | } 29 | } 30 | } 31 | 32 | function resolve(relatedPath) { 33 | return path.join(__dirname, relatedPath) 34 | } 35 | const webpackConfigDev = { 36 | mode: 'development', 37 | plugins: [ 38 | // 定义环境变量为开发环境 39 | new webpack.DefinePlugin({ 40 | 'process.env.NODE_ENV': JSON.stringify('development'), 41 | IS_DEVELOPMETN: true, 42 | }), 43 | // 将打包后的资源注入到html文件内 44 | new HtmlWebpackPlugin({ 45 | template: resolve('../app/index.html'), 46 | dlls: [], 47 | }), 48 | new CleanWebpackPlugin(), 49 | new webpack.HotModuleReplacementPlugin() 50 | ], 51 | devtool: 'cheap-module-eval-source-map', 52 | devServer: { 53 | contentBase: resolve('../app'), 54 | historyApiFallback: false, 55 | open: true, 56 | hot: true, 57 | host: selfIp, 58 | port: PORT, 59 | }, 60 | } 61 | 62 | module.exports = merge(webpackConfigBase, webpackConfigDev) 63 | -------------------------------------------------------------------------------- /scripts/webpack.dll.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 4 | 5 | module.exports = { 6 | mode:"production", 7 | entry: { 8 | vendor: [ 9 | // '@babel/polyfill', 10 | 'react', 11 | 'react-dom', 12 | 'react-router', 13 | 'axios', 14 | 'lodash' 15 | ], 16 | redux: [ 17 | 'redux', 18 | 'redux-thunk', 19 | 'react-redux', 20 | 'react-router-redux', 21 | ], 22 | }, 23 | devtool: 'source-mapcheap-module-eval-souce-map', 24 | output: { 25 | filename: '[name].dll.js', 26 | path: path.join(__dirname, '../app/resource/dll'), 27 | library: '[name]_[hash]', 28 | }, 29 | performance: false, 30 | plugins: [ 31 | new CleanWebpackPlugin({ 32 | cleanOnceBeforeBuildPatterns:[path.join(__dirname, '../app/resource/dll')], 33 | verbose:true, 34 | }), 35 | // 定义环境变量为开发环境 36 | new webpack.DefinePlugin({ 37 | 'process.env.NODE_ENV': JSON.stringify('production'), 38 | IS_DEVELOPMETN: true, 39 | }), 40 | 41 | // 使用插件 DllPlugin 42 | new webpack.DllPlugin({ 43 | path: path.join(__dirname, '../app/resource/dll', '[name].manifest.json'), 44 | // This must match the output.library option above 45 | name: '[name]_[hash]', 46 | context: __dirname 47 | }), 48 | 49 | 50 | ] 51 | }; -------------------------------------------------------------------------------- /scripts/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | 2 | const webpack = require('webpack') 3 | const path = require('path') 4 | const merge = require('webpack-merge') 5 | const webpackConfigBase = require('./webpack.base.config') 6 | const Copy = require('copy-webpack-plugin') 7 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') 8 | const HtmlWebpackPlugin = require('html-webpack-plugin') 9 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 10 | const TerserJSPlugin = require("terser-webpack-plugin"); 11 | const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); 12 | 13 | function resolve(relatedPath) { 14 | return path.join(__dirname, relatedPath) 15 | } 16 | 17 | const webpackConfigProd = { 18 | mode: 'production', 19 | output: { 20 | publicPath: './', 21 | }, 22 | devtool: 'cheap-module-source-map', 23 | optimization: { 24 | minimizer: [ 25 | new TerserJSPlugin({ // 多进程压缩 26 | // 设置缓存目录 27 | cache: path.resolve('.cache'), 28 | parallel: 4,// 开启多进程压缩 29 | // sourceMap, 30 | terserOptions: { 31 | compress: { 32 | // 删除所有的 `console` 语句 33 | drop_console: true, 34 | }, 35 | }, 36 | }), 37 | ] 38 | }, 39 | plugins: [ 40 | // 定义环境变量为开发环境 41 | new webpack.DefinePlugin({ 42 | 'process.env.NODE_ENV': JSON.stringify('production'), 43 | IS_DEVELOPMETN: false, 44 | }), 45 | // 将打包后的资源注入到html文件内 46 | new HtmlWebpackPlugin({ 47 | // inject: true, // will inject the main bundle to index.html 48 | template: resolve('../app/index.html'), 49 | // mapConfig:'http://192.168.0.1/map_config.js', 50 | // 这里列出要加入html中的js文件 注释不用dll 51 | dlls: [ 52 | // './resource/dll/vendor.dll.js', 53 | // './resource/dll/redux.dll.js', 54 | ], 55 | }), 56 | // 分析代码 57 | new BundleAnalyzerPlugin({ analyzerMode: 'static' }), 58 | new Copy([ 59 | // { from: './app/resource/dll', to: '../dist/resource/dll' }, 60 | ]), 61 | new OptimizeCSSAssetsPlugin(), 62 | new CleanWebpackPlugin(), 63 | ], 64 | } 65 | 66 | module.exports = merge(webpackConfigBase, webpackConfigProd) 67 | -------------------------------------------------------------------------------- /scripts/webpack.testing.config.js: -------------------------------------------------------------------------------- 1 | 2 | const webpack = require('webpack') 3 | const path = require('path') 4 | const merge = require('webpack-merge') 5 | const webpackConfigBase = require('./webpack.base.config') 6 | const Copy = require('copy-webpack-plugin') 7 | const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') 8 | const HtmlWebpackPlugin = require('html-webpack-plugin') 9 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 10 | 11 | function resolve(relatedPath) { 12 | return path.join(__dirname, relatedPath) 13 | } 14 | 15 | const webpackConfigProd = { 16 | mode: 'development', 17 | output: { 18 | publicPath: './', 19 | }, 20 | plugins: [ 21 | // 定义环境变量为开发环境 22 | new webpack.DefinePlugin({ 23 | 'process.env.NODE_ENV': JSON.stringify('testing'), 24 | IS_DEVELOPMETN: false, 25 | }), 26 | // 将打包后的资源注入到html文件内 27 | new HtmlWebpackPlugin({ 28 | // inject: true, // will inject the main bundle to index.html 29 | template: resolve('../app/index.html'), 30 | // mapConfig:'http://192.168.0.1/map_config.js', 注释不用dll 31 | // 这里列出要加入html中的js文件 32 | dlls: [ 33 | // './resource/dll/vendor.dll.js', 34 | // './resource/dll/redux.dll.js', 35 | ], 36 | }), 37 | 38 | // 分析代码 39 | new BundleAnalyzerPlugin({ analyzerMode: 'static' }), 40 | new Copy([ 41 | // { from: './app/resource/dll', to: '../dist/resource/dll' }, 42 | ]), 43 | new CleanWebpackPlugin(), 44 | ], 45 | } 46 | 47 | module.exports = merge(webpackConfigBase, webpackConfigProd) 48 | -------------------------------------------------------------------------------- /test/Enzyme.js: -------------------------------------------------------------------------------- 1 | import Enzyme from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | 4 | Enzyme.configure({ 5 | adapter: new Adapter(), 6 | }); 7 | 8 | export default Enzyme; 9 | -------------------------------------------------------------------------------- /test/setCenter/sys/moduleManage/index.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../Enzyme.js"; 3 | import RoleManage from "../../../../app/pages/set/roleManage/index"; 4 | import ModuleManage from "../../../../app/pages/set/moduleManage/index"; 5 | import AddModal from "../../../../app/pages/set/moduleManage/modal/moduleAdd"; 6 | import fetchTreeList from "../../../../app/mocks/apis/sys/roleManage/fetchTreeList"; 7 | import ButtonModal from "../../../../app/pages/set/moduleManage/modal/buttonModal"; 8 | jest.mock("../../../../app/pages/set/moduleManage/modal/addButtonModal"); 9 | 10 | let form; 11 | let moduleManage = Enzyme.mount(); 12 | console.log(moduleManage) 13 | moduleManage.setState({ tableDataSource: fetchTreeList.data.list }); 14 | jest.mock("../../../../app/configs/ajax"); 15 | jest.mock("../../../../app/apis/manage.js"); 16 | //页面树 17 | test("tree", () => { 18 | //进入页面渲染 19 | expect(moduleManage.find("tbody tr").length).toBe( 20 | fetchTreeList.data.list.length 21 | ); 22 | //点击tree效果 23 | moduleManage 24 | .find("tbody tr") 25 | .at(0) 26 | .find("span") 27 | .at(1) 28 | .simulate("click"); 29 | expect(moduleManage.find("tbody tr").length).toBe( 30 | fetchTreeList.data.list.length + fetchTreeList.data.list[0].children.length 31 | ); 32 | //状态以上线的类名 33 | expect( 34 | moduleManage 35 | .find(".success") 36 | .at(0) 37 | .text() 38 | ).toBe("已上线"); 39 | }); 40 | test("cancelButton", () => { 41 | moduleManage.instance().cancelButton(); 42 | moduleManage.instance().handleCancel(); 43 | moduleManage.setState({ buttonEditState: "add" }); 44 | moduleManage.instance().handleAdd({}); 45 | 46 | }); 47 | //新增模块 48 | test("addButton/editButton", () => { 49 | moduleManage.find("button").simulate("click"); 50 | //新建按钮点击 51 | expect(moduleManage.state("Visible")).toBe(true); 52 | //新建子菜单按钮点击 53 | moduleManage 54 | .find("tbody tr") 55 | .at(0) 56 | .find("a") 57 | .at(0) 58 | .simulate("click"); 59 | expect(moduleManage.state("title")).toBe("新增子菜单"); 60 | //权限按钮点击 61 | moduleManage 62 | .find("tbody tr") 63 | .at(0) 64 | .find("a") 65 | .at(3) 66 | .simulate("click"); 67 | expect(moduleManage.state("buttonVisible")).toBe(true); 68 | }); 69 | -------------------------------------------------------------------------------- /test/setCenter/sys/moduleManage/module/addButtonModal.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { createStore } from "redux"; 3 | import { Provider } from "react-redux"; 4 | import Enzyme from "../../../../Enzyme.js"; 5 | import RoleManage from "../../../../../app/pages/set/roleManage/index"; 6 | import ModuleManage from "../../../../../app/pages/set/moduleManage/index"; 7 | import AddButtonModal from "../../../../../app/pages/set/moduleManage/modal/addButtonModal"; 8 | import fetchButtonList from "../../../../../app/mocks/apis/sys/roleManage/fetchButtonList"; 9 | import rootReducer from "../../../../../app/redux/reducers"; 10 | 11 | const moduleManage = Enzyme.mount(); 12 | jest.mock("../../../../../app/configs/ajax"); 13 | jest.mock("../../../../../app/apis/manage.js"); 14 | jest.mock("../../../../../app/components/draw/draw"); 15 | // jest.mock("../../../../../app/pages/set/moduleManage/modal/addButtonModal"); 16 | 17 | let store; 18 | let wrapper; 19 | let form; 20 | //新增 参数 21 | const addParam = { 22 | buttonEditData: {}, 23 | title: "新增按钮权限", 24 | onCancel: moduleManage.instance().handleCancel, 25 | handleAdd: moduleManage.instance().handleAdd, 26 | state: "add", 27 | visible: true 28 | }; 29 | store = createStore(rootReducer); 30 | wrapper = Enzyme.mount( 31 | 32 | (form = node)} /> 33 | 34 | ); 35 | //当前页面的WrappedComponent 36 | const ButtonModal = wrapper.prop("children").type.WrappedComponent; 37 | 38 | test("add", () => { 39 | moduleManage.setState({ buttonEditState: "add" }); 40 | const buttonModal = Enzyme.mount( 41 | 42 | ); 43 | buttonModal 44 | .find(".ant-modal-footer button") 45 | .at(0) 46 | .simulate("click"); 47 | }); 48 | //编辑 49 | test("edit", () => { 50 | moduleManage.setState({ buttonEditState: "edit" }); 51 | const editParam = { 52 | buttonEditData: fetchButtonList.data.list[0], 53 | handleOk: moduleManage.instance().handleOk, 54 | title: "修改按钮权限", 55 | onCancel: moduleManage.instance().handleCancel, 56 | handleAdd: moduleManage.instance().handleAdd, 57 | state: "edit" 58 | }; 59 | const buttonModal = Enzyme.mount( 60 | 61 | ); 62 | buttonModal 63 | .find(".ant-modal-footer button") 64 | .at(0) 65 | .simulate("click"); 66 | buttonModal 67 | .find(".ant-modal-footer button") 68 | .at(0) 69 | .simulate("click"); 70 | buttonModal 71 | .prop("form") 72 | .setFieldsValue({ resName: fetchButtonList.data.list[0].resName }); 73 | buttonModal 74 | .prop("form") 75 | .setFieldsValue({ sort: fetchButtonList.data.list[0].sort }); 76 | buttonModal 77 | .prop("form") 78 | .setFieldsValue({ resKey: fetchButtonList.data.list[0].resKey }); 79 | buttonModal 80 | .find(".ant-modal-footer button") 81 | .at(0) 82 | .simulate("click"); 83 | }); 84 | -------------------------------------------------------------------------------- /test/setCenter/sys/moduleManage/module/addmodal.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../../Enzyme.js"; 3 | import RoleManage from "../../../../../app/pages/set/roleManage/index"; 4 | import ModuleManage from "../../../../../app/pages/set/moduleManage/index"; 5 | import AddModal from "../../../../../app/pages/set/moduleManage/modal/moduleAdd"; 6 | import fetchModuleDetail from "../../../../../app/mocks/apis/sys/moduleManage/fetchModuleDetail"; 7 | 8 | const moduleManage = Enzyme.mount(); 9 | jest.mock("../../../../../app/configs/ajax"); 10 | jest.mock("../../../../../app/apis/manage.js"); 11 | jest.mock("../../../../../app/components/draw/draw"); 12 | jest.mock("../../../../../app/pages/set/moduleManage/modal/addButtonModal"); 13 | 14 | let form; 15 | const ModalParam = { 16 | handleOk: moduleManage.instance().handleOk, 17 | visible: true, 18 | title: moduleManage.state("title"), 19 | pid: "", 20 | itemId: "", 21 | values: [], 22 | type: "add", 23 | onCancel: moduleManage.instance().handleCancel 24 | }; 25 | 26 | function modalParam(ModalParam) { 27 | Enzyme.mount( 28 | (form = node)} {...ModalParam} /> 29 | ); 30 | const addModal = Enzyme.mount( 31 | 32 | ); 33 | return addModal; 34 | } 35 | test("add", () => { 36 | const add = { 37 | handleOk: moduleManage.instance().handleOk, 38 | title: "新增菜单", 39 | Visible: true, 40 | pid: "", 41 | itemId: 10063, 42 | type: "add", 43 | values: {} 44 | }; 45 | const addModal = modalParam(add); 46 | addModal 47 | .find(".ant-modal-footer button") 48 | .at(0) 49 | .simulate("click"); 50 | addModal 51 | .prop("form") 52 | .setFieldsValue({ parentId: fetchModuleDetail.data.deptCode }); 53 | addModal 54 | .prop("form") 55 | .setFieldsValue({ resName: fetchModuleDetail.data.resName }); 56 | addModal 57 | .prop("form") 58 | .setFieldsValue({ sort: fetchModuleDetail.data.sort }); 59 | addModal 60 | .prop("form") 61 | .setFieldsValue({ resModule: fetchModuleDetail.data.resModule }); 62 | addModal 63 | .prop("form") 64 | .setFieldsValue({ resKey: fetchModuleDetail.data.resKey }); 65 | addModal 66 | .prop("form") 67 | .setFieldsValue({ resIcon: fetchModuleDetail.data.resIcon }); 68 | addModal 69 | .find(".ant-modal-footer button") 70 | .at(0) 71 | .simulate("click"); 72 | }); 73 | test("edit", () => { 74 | //编辑参数 75 | const editParam = { 76 | handleOk: moduleManage.instance().handleOk, 77 | title: "修改菜单", 78 | Visible: true, 79 | pid: "", 80 | itemId: 10063, 81 | type: "modify", 82 | values: fetchModuleDetail.data 83 | }; 84 | const editModal = modalParam(editParam); 85 | //表单验证 86 | editModal.prop("form").validateFields((err, values) => { 87 | expect(values.parentId).toBe(editModal.prop("pid")); 88 | expect(values.resName).toBe(fetchModuleDetail.data.resName); 89 | expect(values.sort).toBe(String(fetchModuleDetail.data.sort)); 90 | expect(values.resModule).toBe(fetchModuleDetail.data.resModule); 91 | expect(values.resKey).toBe(fetchModuleDetail.data.resKey); 92 | expect(values.resIcon).toBe(fetchModuleDetail.data.resIcon); 93 | }); 94 | //提交 95 | editModal 96 | .find(".ant-modal-footer button") 97 | .at(0) 98 | .simulate("click"); 99 | 100 | }); 101 | -------------------------------------------------------------------------------- /test/setCenter/sys/moduleManage/module/buttonModal.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../../Enzyme.js"; 3 | import RoleManage from "../../../../../app/pages/set/roleManage/index"; 4 | import ModuleManage from "../../../../../app/pages/set/moduleManage/index"; 5 | import ButtonModal from "../../../../../app/pages/set/moduleManage/modal/buttonModal"; 6 | import fetchButtonList from "../../../../../app/mocks/apis/sys/roleManage/fetchButtonList"; 7 | 8 | jest.mock("../../../../../app/configs/ajax"); 9 | jest.mock("../../../../../app/apis/manage.js"); 10 | jest.mock("../../../../../app/components/draw/draw"); 11 | jest.mock("../../../../../app/pages/set/moduleManage/modal/addButtonModal"); 12 | 13 | const moduleManage = Enzyme.mount(); 14 | function modalParam(ModalParam) { 15 | return Enzyme.mount(); 16 | } 17 | fetchButtonList.data.list[0].status = 1; 18 | //页面表格渲染 19 | const editParam = { 20 | Visible: true, 21 | pid: "", 22 | itemId: 10063, 23 | dataSource: fetchButtonList.data.list, 24 | listLoading: true, 25 | title: "模块按钮权限列表", 26 | addButton: moduleManage.instance().addButton, 27 | updateList: moduleManage.instance().getButtonList, 28 | editButton: moduleManage.instance().editButton 29 | }; 30 | const BtnModal = modalParam(editParam); 31 | 32 | test("delete", () => { 33 | BtnModal.find("tbody tr") 34 | .at(0) 35 | .find("a") 36 | .at(2) 37 | .simulate("click"); 38 | BtnModal.find("Popconfirm button") 39 | .at(1) 40 | .simulate("click"); 41 | }); 42 | test("edit", () => { 43 | BtnModal.find("tbody tr") 44 | .at(0) 45 | .find("a") 46 | .at(1) 47 | .simulate("click"); 48 | }); 49 | test("showOrHide", () => { 50 | BtnModal.find("tbody tr") 51 | .at(0) 52 | .find("a") 53 | .at(0) 54 | .simulate("click"); 55 | BtnModal.find("Popconfirm button") 56 | .at(1) 57 | .simulate("click"); 58 | }); 59 | test("add", () => { 60 | BtnModal.find(".ant-modal-footer button") 61 | .at(0) 62 | .simulate("click"); 63 | }); 64 | //表格数据 65 | test("module list", () => { 66 | expect(BtnModal.find("tbody tr").length).toBe( 67 | fetchButtonList.data.list.length 68 | ); 69 | }); 70 | -------------------------------------------------------------------------------- /test/setCenter/sys/moduleManage/moduleList.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../Enzyme.js"; 3 | import RoleManage from "../../../../app/pages/set/roleManage/index"; 4 | import ModuleManage from "../../../../app/pages/set/moduleManage/index"; 5 | import AddModal from "../../../../app/pages/set/moduleManage/modal/moduleAdd"; 6 | import fetchModuleList from "../../../../app/mocks/apis/sys/moduleManage/fetchModuleList"; 7 | import ModuleList from "../../../../app/pages/set/moduleManage/moduleList"; 8 | let form; 9 | let moduleManage = Enzyme.mount(); 10 | moduleManage.setState({ tableDataSource: fetchModuleList.data.list }); 11 | jest.mock("../../../../app/configs/ajax"); 12 | jest.mock("../../../../app/apis/manage.js"); 13 | fetchModuleList.data.list[0].status = true; 14 | fetchModuleList.data.list[1].resName = "模块管理"; 15 | const param = { 16 | dataSource: fetchModuleList.data.list, 17 | loading: true, 18 | onDelete: moduleManage.instance().handleDelete, 19 | onModify: moduleManage.instance().handleModify, 20 | onUpdataStatus: moduleManage.instance().handleChangeStatus, 21 | onAddNode: moduleManage.instance().handleAddNode, 22 | buttonList: moduleManage.instance().buttonList 23 | }; 24 | let moduleList = Enzyme.mount(); 25 | console.log(moduleList) 26 | fetchModuleList.data.list[1].resName = "123"; 27 | moduleList.setProps({ dataSource: fetchModuleList.data.list }); 28 | test("addButton", () => { 29 | moduleList 30 | .find("tbody tr") 31 | .at(0) 32 | .find("a") 33 | .at(0) 34 | .simulate("click"); 35 | expect(moduleManage.state("title")).toBe("新增子菜单"); 36 | }); 37 | test("editButton", () => { 38 | moduleList 39 | .find("tbody tr") 40 | .at(0) 41 | .find("a") 42 | .at(1) 43 | .simulate("click"); 44 | expect(moduleManage.state("title")).toBe("修改菜单"); 45 | }); 46 | test("UpdataStatus", () => { 47 | moduleList 48 | .find("tbody tr") 49 | .at(1) 50 | .find("a") 51 | .at(2) 52 | .simulate("click"); 53 | moduleList 54 | .find("Popconfirm button") 55 | .at(1) 56 | .simulate("click"); 57 | }); 58 | test("delete", () => { 59 | //点击tree效果 60 | moduleList 61 | .find("tbody tr") 62 | .at(0) 63 | .find("span") 64 | .at(1) 65 | .simulate("click"); 66 | //点击子元素的删除按钮 67 | moduleList 68 | .find("tbody tr") 69 | .at(1) 70 | .find("a") 71 | .at(2) 72 | .simulate("click"); 73 | moduleList 74 | .find("Popconfirm button") 75 | .at(1) 76 | .simulate("click"); 77 | }); 78 | -------------------------------------------------------------------------------- /test/setCenter/sys/roleManage/index.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../Enzyme.js"; 3 | import RoleManage from "../../../../app/pages/set/roleManage/index"; 4 | import fetchRoleList from "../../../../app/mocks/apis/sys/userManage/fetchRoleList"; 5 | import fetchModuleListInRole from "../../../../app/mocks/apis/sys/roleManage/fetchModuleListInRole"; 6 | import RoleList from "../../../../app/pages/set/roleManage/roleList"; 7 | import fetchUserList from "../../../../app/mocks/apis/sys/userManage/fetchUserList"; 8 | jest.mock("../../../../app/configs/ajax"); 9 | jest.mock("../../../../app/apis/manage.js"); 10 | let form; 11 | fetchRoleList.data.list[0].id = null; 12 | const listParam = { 13 | roles: fetchRoleList.data.list, 14 | btnRights: {} 15 | }; 16 | const roleList = Enzyme.mount(); 17 | 18 | Enzyme.mount( (form = node)} />); 19 | let roleManage = Enzyme.mount( 20 | 21 | ); 22 | 23 | describe("index", () => { 24 | const eve = { 25 | target: { 26 | value: "setpeoples" 27 | } 28 | }; 29 | roleManage.instance().changeTab(eve); 30 | eve.target.value = "stepTree"; 31 | roleManage.instance().changeTab(eve); 32 | eve.target.value = "setmodules"; 33 | roleManage.instance().changeTab(eve); 34 | roleManage.setState({ activeTab: "setpeoples" }); 35 | roleManage.instance().getData("init"); 36 | roleManage.instance().returnContent("i"); 37 | 38 | roleManage.setState({ 39 | btnRights: { 40 | add: false, 41 | edit: true, 42 | deleteRole: true, 43 | deletePolice: false 44 | } 45 | }); 46 | roleManage.instance().renderColumn(); 47 | roleManage.setState({ 48 | btnRights: { 49 | add: true, 50 | edit: true, 51 | deleteRole: true, 52 | deletePolice: true 53 | } 54 | }); 55 | //搜索 56 | test("search", () => { 57 | roleManage.instance().handleRoleSearch("123"); 58 | }); 59 | //编辑保存 60 | test("editsave", () => { 61 | roleManage.setState({ activeTab: "setpeoples" }); 62 | roleManage 63 | .find(".left button") 64 | .at(0) 65 | .simulate("click"); 66 | }); 67 | //删除 68 | test("delete", () => { 69 | roleManage.setState({ activeTab: "setpeoples" }); 70 | roleManage 71 | .find("tbody tr") 72 | .at(0) 73 | .find("a") 74 | .simulate("click"); 75 | roleManage 76 | .find("Popconfirm button") 77 | .at(1) 78 | .simulate("click"); 79 | }); 80 | //列表搜索 81 | test("listSearch", () => { 82 | const event = { 83 | stopPropagation: function() {} 84 | }; 85 | roleManage.instance().handleSearch(event); 86 | }); 87 | //提交 88 | test("测试提交", () => { 89 | roleManage.setState({ activeTab: "setpeoples" }); 90 | 91 | roleManage.instance().handleOk(); 92 | roleManage.setState({ activeTab: "setmodules" }); 93 | 94 | roleManage.instance().handleOk(); 95 | }); 96 | //Modal关闭函数 97 | test("Modal取消", () => { 98 | roleManage.instance().handleCancel(); 99 | }); 100 | test("pagenext", () => { 101 | roleManage.instance().pageChange(2); 102 | expect(roleManage.state().peopleSearchKey.pageNo).toBe(2); 103 | roleManage.instance().pageSizeChange({}, 20); 104 | expect(roleManage.state().peopleSearchKey.pageSize).toBe(20); 105 | }); 106 | }); 107 | //roleList模块 108 | describe("roleList", () => { 109 | roleList.setProps({ 110 | roles: fetchRoleList.data.list, 111 | handleRoleDelete: roleManage.instance().handleRoleDelete, 112 | onCurrentIndex: roleManage.instance().handleCurrentIndex, 113 | btnRights: roleManage.state().btnRights, 114 | onRoleModify: roleManage.instance().onRoleModify 115 | }); 116 | roleManage.setState({ 117 | roleListResult: false 118 | }); 119 | //左侧角色列表查询 120 | test("fetchUserList", () => { 121 | expect(roleManage.find(".roleslist li").length).toBe( 122 | fetchRoleList.data.list.length 123 | ); 124 | }); 125 | //搜索 126 | test("onSearch", () => { 127 | roleManage.find('.ant-input-wrapper .ant-input-suffix').simulate('click') 128 | roleManage.find('.ant-input-wrapper .ant-input-suffix i').simulate('click') 129 | }); 130 | //编辑 131 | 132 | test("edit", () => { 133 | roleList 134 | .find("li") 135 | .at(0) 136 | .simulate("mouseover"); 137 | roleList 138 | .find(".icons") 139 | .at(0) 140 | .find("i") 141 | .at(0) 142 | .simulate("click"); 143 | }); 144 | //删除 145 | test("delete", () => { 146 | roleList 147 | .find("li") 148 | .at(0) 149 | .simulate("mouseover"); 150 | roleList 151 | .find(".icons") 152 | .at(0) 153 | .find("i") 154 | .at(1) 155 | .simulate("click"); 156 | roleList 157 | .find("Popconfirm button") 158 | .at(1) 159 | .simulate("click"); 160 | }); 161 | //左侧菜单栏点击事件 162 | test("nameClick", () => { 163 | roleManage.setState({ activeTab: "stepTree" }); 164 | roleManage 165 | .find(".roleslist li") 166 | .at(0) 167 | .find(".name") 168 | .simulate("click"); 169 | roleManage.setState({ activeTab: "setpeoples" }); 170 | roleManage 171 | .find(".roleslist li") 172 | .at(0) 173 | .find(".name") 174 | .simulate("click"); 175 | roleManage.setState({ activeTab: "setmodules" }); 176 | roleManage 177 | .find(".roleslist li") 178 | .at(0) 179 | .find(".name") 180 | .simulate("click"); 181 | expect(roleManage.state("currRoleId")).toBe(fetchRoleList.data.list[0].id); 182 | }); 183 | //添加模板 184 | test("addModule", () => { 185 | roleManage.find(".ant-input-group-addon i").simulate("click"); 186 | expect(roleManage.state("title")).toBe("新增角色"); 187 | expect(roleManage.state("type")).toBe("add"); 188 | }); 189 | }); 190 | //校色树tab 191 | test("UserTreeTab", () => { 192 | roleManage.setState({ 193 | activeTab: "stepTree", 194 | treeData: fetchModuleListInRole.data.list 195 | }); 196 | expect(roleManage.find("tbody tr").length).toBe( 197 | fetchModuleListInRole.data.list.length 198 | ); 199 | roleManage 200 | .find("tbody tr") 201 | .at(0) 202 | .find("span") 203 | .at(1) 204 | .simulate("click"); 205 | expect(roleManage.find("tbody tr").length).toBe( 206 | fetchModuleListInRole.data.list.length + 207 | fetchModuleListInRole.data.list[0].children.length 208 | ); 209 | }); 210 | -------------------------------------------------------------------------------- /test/setCenter/sys/roleManage/modal/buttonModal.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../../Enzyme.js"; 3 | import RoleManage from "../../../../../app/pages/set/roleManage/index"; 4 | import ButtonModal from "../../../../../app/pages/set/roleManage/modal/buttonModal"; 5 | jest.mock("../../../../../app/configs/ajax"); 6 | jest.mock("../../../../../app/apis/manage.js"); 7 | jest.mock("../../../../../app/components/draw/draw"); 8 | let form1; 9 | Enzyme.mount( (form1 = node)} />); 10 | let roleManage = Enzyme.mount( 11 | 12 | ); 13 | const callback = {}; 14 | let form = {}; 15 | 16 | const param = { 17 | title: "按钮权限列表", 18 | type: "add", 19 | pid: 10062, 20 | itemId: 1, 21 | cancelButton: roleManage.instance().cancelButton, 22 | saveChecked: roleManage.instance().saveChecked, 23 | checkedIdArr: [] 24 | }; 25 | let buttonModal = Enzyme.mount(); 26 | test("全选按钮", () => { 27 | buttonModal 28 | .find(".ant-modal-footer button") 29 | .at(0) 30 | .simulate("click"); 31 | }); 32 | buttonModal.setState({ 33 | selectedRowKeys: [134] 34 | }); 35 | test("初始化", () => { 36 | buttonModal.instance().getList(); 37 | }); 38 | test("确定按钮", () => { 39 | buttonModal 40 | .find(".ant-modal-footer button") 41 | .at(1) 42 | .simulate("click"); 43 | }); 44 | test("页面按钮点击选中", () => { 45 | buttonModal 46 | .find(".ant-spin-container button") 47 | .at(0) 48 | .simulate("click"); 49 | }); 50 | -------------------------------------------------------------------------------- /test/setCenter/sys/roleManage/modal/roleAdd.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../../Enzyme.js"; 3 | import RoleManage from "../../../../../app/pages/set/roleManage/index"; 4 | import RoleAdd from "../../../../../app/pages/set/roleManage/modal/roleAdd"; 5 | import fetchRoleDetail from "../../../../../app/mocks/apis/sys/roleManage/fetchRoleDetail"; 6 | jest.mock("../../../../../app/configs/ajax"); 7 | jest.mock("../../../../../app/apis/manage.js"); 8 | jest.mock("../../../../../app/components/draw/draw"); 9 | let form1; 10 | Enzyme.mount( (form1 = node)} />); 11 | let roleManage = Enzyme.mount( 12 | 13 | ); 14 | const callback = {}; 15 | let form = {}; 16 | fetchRoleDetail.data.tjFlag='123' 17 | const param = { 18 | visible: true, 19 | title: "修改角色", 20 | onCancel: roleManage.instance().handleCancel, 21 | handleOk: roleManage.instance().handleOk, 22 | value: fetchRoleDetail.data, 23 | type: "modify", 24 | modifyId: 1 25 | }; 26 | let Form = Enzyme.mount( 27 | (form = node)} /> 28 | ); 29 | 30 | let roleAdd = Enzyme.mount( 31 | 32 | ); 33 | test("编辑提交", () => { 34 | const event = { 35 | preventDefault: function() {} 36 | }; 37 | roleAdd.instance().handleSubmit(event); 38 | expect(roleAdd.find(".ant-modal-title").text()).toBe("修改角色"); 39 | }); 40 | test("新增提交", () => { 41 | const event = { 42 | preventDefault: function() {} 43 | }; 44 | roleAdd.setProps({ 45 | visible: true, 46 | title: "新增角色", 47 | onCancel: roleManage.instance().handleCancel, 48 | handleOk: roleManage.instance().handleOk, 49 | value: { roleName: "", sort: "", tjFlag: "123" }, 50 | type: "add" 51 | }); 52 | roleAdd 53 | .find(".ant-modal-footer button") 54 | .at(0) 55 | .simulate("click"); 56 | expect(roleAdd.find(".ant-modal-title").text()).toBe("新增角色"); 57 | roleAdd.prop("form").setFieldsValue({ roleName: "" }); 58 | roleAdd 59 | .find(".ant-modal-footer button") 60 | .at(0) 61 | .simulate("click"); 62 | roleAdd 63 | .find(".ant-modal-footer button") 64 | .at(0) 65 | .simulate("click"); 66 | }); 67 | 68 | -------------------------------------------------------------------------------- /test/setCenter/sys/roleManage/roleCheckbox.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../Enzyme.js"; 3 | import RoleManage from "../../../../app/pages/set/roleManage/index"; 4 | import fetchRoleList from "../../../../app/mocks/apis/sys/userManage/fetchRoleList"; 5 | import UserList from "../../../../app/mocks/apis/sys/userManage/fetchUserList"; 6 | import fetchTreeList from "../../../../app/mocks/apis/sys/roleManage/fetchTreeList"; 7 | import RoleModuleList from "../../../../app/pages/set/roleManage/roleModuleList"; 8 | 9 | let form; 10 | Enzyme.mount( (form = node)} />); 11 | let roleManage = Enzyme.mount( 12 | 13 | ); 14 | 15 | 16 | test("roleCheckbox", () => { 17 | const listParam = { 18 | dataSource: [], 19 | checkedId: [] 20 | }; 21 | const roleModule = Enzyme.mount(); 22 | roleModule.setProps({ 23 | dataSource: fetchTreeList.data.list, 24 | checkedId: [10062, 10063, 10108, 10109, 10110] 25 | }); 26 | roleModule 27 | .find("tbody tr") 28 | .at(1) 29 | .find("span") 30 | .at(1) 31 | .simulate("click"); 32 | }); 33 | -------------------------------------------------------------------------------- /test/setCenter/sys/roleManage/roleModuleList.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../Enzyme.js"; 3 | import RoleManage from "../../../../app/pages/set/roleManage/index"; 4 | import fetchRoleList from "../../../../app/mocks/apis/sys/userManage/fetchRoleList"; 5 | import UserList from "../../../../app/mocks/apis/sys/userManage/fetchUserList"; 6 | import fetchTreeList from "../../../../app/mocks/apis/sys/roleManage/fetchTreeList"; 7 | import fetchModuleListInRole from "../../../../app/mocks/apis/sys/roleManage/fetchModuleListInRole"; 8 | import RoleModuleList from "../../../../app/pages/set/roleManage/roleModuleList"; 9 | import RoleCheckbox from "../../../../app/pages/set/roleManage/roleCheckbox"; 10 | jest.mock("../../../../app/configs/ajax"); 11 | jest.mock("../../../../app/apis/manage.js"); 12 | let form; 13 | Enzyme.mount( (form = node)} />); 14 | let roleManage = Enzyme.mount( 15 | 16 | ); 17 | 18 | describe("roleModuleList", () => { 19 | const listParam = { 20 | dataSource: [], 21 | checkedId: [], 22 | onCheckModify: roleManage.instance().handleCheckModify, 23 | buttonList:roleManage.instance().buttonList 24 | }; 25 | const roleModule = Enzyme.mount(); 26 | roleModule.setProps({ 27 | dataSource: fetchModuleListInRole.data.list, 28 | checkedId: [10062, 10063, 10108, 10109, 10110, 10118, 11003] 29 | }); 30 | test("rolecheckbox", () => { 31 | const checkboxParam = { 32 | checkItem: fetchModuleListInRole.data.list[1].children[1], 33 | onChecked: roleModule.instance().onChecked, 34 | defaultChecked: false, 35 | nowRoleName: undefined 36 | }; 37 | const roleCheckbox = Enzyme.mount(); 38 | roleCheckbox.setProps({ defaultChecked: true }); 39 | const event = { 40 | target: { 41 | checked: false 42 | } 43 | }; 44 | roleCheckbox.instance().onChange(event); 45 | //未开通的点击成已开通 46 | event.target.checked = true; 47 | roleCheckbox.setProps({ 48 | checkItem: fetchModuleListInRole.data.list[1] 49 | }); 50 | roleCheckbox.instance().onChange(event); 51 | 52 | event.target.checked = false; 53 | //onInArray函数 54 | roleCheckbox.setProps({ 55 | checkItem: fetchModuleListInRole.data.list[1].children[2] 56 | }); 57 | roleModule.setState({ checkedIds: null }); 58 | roleCheckbox.instance().onChange(event); 59 | roleModule.setState({ 60 | checkedIds: [10062, 10108] 61 | }); 62 | roleCheckbox.setProps({ 63 | checkItem: fetchModuleListInRole.data.list[1].children[0] 64 | }); 65 | roleCheckbox.instance().onChange(event); 66 | 67 | //fatherArr.length === 1判断 68 | 69 | fetchModuleListInRole.data.list[1].children.pop(); 70 | fetchModuleListInRole.data.list[1].children.pop(); 71 | roleCheckbox.setProps({ 72 | checkItem: fetchModuleListInRole.data.list[1].children[0] 73 | }); 74 | event.target.checked = false; 75 | roleCheckbox.instance().onChange(event); 76 | event.target.checked = true; 77 | roleCheckbox.instance().onChange(event); 78 | //拥有两个父级 79 | event.target.checked = false; 80 | roleCheckbox.setProps({ 81 | checkItem: fetchModuleListInRole.data.list[1].children[0].children[0] 82 | }); 83 | roleCheckbox.instance().onChange(event); 84 | }); 85 | //按钮权限 86 | test('buttonList',()=>{ 87 | roleModule.find('tbody tr').at(0).find('a').simulate('click') 88 | }) 89 | 90 | }); 91 | -------------------------------------------------------------------------------- /test/setCenter/sys/userManage/index.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../Enzyme.js"; 3 | import UserName from "../../../../app/pages/set/userManage/index"; 4 | import TreeList from "../../../../app/pages/set/userManage/treeList"; 5 | import UserList from "../../../../app/mocks/apis/sys/userManage/fetchUserList"; 6 | import AddPolice from "../../../../app/pages/set/userManage/modal/addPolice"; 7 | import userDeptResult from "../../../../app/mocks/apis/sys/userManage/fetchUserDepttList"; 8 | import TableList from "../../../../app/components/tableList/tableList"; 9 | jest.mock("../../../../app/configs/ajax"); 10 | jest.mock("../../../../app/apis/manage"); 11 | 12 | let form; 13 | Enzyme.mount( (form = node)} />); 14 | let UserManage = Enzyme.mount( 15 | 16 | ); 17 | const param = { 18 | deptCode: "370200000000" 19 | }; 20 | UserManage.setState({ 21 | searchKey: param, 22 | userListResult: UserList.data, 23 | userDeptResult: userDeptResult.data, 24 | btnRights: { 25 | view: false, 26 | freeze: false, 27 | delete: false, 28 | edit: false, 29 | add: false 30 | } // 按钮权限的数组 31 | }); 32 | 33 | UserManage.setState({ 34 | btnRights: { 35 | view: true, 36 | freeze: true, 37 | delete: true, 38 | edit: true, 39 | add: true 40 | } // 按钮权限的数组 41 | }); 42 | // 搜索按钮点击 43 | test("search", () => { 44 | const event = { 45 | preventDefault: function() {} 46 | }; 47 | UserManage.instance().handleSearch(event); 48 | }); 49 | 50 | // 新增 51 | test("handleChangeStatusAdd", () => { 52 | UserManage.setState({ 53 | searchKey: { 54 | deptCode: null 55 | } 56 | }); 57 | UserManage.find("Button") 58 | .at(1) 59 | .simulate("click"); 60 | 61 | UserManage.setState({ 62 | searchKey: { 63 | deptCode: "370200000000" 64 | } 65 | }); 66 | UserManage.find("Button") 67 | .at(1) 68 | .simulate("click"); 69 | expect(UserManage.state().moduletitle).toBe("新增"); 70 | }); 71 | 72 | //点击用户详情 73 | test("handleChangeStatusEdit", () => { 74 | UserManage.setState({ 75 | searchKey: param, 76 | userListResult: UserList.data, 77 | userDeptResult: userDeptResult.data, 78 | PoliceAddVisible: false, 79 | moduletype: "edit", 80 | userRoleSetResult: {} 81 | }); 82 | UserManage.find("tbody tr") 83 | .at(0) 84 | .find("a") 85 | .at(0) 86 | .simulate("click"); 87 | expect(UserManage.state().PoliceAddVisible).toBe(true); 88 | UserManage.instance().handleCancel(); 89 | }); 90 | 91 | //冻结账户 92 | test("handleChangeStatus", () => { 93 | UserManage.find("tbody tr") 94 | .at(0) 95 | .find("a") 96 | .at(1) 97 | .simulate("click"); 98 | UserManage.find("Popconfirm button") 99 | .at(1) 100 | .simulate("click"); 101 | UserManage.find("tbody tr") 102 | .at(1) 103 | .find("a") 104 | .at(1) 105 | .simulate("click"); 106 | UserManage.find("Popconfirm button") 107 | .at(1) 108 | .simulate("click"); 109 | }); 110 | 111 | // 同步人员 112 | test("synchronize", () => { 113 | UserManage.find(".page-footer Button") 114 | .at(1) 115 | .simulate("click"); 116 | }); 117 | //页码改变 118 | test("pagenext", () => { 119 | UserManage.instance().pageChange(2); 120 | expect(UserManage.state().searchKey.pageNo).toBe(2); 121 | UserManage.instance().pageSizeChange({}, 20); 122 | expect(UserManage.state().searchKey.pageSize).toBe(20); 123 | }); 124 | // treelist模块 125 | describe("treeList", () => { 126 | const treeListParam = { 127 | curDeptCode: "370200000000", 128 | onSelect: UserManage.instance().onSelect 129 | }; 130 | const treeList = Enzyme.mount(); 131 | //树点击事件 132 | treeList.setProps({ 133 | trees: userDeptResult.data.list 134 | }); 135 | it("treeClick", () => { 136 | treeList 137 | .find("li") 138 | .at(0) 139 | .find("span") 140 | .at(0) 141 | .simulate("click"); 142 | expect(treeList.state("expandedKeys")).toContain( 143 | userDeptResult.data.list[0].deptCode 144 | ); 145 | }); 146 | //树内容点击事件 147 | it("treeListClick", () => { 148 | treeList 149 | .find("li") 150 | .at(0) 151 | .find("span") 152 | .at(1) 153 | .simulate("click"); 154 | treeList 155 | .find("li") 156 | .at(1) 157 | .find("span") 158 | .at(1) 159 | .simulate("click"); 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /test/setCenter/sys/userManage/modal/addPolice.spec.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Enzyme from "../../../../Enzyme.js"; 3 | import UserName from "../../../../../app/pages/set/userManage/index"; 4 | import AddPolice from "../../../../../app/pages/set/userManage/modal/addPolice"; 5 | import roleList from "../../../../../app/mocks/apis/sys/userManage/fetchRoleList"; 6 | import fetchUserDetail from "../../../../../app/mocks/apis/sys/userManage/fetchUserDetail"; 7 | import UserList from "../../../../../app/mocks/apis/sys/userManage/fetchUserList"; 8 | 9 | import Draw from "../../../../../app/components/draw/draw"; 10 | jest.mock("../../../../../app/configs/ajax"); 11 | 12 | 13 | 14 | jest.mock("../../../../../app/components/draw/draw"); 15 | let form1; 16 | Enzyme.mount( (form1 = node)} />); 17 | let UserManage = Enzyme.mount( 18 | 19 | ); 20 | const callback = {}; 21 | 22 | let form = {}; 23 | const param = { 24 | deptId: "370200000000", 25 | handleOk: UserManage.instance().handleOk, 26 | title: "新增", 27 | type: "add", 28 | visible: true, 29 | roleList: roleList.data.list, 30 | values: {}, 31 | onCancel: UserManage.instance().onCancel 32 | }; 33 | UserList.data.totalCount = 10; 34 | UserManage.setState({ 35 | userListResult: UserList.data 36 | }); 37 | let Form = Enzyme.mount( 38 | (form = node)} 42 | /> 43 | ); 44 | 45 | let policeFrom = Enzyme.mount( 46 | 51 | ); 52 | //新增弹出框基础信息验证 53 | test("addInit", () => { 54 | UserManage.setState({ 55 | moduletype: "add", 56 | userListResult: UserList.data 57 | }); 58 | policeFrom 59 | .find("button") 60 | .at(2) 61 | .simulate("click"); 62 | policeFrom 63 | .prop("form") 64 | .setFieldsValue({ chineseName: fetchUserDetail.data.chineseName }); 65 | policeFrom 66 | .prop("form") 67 | .setFieldsValue({ password: fetchUserDetail.data.password }); 68 | policeFrom 69 | .prop("form") 70 | .setFieldsValue({ username: fetchUserDetail.data.username }); 71 | policeFrom 72 | .prop("form") 73 | .setFieldsValue({ idcardNo: fetchUserDetail.data.idcardNo }); 74 | policeFrom 75 | .prop("form") 76 | .setFieldsValue({ deptCode: fetchUserDetail.data.deptCode }); 77 | policeFrom 78 | .prop("form") 79 | .setFieldsValue({ phoneNo: fetchUserDetail.data.phoneNo }); 80 | policeFrom 81 | .prop("form") 82 | .setFieldsValue({ gxdwdm: fetchUserDetail.data.gxdwdm }); 83 | policeFrom 84 | .prop("form") 85 | .setFieldsValue({ roleIds: fetchUserDetail.data.roleIds }); 86 | expect(policeFrom.find("Drawer").props().title).toBe("新增"); 87 | expect(policeFrom.find("Drawer").props().visible).toBe(param.visible); 88 | policeFrom 89 | .find("button") 90 | .at(2) 91 | .simulate("click"); 92 | }); 93 | //编辑框基础信息验证 94 | test("editInit", () => { 95 | UserManage.setState({ 96 | moduletype: "edit", 97 | userListResult: UserList.data 98 | }); 99 | const param = { 100 | deptId: "370200000000", 101 | handleOk: UserManage.instance().handleOk, 102 | title: "编辑", 103 | type: "edit", 104 | visible: true, 105 | roleList: roleList.data.list, 106 | values: fetchUserDetail.data 107 | }; 108 | policeFrom.setProps(param); 109 | expect(policeFrom.find("Drawer").props().title).toBe("编辑"); 110 | policeFrom 111 | .find("button") 112 | .at(2) 113 | .simulate("click"); 114 | policeFrom 115 | .find("button") 116 | .at(3) 117 | .simulate("click"); 118 | }); 119 | --------------------------------------------------------------------------------