├── .gitignore ├── README.md ├── config-overrides.js ├── config ├── env.js ├── jest │ ├── cssTransform.js │ └── fileTransform.js ├── paths.js ├── webpack.config.js └── webpackDevServer.config.js ├── package-lock.json ├── package.json ├── public ├── assets │ ├── bike.jpg │ ├── carousel-img │ │ ├── carousel-1.jpg │ │ ├── carousel-2.jpg │ │ └── carousel-3.jpg │ ├── end_point.png │ ├── imooc.png │ ├── logo-ant.svg │ ├── start_point.png │ └── user_location.png ├── carousel-img │ ├── carousel-1.jpg │ ├── carousel-2.jpg │ └── carousel-3.jpg ├── favicon.ico ├── gallery │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 2.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.png │ ├── 24.png │ ├── 25.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ └── 9.png ├── index.html └── manifest.json ├── scripts ├── build.js ├── start.js └── test.js ├── src ├── App.css ├── App.js ├── App.test.js ├── admin.js ├── axios │ └── index.js ├── common.js ├── components │ ├── BaseForm │ │ └── index.js │ ├── ETable │ │ ├── index.js │ │ └── index.less │ ├── Footer │ │ ├── index.js │ │ └── index.less │ ├── Header │ │ ├── index.js │ │ └── index.less │ └── NavLeft │ │ ├── index.js │ │ └── index.less ├── config │ └── menuConfig.js ├── index.css ├── index.js ├── logo.svg ├── pages │ ├── Home │ │ ├── index.js │ │ └── index.less │ ├── Login │ │ ├── index.js │ │ └── index.less │ ├── NoMatch │ │ ├── index.js │ │ └── index.less │ ├── city │ │ └── index.js │ ├── echarts │ │ ├── bar │ │ │ └── index.js │ │ ├── echartTheme.js │ │ ├── line │ │ │ └── index.js │ │ ├── pie │ │ │ └── index.js │ │ └── themeLight.js │ ├── form │ │ ├── login.js │ │ └── register.js │ ├── map │ │ └── bikeMap.js │ ├── order │ │ ├── detail.js │ │ ├── detail.less │ │ └── index.js │ ├── permission │ │ └── index.js │ ├── rich │ │ └── index.js │ ├── router_demo │ │ ├── About.js │ │ ├── Home.js │ │ ├── Info.js │ │ ├── Main.js │ │ ├── NoMatch.js │ │ ├── Topics.js │ │ ├── User.js │ │ └── router.js │ ├── table │ │ ├── basicTable.js │ │ └── highTable.js │ ├── ui │ │ ├── buttons.js │ │ ├── carousel.js │ │ ├── gallery.js │ │ ├── loadings.js │ │ ├── messages.js │ │ ├── modals.js │ │ ├── notice.js │ │ ├── tabs.js │ │ └── ui.less │ └── user │ │ └── index.js ├── redux │ ├── action │ │ └── index.js │ ├── reducer │ │ └── index.js │ └── store │ │ └── configureStore.js ├── resource │ ├── api │ │ ├── .json │ │ ├── city │ │ │ ├── list.json │ │ │ └── open.json │ │ ├── info_alarm.json │ │ ├── map │ │ │ └── bike_list.json │ │ ├── mock.json │ │ ├── open_city.json │ │ ├── order │ │ │ ├── detail.json │ │ │ ├── ebike_info.json │ │ │ ├── finish_order.json │ │ │ └── list.json │ │ ├── permission │ │ │ └── edit.json │ │ ├── proxy.json │ │ ├── query.json │ │ ├── restful │ │ │ └── _id │ │ │ │ └── list.json │ │ ├── role │ │ │ ├── create.json │ │ │ ├── list.json │ │ │ ├── user_list.json │ │ │ └── user_role_edit.json │ │ ├── table │ │ │ ├── high │ │ │ │ └── list.json │ │ │ ├── list.json │ │ │ └── list1.json │ │ ├── upload.json │ │ └── user │ │ │ ├── add.json │ │ │ ├── delete.json │ │ │ └── edit.json │ ├── assets │ │ ├── bike.jpg │ │ ├── carousel-img │ │ │ ├── carousel-1.jpg │ │ │ ├── carousel-2.jpg │ │ │ └── carousel-3.jpg │ │ ├── end_point.png │ │ ├── imooc.png │ │ ├── logo-ant.svg │ │ ├── start_point.png │ │ └── user_location.png │ ├── carousel-img │ │ ├── carousel-1.jpg │ │ ├── carousel-2.jpg │ │ └── carousel-3.jpg │ ├── common.less │ ├── default.less │ ├── doc.js │ ├── favicon.ico │ ├── gallery │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 15.png │ │ ├── 16.png │ │ ├── 17.png │ │ ├── 18.png │ │ ├── 19.png │ │ ├── 2.png │ │ ├── 20.png │ │ ├── 21.png │ │ ├── 22.png │ │ ├── 23.png │ │ ├── 24.png │ │ ├── 25.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png │ ├── header │ │ └── index.less │ ├── image │ │ └── demo.png │ ├── loading.html │ ├── loading.less │ ├── menuConfig.js │ ├── order │ │ └── detail.less │ └── ui.less ├── router.js ├── serviceWorker.js ├── style │ ├── common.less │ ├── default.less │ └── loading.less └── utils │ └── utils.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /config-overrides.js: -------------------------------------------------------------------------------- 1 | const { injectBabelPlugin } = require('react-app-rewired'); 2 | const rewireLess = require('react-app-rewire-less'); 3 | 4 | module.exports = function override(config, env) { 5 | config = injectBabelPlugin( 6 | // ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], 7 | ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }], //直接修改less变量 8 | config, 9 | ); 10 | config = rewireLess.withLoaderOptions({ 11 | modifyVars: { "@primary-color": "#f9c700" }, 12 | javascriptEnabled: true, 13 | })(config, env); 14 | return config; 15 | }; -------------------------------------------------------------------------------- /config/env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const paths = require('./paths'); 6 | 7 | // Make sure that including paths.js after env.js will read .env variables. 8 | delete require.cache[require.resolve('./paths')]; 9 | 10 | const NODE_ENV = process.env.NODE_ENV; 11 | if (!NODE_ENV) { 12 | throw new Error( 13 | 'The NODE_ENV environment variable is required but was not specified.' 14 | ); 15 | } 16 | 17 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use 18 | var dotenvFiles = [ 19 | `${paths.dotenv}.${NODE_ENV}.local`, 20 | `${paths.dotenv}.${NODE_ENV}`, 21 | // Don't include `.env.local` for `test` environment 22 | // since normally you expect tests to produce the same 23 | // results for everyone 24 | NODE_ENV !== 'test' && `${paths.dotenv}.local`, 25 | paths.dotenv, 26 | ].filter(Boolean); 27 | 28 | // Load environment variables from .env* files. Suppress warnings using silent 29 | // if this file is missing. dotenv will never modify any environment variables 30 | // that have already been set. Variable expansion is supported in .env files. 31 | // https://github.com/motdotla/dotenv 32 | // https://github.com/motdotla/dotenv-expand 33 | dotenvFiles.forEach(dotenvFile => { 34 | if (fs.existsSync(dotenvFile)) { 35 | require('dotenv-expand')( 36 | require('dotenv').config({ 37 | path: dotenvFile, 38 | }) 39 | ); 40 | } 41 | }); 42 | 43 | // We support resolving modules according to `NODE_PATH`. 44 | // This lets you use absolute paths in imports inside large monorepos: 45 | // https://github.com/facebook/create-react-app/issues/253. 46 | // It works similar to `NODE_PATH` in Node itself: 47 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders 48 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. 49 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims. 50 | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 51 | // We also resolve them to make sure all tools using them work consistently. 52 | const appDirectory = fs.realpathSync(process.cwd()); 53 | process.env.NODE_PATH = (process.env.NODE_PATH || '') 54 | .split(path.delimiter) 55 | .filter(folder => folder && !path.isAbsolute(folder)) 56 | .map(folder => path.resolve(appDirectory, folder)) 57 | .join(path.delimiter); 58 | 59 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 60 | // injected into the application via DefinePlugin in Webpack configuration. 61 | const REACT_APP = /^REACT_APP_/i; 62 | 63 | function getClientEnvironment(publicUrl) { 64 | const raw = Object.keys(process.env) 65 | .filter(key => REACT_APP.test(key)) 66 | .reduce( 67 | (env, key) => { 68 | env[key] = process.env[key]; 69 | return env; 70 | }, 71 | { 72 | // Useful for determining whether we’re running in production mode. 73 | // Most importantly, it switches React into the correct mode. 74 | NODE_ENV: process.env.NODE_ENV || 'development', 75 | // Useful for resolving the correct path to static assets in `public`. 76 | // For example, . 77 | // This should only be used as an escape hatch. Normally you would put 78 | // images into the `src` and `import` them in code to get their paths. 79 | PUBLIC_URL: publicUrl, 80 | } 81 | ); 82 | // Stringify all values so we can feed into Webpack DefinePlugin 83 | const stringified = { 84 | 'process.env': Object.keys(raw).reduce((env, key) => { 85 | env[key] = JSON.stringify(raw[key]); 86 | return env; 87 | }, {}), 88 | }; 89 | 90 | return { raw, stringified }; 91 | } 92 | 93 | module.exports = getClientEnvironment; 94 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/en/webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | const assetFilename = JSON.stringify(path.basename(filename)); 11 | 12 | if (filename.match(/\.svg$/)) { 13 | return `module.exports = { 14 | __esModule: true, 15 | default: ${assetFilename}, 16 | ReactComponent: (props) => ({ 17 | $$typeof: Symbol.for('react.element'), 18 | type: 'svg', 19 | ref: null, 20 | key: null, 21 | props: Object.assign({}, props, { 22 | children: ${assetFilename} 23 | }) 24 | }), 25 | };`; 26 | } 27 | 28 | return `module.exports = ${assetFilename};`; 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | 7 | // Make sure any symlinks in the project folder are resolved: 8 | // https://github.com/facebook/create-react-app/issues/637 9 | const appDirectory = fs.realpathSync(process.cwd()); 10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath); 11 | 12 | const envPublicUrl = process.env.PUBLIC_URL; 13 | 14 | function ensureSlash(inputPath, needsSlash) { 15 | const hasSlash = inputPath.endsWith('/'); 16 | if (hasSlash && !needsSlash) { 17 | return inputPath.substr(0, inputPath.length - 1); 18 | } else if (!hasSlash && needsSlash) { 19 | return `${inputPath}/`; 20 | } else { 21 | return inputPath; 22 | } 23 | } 24 | 25 | const getPublicUrl = appPackageJson => 26 | envPublicUrl || require(appPackageJson).homepage; 27 | 28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer 29 | // "public path" at which the app is served. 30 | // Webpack needs to know it to put the right 28 | 29 | 30 | 31 |
32 | 33 | 40 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'production'; 5 | process.env.NODE_ENV = 'production'; 6 | 7 | // Makes the script crash on unhandled rejections instead of silently 8 | // ignoring them. In the future, promise rejections that are not handled will 9 | // terminate the Node.js process with a non-zero exit code. 10 | process.on('unhandledRejection', err => { 11 | throw err; 12 | }); 13 | 14 | // Ensure environment variables are read. 15 | require('../config/env'); 16 | 17 | 18 | const path = require('path'); 19 | const chalk = require('chalk'); 20 | const fs = require('fs-extra'); 21 | const webpack = require('webpack'); 22 | const bfj = require('bfj'); 23 | const configFactory = require('../config/webpack.config'); 24 | const paths = require('../config/paths'); 25 | const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); 26 | const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages'); 27 | const printHostingInstructions = require('react-dev-utils/printHostingInstructions'); 28 | const FileSizeReporter = require('react-dev-utils/FileSizeReporter'); 29 | const printBuildError = require('react-dev-utils/printBuildError'); 30 | 31 | const measureFileSizesBeforeBuild = 32 | FileSizeReporter.measureFileSizesBeforeBuild; 33 | const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild; 34 | const useYarn = fs.existsSync(paths.yarnLockFile); 35 | 36 | // These sizes are pretty large. We'll warn for bundles exceeding them. 37 | const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; 38 | const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; 39 | 40 | const isInteractive = process.stdout.isTTY; 41 | 42 | // Warn and crash if required files are missing 43 | if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { 44 | process.exit(1); 45 | } 46 | 47 | // Process CLI arguments 48 | const argv = process.argv.slice(2); 49 | const writeStatsJson = argv.indexOf('--stats') !== -1; 50 | 51 | // Generate configuration 52 | const config = configFactory('production'); 53 | 54 | // We require that you explicitly set browsers and do not fall back to 55 | // browserslist defaults. 56 | const { checkBrowsers } = require('react-dev-utils/browsersHelper'); 57 | checkBrowsers(paths.appPath, isInteractive) 58 | .then(() => { 59 | // First, read the current file sizes in build directory. 60 | // This lets us display how much they changed later. 61 | return measureFileSizesBeforeBuild(paths.appBuild); 62 | }) 63 | .then(previousFileSizes => { 64 | // Remove all content but keep the directory so that 65 | // if you're in it, you don't end up in Trash 66 | fs.emptyDirSync(paths.appBuild); 67 | // Merge with the public folder 68 | copyPublicFolder(); 69 | // Start the webpack build 70 | return build(previousFileSizes); 71 | }) 72 | .then( 73 | ({ stats, previousFileSizes, warnings }) => { 74 | if (warnings.length) { 75 | console.log(chalk.yellow('Compiled with warnings.\n')); 76 | console.log(warnings.join('\n\n')); 77 | console.log( 78 | '\nSearch for the ' + 79 | chalk.underline(chalk.yellow('keywords')) + 80 | ' to learn more about each warning.' 81 | ); 82 | console.log( 83 | 'To ignore, add ' + 84 | chalk.cyan('// eslint-disable-next-line') + 85 | ' to the line before.\n' 86 | ); 87 | } else { 88 | console.log(chalk.green('Compiled successfully.\n')); 89 | } 90 | 91 | console.log('File sizes after gzip:\n'); 92 | printFileSizesAfterBuild( 93 | stats, 94 | previousFileSizes, 95 | paths.appBuild, 96 | WARN_AFTER_BUNDLE_GZIP_SIZE, 97 | WARN_AFTER_CHUNK_GZIP_SIZE 98 | ); 99 | console.log(); 100 | 101 | const appPackage = require(paths.appPackageJson); 102 | const publicUrl = paths.publicUrl; 103 | const publicPath = config.output.publicPath; 104 | const buildFolder = path.relative(process.cwd(), paths.appBuild); 105 | printHostingInstructions( 106 | appPackage, 107 | publicUrl, 108 | publicPath, 109 | buildFolder, 110 | useYarn 111 | ); 112 | }, 113 | err => { 114 | console.log(chalk.red('Failed to compile.\n')); 115 | printBuildError(err); 116 | process.exit(1); 117 | } 118 | ) 119 | .catch(err => { 120 | if (err && err.message) { 121 | console.log(err.message); 122 | } 123 | process.exit(1); 124 | }); 125 | 126 | // Create the production build and print the deployment instructions. 127 | function build(previousFileSizes) { 128 | console.log('Creating an optimized production build...'); 129 | 130 | let compiler = webpack(config); 131 | return new Promise((resolve, reject) => { 132 | compiler.run((err, stats) => { 133 | let messages; 134 | if (err) { 135 | if (!err.message) { 136 | return reject(err); 137 | } 138 | messages = formatWebpackMessages({ 139 | errors: [err.message], 140 | warnings: [], 141 | }); 142 | } else { 143 | messages = formatWebpackMessages( 144 | stats.toJson({ all: false, warnings: true, errors: true }) 145 | ); 146 | } 147 | if (messages.errors.length) { 148 | // Only keep the first error. Others are often indicative 149 | // of the same problem, but confuse the reader with noise. 150 | if (messages.errors.length > 1) { 151 | messages.errors.length = 1; 152 | } 153 | return reject(new Error(messages.errors.join('\n\n'))); 154 | } 155 | if ( 156 | process.env.CI && 157 | (typeof process.env.CI !== 'string' || 158 | process.env.CI.toLowerCase() !== 'false') && 159 | messages.warnings.length 160 | ) { 161 | console.log( 162 | chalk.yellow( 163 | '\nTreating warnings as errors because process.env.CI = true.\n' + 164 | 'Most CI servers set it automatically.\n' 165 | ) 166 | ); 167 | return reject(new Error(messages.warnings.join('\n\n'))); 168 | } 169 | 170 | const resolveArgs = { 171 | stats, 172 | previousFileSizes, 173 | warnings: messages.warnings, 174 | }; 175 | if (writeStatsJson) { 176 | return bfj 177 | .write(paths.appBuild + '/bundle-stats.json', stats.toJson()) 178 | .then(() => resolve(resolveArgs)) 179 | .catch(error => reject(new Error(error))); 180 | } 181 | 182 | return resolve(resolveArgs); 183 | }); 184 | }); 185 | } 186 | 187 | function copyPublicFolder() { 188 | fs.copySync(paths.appPublic, paths.appBuild, { 189 | dereference: true, 190 | filter: file => file !== paths.appHtml, 191 | }); 192 | } 193 | -------------------------------------------------------------------------------- /scripts/start.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'development'; 5 | process.env.NODE_ENV = 'development'; 6 | 7 | // Makes the script crash on unhandled rejections instead of silently 8 | // ignoring them. In the future, promise rejections that are not handled will 9 | // terminate the Node.js process with a non-zero exit code. 10 | process.on('unhandledRejection', err => { 11 | throw err; 12 | }); 13 | 14 | // Ensure environment variables are read. 15 | require('../config/env'); 16 | 17 | 18 | const fs = require('fs'); 19 | const chalk = require('chalk'); 20 | const webpack = require('webpack'); 21 | const WebpackDevServer = require('webpack-dev-server'); 22 | const clearConsole = require('react-dev-utils/clearConsole'); 23 | const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles'); 24 | const { 25 | choosePort, 26 | createCompiler, 27 | prepareProxy, 28 | prepareUrls, 29 | } = require('react-dev-utils/WebpackDevServerUtils'); 30 | const openBrowser = require('react-dev-utils/openBrowser'); 31 | const paths = require('../config/paths'); 32 | const configFactory = require('../config/webpack.config'); 33 | const createDevServerConfig = require('../config/webpackDevServer.config'); 34 | 35 | const useYarn = fs.existsSync(paths.yarnLockFile); 36 | const isInteractive = process.stdout.isTTY; 37 | 38 | // Warn and crash if required files are missing 39 | if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) { 40 | process.exit(1); 41 | } 42 | 43 | // Tools like Cloud9 rely on this. 44 | const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; 45 | const HOST = process.env.HOST || '0.0.0.0'; 46 | 47 | if (process.env.HOST) { 48 | console.log( 49 | chalk.cyan( 50 | `Attempting to bind to HOST environment variable: ${chalk.yellow( 51 | chalk.bold(process.env.HOST) 52 | )}` 53 | ) 54 | ); 55 | console.log( 56 | `If this was unintentional, check that you haven't mistakenly set it in your shell.` 57 | ); 58 | console.log( 59 | `Learn more here: ${chalk.yellow('http://bit.ly/CRA-advanced-config')}` 60 | ); 61 | console.log(); 62 | } 63 | 64 | // We require that you explictly set browsers and do not fall back to 65 | // browserslist defaults. 66 | const { checkBrowsers } = require('react-dev-utils/browsersHelper'); 67 | checkBrowsers(paths.appPath, isInteractive) 68 | .then(() => { 69 | // We attempt to use the default port but if it is busy, we offer the user to 70 | // run on a different port. `choosePort()` Promise resolves to the next free port. 71 | return choosePort(HOST, DEFAULT_PORT); 72 | }) 73 | .then(port => { 74 | if (port == null) { 75 | // We have not found a port. 76 | return; 77 | } 78 | const config = configFactory('development'); 79 | const protocol = process.env.HTTPS === 'true' ? 'https' : 'http'; 80 | const appName = require(paths.appPackageJson).name; 81 | const urls = prepareUrls(protocol, HOST, port); 82 | // Create a webpack compiler that is configured with custom messages. 83 | const compiler = createCompiler(webpack, config, appName, urls, useYarn); 84 | // Load proxy config 85 | const proxySetting = require(paths.appPackageJson).proxy; 86 | const proxyConfig = prepareProxy(proxySetting, paths.appPublic); 87 | // Serve webpack assets generated by the compiler over a web server. 88 | const serverConfig = createDevServerConfig( 89 | proxyConfig, 90 | urls.lanUrlForConfig 91 | ); 92 | const devServer = new WebpackDevServer(compiler, serverConfig); 93 | // Launch WebpackDevServer. 94 | devServer.listen(port, HOST, err => { 95 | if (err) { 96 | return console.log(err); 97 | } 98 | if (isInteractive) { 99 | clearConsole(); 100 | } 101 | console.log(chalk.cyan('Starting the development server...\n')); 102 | openBrowser(urls.localUrlForBrowser); 103 | }); 104 | 105 | ['SIGINT', 'SIGTERM'].forEach(function(sig) { 106 | process.on(sig, function() { 107 | devServer.close(); 108 | process.exit(); 109 | }); 110 | }); 111 | }) 112 | .catch(err => { 113 | if (err && err.message) { 114 | console.log(err.message); 115 | } 116 | process.exit(1); 117 | }); 118 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Do this as the first thing so that any code reading it knows the right env. 4 | process.env.BABEL_ENV = 'test'; 5 | process.env.NODE_ENV = 'test'; 6 | process.env.PUBLIC_URL = ''; 7 | 8 | // Makes the script crash on unhandled rejections instead of silently 9 | // ignoring them. In the future, promise rejections that are not handled will 10 | // terminate the Node.js process with a non-zero exit code. 11 | process.on('unhandledRejection', err => { 12 | throw err; 13 | }); 14 | 15 | // Ensure environment variables are read. 16 | require('../config/env'); 17 | 18 | 19 | const jest = require('jest'); 20 | const execSync = require('child_process').execSync; 21 | let argv = process.argv.slice(2); 22 | 23 | function isInGitRepository() { 24 | try { 25 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' }); 26 | return true; 27 | } catch (e) { 28 | return false; 29 | } 30 | } 31 | 32 | function isInMercurialRepository() { 33 | try { 34 | execSync('hg --cwd . root', { stdio: 'ignore' }); 35 | return true; 36 | } catch (e) { 37 | return false; 38 | } 39 | } 40 | 41 | // Watch unless on CI, in coverage mode, or explicitly running all tests 42 | if ( 43 | !process.env.CI && 44 | argv.indexOf('--coverage') === -1 && 45 | argv.indexOf('--watchAll') === -1 46 | ) { 47 | // https://github.com/facebook/create-react-app/issues/5210 48 | const hasSourceControl = isInGitRepository() || isInMercurialRepository(); 49 | argv.push(hasSourceControl ? '--watch' : '--watchAll'); 50 | } 51 | 52 | 53 | jest.run(argv); 54 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | /**路由入口组件 */ 2 | 3 | import React, { Component } from 'react'; 4 | import './App.css'; 5 | 6 | class App extends Component { 7 | render() { 8 | return ( 9 |
10 | {this.props.children} 11 |
12 | ); 13 | } 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/admin.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Row, Col } from 'antd'; 3 | import Header from './components/Header' 4 | import Footer from './components/Footer' 5 | import NavLeft from './components/NavLeft' 6 | import './style/common.less' 7 | // import Home from './pages/Home' 8 | 9 | export default class Admin extends React.Component { 10 | 11 | render() { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | {/* */} 21 | {this.props.children} 22 | 23 |
24 | 25 |
26 | ) 27 | } 28 | } -------------------------------------------------------------------------------- /src/axios/index.js: -------------------------------------------------------------------------------- 1 | import JsonP from 'jsonp' 2 | import axios from 'axios' 3 | import { Modal } from 'antd'; 4 | import Utils from './../utils/utils' 5 | 6 | export default class Axios{ 7 | 8 | static requestList(_this, url, params, isMock){ 9 | var data = { 10 | params: params, 11 | isMock //使用Mock数据 12 | } 13 | this.ajax({ 14 | url, 15 | data 16 | }).then((data) => { 17 | if(data && data.list){ 18 | let list = data.list.item_list.map((item, index) => { 19 | item.key = index; 20 | return item; 21 | }); 22 | _this.setState({ 23 | list, 24 | selectedRowKeys: [],//重置 25 | pagination:Utils.pagination(data,(current)=>{ 26 | _this.params.page = current; 27 | _this.requestList(); 28 | }) 29 | }) 30 | } 31 | }) 32 | } 33 | 34 | static jsonp(options){ 35 | new Promise((resolve, reject) => { 36 | JsonP(options.url,{ 37 | param:'callback' 38 | }, function (err, response) { 39 | if(response.status === 'success'){ 40 | resolve(response); 41 | }else{ 42 | reject(response.message); 43 | } 44 | }) 45 | }) 46 | } 47 | 48 | static ajax(options){ 49 | let loading; 50 | if(options.data && options.data.isShowLoading !== false){ 51 | loading = document.getElementById('ajaxLoading'); 52 | loading.style.display = 'block'; 53 | } 54 | let baseApi = 'https://www.easy-mock.com/mock/5c2c7c1b580d6209d1e2aa88/mockapi' 55 | // let baseApi = ''; 56 | // if(options.isMock){ 57 | // baseApi = 'https://www.easy-mock.com/mock/5c2c7c1b580d6209d1e2aa88/mockapi' 58 | // }else{ 59 | // baseApi = 'https://www.easy-mock.com'//改为真实的服务端接口地址 60 | // } 61 | 62 | return new Promise((resolve,reject) => { 63 | axios({ 64 | url: options.url, 65 | method:'get', 66 | baseURL: baseApi, 67 | timeout: 5000, 68 | params: (options.data && options.data.params) || '' 69 | }).then((response)=>{ 70 | if(options.data && options.data.isShowLoading !== false){ 71 | loading = document.getElementById('ajaxLoading'); 72 | loading.style.display = 'none'; 73 | } 74 | if(response.status === 200){ 75 | let res = response.data; 76 | if(res.code === 0){ 77 | resolve(res); 78 | }else{ 79 | Modal.info({ 80 | title: '提示', 81 | content: res.msg 82 | }) 83 | } 84 | }else{ 85 | reject(response.data) 86 | } 87 | }) 88 | }); 89 | } 90 | } -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Row } from 'antd'; 3 | import Header from './components/Header' 4 | import './style/common.less' 5 | 6 | export default class Common extends React.Component { 7 | 8 | render() { 9 | return ( 10 |
11 | 12 |
13 | 14 | 15 | {this.props.children} 16 | 17 |
18 | ); 19 | } 20 | } -------------------------------------------------------------------------------- /src/components/BaseForm/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Input, Select, Form, Button, Checkbox, DatePicker} from 'antd' 3 | import Utils from '../../utils/utils' 4 | const FormItem = Form.Item; 5 | 6 | class FilterForm extends React.Component{ 7 | 8 | handleFilterSubmit = () => { 9 | let fieldsValue = this.props.form.getFieldsValue(); 10 | this.props.filterSubmit(fieldsValue); 11 | } 12 | 13 | reset = () => { 14 | this.props.form.resetFields(); 15 | } 16 | 17 | initFormList = () => { 18 | const {getFieldDecorator } = this.props.form; 19 | const formList = this.props.formList; 20 | const formItemList = []; 21 | if(formList && formList.length>0){ 22 | formList.forEach((item, i) => { 23 | let label = item.label; 24 | let field = item.field; 25 | let initialValue = item.initialValue || ''; 26 | let placeholder = item.placeholder; 27 | let width = item.width; 28 | if(item.type === '时间查询'){ 29 | const begin_time = 30 | { 31 | getFieldDecorator('begin_time')( 32 | 33 | ) 34 | } 35 | ; 36 | formItemList.push(begin_time); 37 | //~后省略冒号:label="~" colon={false} 38 | const end_time = 39 | { 40 | getFieldDecorator('end_time')( 41 | 42 | ) 43 | } 44 | ; 45 | formItemList.push(end_time); 46 | }else if(item.type == 'INPUT'){ 47 | const INPUT = 48 | { 49 | getFieldDecorator([field])( 50 | 51 | ) 52 | } 53 | ; 54 | formItemList.push(INPUT); 55 | }else if(item.type === 'SELECT'){ 56 | const SELECT = 57 | { 58 | getFieldDecorator([field],{ 59 | initialValue: initialValue 60 | })( 61 | 67 | ) 68 | } 69 | ; 70 | formItemList.push(SELECT); 71 | }else if(item.type === 'CHECKBOX'){ 72 | const CHECKBOX = 73 | { 74 | getFieldDecorator([field],{ 75 | valuePropName: 'checked', 76 | initialValue: initialValue //true | false 77 | })( 78 | 79 | {label} 80 | 81 | ) 82 | } 83 | ; 84 | formItemList.push(CHECKBOX); 85 | }else if(item.type === 'DATE'){ 86 | const DATEPICKER = 87 | { 88 | getFieldDecorator([field])( 89 | 90 | ) 91 | } 92 | ; 93 | formItemList.push(DATEPICKER); 94 | } 95 | }) 96 | } 97 | return formItemList; 98 | } 99 | 100 | render(){ 101 | return ( 102 |
103 | {this.initFormList()} 104 | 105 | 106 | 107 | 108 |
109 | ) 110 | } 111 | } 112 | export default Form.create({})(FilterForm) -------------------------------------------------------------------------------- /src/components/ETable/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Utils from '../../utils/utils' 3 | import {Table} from 'antd' 4 | import "./index.less" 5 | export default class ETable extends React.Component { 6 | 7 | state = {} 8 | //处理行点击事件 9 | onRowClick = (record, index) => { 10 | let rowSelection = this.props.rowSelection; 11 | if(rowSelection == 'checkbox'){ 12 | let selectedRowKeys = this.props.selectedRowKeys; 13 | let selectedIds = this.props.selectedIds; 14 | let selectedItem = this.props.selectedItem || []; 15 | if (selectedIds) { 16 | const i = selectedIds.indexOf(record.id); 17 | if (i == -1) {//避免重复添加 18 | selectedIds.push(record.id) 19 | selectedRowKeys.push(index); 20 | selectedItem.push(record); 21 | }else{ 22 | selectedIds.splice(i,1); 23 | selectedRowKeys.splice(i,1); 24 | selectedItem.splice(i,1); 25 | } 26 | } else { 27 | selectedIds = [record.id]; 28 | selectedRowKeys = [index] 29 | selectedItem = [record]; 30 | } 31 | this.props.updateSelectedItem(selectedRowKeys,selectedItem || {},selectedIds); 32 | }else{ 33 | let selectKey = [index]; 34 | const selectedRowKeys = this.props.selectedRowKeys; 35 | if (selectedRowKeys && selectedRowKeys[0] == index){ 36 | return; 37 | } 38 | this.props.updateSelectedItem(selectKey,record || {}); 39 | } 40 | }; 41 | 42 | // 选择框变更 43 | onSelectChange = (selectedRowKeys, selectedRows) => { 44 | let rowSelection = this.props.rowSelection; 45 | const selectedIds = []; 46 | if(rowSelection == 'checkbox'){ 47 | selectedRows.map((item)=>{ 48 | selectedIds.push(item.id); 49 | }); 50 | this.setState({ 51 | selectedRowKeys, 52 | selectedIds:selectedIds, 53 | selectedItem: selectedRows[0] 54 | }); 55 | } 56 | this.props.updateSelectedItem(selectedRowKeys,selectedRows[0],selectedIds); 57 | }; 58 | 59 | onSelectAll = (selected, selectedRows, changeRows) => { 60 | let selectedIds = []; 61 | let selectKey = []; 62 | selectedRows.forEach((item,i)=> { 63 | selectedIds.push(item.id); 64 | selectKey.push(i); 65 | }); 66 | this.props.updateSelectedItem(selectKey,selectedRows[0] || {},selectedIds); 67 | } 68 | 69 | getOptions = () => { 70 | let p = this.props; 71 | const name_list = { 72 | "订单编号":170, 73 | "车辆编号":80, 74 | "手机号码":96, 75 | "用户姓名":70, 76 | "密码":70, 77 | "运维区域":300, 78 | "车型":42, 79 | "故障编号":76, 80 | "代理商编码":97, 81 | "角色ID":64 82 | }; 83 | if (p.columns && p.columns.length > 0) { 84 | p.columns.forEach((item)=> { 85 | //开始/结束 时间 86 | if(!item.title){ 87 | return 88 | } 89 | if(!item.width){ 90 | if(item.title.indexOf("时间") > -1 && item.title.indexOf("持续时间") < 0){ 91 | item.width = 132 92 | }else if(item.title.indexOf("图片") > -1){ 93 | item.width = 86 94 | }else if(item.title.indexOf("权限") > -1 || item.title.indexOf("负责城市") > -1){ 95 | item.width = '40%'; 96 | item.className = "text-left"; 97 | }else{ 98 | if(name_list[item.title]){ 99 | item.width = name_list[item.title]; 100 | } 101 | } 102 | } 103 | item.bordered = true; 104 | }); 105 | } 106 | const { selectedRowKeys } = this.props; 107 | const rowSelection = { 108 | type: 'radio', 109 | selectedRowKeys, 110 | onChange: this.onSelectChange, 111 | onSelect:(record, selected, selectedRows)=>{ 112 | console.log('...') 113 | }, 114 | onSelectAll:this.onSelectAll 115 | }; 116 | let row_selection = this.props.rowSelection; 117 | // 当属性未false或者null时,说明没有单选或者复选列 118 | if(row_selection===false || row_selection === null){ 119 | row_selection = false; 120 | }else if(row_selection == 'checkbox'){ 121 | //设置类型未复选框 122 | rowSelection.type = 'checkbox'; 123 | }else{ 124 | //默认未单选 125 | row_selection = 'radio'; 126 | } 127 | return ({ 133 | onClick: ()=>{ 134 | if(!row_selection){ 135 | return; 136 | } 137 | this.onRowClick(record,index) 138 | } 139 | })} 140 | /> 141 | }; 142 | render = () => { 143 | return ( 144 |
145 | {this.getOptions()} 146 |
147 | ) 148 | } 149 | } -------------------------------------------------------------------------------- /src/components/ETable/index.less: -------------------------------------------------------------------------------- 1 | @import '../../style/default'; 2 | .ant-table{ 3 | &-thead > tr > th, 4 | &-tbody > tr > td{ 5 | padding:14px 6px; 6 | text-align:center; 7 | } 8 | .ant-table-selection-column{ 9 | min-width:42px!important; 10 | width:42px!important;; 11 | } 12 | 13 | .text-center { 14 | text-align: center; 15 | } 16 | .text-left { 17 | text-align: left; 18 | } 19 | &.ant-table-middle{ 20 | &-thead > tr > th, 21 | &-tbody > tr > td{ 22 | padding:10px 6px; 23 | } 24 | } 25 | &.ant-table-small{ 26 | &-thead > tr > th, 27 | &-tbody > tr > td{ 28 | padding:8px 6px; 29 | } 30 | } 31 | } 32 | .ant-table-pagination{ 33 | padding:0 20px; 34 | } 35 | 36 | .content-wrap{ 37 | background: #ffffff; 38 | border: 1px solid #e8e8e8; 39 | margin-top: -3px; 40 | .ant-table-wrapper{ 41 | margin-left: -1px; 42 | margin-right: -2px; 43 | } 44 | } -------------------------------------------------------------------------------- /src/components/Footer/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './index.less'; 3 | 4 | export default class Footer extends React.Component { 5 | render() { 6 | return ( 7 |
8 | 版权所有:柳洁琼Elena 9 |
10 | ) 11 | } 12 | } -------------------------------------------------------------------------------- /src/components/Footer/index.less: -------------------------------------------------------------------------------- 1 | @import "./../../style/default.less"; 2 | 3 | .footer{ 4 | height: 100px; 5 | padding: 40px 0; 6 | text-align: center; 7 | color: @colorJ; 8 | } -------------------------------------------------------------------------------- /src/components/Header/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Row, Col } from 'antd' 3 | import './index.less' 4 | import Util from '../../utils/utils' 5 | import axios from '../../axios'; 6 | import {connect} from 'react-redux' //连接器 7 | 8 | class Header extends React.Component { 9 | state = {} 10 | componentWillMount() { 11 | this.setState({ 12 | userName: '莱茵月牙' 13 | }) 14 | setInterval(() => { 15 | let sysTime = Util.formatDate(new Date().getTime()); 16 | this.setState({ 17 | sysTime 18 | }) 19 | }, 1000) 20 | //this.getWeatherAPIDate();由于百度API禁止了服务,故该功能暂时不使用 21 | } 22 | getWeatherAPIDate() { 23 | let city = encodeURIComponent('杭州'); 24 | axios.jsonp({ 25 | url: 'http://api.map.baidu.com/telematics/v3/weather?location='+city+'&output=json&ak=kwQXPVDYPZIYArkpi3rQT7aZHTGTCCB2' 26 | }).then((res) => { 27 | if(res.status === 'success'){ 28 | let data = res.result[0].weather_data[0]; 29 | this.setState({ 30 | dayPictureUrl:data.dayPictureUrl, 31 | weather:data.weather 32 | }) 33 | } 34 | }) 35 | } 36 | render() { 37 | const {menuName, menuType} = this.props; 38 | return ( 39 |
40 | 41 | { 42 | menuType ? 43 |
44 | 45 | LJQ 通用管理系统 46 | : '' 47 | } 48 | 49 | 欢迎,{this.state.userName} 50 | 退出 51 | 52 | 53 | { 54 | menuType ? '' : 55 | 56 | 57 | {menuName || '首页'} 58 | 59 | 60 | {this.state.sysTime} 61 | 晴转多云 62 | 63 | 64 | } 65 | 66 | ) 67 | } 68 | } 69 | //将state.menuName 绑定到 props 的menuName 70 | const mapStateToProps = state => { 71 | return { 72 | menuName: state.menuName 73 | } 74 | } 75 | export default connect(mapStateToProps)(Header) -------------------------------------------------------------------------------- /src/components/Header/index.less: -------------------------------------------------------------------------------- 1 | @import './../../style/default.less'; 2 | 3 | .header{ 4 | background-color: @colorM; 5 | .header-top{ 6 | height: 60px; 7 | line-height: 60px; 8 | padding: 0 20px; 9 | text-align: right; 10 | .logo{ 11 | line-height: 60px; 12 | text-align: left; 13 | font-size: 18px; 14 | img{ 15 | height: 40px; 16 | vertical-align: middle; 17 | } 18 | span{ 19 | margin-left: 5px; 20 | } 21 | } 22 | a{ 23 | margin-left: 40px; 24 | } 25 | } 26 | .breadcrumb{ 27 | height: 40px; 28 | line-height: 40px; 29 | padding: 0 20px; 30 | border-top: 1px solid #f9c700; 31 | position: relative; //父级元素相对定位 32 | .breadcrumb-title{ 33 | font-size: @fontC; 34 | text-align: center; 35 | &:after{ 36 | position: absolute; //绝对定位 37 | content: ''; //设为空用于占位 38 | left: 73px; 39 | top: 39px; 40 | border-top: 9px solid @colorM; 41 | border-left: 12px solid transparent; 42 | border-right: 12px solid transparent; 43 | } 44 | } 45 | .weather{ 46 | text-align: right; 47 | .date{ 48 | margin-right: 10px; 49 | } 50 | } 51 | } 52 | } 53 | 54 | //.common 页面简单头 55 | .simple-page{ 56 | .header-top{ 57 | background: #1890ff; 58 | color: @colorM; 59 | } 60 | .ant-form, .ant-col-12, .weather{ 61 | display: none; 62 | } 63 | } -------------------------------------------------------------------------------- /src/components/NavLeft/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Menu } from 'antd'; 3 | import {NavLink} from 'react-router-dom' 4 | import {connect} from 'react-redux' //连接器 5 | import { switchMenu } from './../../redux/action' //事件行为 6 | import MenuConfig from './../../config/menuConfig' 7 | import './index.less' 8 | 9 | const SubMenu = Menu.SubMenu; 10 | 11 | class NavLeft extends React.Component { 12 | state = { 13 | currentKey: '' 14 | } 15 | handleClick = ({item, key}) => { 16 | if (key === this.state.currentKey) { 17 | return false; 18 | } 19 | // 事件派发,自动调用reducer,通过reducer保存到store对象中 20 | const { dispatch } = this.props; 21 | dispatch(switchMenu(item.props.title)) 22 | // console.log(item) 23 | this.setState({ 24 | currentKey: key 25 | }) 26 | } 27 | homeHandleClick = () => { 28 | const { dispatch } = this.props; 29 | dispatch(switchMenu('首页')); 30 | this.setState({ 31 | currentKey: "" 32 | }); 33 | }; 34 | componentWillMount() { 35 | const MenuTreeNode = this.renderMenu(MenuConfig); 36 | let currentKey = window.location.hash.replace(/#|\?.*$/g, ''); 37 | this.setState({ 38 | currentKey, 39 | MenuTreeNode 40 | }) 41 | } 42 | //菜单渲染 -- 递归 43 | renderMenu = (data) => { 44 | return data.map((item) => { 45 | if(item.children) { 46 | return ( 47 | 48 | {this.renderMenu(item.children)} 49 | 50 | ) 51 | } 52 | return 53 | {item.title} 54 | 55 | }) 56 | } 57 | render() { 58 | return ( 59 |
60 |
61 | 62 |

LJQ MS

63 |
64 | 69 | {this.state.MenuTreeNode} 70 | 71 |
72 | ) 73 | } 74 | } 75 | export default connect()(NavLeft) -------------------------------------------------------------------------------- /src/components/NavLeft/index.less: -------------------------------------------------------------------------------- 1 | .nav-left{ 2 | .logo{ 3 | line-height: calc(9vh); 4 | padding-left: 20px; 5 | background-color:#002140; 6 | img { 7 | height: 35px; 8 | } 9 | h1{ 10 | color: #ffffff; 11 | font-size: 20px; 12 | display: inline-block; 13 | vertical-align: middle; 14 | margin: 0 0 0 10px; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/config/menuConfig.js: -------------------------------------------------------------------------------- 1 | const menuList = [ 2 | { 3 | title:'首页', 4 | key:'/home' 5 | }, 6 | { 7 | title:'UI', 8 | key:'/ui', 9 | children:[ 10 | { 11 | title:'按钮', 12 | key:'/ui/buttons', 13 | }, 14 | { 15 | title:'弹框', 16 | key:'/ui/modals', 17 | }, 18 | { 19 | title:'Loading', 20 | key:'/ui/loadings', 21 | }, 22 | { 23 | title:'通知提醒', 24 | key:'/ui/notification', 25 | }, 26 | { 27 | title:'全局Message', 28 | key:'/ui/messages', 29 | }, 30 | { 31 | title:'Tab页签', 32 | key:'/ui/tabs', 33 | }, 34 | { 35 | title:'图片画廊', 36 | key:'/ui/gallery', 37 | }, 38 | { 39 | title:'轮播图', 40 | key:'/ui/carousel', 41 | } 42 | ] 43 | }, 44 | { 45 | title:'表单', 46 | key:'/form', 47 | children:[ 48 | { 49 | title:'登录', 50 | key:'/form/login', 51 | }, 52 | { 53 | title:'注册', 54 | key:'/form/reg', 55 | } 56 | ] 57 | }, 58 | { 59 | title:'表格', 60 | key:'/table', 61 | children:[ 62 | { 63 | title:'基础表格', 64 | key:'/table/basic', 65 | }, 66 | { 67 | title:'高级表格', 68 | key:'/table/high', 69 | } 70 | ] 71 | }, 72 | { 73 | title:'富文本', 74 | key:'/rich' 75 | }, 76 | { 77 | title:'城市管理', 78 | key:'/city' 79 | }, 80 | { 81 | title:'订单管理', 82 | key:'/order', 83 | btnList:[ 84 | { 85 | title:'订单详情', 86 | key:'/order/detail' 87 | }, 88 | { 89 | title:'结束订单', 90 | key:'/order/finish' 91 | } 92 | ] 93 | }, 94 | { 95 | title:'员工管理', 96 | key:'/user' 97 | }, 98 | { 99 | title:'车辆地图', 100 | key:'/bikeMap' 101 | }, 102 | { 103 | title:'图标', 104 | key:'/charts', 105 | children:[ 106 | { 107 | title:'柱形图', 108 | key:'/charts/bar' 109 | }, 110 | { 111 | title:'饼图', 112 | key:'/charts/pie' 113 | }, 114 | { 115 | title:'折线图', 116 | key:'/charts/line' 117 | }, 118 | ] 119 | }, 120 | { 121 | title:'权限设置', 122 | key:'/permission' 123 | }, 124 | ]; 125 | export default menuList; -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | // import App from './App'; 5 | // import Admin from './admin' 6 | import Router from './router' 7 | import { Provider } from 'react-redux' 8 | import configureStore from './redux/store/configureStore' 9 | // import Router from './pages/router_demo/router' 10 | import * as serviceWorker from './serviceWorker'; 11 | 12 | const store = configureStore(); 13 | ReactDOM.render( 14 | 15 | 16 | , 17 | document.getElementById('root')); 18 | 19 | // If you want your app to work offline and load faster, you can change 20 | // unregister() to register() below. Note this comes with some pitfalls. 21 | // Learn more about service workers: http://bit.ly/CRA-PWA 22 | serviceWorker.unregister(); 23 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/pages/Home/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './index.less' 3 | 4 | export default class Home extends React.Component{ 5 | render() { 6 | return ( 7 |
8 | 欢迎学习慕课后台管理系统课程 9 |
10 | ) 11 | } 12 | } -------------------------------------------------------------------------------- /src/pages/Home/index.less: -------------------------------------------------------------------------------- 1 | @import './../../style/default.less'; 2 | 3 | .home-wrap{ 4 | background-color: @colorM; 5 | height: calc(62vh); 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | font-size: 20px; 10 | } -------------------------------------------------------------------------------- /src/pages/Login/index.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | class Login extends Component{ 3 | render(){ 4 | return( 5 |
6 | this is login. 7 |
8 | ); 9 | } 10 | } 11 | export default Login; -------------------------------------------------------------------------------- /src/pages/Login/index.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/pages/Login/index.less -------------------------------------------------------------------------------- /src/pages/NoMatch/index.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | class NoMatch extends Component{ 3 | render(){ 4 | return( 5 |
6 | 404 No Found !!! 7 |
8 | ); 9 | } 10 | } 11 | export default NoMatch; -------------------------------------------------------------------------------- /src/pages/NoMatch/index.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/pages/NoMatch/index.less -------------------------------------------------------------------------------- /src/pages/echarts/bar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Card} from 'antd' 3 | //导入主题 4 | import echartTheme from './../echartTheme' 5 | import themeLight from './../themeLight' 6 | //全部加载 7 | // import echarts from 'echarts' 8 | //按需加载 9 | import echarts from 'echarts/lib/echarts' 10 | //必需基础组件 11 | import 'echarts/lib/component/tooltip' 12 | import 'echarts/lib/component/title' 13 | import 'echarts/lib/component/legend' 14 | import 'echarts/lib/component/markPoint' 15 | //导入矩形图 16 | import 'echarts/lib/chart/bar' 17 | import ReactEcharts from 'echarts-for-react' 18 | 19 | export default class Bar extends React.Component{ 20 | 21 | componentWillMount(){ 22 | echarts.registerTheme('Default', echartTheme); 23 | echarts.registerTheme('Light', themeLight); 24 | } 25 | 26 | getOption = () => { 27 | let option = { 28 | title: { 29 | text: '用户骑行订单' 30 | }, 31 | tooltip: {//提示条 32 | trigger: 'axis' 33 | }, 34 | xAxis: { //X轴 35 | data: ['周一','周二','周三','周四','周五','周六','周日'] 36 | }, 37 | yAxis: { //Y轴 38 | type: 'value' 39 | }, 40 | series: [ //整体数据源 41 | { 42 | name: '订单量', 43 | type: 'bar', 44 | data: [1000, 2000, 1500, 3000, 2000, 1200, 800] 45 | } 46 | ] 47 | } 48 | return option; 49 | } 50 | 51 | getOption2 = () => { 52 | let option = { 53 | title: { 54 | text: '用户骑行订单' 55 | }, 56 | legend: { //可过滤父标题 57 | data: ['OFO','摩拜','小蓝'] 58 | }, 59 | tooltip: { 60 | trigger: 'axis' 61 | }, 62 | xAxis: { 63 | data: ['周一','周二','周三','周四','周五','周六','周日'] 64 | }, 65 | yAxis: { 66 | type: 'value' 67 | }, 68 | series: [ //整体数据源 69 | { 70 | name: 'OFO', 71 | type: 'bar', 72 | data: [2000, 3000, 5500, 7000, 8000, 12000, 20000] 73 | }, 74 | { 75 | name: '摩拜', 76 | type: 'bar', 77 | data: [1500, 3000, 4500, 6000, 8000, 10000, 15000] 78 | }, 79 | { 80 | name: '小蓝', 81 | type: 'bar', 82 | data: [1000, 2500, 4000, 4500, 6000, 7000, 8000] 83 | } 84 | ] 85 | } 86 | return option; 87 | } 88 | 89 | render(){ 90 | return( 91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 |
99 | ) 100 | } 101 | } -------------------------------------------------------------------------------- /src/pages/echarts/echartTheme.js: -------------------------------------------------------------------------------- 1 | //主题 2 | export default { 3 | "color": [ 4 | "#f9c700", 5 | "#ff5400", 6 | "#6699cc", 7 | "#9cb3c5", 8 | "#e0e6ec", 9 | "#666666", 10 | "#787464", 11 | "#cc7e63", 12 | "#724e58", 13 | "#4b565b" 14 | ], 15 | "backgroundColor": "#ffffff", 16 | "textStyle": {}, 17 | "title": { 18 | "textStyle": { 19 | "color": "#cccccc" 20 | }, 21 | "subtextStyle": { 22 | "color": "#cccccc" 23 | } 24 | }, 25 | "line": { 26 | "itemStyle": { 27 | "normal": { 28 | "borderWidth": 1 29 | } 30 | }, 31 | "lineStyle": { 32 | "normal": { 33 | "width": 2 34 | } 35 | }, 36 | "symbolSize": "10", 37 | "symbol": "emptyCircle", 38 | "smooth": false 39 | }, 40 | "pie": { 41 | "itemStyle": { 42 | "normal": { 43 | "borderWidth": 0, 44 | "borderColor": "#ccc" 45 | }, 46 | "emphasis": { 47 | "borderWidth": 0, 48 | "borderColor": "#ccc" 49 | } 50 | } 51 | }, 52 | "categoryAxis": { 53 | "axisLine": { 54 | "show": true, 55 | "lineStyle": { 56 | "color": "#f1f3f5" 57 | } 58 | }, 59 | "axisTick": { 60 | "show": true, 61 | "lineStyle": { 62 | "color": "#f1f3f5" 63 | } 64 | }, 65 | "axisLabel": { 66 | "show": true, 67 | "textStyle": { 68 | "color": "#999999", 69 | "fontSize": "14" 70 | } 71 | }, 72 | "splitLine": { 73 | "show": true, 74 | "lineStyle": { 75 | "color": [ 76 | "#f1f3f5" 77 | ] 78 | } 79 | }, 80 | "splitArea": { 81 | "show": false, 82 | "areaStyle": { 83 | "color": [ 84 | "rgba(250,250,250,0.3)", 85 | "rgba(200,200,200,0.3)" 86 | ] 87 | } 88 | } 89 | }, 90 | "valueAxis": { 91 | "axisLine": { 92 | "show": true, 93 | "lineStyle": { 94 | "color": "#f1f3f5" 95 | } 96 | }, 97 | "axisTick": { 98 | "show": true, 99 | "lineStyle": { 100 | "color": "#f1f3f5" 101 | } 102 | }, 103 | "axisLabel": { 104 | "show": true, 105 | "textStyle": { 106 | "color": "#999999", 107 | "fontSize": "14" 108 | } 109 | }, 110 | "splitLine": { 111 | "show": true, 112 | "lineStyle": { 113 | "color": [ 114 | "#f1f3f5" 115 | ] 116 | } 117 | }, 118 | "splitArea": { 119 | "show": false, 120 | "areaStyle": { 121 | "color": [ 122 | "rgba(250,250,250,0.3)", 123 | "rgba(200,200,200,0.3)" 124 | ] 125 | } 126 | } 127 | }, 128 | "toolbox": { 129 | "iconStyle": { 130 | "normal": { 131 | "borderColor": "#999999" 132 | }, 133 | "emphasis": { 134 | "borderColor": "#666666" 135 | } 136 | } 137 | }, 138 | "legend": { 139 | "textStyle": { 140 | "color": "#333333" 141 | } 142 | }, 143 | "tooltip": { 144 | "axisPointer": { 145 | "lineStyle": { 146 | "color": "#cccccc", 147 | "width": 1 148 | }, 149 | "crossStyle": { 150 | "color": "#cccccc", 151 | "width": 1 152 | } 153 | } 154 | }, 155 | "timeline": { 156 | "lineStyle": { 157 | "color": "#293c55", 158 | "width": 1 159 | }, 160 | "itemStyle": { 161 | "normal": { 162 | "color": "#293c55", 163 | "borderWidth": 1 164 | }, 165 | "emphasis": { 166 | "color": "#a9334c" 167 | } 168 | }, 169 | "controlStyle": { 170 | "normal": { 171 | "color": "#293c55", 172 | "borderColor": "#293c55", 173 | "borderWidth": 0.5 174 | }, 175 | "emphasis": { 176 | "color": "#293c55", 177 | "borderColor": "#293c55", 178 | "borderWidth": 0.5 179 | } 180 | }, 181 | "checkpointStyle": { 182 | "color": "#e43c59", 183 | "borderColor": "rgba(194,53,49,0.5)" 184 | }, 185 | "label": { 186 | "normal": { 187 | "textStyle": { 188 | "color": "#293c55" 189 | } 190 | }, 191 | "emphasis": { 192 | "textStyle": { 193 | "color": "#293c55" 194 | } 195 | } 196 | } 197 | }, 198 | "markPoint": { 199 | "label": { 200 | "normal": { 201 | "textStyle": { 202 | "color": "#ffffff" 203 | } 204 | }, 205 | "emphasis": { 206 | "textStyle": { 207 | "color": "#ffffff" 208 | } 209 | } 210 | } 211 | } 212 | } -------------------------------------------------------------------------------- /src/pages/echarts/line/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Card} from 'antd' 3 | //导入主题 4 | import echartTheme from './../echartTheme' 5 | import themeLight from './../themeLight' 6 | //全部加载 7 | // import echarts from 'echarts' 8 | //按需加载 9 | import echarts from 'echarts/lib/echarts' 10 | //必需基础组件 11 | import 'echarts/lib/component/tooltip' 12 | import 'echarts/lib/component/title' 13 | import 'echarts/lib/component/legend' 14 | import 'echarts/lib/component/markPoint' 15 | //导入折现图 16 | import 'echarts/lib/chart/line' 17 | import ReactEcharts from 'echarts-for-react' 18 | 19 | export default class Line extends React.Component{ 20 | 21 | componentWillMount(){ 22 | echarts.registerTheme('Default', echartTheme); 23 | echarts.registerTheme('Light', themeLight); 24 | } 25 | 26 | getOption = () => { 27 | let option = { 28 | title: { 29 | text: '用户骑行订单' 30 | }, 31 | tooltip: { 32 | trigger: 'axis' 33 | }, 34 | xAxis: { 35 | data: [ 36 | '周一','周二','周三','周四','周五','周六','周日' 37 | ] 38 | }, 39 | yAxis: { 40 | type: 'value' 41 | }, 42 | series: [ 43 | { 44 | name: '订单量', 45 | type: 'line', 46 | data: [1000,2000,1500,3000,2000,1200,800] //趋势点 47 | } 48 | ] 49 | } 50 | return option; 51 | } 52 | 53 | getOption2 = () => { 54 | let option = { 55 | title: { 56 | text: '用户骑行订单' 57 | }, 58 | tooltip: { 59 | trigger: 'axis' 60 | }, 61 | legend: { 62 | data: ['OFO订单量','摩拜订单量'] 63 | }, 64 | xAxis: { 65 | data: [ 66 | '周一','周二','周三','周四','周五','周六','周日' 67 | ] 68 | }, 69 | yAxis: { 70 | type: 'value' 71 | }, 72 | series: [ 73 | { 74 | name: 'OFO订单量', 75 | type: 'line', 76 | data: [1200,3000,4500,6000,8000,12000,20000] //趋势点 77 | }, 78 | { 79 | name: '摩拜订单量', 80 | type: 'line', 81 | data: [1000,2000,5500,6000,8000,10000,12000] //趋势点 82 | } 83 | ] 84 | } 85 | return option; 86 | } 87 | 88 | getOption3 = () => { 89 | let option = { 90 | title: { 91 | text: '用户骑行订单' 92 | }, 93 | tooltip: { 94 | trigger: 'axis' 95 | }, 96 | xAxis: { 97 | boundaryGap: false, //坐标轴从起点开始,true时在中间 98 | data: ['周一','周二','周三','周四','周五','周六','周日'] 99 | }, 100 | yAxis: { 101 | type: 'value' 102 | }, 103 | series: [ 104 | { 105 | name: '订单量', 106 | type: 'line', 107 | data: [1000,2000,1500,3000,2000,1200,800], //趋势点 108 | areaStyle: {} //区域填充颜色 109 | } 110 | ] 111 | } 112 | return option; 113 | } 114 | 115 | render(){ 116 | return( 117 |
118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
128 | ) 129 | } 130 | } -------------------------------------------------------------------------------- /src/pages/echarts/pie/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Card} from 'antd' 3 | //导入主题 4 | import echartTheme from './../echartTheme' 5 | import themeLight from './../themeLight' 6 | //全部加载 7 | // import echarts from 'echarts' 8 | //按需加载 9 | import echarts from 'echarts/lib/echarts' 10 | //必需基础组件 11 | import 'echarts/lib/component/tooltip' 12 | import 'echarts/lib/component/title' 13 | import 'echarts/lib/component/legend' 14 | import 'echarts/lib/component/markPoint' 15 | //导入饼图 16 | import 'echarts/lib/chart/pie' 17 | import ReactEcharts from 'echarts-for-react' 18 | 19 | export default class Pie extends React.Component{ 20 | 21 | componentWillMount(){ 22 | echarts.registerTheme('Default', echartTheme); 23 | echarts.registerTheme('Light', themeLight); 24 | } 25 | 26 | getOption = () => { 27 | let option = { 28 | title: { 29 | text: '用户骑行订单', 30 | x: 'center' //水平方向居中 31 | }, 32 | legend: { 33 | orient: 'vertical', //垂直方向排列 34 | right: 10, //绝对定位位置 35 | top: 20, 36 | bottom: 20, 37 | data: ['周一','周二','周三','周四','周五','周六','周日'] 38 | }, 39 | tooltip:{ 40 | trigger: 'item', 41 | formatter: '{a}
{b}:{c}({d}%)' //格式化提示项 42 | }, 43 | series: [ 44 | { 45 | name: '订单量', 46 | type: 'pie', 47 | data: [ 48 | { 49 | value: 1000, 50 | name: '周一' 51 | }, 52 | { 53 | value: 1000, 54 | name: '周二' 55 | }, 56 | { 57 | value: 2000, 58 | name: '周三' 59 | }, 60 | { 61 | value: 1500, 62 | name: '周四' 63 | }, 64 | { 65 | value: 3000, 66 | name: '周五' 67 | }, 68 | { 69 | value: 2000, 70 | name: '周六' 71 | }, 72 | { 73 | value: 1200, 74 | name: '周日' 75 | } 76 | ] 77 | } 78 | ] 79 | } 80 | return option; 81 | } 82 | 83 | getOption2 = () => { 84 | let option = { 85 | title: { 86 | text: '用户骑行订单', 87 | x: 'center' //水平方向居中 88 | }, 89 | legend: { 90 | orient: 'vertical', //垂直方向排列 91 | right: 10, //绝对定位位置 92 | top: 20, 93 | bottom: 20, 94 | data: ['周一','周二','周三','周四','周五','周六','周日'] 95 | }, 96 | tooltip:{ 97 | trigger: 'item', 98 | formatter: '{a}
{b}:{c}({d}%)' //格式化提示项 99 | }, 100 | series: [ 101 | { 102 | name: '订单量', 103 | type: 'pie', 104 | radius: ['50%','80%'], //内环外环大小 105 | // center: ['30%','60%'], //x轴y轴位置 106 | data: [ 107 | { 108 | value: 1000, 109 | name: '周一' 110 | }, 111 | { 112 | value: 1000, 113 | name: '周二' 114 | }, 115 | { 116 | value: 2000, 117 | name: '周三' 118 | }, 119 | { 120 | value: 1500, 121 | name: '周四' 122 | }, 123 | { 124 | value: 3000, 125 | name: '周五' 126 | }, 127 | { 128 | value: 2000, 129 | name: '周六' 130 | }, 131 | { 132 | value: 1200, 133 | name: '周日' 134 | } 135 | ] 136 | } 137 | ] 138 | } 139 | return option; 140 | } 141 | 142 | getOption3 = () => { 143 | let option = { 144 | title: { 145 | text: '用户骑行订单', 146 | x: 'center' //水平方向居中 147 | }, 148 | legend: { 149 | orient: 'vertical', //垂直方向排列 150 | right: 10, //绝对定位位置 151 | top: 20, 152 | bottom: 20, 153 | data: ['周一','周二','周三','周四','周五','周六','周日'] 154 | }, 155 | tooltip:{ 156 | trigger: 'item', 157 | formatter: '{a}
{b}:{c}({d}%)' //格式化提示项 158 | }, 159 | series: [ 160 | { 161 | name: '订单量', 162 | type: 'pie', 163 | data: [ 164 | { 165 | value: 1000, 166 | name: '周一' 167 | }, 168 | { 169 | value: 1000, 170 | name: '周二' 171 | }, 172 | { 173 | value: 2000, 174 | name: '周三' 175 | }, 176 | { 177 | value: 1500, 178 | name: '周四' 179 | }, 180 | { 181 | value: 3000, 182 | name: '周五' 183 | }, 184 | { 185 | value: 2000, 186 | name: '周六' 187 | }, 188 | { 189 | value: 1200, 190 | name: '周日' 191 | } 192 | ].sort((a,b) => { //数据排序 193 | return a.value - b.value; 194 | }), 195 | roseType:'radius', //数据大、半径大 196 | } 197 | ] 198 | } 199 | return option; 200 | } 201 | 202 | render(){ 203 | return( 204 |
205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 |
215 | ) 216 | } 217 | } -------------------------------------------------------------------------------- /src/pages/echarts/themeLight.js: -------------------------------------------------------------------------------- 1 | //主题 2 | var colorPalette = [ 3 | '#C1232B', 4 | '#27727B', 5 | '#FCCE10', 6 | '#E87C25', 7 | '#B5C334', 8 | '#FE8463', 9 | '#9BCA63', 10 | '#FAD860', 11 | '#F3A43B', 12 | '#60C0DD', 13 | '#D7504B', 14 | '#C6E579', 15 | '#F4E001', 16 | '#F0805A', 17 | '#26C0C0' 18 | ]; 19 | export default { 20 | 21 | color: colorPalette, 22 | 23 | title: { 24 | textStyle: { 25 | fontWeight: 'normal', 26 | color: '#27727B' 27 | } 28 | }, 29 | 30 | visualMap: { 31 | color: ['#C1232B', '#FCCE10'] 32 | }, 33 | 34 | toolbox: { 35 | iconStyle: { 36 | normal: { 37 | borderColor: colorPalette[0] 38 | } 39 | } 40 | }, 41 | 42 | tooltip: { 43 | backgroundColor: 'rgba(50,50,50,0.5)', 44 | axisPointer: { 45 | type: 'line', 46 | lineStyle: { 47 | color: '#27727B', 48 | type: 'dashed' 49 | }, 50 | crossStyle: { 51 | color: '#27727B' 52 | }, 53 | shadowStyle: { 54 | color: 'rgba(200,200,200,0.3)' 55 | } 56 | } 57 | }, 58 | 59 | dataZoom: { 60 | dataBackgroundColor: 'rgba(181,195,52,0.3)', 61 | fillerColor: 'rgba(181,195,52,0.2)', 62 | handleColor: '#27727B' 63 | }, 64 | 65 | categoryAxis: { 66 | axisLine: { 67 | lineStyle: { 68 | color: '#27727B' 69 | } 70 | }, 71 | splitLine: { 72 | show: false 73 | } 74 | }, 75 | 76 | valueAxis: { 77 | axisLine: { 78 | show: false 79 | }, 80 | splitArea: { 81 | show: false 82 | }, 83 | splitLine: { 84 | lineStyle: { 85 | color: ['#ccc'], 86 | type: 'dashed' 87 | } 88 | } 89 | }, 90 | 91 | timeline: { 92 | lineStyle: { 93 | color: '#27727B' 94 | }, 95 | controlStyle: { 96 | normal: { 97 | color: '#27727B', 98 | borderColor: '#27727B' 99 | } 100 | }, 101 | symbol: 'emptyCircle', 102 | symbolSize: 3 103 | }, 104 | 105 | line: { 106 | itemStyle: { 107 | normal: { 108 | borderWidth: 2, 109 | borderColor: '#fff', 110 | lineStyle: { 111 | width: 3 112 | } 113 | }, 114 | emphasis: { 115 | borderWidth: 0 116 | } 117 | }, 118 | symbol: 'circle', 119 | symbolSize: 3.5 120 | }, 121 | 122 | candlestick: { 123 | itemStyle: { 124 | normal: { 125 | color: '#C1232B', 126 | color0: '#B5C334', 127 | lineStyle: { 128 | width: 1, 129 | color: '#C1232B', 130 | color0: '#B5C334' 131 | } 132 | } 133 | } 134 | }, 135 | 136 | graph: { 137 | color: colorPalette 138 | }, 139 | 140 | map: { 141 | label: { 142 | normal: { 143 | textStyle: { 144 | color: '#C1232B' 145 | } 146 | }, 147 | emphasis: { 148 | textStyle: { 149 | color: 'rgb(100,0,0)' 150 | } 151 | } 152 | }, 153 | itemStyle: { 154 | normal: { 155 | areaColor: '#ddd', 156 | borderColor: '#eee' 157 | }, 158 | emphasis: { 159 | areaColor: '#fe994e' 160 | } 161 | } 162 | }, 163 | 164 | gauge: { 165 | axisLine: { 166 | lineStyle: { 167 | color: [ 168 | [ 169 | 0.2, '#B5C334' 170 | ], 171 | [ 172 | 0.8, '#27727B' 173 | ], 174 | [1, '#C1232B'] 175 | ] 176 | } 177 | }, 178 | axisTick: { 179 | splitNumber: 2, 180 | length: 5, 181 | lineStyle: { 182 | color: '#fff' 183 | } 184 | }, 185 | axisLabel: { 186 | textStyle: { 187 | color: '#fff' 188 | } 189 | }, 190 | splitLine: { 191 | length: '5%', 192 | lineStyle: { 193 | color: '#fff' 194 | } 195 | }, 196 | title: { 197 | offsetCenter: [0, -20] 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /src/pages/form/login.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Card, Form, Input, Button, message, Icon, Checkbox} from 'antd' 3 | 4 | const FormItem = Form.Item 5 | 6 | class FormLogin extends React.Component{ 7 | handleSubmit = () => { 8 | let userInfo = this.props.form.getFieldsValue(); 9 | this.props.form.validateFields((err, values) => { 10 | if(!err){ 11 | message.success(`${userInfo.userName} 恭喜你,您通过本次表单组件学习,当前密码为:${userInfo.userPwd}`) 12 | } 13 | }) 14 | } 15 | 16 | render(){ 17 | const { getFieldDecorator } = this.props.form; 18 | return ( 19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 | { 37 | getFieldDecorator('userName', { 38 | initialValue:'Elena', 39 | rules:[ 40 | { 41 | required: true, 42 | message:'用户名不能为空' 43 | }, 44 | { 45 | min:5, max:10, 46 | message: '长度不在范围内' 47 | }, 48 | { 49 | pattern: new RegExp('^\\w+$','g'), 50 | message: '用户名必须为字母或数字' 51 | } 52 | ] 53 | })( 54 | } placeholder="请输入用户名"/> 55 | ) 56 | } 57 | 58 | 59 | { 60 | getFieldDecorator('userPwd', { 61 | initialValue:'123456', 62 | rules:[ 63 | { 64 | required: true, 65 | message:'密码不能为空' 66 | }, 67 | { 68 | min:6, max:8, 69 | message: '长度不在范围内' 70 | } 71 | ] 72 | })( 73 | } type="password" placeholder="请输入密码"/> 74 | ) 75 | } 76 | 77 | 78 | { 79 | getFieldDecorator('remember', { 80 | valuePropName: 'checked', 81 | initialValue: true, 82 | })( 83 | 记住密码 84 | ) 85 | } 86 | 忘记密码 87 | 88 | 89 | 90 | 91 | 92 |
93 |
94 | ) 95 | } 96 | } 97 | 98 | export default Form.create()(FormLogin); -------------------------------------------------------------------------------- /src/pages/map/bikeMap.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Card} from 'antd' 3 | import axios from './../../axios' 4 | import BaseForm from '../../components/BaseForm' 5 | 6 | export default class BikeMap extends React.Component{ 7 | 8 | state = { 9 | list:[] 10 | } 11 | 12 | map=''; 13 | 14 | params = { 15 | page: 1 16 | } 17 | 18 | formList = [ 19 | { 20 | type: 'SELECT', 21 | label: '城市', 22 | field: 'city_id', 23 | placeholder: '全部', 24 | initialValue: '0', 25 | list: [ 26 | {id: '0', name: '全部'}, 27 | {id: '1', name: '北京'}, 28 | {id: '2', name: '天津'}, 29 | {id: '3', name: '深圳'}, 30 | ] 31 | 32 | },{ 33 | type: '时间查询' 34 | },{ 35 | type: 'SELECT', 36 | label: '订单状态', 37 | field: 'order_status', 38 | placeholder: '全部', 39 | initialValue: '0', 40 | list: [ 41 | {id: '0', name: '全部'}, 42 | {id: '1', name: '进行中'}, 43 | {id: '2', name: '行程结束'} 44 | ] 45 | } 46 | ] 47 | 48 | componentDidMount(){ 49 | this.requestList(); 50 | } 51 | 52 | requestList = () => { 53 | axios.ajax({ 54 | url: '/map/bike_list', 55 | data: { 56 | params: this.params 57 | } 58 | }).then((res) => { 59 | if(res.code === 0){ 60 | this.setState({ 61 | total_count: res.list.total_count 62 | }) 63 | this.renderMap(res); 64 | } 65 | }) 66 | } 67 | 68 | //查询表单 69 | handleFilterSubmit = (filterParams) => { 70 | this.params = filterParams; 71 | this.requestList(); 72 | } 73 | 74 | //初始化地图 75 | renderMap = (res) => { 76 | //渲染地图数据 77 | let list = res.list.route_list; 78 | this.map = new window.BMap.Map('container'); 79 | let gps1 = list[0].split(','); 80 | let startPoint = new window.BMap.Point(gps1[0],gps1[1]); 81 | let gps2 = list[list.length-1].split(','); 82 | let endPoint = new window.BMap.Point(gps2[0],gps2[1]); 83 | this.map.centerAndZoom(endPoint, 11); 84 | 85 | //起点 -- 图标Icon/覆盖物Marker/添加addOverlay 86 | let startPointIcon = new window.BMap.Icon('/assets/start_point.png', new window.BMap.Size(36,42),{ 87 | imageSize: new window.BMap.Size(36,42), 88 | anchor: new window.BMap.Size(18,42) //偏移 89 | }) 90 | let bikeMarkerStart = new window.BMap.Marker(startPoint,{icon: startPointIcon}) 91 | this.map.addOverlay(bikeMarkerStart) 92 | 93 | //终点 94 | let endPointIcon = new window.BMap.Icon('/assets/end_point.png', new window.BMap.Size(36,42),{ 95 | imageSize: new window.BMap.Size(36,42), 96 | anchor: new window.BMap.Size(18,42) 97 | }) 98 | let bikeMarkerEnd = new window.BMap.Marker(endPoint,{icon: endPointIcon}) 99 | this.map.addOverlay(bikeMarkerEnd) 100 | 101 | //绘制车辆行驶路线 102 | let routeList = []; 103 | list.forEach((item) => { 104 | let p = item.split(','); 105 | routeList.push(new window.BMap.Point(p[0],p[1])); 106 | }) 107 | let polyLine = new window.BMap.Polyline(routeList, { 108 | strokeColor: '#ef4136', 109 | strokeWeight: 2, 110 | strokeOpacity: 1 111 | }) 112 | this.map.addOverlay(polyLine); 113 | 114 | //绘制服务区 115 | let servicePointList = []; 116 | let serviceList = res.list.service_list; 117 | serviceList.forEach((item) => { 118 | servicePointList.push(new window.BMap.Point(item.lon, item.lat)); 119 | }) 120 | let polyServiceLine = new window.BMap.Polyline(servicePointList, { 121 | strokeColor: '#1869AD', 122 | strokeWeight: 3, 123 | strokeOpacity: 1 124 | }) 125 | this.map.addOverlay(polyServiceLine); 126 | 127 | //添加地图中的自行车图标 128 | let bikeList = res.list.bike_list; 129 | let bikeIcon = new window.BMap.Icon('/assets/bike.jpg', new window.BMap.Size(36,42),{ 130 | imageSize: new window.BMap.Size(36,42), 131 | anchor: new window.BMap.Size(18,42) 132 | }) 133 | bikeList.forEach((item) => { 134 | let p = item.split(','); 135 | let point = new window.BMap.Point(p[0],p[1]); 136 | let bikeMarker = new window.BMap.Marker(point, {icon: bikeIcon}) 137 | this.map.addOverlay(bikeMarker); 138 | }) 139 | 140 | //添加地图控件 141 | this.map.addControl(new window.BMap.ScaleControl({ anchor: window.BMAP_ANCHOR_TOP_RIGHT })); 142 | this.map.addControl(new window.BMap.NavigationControl({ anchor: window.BMAP_ANCHOR_TOP_RIGHT })); 143 | } 144 | 145 | render(){ 146 | return ( 147 |
148 | 149 | 150 | 151 | 152 |
共{this.state.total_count}辆车
153 |
154 |
155 |
156 | ) 157 | } 158 | } 159 | 160 | -------------------------------------------------------------------------------- /src/pages/order/detail.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card } from 'antd'; 3 | import axios from '../../axios'; 4 | import './detail.less'; 5 | 6 | export default class Order extends React.Component{ 7 | 8 | state = {} 9 | 10 | componentDidMount(){ 11 | let orderId = this.props.match.params.orderId; 12 | if(orderId){ 13 | this.getDetailInfo(orderId); 14 | } 15 | } 16 | 17 | getDetailInfo = (orderId) => { 18 | axios.ajax({ 19 | url: '/order/detail', 20 | data: { 21 | params: { 22 | orderId: orderId 23 | } 24 | } 25 | }).then((res) => { 26 | if(res.code === 0){ 27 | this.setState({ 28 | orderInfo: res.list 29 | }) 30 | this.renderMap(res.list); 31 | } 32 | }) 33 | } 34 | 35 | //初始化地图 36 | renderMap = (list) => { 37 | this.map = new window.BMap.Map('orderDetailMap'); 38 | // this.map.centerAndZoom('北京', 11) 39 | //添加地图控件 40 | this.addMapControl(); 41 | //调用路线图绘制方法 42 | this.drawBikeRoute(list.position_list); 43 | //调用服务区绘制方法 44 | this.drawServiceArea(list.area); 45 | } 46 | 47 | //添加地图控件 48 | addMapControl = () => { 49 | let map = this.map; 50 | map.addControl(new window.BMap.ScaleControl({ anchor: window.BMAP_ANCHOR_TOP_RIGHT })); 51 | map.addControl(new window.BMap.NavigationControl({ anchor: window.BMAP_ANCHOR_TOP_RIGHT })); 52 | } 53 | 54 | //绘制用户行驶路线图 55 | drawBikeRoute = (positionList) => { 56 | let startPoint = ''; 57 | let endPoint = ''; 58 | if(positionList.length > 0){ 59 | //起点 60 | let first = positionList[0]; 61 | startPoint = new window.BMap.Point(first.lon, first.lat); 62 | let startIcon = new window.BMap.Icon('/assets/start_point.png', new window.BMap.Size(36,42),{ 63 | imageSize: new window.BMap.Size(36,42), 64 | anchor: new window.BMap.Size(36,42) 65 | }) 66 | 67 | let startMarker = new window.BMap.Marker(startPoint, {icon: startIcon}); 68 | this.map.addOverlay(startMarker); 69 | 70 | //终点 71 | let last = positionList[positionList.length-1]; 72 | endPoint = new window.BMap.Point(last.lon, last.lat); 73 | let endIcon = new window.BMap.Icon('/assets/end_point.png', new window.BMap.Size(36,42),{ 74 | imageSize: new window.BMap.Size(36,42), 75 | anchor: new window.BMap.Size(36,42) 76 | }) 77 | let endMarker = new window.BMap.Marker(endPoint, {icon: endIcon}); 78 | this.map.addOverlay(endMarker); 79 | 80 | //连接路线图 81 | let trackPoint = []; 82 | for(let i=0; i { 101 | let trackPoint = []; 102 | for(let i=0; i 121 | 122 |
123 |
124 |
基础信息
125 |
    126 |
  • 127 |
    用车模式
    128 |
    {info.mode === 1 ? '服务器' : '停车点'}
    129 |
  • 130 |
  • 131 |
    订单编号
    132 |
    {info.order_sn}
    133 |
  • 134 |
  • 135 |
    车辆编号
    136 |
    {info.bike_sn}
    137 |
  • 138 |
  • 139 |
    用户姓名
    140 |
    {info.user_name}
    141 |
  • 142 |
  • 143 |
    手机号码
    144 |
    {info.mobile}
    145 |
  • 146 |
147 |
148 |
149 |
行驶轨迹
150 |
    151 |
  • 152 |
    行驶起点
    153 |
    {info.start_location}
    154 |
  • 155 |
  • 156 |
    行驶终点
    157 |
    {info.end_location}
    158 |
  • 159 |
  • 160 |
    行驶里程
    161 |
    {info.distance/1000}Km
    162 |
  • 163 |
164 |
165 |
166 | 167 | ); 168 | } 169 | } -------------------------------------------------------------------------------- /src/pages/order/detail.less: -------------------------------------------------------------------------------- 1 | @import '../../style/default'; 2 | @import '../../style/common'; 3 | 4 | .detail-items{ 5 | margin-left:90px; 6 | padding:25px 50px 25px 0; 7 | border-bottom:1px solid @colorN; 8 | &:last-child{ 9 | border-bottom:none; 10 | } 11 | .item-title{ 12 | margin:20px 0; 13 | font-size:@fontG; 14 | color:@colorU; 15 | } 16 | .detail-form{ 17 | li{ 18 | .clearfix; 19 | margin:20px 0; 20 | line-height:20px; 21 | font-size:15px; 22 | color:@colorC; 23 | } 24 | } 25 | .detail-form-left{ 26 | float:left; 27 | width:164px; 28 | text-align:right; 29 | color:@colorH; 30 | } 31 | .detail-form-content{ 32 | padding-left:194px; 33 | } 34 | } 35 | .order-map{ 36 | height: 450px; 37 | margin: 25px -31px 0; 38 | } -------------------------------------------------------------------------------- /src/pages/order/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Card, Button, Table, Form, Modal, message } from 'antd'; 3 | import axios from './../../axios/index'; 4 | import BaseForm from './../../components/BaseForm/index'; 5 | const FormItem = Form.Item; 6 | 7 | export default class Order extends React.Component{ 8 | 9 | state = { 10 | orderInfo: {}, 11 | orderConfirmVisible: false 12 | } 13 | params = { 14 | page:1 15 | } 16 | //按照AntD 的getFieldDecorator.option规则定义 17 | formList = [ 18 | { 19 | type: 'SELECT', 20 | label: '城市', 21 | field: 'city_id', 22 | placeholder: '全部', 23 | initialValue: '1', 24 | width: 80, 25 | list: [ 26 | {id: '0', name: '全部'}, 27 | {id: '1', name: '北京'}, 28 | {id: '2', name: '天津'}, 29 | {id: '3', name: '上海'} 30 | ] 31 | }, 32 | { 33 | type: '时间查询' 34 | }, 35 | { 36 | type: 'SELECT', 37 | label: '订单状态', 38 | field: 'order_status', 39 | placeholder: '全部', 40 | initialValue: '1', 41 | width: 80, 42 | list: [ 43 | {id: '0', name: '全部'}, 44 | {id: '1', name: '进行中'}, 45 | {id: '2', name: '结束行程'} 46 | ] 47 | }, 48 | 49 | ] 50 | 51 | componentDidMount(){ 52 | this.requestList(); 53 | } 54 | 55 | handleFilter = (params) => { 56 | this.params = params; 57 | this.requestList(); 58 | } 59 | 60 | requestList = () => { 61 | axios.requestList(this, '/order/list', this.params, true) 62 | } 63 | 64 | //订单结束确认 65 | handleConfirm = () => { 66 | let item = this.state.selectedItem; 67 | if(!item){ 68 | Modal.info({ 69 | title: '信息', 70 | content: '请选择一条订单进行结束' 71 | }) 72 | return; 73 | } 74 | axios.ajax({ 75 | url: '/order/ebike_info', 76 | data: { 77 | params: { 78 | orderId: item.id 79 | } 80 | } 81 | }).then((res) => { 82 | if(res.code === 0 ){ 83 | this.setState({ 84 | orderInfo: res.list, 85 | orderConfirmVisible: true 86 | }) 87 | } 88 | }) 89 | } 90 | 91 | //结束订单 92 | handleFinishOrder = () => { 93 | let item = this.state.selectedItem; 94 | axios.ajax({ 95 | url: '/order/finish_order', 96 | data: { 97 | params: { 98 | orderId: item.id 99 | } 100 | } 101 | }).then((res) => { 102 | if(res.code === 0){ 103 | message.success('订单结束成功') 104 | this.setState({ 105 | orderConfirmVisible: false 106 | }) 107 | this.requestList(); 108 | } 109 | }) 110 | } 111 | onRowClick = (record, index) => { 112 | let selectKey = [index]; 113 | this.setState({ 114 | selectedRowKeys: selectKey, 115 | selectedItem: record 116 | }) 117 | } 118 | 119 | //订单详情页 120 | openOrderDetail = () => { 121 | let item = this.state.selectedItem; 122 | if(!item){ 123 | Modal.info({ 124 | title: '信息', 125 | content: '请先选择一条订单' 126 | }) 127 | return; 128 | } 129 | window.open(`/#/common/order/detail/${item.id}`,'_blank') 130 | } 131 | 132 | render(){ 133 | const columns = [ 134 | { 135 | title: '订单编号', 136 | dataIndex: 'order_sn' 137 | }, 138 | { 139 | title: '车辆编号', 140 | dataIndex: 'bike_sn' 141 | }, 142 | { 143 | title: '用户名', 144 | dataIndex: 'user_name' 145 | }, 146 | { 147 | title: '手机号', 148 | dataIndex: 'mobile' 149 | }, 150 | { 151 | title: '里程', 152 | dataIndex: 'distance', 153 | render(distance){ 154 | return distance/1000 + 'Km'; 155 | } 156 | }, 157 | { 158 | title: '行驶时长', 159 | dataIndex: 'total_time' 160 | }, 161 | { 162 | title: '状态', 163 | dataIndex: 'status' 164 | }, 165 | { 166 | title: '开始时间', 167 | dataIndex: 'start_time' 168 | }, 169 | { 170 | title: '结束时间', 171 | dataIndex: 'end_time' 172 | }, 173 | { 174 | title: '订单金额', 175 | dataIndex: 'total_fee' 176 | }, 177 | { 178 | title: '实付金额', 179 | dataIndex: 'user_pay' 180 | } 181 | ] 182 | const formItemLayout = { 183 | labelCol: { 184 | span: 5 185 | }, 186 | wrapperCol: { 187 | span: 19 188 | } 189 | } 190 | const selectedRowKeys = this.state.selectedRowKeys; 191 | const rowSelection = { 192 | type: 'radio', 193 | selectedRowKeys 194 | } 195 | 196 | return ( 197 |
198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 |
206 |
{ 213 | return { 214 | onClick: () => { 215 | this.onRowClick(record, index); 216 | } 217 | } 218 | }} 219 | /> 220 | 221 | { 225 | this.setState({ 226 | orderConfirmVisible: false 227 | }) 228 | }} 229 | onOk={this.handleFinishOrder} 230 | width={600}> 231 |
232 | 233 | {this.state.orderInfo.bike_sn} 234 | 235 | 236 | {this.state.orderInfo.battery + '%'} 237 | 238 | 239 | {this.state.orderInfo.start_time} 240 | 241 | 242 | {this.state.orderInfo.location} 243 | 244 | 245 |
246 | 247 | ) 248 | } 249 | } -------------------------------------------------------------------------------- /src/pages/rich/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Card, Button, Modal} from 'antd' 3 | import {Editor} from 'react-draft-wysiwyg' 4 | import draftjs from 'draftjs-to-html' 5 | import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css' 6 | 7 | export default class RichText extends React.Component{ 8 | state = { 9 | showRichText: false, 10 | editorContent: '', 11 | editorState: '' 12 | } 13 | handleClearContent = () => { 14 | this.setState({ 15 | editorState: '' 16 | }) 17 | } 18 | handleGetText = () => { 19 | this.setState({ 20 | showRichText: true 21 | }) 22 | } 23 | onEditorStateChange = (editorState) => { 24 | this.setState({ 25 | editorState 26 | }) 27 | } 28 | onEditorChange = (editorContent) => { 29 | this.setState({ 30 | editorContent 31 | }) 32 | } 33 | render(){ 34 | const { editorState, editorContent } = this.state; 35 | return ( 36 |
37 | 38 | 39 | 40 | 41 | 42 | 51 | 52 | { 56 | this.setState({ 57 | showRichText: false 58 | }) 59 | }} 60 | footer={null}> 61 | {draftjs(this.state.editorContent)} 62 | 63 |
64 | ) 65 | } 66 | } -------------------------------------------------------------------------------- /src/pages/router_demo/About.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | class About extends Component{ 3 | render(){ 4 | return( 5 |
6 | this is About. 7 |
8 | ); 9 | } 10 | } 11 | export default About; -------------------------------------------------------------------------------- /src/pages/router_demo/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router-dom' 3 | 4 | class Home extends React.Component{ 5 | render(){ 6 | return( 7 |
8 | {/*页面导航的配置*/} 9 | 23 |
24 | {/*找到路由匹配的组件后呈现的位置*/} 25 | {this.props.children} 26 |
27 | ); 28 | } 29 | } 30 | export default Home;  -------------------------------------------------------------------------------- /src/pages/router_demo/Info.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | class Info extends Component{ 3 | render(){ 4 | return( 5 |
6 | 这里是测试动态路由功能 7 | 动态路由的值时:{this.props.match.params.value} 8 |
9 | ); 10 | } 11 | } 12 | export default Info; -------------------------------------------------------------------------------- /src/pages/router_demo/Main.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | import {Link} from 'react-router-dom' 3 | 4 | class Main extends Component{ 5 | render(){ 6 | return( 7 |
8 | this is Main. 9 |
10 | 动态路由1 11 |
12 | 动态路由2 13 |
14 | {this.props.children} 15 |
16 | ); 17 | } 18 | } 19 | export default Main; -------------------------------------------------------------------------------- /src/pages/router_demo/NoMatch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | class NoMatch extends React.Component{ 3 | render(){ 4 | return( 5 |
6 | 404 Not Found 7 |
8 | ); 9 | } 10 | } 11 | export default NoMatch; -------------------------------------------------------------------------------- /src/pages/router_demo/Topics.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | class Topics extends Component{ 3 | render(){ 4 | return( 5 |
6 | this is topics. 7 |
8 | ); 9 | } 10 | } 11 | export default Topics; -------------------------------------------------------------------------------- /src/pages/router_demo/User.js: -------------------------------------------------------------------------------- 1 | import React,{Component} from 'react'; 2 | class User extends Component{ 3 | render(){ 4 | return( 5 |
6 | this is User. 7 |
8 | ); 9 | } 10 | } 11 | export default User; -------------------------------------------------------------------------------- /src/pages/router_demo/router.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {HashRouter as Router,Route,Switch} from 'react-router-dom' 3 | import Main from './Main'; 4 | import About from './About'; 5 | import Topics from './Topics'; 6 | // import User from './User'; 7 | import Info from './Info'; 8 | import Home from './Home' 9 | import NoMatch from './NoMatch' 10 | 11 | export default class IRouter extends React.Component{ 12 | 13 | render(){ 14 | return ( 15 | 16 | 17 | 18 | {/*根据导航配置找到对应的组件*/} 19 | 20 |
21 | 22 |
23 | }>
24 | 25 | 26 | 27 |
28 |
29 |
30 | ) 31 | } 32 | } -------------------------------------------------------------------------------- /src/pages/ui/buttons.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Button, Radio} from 'antd' 3 | import './ui.less' 4 | 5 | class Buttons extends React.Component{ 6 | 7 | state = { 8 | loading: true, 9 | size: 'default' 10 | } 11 | 12 | handleCloseLoading = () =>{ 13 | this.setState({ 14 | loading: false 15 | }) 16 | } 17 | 18 | handleChange = (e) => { 19 | this.setState({ 20 | size: e.target.value 21 | }) 22 | } 23 | 24 | render(){ 25 | return( 26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 | ); 68 | } 69 | } 70 | export default Buttons; -------------------------------------------------------------------------------- /src/pages/ui/carousel.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Carousel} from 'antd' 3 | import './ui.less' 4 | 5 | export default class Carousels extends React.Component{ 6 | render(){ 7 | return ( 8 |
9 | 10 | 11 |

Ant Motion Banner - React

12 |

Ant Motion Banner - Vue

13 |

Ant Motion Banner - Angular

14 |
15 |
16 | 17 | 18 |
>
19 |
20 |
21 |
22 |
23 |
24 | ) 25 | } 26 | } -------------------------------------------------------------------------------- /src/pages/ui/gallery.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Row, Col, Modal} from 'antd' 3 | import './ui.less' 4 | 5 | export default class Gallery extends React.Component{ 6 | state = { 7 | visible: false 8 | } 9 | openGallery = (imgSrc) => { 10 | this.setState({ 11 | visible: true, 12 | currentImg: '/gallery/'+imgSrc 13 | }) 14 | } 15 | render(){ 16 | const imgs = [ 17 | ['1.png','2.png','3.png','4.png','5.png'], 18 | ['6.png','7.png','8.png','9.png','10.png'], 19 | ['11.png','12.png','13.png','14.png','15.png'], 20 | ['16.png','17.png','18.png','19.png','20.png'], 21 | ['21.png','22.png','23.png','24.png','25.png'] 22 | ] 23 | const imgList = imgs.map((list) => list.map((item) => 24 | this.openGallery(item)} alt=""/>} 27 | > 28 | 32 | 33 | )) 34 | return ( 35 |
36 | 37 |
38 | {imgList[0]} 39 | 40 | 41 | {imgList[1]} 42 | 43 | 44 | {imgList[2]} 45 | 46 | 47 | {imgList[3]} 48 | 49 | 50 | {imgList[4]} 51 | 52 | 53 | { 59 | this.setState({ 60 | visible: false 61 | }) 62 | }} 63 | footer={null} 64 | > 65 | {} 66 | 67 | 68 | ) 69 | } 70 | } -------------------------------------------------------------------------------- /src/pages/ui/loadings.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Spin, Icon, Alert} from 'antd' 3 | import './ui.less' 4 | 5 | export default class Loadings extends React.Component{ 6 | render() { 7 | const icon = 8 | return ( 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 23 | 28 | 29 | 30 | 35 | 36 | 37 | 42 | 43 | 44 |
45 | ) 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/pages/ui/messages.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Button, message} from 'antd' 3 | import './ui.less' 4 | 5 | export default class Messages extends React.Component{ 6 | showMessage = (type) => { 7 | message[type]("恭喜你,React课程晋级成功"); 8 | } 9 | render(){ 10 | return ( 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /src/pages/ui/modals.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Button, Modal} from 'antd' 3 | import './ui.less' 4 | 5 | export default class Buttons extends React.Component{ 6 | state = { 7 | showModal1: false, 8 | showModal2: false, 9 | showModal3: false, 10 | showModal4: false 11 | } 12 | handleOpen = (type) => { 13 | this.setState({ 14 | [type]: true 15 | }) 16 | } 17 | handleConfirm = (type) => { 18 | Modal[type]({ 19 | title: '确认?', 20 | content:'你确认你学会了React了吗?', 21 | onOk() { 22 | console.log('ok') 23 | }, 24 | onCancel() { 25 | console.log('Cancel') 26 | } 27 | }) 28 | } 29 | render(){ 30 | return ( 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | { 48 | this.setState({ 49 | showModal1: false 50 | }) 51 | }}> 52 |

欢迎使用柳柳版弹框

53 |
54 | { 60 | this.setState({ 61 | showModal2: false 62 | }) 63 | }}> 64 |

欢迎使用柳柳版弹框

65 |
66 | { 71 | this.setState({ 72 | showModal3: false 73 | }) 74 | }}> 75 |

欢迎使用柳柳版弹框

76 |
77 | { 82 | this.setState({ 83 | showModal4: false 84 | }) 85 | }}> 86 |

欢迎使用柳柳版弹框

87 |
88 | 89 |
90 | ) 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/pages/ui/notice.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Button, notification} from 'antd' 3 | import './ui.less' 4 | 5 | export default class Notice extends React.Component{ 6 | openNotification = (type, direction) => { 7 | if(direction){ 8 | notification.config({ 9 | placement: direction 10 | }) 11 | } 12 | notification[type]({ 13 | message:'发工资了', 14 | description:'上个月考勤22天,迟到12天,实发工资2500,请笑纳' 15 | }) 16 | } 17 | render(){ 18 | return ( 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/pages/ui/tabs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Card, Tabs, message, Icon} from 'antd' 3 | import './ui.less' 4 | 5 | const TabPane = Tabs.TabPane; 6 | 7 | export default class Tab extends React.Component{ 8 | handleCallBack = (key) => { 9 | message.info("Hi,您选择了页签:"+key) 10 | } 11 | componentWillMount(){ 12 | this.newTabIndex = 0; 13 | const panes = [ 14 | { 15 | title: 'Tab 1', 16 | content: '欢迎使用柳柳版页签', 17 | key: '1' 18 | }, 19 | { 20 | title: 'Tab 2', 21 | content: '欢迎使用柳柳版页签', 22 | key: '2' 23 | }, 24 | { 25 | title: 'Tab 3', 26 | content: '欢迎使用柳柳版页签', 27 | key: '3' 28 | } 29 | ] 30 | this.setState({ 31 | panes, 32 | activeKey: panes[0].key 33 | }) 34 | } 35 | onChange = (activeKey) => { 36 | this.setState({ 37 | activeKey 38 | }) 39 | } 40 | //onEdit、add、remove直接从官网复制过来即可 41 | onEdit = (targetKey, action) => { 42 | this[action](targetKey); 43 | } 44 | add = () => { 45 | const panes = this.state.panes; 46 | const activeKey = `newTab${this.newTabIndex++}`; 47 | panes.push({ title: activeKey, content: 'Content of new Tab', key: activeKey }); 48 | this.setState({ panes, activeKey }); 49 | } 50 | //activeKey:当前激活的key, targetKey:当前删除的Key 51 | remove = (targetKey) => { 52 | let activeKey = this.state.activeKey; 53 | let lastIndex; 54 | this.state.panes.forEach((pane, i) => { 55 | if (pane.key === targetKey) { 56 | lastIndex = i - 1; 57 | } 58 | }); 59 | const panes = this.state.panes.filter(pane => pane.key !== targetKey); 60 | if (lastIndex >= 0 && activeKey === targetKey) { 61 | activeKey = panes[lastIndex].key; 62 | } 63 | this.setState({ panes, activeKey }); 64 | } 65 | 66 | render() { 67 | return ( 68 |
69 | 70 | 71 | 欢迎使用柳柳版页签 72 | 欢迎使用柳柳版页签 73 | 欢迎使用柳柳版页签 74 | 75 | 76 | 77 | 78 | 增加} key="1">欢迎使用柳柳版页签 79 | 编辑} key="2">欢迎使用柳柳版页签 80 | 删除} key="3">欢迎使用柳柳版页签 81 | 82 | 83 | 84 | 90 | { 91 | this.state.panes.map((panel) => { 92 | return {panel.content} 96 | }) 97 | } 98 | 99 | 100 |
101 | ) 102 | } 103 | } -------------------------------------------------------------------------------- /src/pages/ui/ui.less: -------------------------------------------------------------------------------- 1 | .card-wrap{ 2 | margin-bottom: 10px; 3 | button{ 4 | margin-right: 10px; 5 | } 6 | } 7 | /* modals */ 8 | /* use css to set position of modal */ 9 | .vertical-center-modal { 10 | text-align: center; 11 | white-space: nowrap; 12 | } 13 | 14 | .vertical-center-modal:before { 15 | content: ''; 16 | display: inline-block; 17 | height: 100%; 18 | vertical-align: middle; 19 | width: 0; 20 | } 21 | 22 | .vertical-center-modal .ant-modal { 23 | display: inline-block; 24 | vertical-align: middle; 25 | top: 0; 26 | text-align: left; 27 | } 28 | 29 | /* Carousel For demo */ 30 | .ant-carousel .slick-slide { 31 | text-align: center; 32 | height: 160px; 33 | line-height: 160px; 34 | background: #364d79; 35 | overflow: hidden; 36 | } 37 | 38 | .ant-carousel .slick-slide h3 { 39 | color: rgba(246, 250, 33, 0.966); 40 | } 41 | 42 | // 图片轮播 43 | .slider-wrap .ant-carousel .slick-slide { 44 | height: 240px!important; 45 | } -------------------------------------------------------------------------------- /src/redux/action/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Action 类型:用户事件操作 3 | */ 4 | 5 | export const type = { 6 | SWITCH_MENU : 'SWITCH_MENU' 7 | } 8 | 9 | // 菜单点击切换,修改面包屑名称 10 | export function switchMenu(menuName) { 11 | return { 12 | type:type.SWITCH_MENU, 13 | menuName 14 | } 15 | } -------------------------------------------------------------------------------- /src/redux/reducer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Reducer: 数据处理 3 | */ 4 | import {type} from './../action' 5 | 6 | const initialState = { 7 | menuName: '首页' 8 | } 9 | 10 | const ebikeData = (state = initialState, action) => { 11 | switch (action.type) { 12 | case type.SWITCH_MENU: 13 | return { 14 | ...state, //旧值 15 | menuName: action.menuName //新值 16 | } 17 | break; 18 | default: 19 | return { 20 | ...state 21 | }; 22 | } 23 | } 24 | export default ebikeData; 25 | -------------------------------------------------------------------------------- /src/redux/store/configureStore.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 引入createStore保存数据源 3 | */ 4 | 5 | import {createStore} from 'redux' 6 | import reducer from './../reducer' 7 | //调试工具插件方法 8 | // import { composeWithDevTools } from 'redux-devtools-extension' 9 | 10 | export default () => createStore(reducer) 11 | -------------------------------------------------------------------------------- /src/resource/api/.json: -------------------------------------------------------------------------------- 1 | {success: true, data: {name: "hh"}, _res: {status: 400, data: {success: false}, cookies: {test: "true"}, headers: {Power: "easy-mock"}}} -------------------------------------------------------------------------------- /src/resource/api/city/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": [{ 3 | "id": 1, 4 | "name": "北京" 5 | }, { 6 | "id": 2, 7 | "name": "上海" 8 | }, { 9 | "id": 3, 10 | "name": "天津" 11 | }, { 12 | "id": 5, 13 | "name": "广州" 14 | }, { 15 | "id": 6, 16 | "name": "深圳" 17 | }, { 18 | "id": 7, 19 | "name": "杭州" 20 | }, { 21 | "id": 8, 22 | "name": "成都" 23 | }, { 24 | "id": 9, 25 | "name": "南京" 26 | }, { 27 | "id": 10, 28 | "name": "苏州" 29 | }] 30 | } -------------------------------------------------------------------------------- /src/resource/api/city/open.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":0, 3 | "result": "开通成功" 4 | } -------------------------------------------------------------------------------- /src/resource/api/info_alarm.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "vol_low": 2, 4 | "offline": 12, 5 | "unlock_ex": 0, 6 | "lock_fail": 0, 7 | "op_lock_timeout": 0, 8 | "bat_lock_timeout": 2 9 | }, 10 | "code": 0, 11 | "message": "success" 12 | } -------------------------------------------------------------------------------- /src/resource/api/map/bike_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":0, 3 | "result": { 4 | "total_count": 100, 5 | "bike_list": ['116.356619,40.017782', '116.437107,39.975331', '116.34972,40.070808', '116.323849,39.964714', '116.404912,40.015129', '116.365243,39.958078'], 6 | "route_list": ['116.353101,40.067835', '116.357701,40.053699', '116.374086,40.027626', '116.397801,40.01641'], 7 | "service_list": [{ 8 | "lon": "116.274737", 9 | "lat": "40.139759", 10 | "ts": null 11 | }, 12 | { 13 | "lon": "116.316562", 14 | "lat": "40.144943", 15 | "ts": null 16 | }, 17 | { 18 | "lon": "116.351631", 19 | "lat": "40.129498", 20 | "ts": null 21 | }, 22 | { 23 | "lon": "116.390582", 24 | "lat": "40.082481", 25 | "ts": null 26 | }, 27 | { 28 | "lon": "116.38742", 29 | "lat": "40.01065", 30 | "ts": null 31 | }, 32 | { 33 | "lon": "116.414297", 34 | "lat": "40.01181", 35 | "ts": null 36 | }, 37 | { 38 | "lon": "116.696242", 39 | "lat": "39.964035", 40 | "ts": null 41 | }, 42 | { 43 | "lon": "116.494498", 44 | "lat": "39.851306", 45 | "ts": null 46 | }, 47 | { 48 | "lon": "116.238086", 49 | "lat": "39.848647", 50 | "ts": null 51 | }, 52 | { 53 | "lon": "116.189454", 54 | "lat": "39.999418", 55 | "ts": null 56 | }, 57 | { 58 | "lon": "116.244646", 59 | "lat": "39.990574", 60 | "ts": null 61 | }, 62 | { 63 | "lon": "116.281441", 64 | "lat": "40.008703", 65 | "ts": null 66 | }, 67 | { 68 | "lon": "116.271092", 69 | "lat": "40.142201", 70 | "ts": null 71 | }, 72 | { 73 | "lon": "116.271092", 74 | "lat": "40.142201", 75 | "ts": null 76 | } 77 | ] 78 | } 79 | } -------------------------------------------------------------------------------- /src/resource/api/mock.json: -------------------------------------------------------------------------------- 1 | {"success":true,"data":{"projects|3-10":[{"name":"演示用","url":"@url","email":"@email","address":"@county(true)","string|1-10":"★","number|1-100":100,"boolean|1-2":true,"object|2":{"310000":"上海市","320000":"江苏省","330000":"浙江省"}}]}} -------------------------------------------------------------------------------- /src/resource/api/open_city.json: -------------------------------------------------------------------------------- 1 | { 2 | 'code':'0', 3 | "result": { 4 | "page": 1, 5 | "page_size": 10, 6 | "total_count": 60, 7 | "page_count": 6, 8 | "item_list|10": [{ 9 | "id|+1": 1, 10 | "name": "@city", 11 | "mode|1-2": 1, 12 | "op_mode|1-2": 1, 13 | "franchisee_id": 77, 14 | "franchisee_name": "松果自营", 15 | "city_admins|1-2": [{ 16 | "user_name": "@cname", 17 | "user_id|+1": 10001 18 | }], 19 | "open_time": "@datetime", 20 | "sys_user_name": "@cname", 21 | "update_time": 1520476737000 22 | }] 23 | } 24 | } -------------------------------------------------------------------------------- /src/resource/api/order/detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":'0', 3 | "msg":'', 4 | "result": { 5 | "status": 2, 6 | "order_sn": "T1803244422704080JGJI", 7 | "bike_sn": "802410001", 8 | "mode|1-2": 1, 9 | "start_location": "北京市昌平区回龙观东大街", 10 | "end_location": "北京市海淀区奥林匹克公园", 11 | "city_id": 1, 12 | "mobile": "13597482075", 13 | "user_name": "@cname", 14 | "distance": 10000, 15 | "bike_gps": "116.398806,40.008637", 16 | "start_time": 1521865027000, 17 | "end_time": 1521865251000, 18 | "total_time": 224, 19 | "position_list": [{ 20 | "lon": 116.361221, 21 | "lat": 40.043776 22 | }, { 23 | "lon": 116.363736, 24 | "lat": 40.038086 25 | }, { 26 | "lon": 116.364599, 27 | "lat": 40.036484 28 | }, { 29 | "lon": 116.373438, 30 | "lat": 40.03538 31 | }, { 32 | "lon": 116.377966, 33 | "lat": 40.036263 34 | }, { 35 | "lon": 116.379762, 36 | "lat": 40.03654 37 | }, { 38 | "lon": 116.38084, 39 | "lat": 40.033225 40 | }, { 41 | "lon": 116.38084, 42 | "lat": 40.029413 43 | }, { 44 | "lon": 116.381343, 45 | "lat": 40.021291 46 | }, { 47 | "lon": 116.381846, 48 | "lat": 40.015821 49 | }, { 50 | "lon": 116.382637, 51 | "lat": 40.008084 52 | }, { 53 | "lon": 116.398806, 54 | "lat": 40.008637 55 | }], 56 | "area": [{ 57 | "lon": "116.274737", 58 | "lat": "40.139759", 59 | "ts": null 60 | }, 61 | { 62 | "lon": "116.316562", 63 | "lat": "40.144943", 64 | "ts": null 65 | }, 66 | { 67 | "lon": "116.351631", 68 | "lat": "40.129498", 69 | "ts": null 70 | }, 71 | { 72 | "lon": "116.390582", 73 | "lat": "40.082481", 74 | "ts": null 75 | }, 76 | { 77 | "lon": "116.38742", 78 | "lat": "40.01065", 79 | "ts": null 80 | }, 81 | { 82 | "lon": "116.414297", 83 | "lat": "40.01181", 84 | "ts": null 85 | }, 86 | { 87 | "lon": "116.696242", 88 | "lat": "39.964035", 89 | "ts": null 90 | }, 91 | { 92 | "lon": "116.494498", 93 | "lat": "39.851306", 94 | "ts": null 95 | }, 96 | { 97 | "lon": "116.238086", 98 | "lat": "39.848647", 99 | "ts": null 100 | }, 101 | { 102 | "lon": "116.189454", 103 | "lat": "39.999418", 104 | "ts": null 105 | }, 106 | { 107 | "lon": "116.244646", 108 | "lat": "39.990574", 109 | "ts": null 110 | }, 111 | { 112 | "lon": "116.281441", 113 | "lat": "40.008703", 114 | "ts": null 115 | }, 116 | { 117 | "lon": "116.271092", 118 | "lat": "40.142201", 119 | "ts": null 120 | }, 121 | { 122 | "lon": "116.271092", 123 | "lat": "40.142201", 124 | "ts": null 125 | } 126 | ], 127 | "area_list": null, 128 | "npl_list": [{ 129 | "id": 8265, 130 | "name": "北辰世纪中心-a座", 131 | "city_id": 1, 132 | "type": 3, 133 | "status": 0, 134 | "map_point": "116.39338796444|40.008120315215;116.39494038009002|40.008177258745;116.39496911688|40.006268094213;116.39512457763|40.004256795877;116.39360214742|40.004222412241;116.39357190147|40.005075745782;116.39351397873|40.005836165232;116.39338796444|40.008120315215", 135 | "map_point_array": ["116.39338796444|40.008120315215", "116.396053|40.008273", "116.396448|40.006338", "116.396915|40.004266", "116.39192|40.004072", "116.391525|40.004984", "116.391381|40.005924", "116.391166|40.007913"], 136 | "map_status": 1, 137 | "creator_name": "赵程程", 138 | "create_time": 1507863539000 139 | }] 140 | } 141 | } -------------------------------------------------------------------------------- /src/resource/api/order/ebike_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":'0', 3 | "result": { 4 | "id": 27296, 5 | "bike_sn": "800116116", 6 | "battery": 100, 7 | "start_time": "@datetime", 8 | "location": "北京市海淀区奥林匹克公园" 9 | } 10 | } -------------------------------------------------------------------------------- /src/resource/api/order/finish_order.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":'0', 3 | "result": 'Ok' 4 | } -------------------------------------------------------------------------------- /src/resource/api/order/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": '0', 3 | "result": { 4 | "page|1-9": 1, 5 | "page_size": 10, 6 | "total_count": 85, 7 | "page_count": 9, 8 | "item_list|10": [{ 9 | "id": 2959165, 10 | "order_sn": /T180[0-9]{6}/, 11 | "bike_sn": "800116090", 12 | "user_id": 908352, 13 | "user_name": "@cname", 14 | "mobile": /1[0-9]{10}/, 15 | "distance": 2000, 16 | "total_time": 4000, 17 | "status|1-2": 1, 18 | "start_time": "@datetime", 19 | "end_time": "@datetime", 20 | "total_fee": 1000, 21 | "user_pay": 300 22 | }] 23 | } 24 | } -------------------------------------------------------------------------------- /src/resource/api/permission/edit.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0 3 | } -------------------------------------------------------------------------------- /src/resource/api/proxy.json: -------------------------------------------------------------------------------- 1 | https://api.m.sohu.com/autonews/pool/?n=%E6%96%B0%E9%97%BB&s=1 -------------------------------------------------------------------------------- /src/resource/api/query.json: -------------------------------------------------------------------------------- 1 | { success :true, data: { default: "hah", _req: function({ _req }) { return _req }, name: function({ _req }) { return _req.query.name || this.default }}} -------------------------------------------------------------------------------- /src/resource/api/restful/_id/list.json: -------------------------------------------------------------------------------- 1 | {"success":true,"data":[{"user":{"name":"演示用"}}]} -------------------------------------------------------------------------------- /src/resource/api/role/create.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0 3 | } -------------------------------------------------------------------------------- /src/resource/api/role/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "result": { 4 | "page": 1, 5 | "page_size": 10, 6 | "total_count": 25, 7 | "page_count": 3, 8 | "item_list|7": [{ 9 | "id|+1": 1, 10 | "role_name": /(管理人员)|(客服专员)|(财务专员)|(市场专员)|(人力专员)|(研发)|(测试)|(系统管理员)/, 11 | "status|0-1": 1, 12 | "authorize_user_name": "@cname", 13 | "authorize_time": 1521270166000, 14 | "create_time": 1499305790000, 15 | "menus": ["/home", "/ui/buttons", "/ui/modals", "/ui/loadings", "/ui/notification", "/ui/messages", "/ui/tabs", "/ui/gallery", "/ui/carousel", "/ui"] 16 | }] 17 | } 18 | } -------------------------------------------------------------------------------- /src/resource/api/role/user_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "result|20": [{ 4 | "status|0-1": 0, 5 | "user_id|+1": 1, 6 | "user_name": "@cname" 7 | }] 8 | } -------------------------------------------------------------------------------- /src/resource/api/role/user_role_edit.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0 3 | } -------------------------------------------------------------------------------- /src/resource/api/table/high/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "message": "", 4 | "result": { 5 | "list|25": [{ 6 | "id|+1": 1, 7 | "username": "Jack", 8 | "sex|1-2": 1, 9 | "age|10-50": 0, 10 | "state|1-5": 1, 11 | "interest|1-8": 1, 12 | "isMarried1|0-1": 1, 13 | "isMarried2|0-1": 1, 14 | "isMarried3|0-1": 1, 15 | "isMarried4|0-1": 1, 16 | "isMarried5|0-1": 1, 17 | "isMarried6|0-1": 1, 18 | "isMarried7|0-1": 1, 19 | "isMarried8|0-1": 1, 20 | "birthday": "2000-01-01", 21 | "address": "北京市海淀区", 22 | "time": "09:00:00" 23 | }], 24 | page: 2, 25 | page_size: 5, 26 | total_count: 30 27 | } 28 | } -------------------------------------------------------------------------------- /src/resource/api/table/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "message": "", 4 | "result": { 5 | "list|10": [{ 6 | "id|+1": 1, 7 | "username": "@cname", 8 | "sex|1-2": 1, 9 | "state|1-5": 1, 10 | "interest|1-8": 1, 11 | "isMarried|0-1": 1, 12 | "birthday": "2000-01-01", 13 | "address": "北京市海淀区", 14 | "time": "09:00:00" 15 | }], 16 | page: 1, 17 | page_size: 10, 18 | total_count: 30 19 | } 20 | } -------------------------------------------------------------------------------- /src/resource/api/table/list1.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "message": "", 4 | "result": { 5 | "list|10": [{ 6 | "id|+1": 1, 7 | "username": "@cname", 8 | "sex|1-2": 1, 9 | "state|1-5": 1, 10 | "interest|1-8": 1, 11 | "isMarried|0-1": 1, 12 | "birthday": "2000-01-01", 13 | "address": "北京市海淀区", 14 | "time": "09:00:00" 15 | }], 16 | page: 1, 17 | page_size: 10, 18 | total_count: 30 19 | } 20 | } -------------------------------------------------------------------------------- /src/resource/api/upload.json: -------------------------------------------------------------------------------- 1 | { data: { img: function({ _req, Mock }) { return _req.body.fileName + "_" + Mock.mock("@image") }}} -------------------------------------------------------------------------------- /src/resource/api/user/add.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":0, 3 | "result": "Ok" 4 | } -------------------------------------------------------------------------------- /src/resource/api/user/delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "code":0 3 | } -------------------------------------------------------------------------------- /src/resource/api/user/edit.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 0, 3 | "result":'Ok' 4 | } -------------------------------------------------------------------------------- /src/resource/assets/bike.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/bike.jpg -------------------------------------------------------------------------------- /src/resource/assets/carousel-img/carousel-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/carousel-img/carousel-1.jpg -------------------------------------------------------------------------------- /src/resource/assets/carousel-img/carousel-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/carousel-img/carousel-2.jpg -------------------------------------------------------------------------------- /src/resource/assets/carousel-img/carousel-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/carousel-img/carousel-3.jpg -------------------------------------------------------------------------------- /src/resource/assets/end_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/end_point.png -------------------------------------------------------------------------------- /src/resource/assets/imooc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/imooc.png -------------------------------------------------------------------------------- /src/resource/assets/logo-ant.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 28 Copy 5 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 42 | 43 | -------------------------------------------------------------------------------- /src/resource/assets/start_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/start_point.png -------------------------------------------------------------------------------- /src/resource/assets/user_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/assets/user_location.png -------------------------------------------------------------------------------- /src/resource/carousel-img/carousel-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/carousel-img/carousel-1.jpg -------------------------------------------------------------------------------- /src/resource/carousel-img/carousel-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/carousel-img/carousel-2.jpg -------------------------------------------------------------------------------- /src/resource/carousel-img/carousel-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/carousel-img/carousel-3.jpg -------------------------------------------------------------------------------- /src/resource/common.less: -------------------------------------------------------------------------------- 1 | @import './default.less'; 2 | @import './loading.less'; 3 | body { 4 | background: @colorL; 5 | font-family: "Helvetica Neue For Number", "PingFang SC Light", "Heiti SC", "San Francisco", "Helvetica", Arial, sans-serif; 6 | } 7 | ul,li{ 8 | list-style: none; 9 | } 10 | .clearfix{ 11 | &:after{ 12 | content:" "; 13 | clear:both; 14 | display:block; 15 | visibility:hidden; 16 | } 17 | } 18 | .container{ 19 | .nav-left{ 20 | background-color:#001529; 21 | color: #ffffff; 22 | height: calc(100vh); 23 | } 24 | .main{ 25 | height: calc(100vh); 26 | background-color: @colorL; 27 | overflow: auto; 28 | } 29 | .content{ 30 | position: relative; 31 | padding: 20px; 32 | } 33 | } 34 | 35 | .content-wrap{ 36 | background: #ffffff; 37 | border: 1px solid #e8e8e8; 38 | margin-top: -3px; 39 | .ant-table-wrapper{ 40 | margin-left: -1px; 41 | margin-right: -2px; 42 | } 43 | } -------------------------------------------------------------------------------- /src/resource/default.less: -------------------------------------------------------------------------------- 1 | /** 常用色值 **/ 2 | @colorA: #f9c700; 3 | @colorB: #ff5400; 4 | @colorC: #333; 5 | @colorD: #6699cc; 6 | @colorE: #9cb3c5; 7 | @colorF: #e0e6ec; 8 | @colorG: #666; 9 | @colorH: #999; 10 | @colorI: #ccc; 11 | @colorJ: #d7d7d7; 12 | @colorK: #e3e3e3; 13 | @colorL: #f1f3f5; 14 | @colorM: #fff; 15 | @colorN: #e5e5e5; 16 | @colorO: #afafaf; 17 | @colorP: #ff8605; 18 | @colorQ: #f9fbfc; 19 | @colorR: #001529; 20 | @colorS: #002140; 21 | @colorT: #232526; 22 | @colorU: #bebebe; 23 | 24 | /** 常用字体大小 **/ 25 | @fontA: 34px; 26 | @fontB: 22px; 27 | @fontC: 18px; 28 | @fontD: 16px; 29 | @fontE: 14px; 30 | @fontF: 12px; 31 | @fontG: 20px; -------------------------------------------------------------------------------- /src/resource/doc.js: -------------------------------------------------------------------------------- 1 | // 百度天气API接口 2 | //http://api.map.baidu.com/telematics/v3/weather?location=beijing&output=json&ak=3p49MVra6urFRGOT9s8UBWr2 3 | -------------------------------------------------------------------------------- /src/resource/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/favicon.ico -------------------------------------------------------------------------------- /src/resource/gallery/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/1.png -------------------------------------------------------------------------------- /src/resource/gallery/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/10.png -------------------------------------------------------------------------------- /src/resource/gallery/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/11.png -------------------------------------------------------------------------------- /src/resource/gallery/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/12.png -------------------------------------------------------------------------------- /src/resource/gallery/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/13.png -------------------------------------------------------------------------------- /src/resource/gallery/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/14.png -------------------------------------------------------------------------------- /src/resource/gallery/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/15.png -------------------------------------------------------------------------------- /src/resource/gallery/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/16.png -------------------------------------------------------------------------------- /src/resource/gallery/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/17.png -------------------------------------------------------------------------------- /src/resource/gallery/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/18.png -------------------------------------------------------------------------------- /src/resource/gallery/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/19.png -------------------------------------------------------------------------------- /src/resource/gallery/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/2.png -------------------------------------------------------------------------------- /src/resource/gallery/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/20.png -------------------------------------------------------------------------------- /src/resource/gallery/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/21.png -------------------------------------------------------------------------------- /src/resource/gallery/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/22.png -------------------------------------------------------------------------------- /src/resource/gallery/23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/23.png -------------------------------------------------------------------------------- /src/resource/gallery/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/24.png -------------------------------------------------------------------------------- /src/resource/gallery/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/25.png -------------------------------------------------------------------------------- /src/resource/gallery/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/3.png -------------------------------------------------------------------------------- /src/resource/gallery/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/4.png -------------------------------------------------------------------------------- /src/resource/gallery/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/5.png -------------------------------------------------------------------------------- /src/resource/gallery/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/6.png -------------------------------------------------------------------------------- /src/resource/gallery/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/7.png -------------------------------------------------------------------------------- /src/resource/gallery/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/8.png -------------------------------------------------------------------------------- /src/resource/gallery/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/gallery/9.png -------------------------------------------------------------------------------- /src/resource/header/index.less: -------------------------------------------------------------------------------- 1 | @import './../../style/default.less'; 2 | .header{ 3 | background-color: @colorM; 4 | .header-top{ 5 | height: 60px; 6 | line-height: 60px; 7 | padding: 0 20px; 8 | text-align: right; 9 | .logo{ 10 | line-height: 60px; 11 | img{ 12 | height:40px; 13 | vertical-align: middle; 14 | } 15 | } 16 | a{ 17 | margin-left: 40px; 18 | } 19 | } 20 | .breadcrumb{ 21 | height: 40px; 22 | line-height: 40px; 23 | padding: 0 20px; 24 | border-top: 1px solid #f9c700; 25 | .breadcrumb-title{ 26 | text-align: center; 27 | font-size: @fontC; 28 | &:after{ 29 | position: absolute; 30 | content: ''; 31 | left:73px; 32 | top:39px; 33 | border-top: 9px solid @colorM; 34 | border-left: 12px solid transparent; 35 | border-right: 12px solid transparent; 36 | } 37 | } 38 | .weather{ 39 | text-align: right; 40 | font-size: 14px; 41 | .date{ 42 | margin-right: 10px; 43 | vertical-align: middle; 44 | } 45 | .weather-img{ 46 | img{ 47 | height: 15px; 48 | } 49 | } 50 | .weather-detail{ 51 | margin-left: 5px; 52 | vertical-align: middle; 53 | } 54 | } 55 | } 56 | } 57 | // common 页面简单头 58 | .simple-page{ 59 | .header-top{ 60 | background:#1890ff; 61 | color:@colorM; 62 | } 63 | .ant-form, 64 | .ant-col-12, 65 | .weather{ 66 | display:none; 67 | } 68 | } -------------------------------------------------------------------------------- /src/resource/image/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/66Web/react-antd-manager/a557e4510314119f8f6a73c478f85547779e93fb/src/resource/image/demo.png -------------------------------------------------------------------------------- /src/resource/loading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Loading 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /src/resource/loading.less: -------------------------------------------------------------------------------- 1 | /** load **/ 2 | .ajax-loading{ 3 | display: none; 4 | .loading{ 5 | position: fixed; 6 | top: 50%; 7 | left: 50%; 8 | transform: translate(-50%,-50%); 9 | padding:0 40px; 10 | height: 80px; 11 | line-height: 80px; 12 | background: rgba(0, 0, 0, 0.75); 13 | border-radius: 6px; 14 | text-align: center; 15 | z-index: 9999; 16 | font-size:@fontD; 17 | color:#fff; 18 | img{ 19 | width: 32px; 20 | vertical-align: middle; 21 | } 22 | span{ 23 | margin-left:12px; 24 | } 25 | } 26 | .overlay{ 27 | position: fixed; 28 | left: 0; 29 | right: 0; 30 | top: 0; 31 | bottom: 0; 32 | z-index: 9998; 33 | background: rgb(255, 255, 255); 34 | opacity: 0.1; 35 | } 36 | } 37 | 38 | /****/ -------------------------------------------------------------------------------- /src/resource/menuConfig.js: -------------------------------------------------------------------------------- 1 | const menuList = [ 2 | { 3 | title:'首页', 4 | key:'/home' 5 | }, 6 | { 7 | title:'UI', 8 | key:'/ui', 9 | children:[ 10 | { 11 | title:'按钮', 12 | key:'/ui/buttons', 13 | }, 14 | { 15 | title:'弹框', 16 | key:'/ui/modals', 17 | }, 18 | { 19 | title:'Loading', 20 | key:'/ui/loadings', 21 | }, 22 | { 23 | title:'通知提醒', 24 | key:'/ui/notification', 25 | }, 26 | { 27 | title:'全局Message', 28 | key:'/ui/messages', 29 | }, 30 | { 31 | title:'Tab页签', 32 | key:'/ui/tabs', 33 | }, 34 | { 35 | title:'图片画廊', 36 | key:'/ui/gallery', 37 | }, 38 | { 39 | title:'轮播图', 40 | key:'/ui/carousel', 41 | } 42 | ] 43 | }, 44 | { 45 | title:'表单', 46 | key:'/form', 47 | children:[ 48 | { 49 | title:'登录', 50 | key:'/form/login', 51 | }, 52 | { 53 | title:'注册', 54 | key:'/form/reg', 55 | } 56 | ] 57 | }, 58 | { 59 | title:'表格', 60 | key:'/table', 61 | children:[ 62 | { 63 | title:'基础表格', 64 | key:'/table/basic', 65 | }, 66 | { 67 | title:'高级表格', 68 | key:'/table/high', 69 | } 70 | ] 71 | }, 72 | { 73 | title:'富文本', 74 | key:'/rich' 75 | }, 76 | { 77 | title:'城市管理', 78 | key:'/city' 79 | }, 80 | { 81 | title:'订单管理', 82 | key:'/order', 83 | btnList:[ 84 | { 85 | title:'订单详情', 86 | key:'detail' 87 | }, 88 | { 89 | title:'结束订单', 90 | key:'finish' 91 | } 92 | ] 93 | }, 94 | { 95 | title:'员工管理', 96 | key:'/user' 97 | }, 98 | { 99 | title:'车辆地图', 100 | key:'/bikeMap' 101 | }, 102 | { 103 | title:'图标', 104 | key:'/charts', 105 | children:[ 106 | { 107 | title:'柱形图', 108 | key:'/charts/bar' 109 | }, 110 | { 111 | title:'饼图', 112 | key:'/charts/pie' 113 | }, 114 | { 115 | title:'折线图', 116 | key:'/charts/line' 117 | }, 118 | ] 119 | }, 120 | { 121 | title:'权限设置', 122 | key:'/permission' 123 | }, 124 | ]; 125 | export default menuList; -------------------------------------------------------------------------------- /src/resource/order/detail.less: -------------------------------------------------------------------------------- 1 | @import '../../style/default'; 2 | @import '../../style/common'; 3 | .detail-items{ 4 | margin-left:90px; 5 | padding:25px 50px 25px 0; 6 | border-bottom:1px solid @colorN; 7 | &:last-child{ 8 | border-bottom:none; 9 | } 10 | .item-title{ 11 | margin:20px 0; 12 | font-size:@fontG; 13 | color:@colorU; 14 | } 15 | .detail-form{ 16 | li{ 17 | .clearfix; 18 | margin:20px 0; 19 | line-height:20px; 20 | font-size:15px; 21 | color:@colorC; 22 | } 23 | } 24 | .detail-form-left{ 25 | float:left; 26 | width:164px; 27 | text-align:right; 28 | color:@colorH; 29 | } 30 | .detail-form-content{ 31 | padding-left:194px; 32 | } 33 | } 34 | .order-map{ 35 | height: 450px; 36 | margin: 25px -31px 0; 37 | } -------------------------------------------------------------------------------- /src/resource/ui.less: -------------------------------------------------------------------------------- 1 | /* ui */ 2 | .ui-wrap{ 3 | 4 | } 5 | .card-wrap{ 6 | margin-bottom: 10px; 7 | } 8 | button{ 9 | margin-right: 20px; 10 | } 11 | .btn-group button{ 12 | margin-right: 0; 13 | } 14 | /* modals */ 15 | /* use css to set position of modal */ 16 | .vertical-center-modal { 17 | text-align: center; 18 | white-space: nowrap; 19 | } 20 | 21 | .vertical-center-modal:before { 22 | content: ''; 23 | display: inline-block; 24 | height: 100%; 25 | vertical-align: middle; 26 | width: 0; 27 | } 28 | 29 | .vertical-center-modal .ant-modal { 30 | display: inline-block; 31 | vertical-align: middle; 32 | top: 0; 33 | text-align: left; 34 | } 35 | 36 | /* 37 | // Use flex which not working in IE 38 | .vertical-center-modal { 39 | display: flex; 40 | align-items: center; 41 | justify-content: center; 42 | } 43 | 44 | .vertical-center-modal .ant-modal { 45 | top: 0; 46 | } 47 | */ 48 | 49 | // Carousel 50 | 51 | /* For demo */ 52 | .ant-carousel .slick-slide { 53 | text-align: center; 54 | height: 160px; 55 | line-height: 160px; 56 | background: #364d79; 57 | overflow: hidden; 58 | } 59 | 60 | .ant-carousel .slick-slide h3 { 61 | color: rgba(246, 250, 33, 0.966); 62 | } 63 | 64 | // 图片轮播 65 | .slider-wrap .ant-carousel .slick-slide { 66 | height: 240px!important; 67 | } -------------------------------------------------------------------------------- /src/router.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {HashRouter, Route, Switch, Redirect} from 'react-router-dom' 3 | import App from './App' 4 | import Login from './pages/Login' 5 | import NoMatch from './pages/NoMatch' 6 | import Admin from './admin' 7 | import Home from './pages/Home' 8 | import Buttons from './pages/ui/buttons' 9 | import Modals from './pages/ui/modals' 10 | import Loadings from './pages/ui/loadings' 11 | import Notice from './pages/ui/notice' 12 | import Messages from './pages/ui/messages' 13 | import Tabs from './pages/ui/tabs' 14 | import Gallery from './pages/ui/gallery' 15 | import Carousel from './pages/ui/carousel' 16 | import FormLogin from './pages/form/login' 17 | import FormRegister from './pages/form/register' 18 | import BasicTable from './pages/table/basicTable' 19 | import HighTable from './pages/table/highTable' 20 | import RichText from './pages/rich/index' 21 | import City from './pages/city/index' 22 | import User from './pages/user/index' 23 | import BikeMap from './pages/map/bikeMap' 24 | import Common from './common' 25 | import Order from './pages/order/index' 26 | import OrderDetail from './pages/order/detail' 27 | import Bar from './pages/echarts/bar' 28 | import Pie from './pages/echarts/pie' 29 | import Line from './pages/echarts/line' 30 | import Permission from './pages/permission' 31 | 32 | export default class IRouter extends React.Component{ 33 | render() { 34 | return ( 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | }/> 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | }/> 74 | 75 | 76 | 77 | ) 78 | } 79 | } -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/style/common.less: -------------------------------------------------------------------------------- 1 | @import './../style/default.less'; 2 | @import './../style/loading.less'; 3 | 4 | ul,li{ 5 | list-style: none; 6 | } 7 | .clearfix{ 8 | &::after{ 9 | content:''; 10 | clear: both; 11 | display: block; 12 | visibility: hidden; 13 | } 14 | } 15 | .content{ 16 | padding: 20px 17 | } 18 | 19 | .container{ 20 | display: flex; 21 | .nav-left{ 22 | width: 15%; 23 | min-width: 180px; 24 | height: calc(80vh); 25 | color: #ffffff; 26 | background-color: #001529; 27 | } 28 | .main{ 29 | flex: 1; 30 | height: calc(100vh); 31 | background-color: @colorL; 32 | overflow: auto; //自动滚动 33 | } 34 | .content{ 35 | position: relative; 36 | padding: 20px; 37 | } 38 | } 39 | 40 | .content-wrap{ 41 | background: #ffffff; 42 | border: 1px solid #e8e8e8; 43 | margin-top: -3px; 44 | .ant-table-wrapper{ 45 | margin-left: -1px; 46 | margin-right: -2px; 47 | } 48 | } 49 | 50 | .operate-wrap, .permission-wrap{ 51 | button{ 52 | margin-right: 10px; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/style/default.less: -------------------------------------------------------------------------------- 1 | /** 常用色值 **/ 2 | @colorA: #f9c700; 3 | @colorB: #ff5400; 4 | @colorC: #333; 5 | @colorD: #6699cc; 6 | @colorE: #9cb3c5; 7 | @colorF: #e0e6ec; 8 | @colorG: #666; 9 | @colorH: #999; 10 | @colorI: #ccc; 11 | @colorJ: #d7d7d7; 12 | @colorK: #e3e3e3; 13 | @colorL: #f1f3f5; 14 | @colorM: #fff; 15 | @colorN: #e5e5e5; 16 | @colorO: #afafaf; 17 | @colorP: #ff8605; 18 | @colorQ: #f9fbfc; 19 | @colorR: #001529; 20 | @colorS: #002140; 21 | @colorT: #232526; 22 | @colorU: #bebebe; 23 | 24 | /** 常用字体大小 **/ 25 | @fontA: 34px; 26 | @fontB: 22px; 27 | @fontC: 18px; 28 | @fontD: 16px; 29 | @fontE: 14px; 30 | @fontF: 12px; 31 | @fontG: 20px; -------------------------------------------------------------------------------- /src/style/loading.less: -------------------------------------------------------------------------------- 1 | /** load **/ 2 | .ajax-loading{ 3 | display: none; 4 | .loading{ 5 | position: fixed; 6 | top: 50%; 7 | left: 50%; 8 | transform: translate(-50%,-50%); 9 | padding:0 40px; 10 | height: 80px; 11 | line-height: 80px; 12 | background: rgba(0, 0, 0, 0.75); 13 | border-radius: 6px; 14 | text-align: center; 15 | z-index: 9999; 16 | font-size:@fontD; 17 | color:#fff; 18 | img{ 19 | width: 32px; 20 | vertical-align: middle; 21 | } 22 | span{ 23 | margin-left:12px; 24 | } 25 | } 26 | .overlay{ 27 | position: fixed; 28 | left: 0; 29 | right: 0; 30 | top: 0; 31 | bottom: 0; 32 | z-index: 9998; 33 | background: rgb(255, 255, 255); 34 | opacity: 0.1; 35 | } 36 | } 37 | 38 | /****/ -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {Select} from 'antd' 3 | const Option = Select.Option 4 | 5 | export default { 6 | formatDate(time){ 7 | if(!time)return ''; 8 | let date = new Date(time); 9 | return date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()+' '+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds() 10 | }, 11 | pagination(data,callback){ 12 | return { 13 | onChange: (current) => { 14 | callback(current) 15 | }, 16 | current: data.page, 17 | pageSize: data.page_size, 18 | total: data.total, 19 | showTotal: () => { 20 | return `共${data.total}条` 21 | }, 22 | showQuickJumper: true 23 | } 24 | }, 25 | getOptionList(data){ 26 | if(!data){ 27 | return []; 28 | } 29 | let options = []; 30 | data.map((item) => { 31 | options.push() 32 | }) 33 | return options; 34 | }, 35 | /** 36 | * ETable 行点击通用函数 37 | * @param {*选中行的索引} selectedRowKeys 38 | * @param {*选中行对象} selectedItem 39 | */ 40 | updateSelectedItem(selectedRowKeys, selectedRows, selectedIds) { 41 | if (selectedIds) { 42 | this.setState({ 43 | selectedRowKeys, 44 | selectedIds: selectedIds, 45 | selectedItem: selectedRows 46 | }) 47 | } else { 48 | this.setState({ 49 | selectedRowKeys, 50 | selectedItem: selectedRows 51 | }) 52 | } 53 | } 54 | } --------------------------------------------------------------------------------