├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── README.md
├── config
├── antd.theme.js
├── webpack.config.js
└── webpack.dist.config.js
├── gulpfile.js
├── package.json
├── res
├── iconfont
│ ├── iconfont.eot
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ └── iconfont.woff
├── images
│ ├── computer.png
│ ├── dongwuyuan.jpg
│ ├── pin.png
│ └── position.jpg
└── media
│ └── tip.mp3
├── src
├── app.jsx
├── components
│ ├── layout
│ │ ├── layout.jsx
│ │ └── layout.less
│ ├── layout2
│ │ ├── layout2.jsx
│ │ └── layout2.less
│ └── modal
│ │ ├── modal.jsx
│ │ └── modal.less
├── index.html
├── index.js
├── main.jsx
├── pages
│ ├── item1
│ │ ├── item1.jsx
│ │ ├── item1.less
│ │ ├── userConfig.jsx
│ │ ├── userConfig.less
│ │ └── userDelete.jsx
│ ├── item2
│ │ ├── item2.jsx
│ │ ├── item2.less
│ │ ├── line.jsx
│ │ └── pie.jsx
│ ├── item3
│ │ ├── item3.jsx
│ │ └── item3.less
│ ├── item4
│ │ ├── item4.jsx
│ │ └── item4.less
│ ├── item5
│ │ ├── item5.jsx
│ │ └── item5.less
│ ├── item6
│ │ └── item6.jsx
│ ├── item7
│ │ └── item7.jsx
│ └── item8
│ │ ├── item8.jsx
│ │ └── item8.less
├── store
│ ├── echartstore.js
│ ├── menustore.js
│ ├── positionstore.js
│ └── tablestore.js
├── testdata
│ ├── localdata
│ │ ├── linelist.json
│ │ ├── menulist.json
│ │ ├── menulist2.json
│ │ ├── pielist.json
│ │ ├── positionlist.json
│ │ └── tablelist.json
│ └── mockdata
│ │ └── menulist.js
└── utils
│ ├── ajax.js
│ ├── errorcode.js
│ ├── localdata.js
│ └── mockdata.js
├── tsconfig.json
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env",
4 | "react"
5 | ],
6 | "plugins": [
7 | ["transform-decorators-legacy"],
8 | ["import", { "libraryName": "antd", "style": true }], // `style: true` 会加载 less 文件
9 | ["transform-class-properties"],
10 | ["transform-object-rest-spread"]
11 | ]
12 | }
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "parser": "babel-eslint",
4 | "env": {
5 | "browser" : true
6 | },
7 | "rules": {
8 | "quotes": [2, "single"],
9 | "semi": 2,
10 | "max-len": [1, 120, 2],
11 | "arrow-body-style": [1, "as-needed"],
12 | "comma-dangle": [2, "never"],
13 | "no-debugger": 2,
14 | "no-console": 2,
15 | "object-curly-spacing": [2, "always"],
16 | "no-undef": [1],
17 | "new-cap": 1,
18 | "no-param-reassign": 2,
19 | "import/no-extraneous-dependencies": 0,
20 | "import/no-unresolved": 0,
21 | "import/extensions": 0,
22 | "global-require": 0,
23 | "react/forbid-prop-types": [2, { "forbid": ["any"] }],
24 | "import/no-dynamic-require": 0,
25 | "no-mixed-operators": 0,
26 | "class-methods-use-this": 0,
27 | "jsx-a11y/media-has-caption": 0,
28 | "react/prefer-stateless-function": 0
29 | }
30 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 | build/
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 基于React搭建的管理后台系统
2 |
3 | ## 技术框架
4 |
5 | - ES6/7 Vanilla JS
6 | - ESLint (代码规范)
7 | - React
8 | - Mobx (统一状态管理)
9 | - React Router (路由)
10 | - Antd (UI框架)
11 | - ECharts (常规图表框架)
12 | - Mock.js (模拟数据服务)
13 | - Babel (ES6/7代码转译浏览器可执行)
14 | - Webpack (打包工具)
15 | - React Amap (高德地图)
16 | - Visjs (拓扑图)
17 |
18 | ## 目录结构
19 |
20 | ```bash
21 | .
22 | ├── config # webpack 配置目录
23 | ├── res # 静态文件目录
24 | └── src # 前端源码目录
25 | ├── index.html # layout
26 | ├── main.js # 入口文件
27 | ├── component # 组件目录
28 | ├── pages # 页面目录
29 | ├── store # Mobx状态管理
30 | ├── testdata # 模拟数据目录
31 | ├── localdata # 本地测试数据
32 | │ └── mockdata # 模拟数据服务器
33 | └── utils # 基础配置文件
34 | ```
35 | ## 安装
36 |
37 | ```bash
38 | git clone https://github.com/labnize/react-router-antd-webpack-gulp.git
39 | cd react-router-antd-webpack-gulp
40 | npm install
41 | ```
42 |
43 | ## 调试
44 |
45 | Just run "gulp" in this root folder
46 | ```
47 | gulp
48 | ```
49 |
50 | ## 打包
51 |
52 | Just run "gulp build" in this root folder
53 | ```
54 | gulp build
55 | ```
56 |
57 |
--------------------------------------------------------------------------------
/config/antd.theme.js:
--------------------------------------------------------------------------------
1 | // const path = require('path');
2 |
3 | module.exports = {
4 | 'font-size-base': '14px',
5 | '@btn-font-size-lg': '14px',
6 | '@modal-mask-bg': 'rgba(255, 255, 255, 0.45)',
7 | '@icon-url': '"../../../../../res/iconfont/iconfont"'
8 | // '@icon-url': `"${path.relative('./~/antd/lib/style/*', './res/iconfont/iconfont')}"`
9 | };
10 |
--------------------------------------------------------------------------------
/config/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
4 | const HtmlWebpackPlugin = require('html-webpack-plugin');
5 | const theme = require('./antd.theme');
6 |
7 | const webpackConfig = {
8 | entry: {
9 | app: path.join(__dirname, '../src/index.js')
10 | },
11 | output: {
12 | path: path.join(__dirname, '../build'),
13 | filename: '[name].js',
14 | publicPath: '/'
15 | },
16 | cache: true,
17 | devtool: 'inline-source-map',
18 | resolve: {
19 | extensions: ['.js', '.jsx'],
20 | alias: {
21 | components: path.join(__dirname, '../src/components'),
22 | images: path.join(__dirname, '../res/images'),
23 | media: path.join(__dirname, '../res/media'),
24 | pages: path.join(__dirname, '../src/pages'),
25 | localData: path.join(__dirname, '../src/testdata/localdata'),
26 | mockData: path.join(__dirname, '../src/testdata/mockdata'),
27 | util: path.join(__dirname, '../src/utils'),
28 | store: path.join(__dirname, '../src/store'),
29 | jquery: path.join(__dirname, '../node_modules/jquery/dist/jquery.min.js')
30 | }
31 | },
32 | module: {
33 | rules: [
34 | {
35 | test: /.jsx?$/,
36 | use: [
37 | 'react-hot-loader/webpack',
38 | 'babel-loader'
39 | ],
40 | exclude: /node_modules/
41 | },
42 | {
43 | test: /\.css$/,
44 | use: [
45 | 'style-loader',
46 | 'css-loader'
47 | ]
48 | },
49 | {
50 | test: /\.(png|jpg|gif)$/,
51 | use: ['url-loader?limit=1&name=images/[name].[hash:8].[ext]']
52 | },
53 | {
54 | test: /\.(woff|woff2|eot|ttf|svg)$/,
55 | use: ['url-loader?limit=1&name=iconfont/[name].[hash:8].[ext]']
56 | },
57 | {
58 | test: /\.mp3$/,
59 | use: ['file-loader?name=media/[name].[hash:8].[ext]']
60 | },
61 | {
62 | test(file) {
63 | return /\.less$/.test(file) && !/\.module\.less$/.test(file);
64 | },
65 | use: ExtractTextPlugin.extract('css-loader?sourceMap&-autoprefixer!' +
66 | `less-loader?{"sourceMap":true,"modifyVars":${JSON.stringify(theme)}}`)
67 | }
68 | ]
69 | },
70 | plugins: [
71 | new webpack.HotModuleReplacementPlugin(),
72 | new ExtractTextPlugin({
73 | filename: 'styles.[contenthash].css',
74 | disable: false,
75 | allChunks: false
76 | }),
77 | new webpack.NoEmitOnErrorsPlugin(),
78 | new webpack.ProvidePlugin({
79 | $: 'jquery',
80 | jQuery: 'jquery',
81 | 'window.jQuery': 'jquery'
82 | }),
83 | new HtmlWebpackPlugin({
84 | filename: 'index.html',
85 | template: path.resolve(__dirname, '../src/index.html'),
86 | inject: true
87 | })
88 | ]
89 | };
90 |
91 | module.exports = webpackConfig;
92 |
--------------------------------------------------------------------------------
/config/webpack.dist.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
5 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
6 | const HtmlWebpackPlugin = require('html-webpack-plugin');
7 | const ProgressBarPlugin = require('progress-bar-webpack-plugin');
8 | const theme = require('./antd.theme');
9 |
10 | const webpackConfig = {
11 | entry: {
12 | app: path.join(__dirname, '../src/index.js'),
13 | vendor: ['react', 'react-dom', 'react-router-dom', 'mobx', 'mobx-react', 'jquery', 'echarts', 'mockjs', 'antd', 'vis']
14 | },
15 | output: {
16 | path: path.join(__dirname, '../build'),
17 | filename: '[name].[chunkhash].js',
18 | publicPath: '/'
19 | },
20 | cache: false,
21 | devtool: false,
22 | resolve: {
23 | extensions: ['.js', '.jsx'],
24 | alias: {
25 | components: path.join(__dirname, '../src/components'),
26 | images: path.join(__dirname, '../res/images'),
27 | media: path.join(__dirname, '../res/media'),
28 | pages: path.join(__dirname, '../src/pages'),
29 | localData: path.join(__dirname, '../src/testdata/localdata'),
30 | mockData: path.join(__dirname, '../src/testdata/mockdata'),
31 | util: path.join(__dirname, '../src/utils'),
32 | store: path.join(__dirname, '../src/store'),
33 | jquery: path.join(__dirname, '../node_modules/jquery/dist/jquery.min.js')
34 | }
35 | },
36 | module: {
37 | rules: [
38 | {
39 | test: /.jsx?$/,
40 | use: [
41 | {
42 | loader: 'react-hot-loader/webpack'
43 | },
44 | {
45 | loader: 'babel-loader'
46 | }
47 | ],
48 | exclude: /node_modules/
49 | },
50 | {
51 | test: /\.css$/,
52 | use: [
53 | 'style-loader',
54 | 'css-loader'
55 | ]
56 | },
57 | {
58 | test: /\.(png|jpg|gif)$/,
59 | use: ['url-loader?limit=1&name=images/[name].[hash:8].[ext]']
60 | },
61 | {
62 | test: /\.(woff|woff2|eot|ttf|svg)$/,
63 | use: ['url-loader?limit=1&name=iconfont/[name].[hash:8].[ext]']
64 | },
65 | {
66 | test: /\.mp3$/,
67 | use: ['file-loader?name=media/[name].[hash:8].[ext]']
68 | },
69 | {
70 | test(file) {
71 | return /\.less$/.test(file) && !/\.module\.less$/.test(file);
72 | },
73 | use: ExtractTextPlugin.extract('css-loader?sourceMap&-autoprefixer!' +
74 | `less-loader?{"sourceMap":true,"modifyVars":${JSON.stringify(theme)}}`)
75 | }
76 | ]
77 | },
78 | plugins: [
79 | new BundleAnalyzerPlugin(),
80 | new webpack.DefinePlugin({
81 | 'process.env': {
82 | NODE_ENV: JSON.stringify('production')
83 | }
84 | }),
85 | new webpack.HashedModuleIdsPlugin(),
86 | new webpack.optimize.CommonsChunkPlugin({
87 | name: ['vendor', 'runtime'],
88 | minChunks: 2
89 | }),
90 | new ExtractTextPlugin({
91 | filename: 'styles.[contenthash].css',
92 | disable: false,
93 | allChunks: false
94 | }),
95 | new webpack.optimize.UglifyJsPlugin({
96 | compress: {
97 | warnings: false
98 | },
99 | mangle: {
100 | except: ['$super', '$', 'exports', 'require'] // 以上变量‘$super’, ‘$’, ‘exports’ or ‘require’,不会被混淆
101 | },
102 | output: {
103 | comments: false
104 | }
105 | }),
106 | new webpack.LoaderOptionsPlugin({
107 | minimize: true
108 | }),
109 | new webpack.NoEmitOnErrorsPlugin(),
110 | new ProgressBarPlugin({
111 | format: ' build [:bar] :percent (:elapsed seconds)',
112 | clear: false,
113 | width: 60
114 | }),
115 | new webpack.ProvidePlugin({
116 | $: 'jquery',
117 | jQuery: 'jquery',
118 | 'window.jQuery': 'jquery'
119 | }),
120 | new HtmlWebpackPlugin({
121 | filename: 'index.html',
122 | template: path.resolve(__dirname, '../src/index.html'),
123 | inject: true,
124 | minify: {
125 | removeAttributeQuotes: true,
126 | removeComments: true,
127 | removeEmptyAttributes: true,
128 | collapseWhitespace: true
129 | }
130 | })
131 | ]
132 | };
133 |
134 | module.exports = webpackConfig;
135 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp');
2 | const open = require('open');
3 | const del = require('del');
4 | const webpack = require('webpack');
5 | const gulpWebpack = require('webpack-stream');
6 | const WebpackDevServer = require('webpack-dev-server');
7 | const webpackDistConfig = require('./config/webpack.dist.config.js');
8 | const webpackDevConfig = require('./config/webpack.config.js');
9 | const path = require('path');
10 |
11 | gulp.task('dev', () => {
12 | const compiler = webpack(webpackDevConfig);
13 | new WebpackDevServer(compiler, {
14 | contentBase: './',
15 | historyApiFallback: true,
16 | hot: true,
17 | noInfo: false,
18 | publicPath: '/',
19 | stats: { colors: true },
20 | host: 'localhost'
21 | }).listen(8090, 'localhost', () => {
22 | console.log('http://127.0.0.1:8090');
23 | console.log('Opening your system browser...');
24 | open('http://127.0.0.1:8090');
25 | });
26 | });
27 |
28 | gulp.task('default', ['dev']);
29 |
30 | gulp.task('clean', () => {
31 | console.log('build folder has been cleaned successfully');
32 | return del(['build/**/*']);
33 | });
34 |
35 | gulp.task('build', ['clean'], () => gulp.src(path.join(__dirname, '../src'))
36 | .pipe(gulpWebpack(webpackDistConfig))
37 | .pipe(gulp.dest('build/')));
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frame",
3 | "version": "0.0.1",
4 | "description": "React Antd demo",
5 | "main": "index.html",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "gulp",
9 | "build": "gulp build"
10 | },
11 | "keywords": [
12 | "react",
13 | "webpack",
14 | "gulp"
15 | ],
16 | "author": "zhuli",
17 | "license": "MIT",
18 | "devDependencies": {
19 | "antd": "^3.0.1",
20 | "autoprefixer": "^7.1.6",
21 | "babel-core": "^6.26.0",
22 | "babel-eslint": "^8.0.2",
23 | "babel-loader": "^7.1.2",
24 | "babel-plugin-import": "^1.6.2",
25 | "babel-plugin-transform-class-properties": "^6.24.1",
26 | "babel-plugin-transform-decorators-legacy": "^1.3.4",
27 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
28 | "babel-polyfill": "^6.26.0",
29 | "babel-preset-env": "^1.6.1",
30 | "babel-preset-react": "^6.24.1",
31 | "css-loader": "^0.28.7",
32 | "echarts": "^3.8.2",
33 | "eslint": "^4.10.0",
34 | "eslint-config-airbnb": "^16.1.0",
35 | "eslint-plugin-import": "^2.8.0",
36 | "eslint-plugin-jsx-a11y": "^6.0.2",
37 | "eslint-plugin-react": "^7.4.0",
38 | "extract-text-webpack-plugin": "^3.0.2",
39 | "file-loader": "^1.1.5",
40 | "gulp": "^3.9.1",
41 | "html-webpack-plugin": "^2.30.1",
42 | "jquery": "^3.2.1",
43 | "json-loader": "^0.5.7",
44 | "less": "^2.7.3",
45 | "less-loader": "^4.0.5",
46 | "mobx": "^3.3.1",
47 | "mobx-react": "^4.3.4",
48 | "mockjs": "^1.0.1-beta3",
49 | "open": "0.0.5",
50 | "progress-bar-webpack-plugin": "^1.10.0",
51 | "prop-types": "^15.6.0",
52 | "react": "^16.1.0",
53 | "react-amap": "^1.0.3",
54 | "react-dom": "^16.1.0",
55 | "react-hot-loader": "^3.1.2",
56 | "react-router-dom": "^4.2.2",
57 | "reconnectingwebsocket": "^1.0.0",
58 | "style-loader": "^0.19.0",
59 | "url-loader": "^0.6.2",
60 | "vis": "^4.21.0",
61 | "webpack": "^3.8.1",
62 | "webpack-bundle-analyzer": "^2.9.1",
63 | "webpack-dev-server": "^2.9.4",
64 | "webpack-stream": "^4.0.0"
65 | },
66 | "dependencies": {
67 | "gojs": "^1.8.6"
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/res/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/res/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/res/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/res/images/computer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/images/computer.png
--------------------------------------------------------------------------------
/res/images/dongwuyuan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/images/dongwuyuan.jpg
--------------------------------------------------------------------------------
/res/images/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/images/pin.png
--------------------------------------------------------------------------------
/res/images/position.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/images/position.jpg
--------------------------------------------------------------------------------
/res/media/tip.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labnize/react-router-mobx-antd-webpack-gulp/b1daeebe8ca942b6a1b75ad550bbc36ad967994b/res/media/tip.mp3
--------------------------------------------------------------------------------
/src/app.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Route, Switch } from 'react-router-dom';
3 |
4 | import item1 from 'pages/item1/item1';
5 | import item2 from 'pages/item2/item2';
6 | import item3 from 'pages/item3/item3';
7 | import item4 from 'pages/item4/item4';
8 | import item5 from 'pages/item5/item5';
9 | import item6 from 'pages/item6/item6';
10 | import item7 from 'pages/item7/item7';
11 | import item8 from 'pages/item8/item8';
12 |
13 | class App extends Component {
14 | render() {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 | }
32 |
33 | export default App;
34 |
--------------------------------------------------------------------------------
/src/components/layout/layout.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { browserHistory } from 'react-router';
3 | import PropTypes from 'prop-types';
4 | import { Layout, Menu, Breadcrumb, Icon, Dropdown } from 'antd';
5 | import menuList from 'data/menulist.json';
6 | // import Util from 'extend/common/util';
7 | import './layout.less';
8 |
9 | const { SubMenu } = Menu;
10 | const { Header, Content, Footer, Sider } = Layout;
11 |
12 | class PageComponent extends Component {
13 | constructor(props) {
14 | super(props);
15 | let name = this.props.name ? this.props.name : '';
16 | let menusAll = this.findMenu(JSON.parse(JSON.stringify(menuList.list)), name);
17 |
18 | this.state = {
19 | menusAll: menusAll
20 | };
21 |
22 | this.handleMenuClick = this.handleMenuClick.bind(this);
23 | this.handleSubMenuClick = this.handleSubMenuClick.bind(this);
24 | this.handleProfileMenuClick = this.handleProfileMenuClick.bind(this);
25 | }
26 |
27 | componentDidMount() {
28 | let layout = $('.layout-content-layout');
29 | let height = $(window).height() - 176 + 'px';
30 | layout.css('height', height);
31 | $(window).resize(function() {
32 | let height = $(window).height() - 176 + 'px';
33 | layout.css('height', height);
34 | });
35 | }
36 |
37 | findMenu(list, key) {
38 | let result = [];
39 | if (key !== '') {
40 | list.forEach((item) => {
41 | if (JSON.stringify(item).indexOf(`"${key}"`) !== -1 || JSON.stringify(item).indexOf(`:${key}`) !== -1) {
42 | if (item.key === key) {
43 | delete item.sub;
44 | result.push(item);
45 | }
46 | if (item.sub && item.sub.length > 0) {
47 | const subResult = this.findMenu(item.sub, key);
48 | delete item.sub;
49 | result = result.concat(item, subResult);
50 | }
51 | }
52 | });
53 | }
54 | return result;
55 | }
56 |
57 | handleMenuClick({ item, key, selectedKeys }) {
58 | console.log(key);
59 | browserHistory.push(`/${key}`);
60 | }
61 |
62 | handleSubMenuClick({ item, key, selectedKeys }) {
63 | console.log(key);
64 | let { menusAll } = this.state;
65 | let url = `${menusAll[0].key}/${key}`;
66 | browserHistory.push(`/${url}`);
67 | }
68 |
69 | handleProfileMenuClick({ item, key, selectedKeys }) {
70 | if (key === 'exit') {
71 | // Util.deleteToken();
72 | browserHistory.push('');
73 | return;
74 | }
75 | browserHistory.push(`/${key}`);
76 | }
77 |
78 | render() {
79 | let { children, activeTab } = this.props;
80 | let [firstMenu, secondMenu, thirdMenu, firstKey, secondKey, thirdKey] = ['', '', '', '', '', ''];
81 | let { menusAll } = this.state;
82 | if (menusAll && menusAll.length > 0) {
83 | if (menusAll.length < 2) {
84 | firstMenu = menusAll[0].name;
85 | firstKey = menusAll[0].key;
86 | } else {
87 | [firstMenu, secondMenu, thirdMenu, firstKey, secondKey, thirdKey] =
88 | [menusAll[0].name, menusAll[1].name, menusAll[2].name, menusAll[0].key, menusAll[1].key, menusAll[2].key];
89 | }
90 | }
91 | let subMenus = menuList.list[activeTab - 1].sub;
92 |
93 | return (
94 |
95 |
96 |
97 |
110 |
111 |
112 |
113 | {firstMenu}
114 | {secondMenu}
115 | {thirdMenu}
116 |
117 |
118 | {
122 | console.log(collapsed, type);
123 | }}
124 | >
125 |
148 |
149 |
150 |
151 | {children}
152 |
153 |
154 |
155 |
158 |
159 | );
160 | }
161 | }
162 |
163 | PageComponent.propTypes = {
164 | children: PropTypes.element.isRequired,
165 | activeTab: PropTypes.number.isRequired,
166 | name: PropTypes.string.isRequired
167 | };
168 |
169 | export default PageComponent;
170 |
--------------------------------------------------------------------------------
/src/components/layout/layout.less:
--------------------------------------------------------------------------------
1 | .layout{
2 | width: 100%;
3 | height: 100%;
4 | position: fixed;
5 | }
6 |
7 | .ant-menu-horizontal{
8 | border-bottom: 0px;
9 | }
10 |
11 | .logo{
12 | width: 200px;
13 | height: 64px;
14 | float: left;
15 | }
16 |
17 | .ant-layout-header{
18 | overflow: auto;
19 | }
20 | .layout-content{
21 | padding: 0 50px;
22 | .layout-content-layout{
23 | padding: 24px 0;
24 | background: #fff;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/components/layout2/layout2.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 | import { Layout, Menu, Icon } from 'antd';
5 | import MenuStore from 'store/menustore';
6 | import { observer } from 'mobx-react';
7 | import menus from 'localData/menulist2.json';
8 | import './layout2.less';
9 |
10 | const {
11 | Header, Content, Footer, Sider
12 | } = Layout;
13 | const menuStore = new MenuStore();
14 |
15 | @observer
16 | class PageComponent extends Component {
17 | constructor(props) {
18 | super(props);
19 | }
20 |
21 | componentDidMount() {
22 | }
23 |
24 | handleMenuClick({ item, key, selectedKeys }) {
25 | console.log(key);
26 | // browserHistory.push(`/${key}`);
27 | }
28 |
29 | render() {
30 | const { children, name } = this.props;
31 | const menuList = menus.list;
32 | const defaultKey = location.pathname.split('/')[1] ? location.pathname.split('/')[1] : 'item1';
33 | // const menuList = menuStore.list; //菜单通过接口获得
34 | // const { menuList } = this.state;
35 | // const firstKey = menuList.list[0].key;
36 | return (
37 |
38 | {
42 | console.log(collapsed, type);
43 | }}
44 | >
45 |
46 |
57 |
58 |
59 |
60 |
61 |
62 | {children}
63 |
64 |
65 |
68 |
69 |
70 | );
71 | }
72 | }
73 |
74 | PageComponent.propTypes = {
75 | children: PropTypes.element.isRequired,
76 | name: PropTypes.string.isRequired
77 | };
78 |
79 | export default PageComponent;
80 |
--------------------------------------------------------------------------------
/src/components/layout2/layout2.less:
--------------------------------------------------------------------------------
1 | .layout{
2 | width: 100%;
3 | height: 100%;
4 | position: fixed;
5 | .content-layout{
6 | padding: 24px;
7 | background: rgb(255, 255, 255);
8 | min-height: 360px;
9 | overflow: auto;
10 | }
11 | }
12 |
13 | .logo{
14 | width: 200px;
15 | height: 64px;
16 | float: left;
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/modal/modal.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ReactDom from 'react-dom';
3 | import { Modal, Spin, Alert } from 'antd';
4 |
5 | import './modal.less';
6 |
7 | class PageComponent extends Component {
8 | constructor(props) {
9 | super(props);
10 |
11 | this.state = {
12 | modal2Visible: false,
13 | option: {}
14 | };
15 | this.eventListener = this.eventListener.bind(this);
16 | this.defaultOptions = {
17 | type: '',
18 | errorMessage: '',
19 | title: ''
20 | };
21 | }
22 |
23 | setModal2Visible(modal2Visible) {
24 | this.setState({ modal2Visible });
25 | }
26 |
27 | show(option) {
28 | this.setState({
29 | modal2Visible: true,
30 | option
31 | });
32 | }
33 |
34 | close() {
35 | this.setState({
36 | modal2Visible: false,
37 | option: this.state.option
38 | });
39 | }
40 |
41 | eventListener(param) {
42 | this.state.option.ok(param);
43 | }
44 |
45 | render() {
46 | const { modal2Visible, option } = this.state;
47 | const options = Object.assign({}, this.defaultOptions, option);
48 | let content = '';
49 | if (options.type === 'loading') {
50 | content = (
51 |
60 |
61 |
62 | );
63 | } else if (options.type === 'notification') {
64 | content = (
65 | this.setModal2Visible(false)}
72 | className="modal-header"
73 | >
74 |
80 |
81 | );
82 | } else if (options.type === 'error') {
83 | content = (
84 | this.setModal2Visible(false)}
90 | onCancel={() => this.setModal2Visible(false)}
91 | className="modal-header"
92 | >
93 |
100 |
101 | );
102 | } else if (options.type === 'dialog') {
103 | content = (
104 | this.setModal2Visible(false)}
111 | className="modal-header"
112 | >
113 | {
114 | options.Dialog ? () : ''
115 | }
116 |
117 | );
118 | }
119 | return (
120 |
121 | {content}
122 |
123 | );
124 | }
125 | }
126 |
127 | const dialogDom = ReactDom.render(, document.getElementById('dialog'));
128 | const modal = {};
129 |
130 | modal.showModel = (option) => {
131 | dialogDom.show(option);
132 | };
133 |
134 | modal.closeModel = () => {
135 | dialogDom.close();
136 | };
137 |
138 | export default modal;
139 |
--------------------------------------------------------------------------------
/src/components/modal/modal.less:
--------------------------------------------------------------------------------
1 | .vertical-center-modal {
2 | text-align: center;
3 | white-space: nowrap;
4 | }
5 |
6 | .vertical-center-modal:before {
7 | content: '';
8 | display: inline-block;
9 | height: 100%;
10 | vertical-align: middle;
11 | width: 0;
12 | }
13 |
14 | .vertical-center-modal .ant-modal {
15 | display: inline-block;
16 | vertical-align: middle;
17 | top: 0;
18 | text-align: center;
19 | }
20 |
21 | .modal-header{
22 | .ant-btn-lg{
23 | font-size: 14px;
24 | }
25 | .noti-alert{
26 | line-height: 35px;
27 | margin-top: 25px;
28 | text-align: left;
29 | .ant-alert-icon{
30 | top: 18px;
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Demo
11 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter } from 'react-router-dom';
4 | import zhCN from 'antd/lib/locale-provider/zh_CN';
5 | import { LocaleProvider } from 'antd';
6 | import App from './app';
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 |
13 | ,
14 | document.getElementById('app')
15 | );
16 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import PropTypes from 'prop-types';
4 | import { Router, Route, IndexRoute, browserHistory } from 'react-router';
5 | import zhCN from 'antd/lib/locale-provider/zh_CN';
6 | import { LocaleProvider } from 'antd';
7 |
8 | import item1 from 'pages/item1/item1';
9 | import item2 from 'pages/item2/item2';
10 | import item3 from 'pages/item3/item3';
11 | import item4 from 'pages/item4/item4';
12 | import item5 from 'pages/item5/item5';
13 | import item6 from 'pages/item6/item6';
14 |
15 | function App(props) {
16 | return (
17 |
18 |
19 | {props.children}
20 |
21 |
22 | );
23 | }
24 |
25 | App.propTypes = {
26 | children: PropTypes.element.isRequired
27 | };
28 |
29 | const routers = (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | );
42 |
43 | ReactDOM.render(routers, document.getElementById('app'));
44 |
--------------------------------------------------------------------------------
/src/pages/item1/item1.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Table, Input, Button } from 'antd';
3 | import Tablestore from 'store/tablestore';
4 | import { observer } from 'mobx-react';
5 | import { observable } from 'mobx';
6 | import Layout from 'components/layout2/layout2';
7 | import modal from 'components/modal/modal';
8 | import UserConfig from './userConfig';
9 | import UserDelete from './userDelete';
10 | import './item1.less';
11 |
12 | const Search = Input.Search;
13 | const store = new Tablestore();
14 | const url = 'claa/tablelist';
15 | const columns = [{
16 | title: '用户名',
17 | dataIndex: 'username',
18 | key: 'username',
19 | render: text => {text}
20 | }, {
21 | title: '角色名',
22 | dataIndex: 'rolename',
23 | key: 'rolename'
24 | }, {
25 | title: '归属组织',
26 | dataIndex: 'belongOrg',
27 | key: 'belongOrg'
28 | }, {
29 | title: '归属用户',
30 | dataIndex: 'belongUser',
31 | key: 'belongUser'
32 | }, {
33 | title: '创建时间',
34 | dataIndex: 'createTime',
35 | key: 'createTime',
36 | sorter: true
37 | }, {
38 | title: '操作',
39 | dataIndex: 'action',
40 | key: 'action',
41 | render: (text, record, index) => (
42 |
43 | this.editUser(index)} role="presentation" >编辑
44 |
45 | this.deleteUser(index)} role="presentation" >删除
46 |
47 | )
48 | }];
49 |
50 | @observer
51 | class PageComponent extends Component {
52 | constructor(props) {
53 | super(props);
54 |
55 | this.handleTableChange = this.handleTableChange.bind(this);
56 | this.createUser = this.createUser.bind(this);
57 | this.editUser = this.editUser.bind(this);
58 | this.searchUser = this.searchUser.bind(this);
59 | }
60 |
61 | componentDidMount() {
62 | this.doQuery();
63 | }
64 |
65 | // onSelectChange = (selectedRowKeys, selectedRows) => {
66 | // console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
67 | // };
68 |
69 | title = () => '用户管理';
70 |
71 | @observable obserdata = {
72 | sorterField: '',
73 | sorterOrder: '',
74 | tableList: [],
75 | searchValue: ''
76 | };
77 |
78 | doQuery() {
79 | const param = {
80 | loadingFlag: true,
81 | url,
82 | method: 'GET',
83 | data: {
84 | pageSize: store.data.pagination.pageSize,
85 | current: store.data.pagination.current,
86 | sorterField: this.obserdata.sorterField,
87 | sorterOrder: this.obserdata.sorterOrder,
88 | searchValue: this.obserdata.searchValue
89 | }
90 | };
91 | store.fetchData(param);
92 | }
93 |
94 | handleTableChange(pagination, filters, sorter) {
95 | store.changeCurrentPage(pagination.current);
96 | this.obserdata.sorterField = sorter.field;
97 | this.obserdata.sorterOrder = sorter.order;
98 | this.doQuery();
99 | }
100 |
101 | createUser() {
102 | modal.showModel({
103 | type: 'dialog',
104 | title: '新增用户',
105 | Dialog: UserConfig,
106 | ok: (value) => {
107 | this.okHandler(value, 0);
108 | },
109 | param: {}
110 | });
111 | }
112 |
113 | okHandler(value, type) {
114 | const that = this;
115 | const params = {
116 | loadingFlag: false,
117 | url,
118 | method: 'POST',
119 | data: {
120 | type,
121 | username: value.username,
122 | rolename: value.rolename,
123 | userDesc: value.userDesc
124 | },
125 | successFn() {
126 | that.doQuery();
127 | }
128 | };
129 | store.createUser(params);
130 | }
131 |
132 | editUser(index) {
133 | modal.showModel({
134 | type: 'dialog',
135 | title: '编辑用户',
136 | Dialog: UserConfig,
137 | ok: (value) => {
138 | this.okHandler(value, 1);
139 | },
140 | param: this.obserdata.tableList[index]
141 | });
142 | }
143 |
144 | deleteUser(index) {
145 | const that = this;
146 | modal.showModel({
147 | type: 'dialog',
148 | title: '删除用户',
149 | Dialog: UserDelete,
150 | ok: () => {
151 | const params = {
152 | loadingFlag: false,
153 | url,
154 | method: 'POST',
155 | data: {
156 | id: [index]
157 | },
158 | successFn() {
159 | that.doQuery();
160 | }
161 | };
162 | store.deleteUser(params);
163 | },
164 | param: {
165 | text: '确定要删除该用户吗?'
166 | }
167 | });
168 | }
169 |
170 | searchUser(value) {
171 | this.obserdata.searchValue = value;
172 | this.doQuery();
173 | }
174 |
175 | render() {
176 | const dataSource = store.data.list.slice();
177 | this.obserdata.tableList = dataSource;
178 | const rowSelection = {
179 | onChange: this.onSelectChange
180 | };
181 | return (
182 |
183 |
184 |
185 | this.searchUser(value)}
189 | />
190 |
191 |
192 |
193 |
203 |
204 |
205 | );
206 | }
207 | }
208 |
209 | export default PageComponent;
210 |
--------------------------------------------------------------------------------
/src/pages/item1/item1.less:
--------------------------------------------------------------------------------
1 | .item1{
2 | position: relative;
3 | .search{
4 | position: absolute;
5 | right: 0;
6 | z-index: 99;
7 | .apart-line {
8 | position: relative;
9 | display: inline-block;
10 | width: 1px;
11 | height: 28px;
12 | top: 9px;
13 | margin: 0 10px;
14 | background: rgb(229, 235, 241);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/pages/item1/userConfig.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Form, Input, Radio, Button } from 'antd';
3 | import PropTypes from 'prop-types';
4 | import modal from 'components/modal/modal';
5 |
6 | import './userConfig.less';
7 |
8 | const FormItem = Form.Item;
9 | const { TextArea } = Input;
10 |
11 | class PageComponent extends Component {
12 | static cancelClickHandler() {
13 | modal.closeModel();
14 | }
15 |
16 | handleSubmit = (e) => {
17 | e.preventDefault();
18 | this.props.form.validateFields((err, values) => {
19 | if (!err) {
20 | console.log('Received values of form: ', values);
21 |
22 | const param = {
23 | username: values.username,
24 | rolename: values.rolename,
25 | userDesc: values.userDesc
26 | };
27 | this.props.onTrigger(param);
28 | }
29 | });
30 | };
31 |
32 | render() {
33 | const formItemLayout = {
34 | labelCol: { span: 5 },
35 | wrapperCol: { span: 16 }
36 | };
37 | const { getFieldDecorator } = this.props.form;
38 | return (
39 |
40 |
86 |
87 | );
88 | }
89 | }
90 |
91 | PageComponent.propTypes = {
92 | form: PropTypes.object.isRequired,
93 | onTrigger: PropTypes.func.isRequired
94 | };
95 |
96 | const WrappedNormalLoginForm = Form.create({
97 | mapPropsToFields(props) {
98 | const { param } = props;
99 | const rolename = param.rolename ? param.rolename : '';
100 | const username = param.username ? param.username : '';
101 | const desc = param.desc ? param.desc : '';
102 | return {
103 | rolename: { value: rolename },
104 | username: { value: username },
105 | userDesc: { value: desc }
106 | };
107 | }
108 | })(PageComponent);
109 | export default WrappedNormalLoginForm;
110 |
--------------------------------------------------------------------------------
/src/pages/item1/userConfig.less:
--------------------------------------------------------------------------------
1 | .userConfig{
2 | .footer{
3 | text-align: center;
4 | border-top: 1px solid #e9e9e9;
5 | padding-top: 20px;
6 | }
7 | }
8 |
9 | .userDelete{
10 | .content{
11 | margin: 30px 10px;
12 | text-align: center;
13 | font-size: 20px;
14 | }
15 | .footer{
16 | text-align: center;
17 | border-top: 1px solid #e9e9e9;
18 | padding-top: 20px;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/pages/item1/userDelete.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Button } from 'antd';
3 | import PropTypes from 'prop-types';
4 | import modal from 'components/modal/modal';
5 |
6 | class PageComponent extends Component {
7 | static cancelClickHandler() {
8 | modal.closeModel();
9 | }
10 | constructor(props) {
11 | super(props);
12 | this.okClickHandler = this.okClickHandler.bind(this);
13 | }
14 |
15 | okClickHandler() {
16 | this.props.onTrigger();
17 | }
18 |
19 | render() {
20 | const { param } = this.props;
21 | return (
22 |
23 |
26 |
27 |
30 |
33 |
34 |
35 | );
36 | }
37 | }
38 | PageComponent.propTypes = {
39 | param: PropTypes.object.isRequired,
40 | onTrigger: PropTypes.func.isRequired
41 | };
42 |
43 | export default PageComponent;
44 |
--------------------------------------------------------------------------------
/src/pages/item2/item2.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Tabs } from 'antd';
3 | import { observer } from 'mobx-react';
4 | import Layout from 'components/layout2/layout2';
5 | import Echartstore from 'store/echartstore';
6 | import Lines from './line';
7 | import Pie from './pie';
8 | import './item2.less';
9 |
10 |
11 | const TabPane = Tabs.TabPane;
12 | const urlLine = 'claa/linelist';
13 | const urlPie = 'claa/pielist';
14 | const store = new Echartstore();
15 |
16 | @observer
17 | class PageComponent extends Component {
18 | static doQueryLine() {
19 | const param = {
20 | loadingFlag: true,
21 | url: urlLine,
22 | method: 'GET',
23 | data: {}
24 | };
25 | store.fetchData(param);
26 | }
27 |
28 | static doQueryPie() {
29 | const param = {
30 | loadingFlag: true,
31 | url: urlPie,
32 | method: 'GET',
33 | data: {}
34 | };
35 | store.fetchPieData(param);
36 | }
37 |
38 | componentDidMount() {
39 | PageComponent.doQueryLine();
40 | PageComponent.doQueryPie();
41 | }
42 |
43 | render() {
44 | const lineData = store.data.list.slice();
45 | const pieData = store.data.pieList.slice();
46 | return (
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
59 |
60 |
61 |
62 |
63 | );
64 | }
65 | }
66 |
67 | export default PageComponent;
68 |
--------------------------------------------------------------------------------
/src/pages/item2/item2.less:
--------------------------------------------------------------------------------
1 | .item2{
2 | .tabLine{
3 | height:400px;
4 | margin-top: 20px;
5 | }
6 | }
--------------------------------------------------------------------------------
/src/pages/item2/line.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import echarts from 'echarts';
3 | import PropTypes from 'prop-types';
4 |
5 | let LineChart = echarts;
6 |
7 | class PageComponent extends Component {
8 | static resizeLines() {
9 | const lineInstance = echarts.getInstanceByDom(document.getElementById('lineChart'));
10 | lineInstance.resize();
11 | }
12 | componentDidMount() {
13 | LineChart = echarts.init(document.getElementById('lineChart'));
14 | if (this.props.param && this.props.param.length) {
15 | this.initLines();
16 | }
17 | $(window).on('resize', PageComponent.resizeLines);
18 | }
19 |
20 | componentWillReceiveProps(nextProps) {
21 | if (this.props !== nextProps) {
22 | this.props = nextProps;
23 | if (this.props.param && this.props.param.length) {
24 | this.initLines();
25 | }
26 | }
27 | }
28 |
29 | componentWillUnmount() {
30 | $(window).off('resize');
31 | }
32 |
33 | initLines() {
34 | const { param } = this.props;
35 | const successrate = [];
36 | const maxsuccessimagerate = [];
37 | const maxsuccessregionrate = [];
38 | const maxfailimagerate = [];
39 | const maxfailregionrate = [];
40 | const counttime = [];
41 | param.forEach((value) => {
42 | successrate.push(value.successrate);
43 | maxsuccessimagerate.push(value.maxsuccessimagerate);
44 | maxsuccessregionrate.push(value.maxsuccessregionrate);
45 | maxfailimagerate.push(value.maxfailimagerate);
46 | maxfailregionrate.push(value.maxfailregionrate);
47 | counttime.push(value.counttime);
48 | });
49 |
50 | const option = {
51 | title: {
52 | text: '堆叠区域图',
53 | x: 'center'
54 | },
55 | color: ['#dd5820', '#007ac2', '#81c267', '#facc41'],
56 | tooltip: {
57 | trigger: 'axis'
58 | },
59 | legend: {
60 | top: '30',
61 | data: ['测试一', '测试二', '测试三', '测试四', '测试五']
62 | },
63 | grid: {
64 | left: '3%',
65 | right: '4%',
66 | bottom: '3%',
67 | containLabel: true
68 | },
69 | toolbox: {
70 | right: 60,
71 | feature: {
72 | saveAsImage: {}
73 | }
74 | },
75 | xAxis: [
76 | {
77 | type: 'category',
78 | boundaryGap: false,
79 | data: counttime
80 | }
81 | ],
82 | yAxis: [
83 | {
84 | type: 'value',
85 | axisLabel: {
86 | textStyle: {
87 | color: '#5a6c77',
88 | fontSize: '12',
89 | extraCssText: 'line-height:30px'
90 | }
91 | }
92 | }
93 | ],
94 | series: [
95 | {
96 | name: '测试一',
97 | type: 'line',
98 | data: successrate
99 | }, {
100 | name: '测试二',
101 | type: 'line',
102 | data: maxsuccessimagerate
103 | }, {
104 | name: '测试三',
105 | type: 'line',
106 | data: maxsuccessregionrate
107 | }, {
108 | name: '测试四',
109 | type: 'line',
110 | data: maxfailimagerate
111 | }, {
112 | name: '测试五',
113 | type: 'line',
114 | data: maxfailregionrate
115 | }
116 | ]
117 | };
118 |
119 | LineChart.setOption(option);
120 | }
121 |
122 | render() {
123 | return (
124 |
125 | );
126 | }
127 | }
128 |
129 | PageComponent.propTypes = {
130 | param: PropTypes.array.isRequired
131 | };
132 | export default PageComponent;
133 |
--------------------------------------------------------------------------------
/src/pages/item2/pie.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import echarts from 'echarts';
3 | import PropTypes from 'prop-types';
4 |
5 | let pieChart = echarts;
6 |
7 | class PageComponent extends Component {
8 | static resizePie() {
9 | const pieInstance = echarts.getInstanceByDom(document.getElementById('pieChart'));
10 | pieInstance.resize();
11 | }
12 | componentDidMount() {
13 | pieChart = echarts.init(document.getElementById('pieChart'));
14 | if (this.props.param && this.props.param.length) {
15 | this.initPie();
16 | }
17 | $(window).on('resize', PageComponent.resizePie);
18 | }
19 |
20 | componentWillReceiveProps(nextProps) {
21 | if (this.props !== nextProps) {
22 | this.props = nextProps;
23 | if (this.props.param && this.props.param.length) {
24 | this.initPie();
25 | }
26 | }
27 | }
28 |
29 | componentWillUnmount() {
30 | $(window).off('resize');
31 | }
32 |
33 | initPie() {
34 | const { param } = this.props;
35 | const legendData = [];
36 | const pieData = [];
37 | param.forEach((value) => {
38 | legendData.push(value.clusterName);
39 | const { usableNodes, clusterName } = value;
40 | pieData.push({
41 | value: usableNodes,
42 | name: clusterName
43 | });
44 | });
45 |
46 | const option = {
47 | title: {
48 | text: '区域分布图',
49 | x: 'center'
50 | },
51 | color: ['#dd5820', '#007ac2', '#81c267', '#5686cb', '#facc41'],
52 | tooltip: {
53 | trigger: 'item',
54 | formatter: '{a}
{b} : {c} ({d}%)'
55 | },
56 | legend: {
57 | bottom: '10',
58 | data: legendData
59 | },
60 | toolbox: {
61 | right: 60,
62 | feature: {
63 | saveAsImage: {}
64 | }
65 | },
66 | series: [
67 | {
68 | name: '来源',
69 | type: 'pie',
70 | radius: '65%',
71 | center: ['50%', '48%'],
72 | data: pieData,
73 | itemStyle: {
74 | emphasis: {
75 | shadowBlur: 10,
76 | shadowOffsetX: 0,
77 | shadowColor: 'rgba(0, 0, 0, 0.5)'
78 | }
79 | }
80 | }
81 | ]
82 | };
83 |
84 | pieChart.setOption(option);
85 | }
86 |
87 | render() {
88 | return (
89 |
90 | );
91 | }
92 | }
93 |
94 | PageComponent.propTypes = {
95 | param: PropTypes.array.isRequired
96 | };
97 | export default PageComponent;
98 |
--------------------------------------------------------------------------------
/src/pages/item3/item3.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Button } from 'antd';
3 | import { observer } from 'mobx-react';
4 | import Layout from 'components/layout2/layout2';
5 | import Positionstore from 'store/positionstore';
6 | import imgPin from 'images/pin.png';
7 | import imgPosition from 'images/position.jpg';
8 | import './item3.less';
9 |
10 | const store = new Positionstore();
11 | const url = 'claa/positionlist';
12 | const nn6 = document.getElementById && !document.all;
13 | let oDiv;
14 | let orign = 1;
15 | let oDragObj;
16 | let isdrag = false;
17 | let x;
18 | let y;
19 | let nTX;
20 | let nTY;
21 |
22 | @observer
23 | class PageComponent extends Component {
24 | static doQuery() {
25 | const param = {
26 | loadingFlag: true,
27 | url,
28 | method: 'GET',
29 | data: {}
30 | };
31 | store.fetchDataPosition(param);
32 | }
33 |
34 | // 获取div的四个顶点坐标
35 | static getDivPosition() {
36 | const odiv = document.getElementById('picDiv');
37 | const screnWidth = document.body.clientWidth;
38 | return {
39 | xLeft: odiv.getBoundingClientRect().left,
40 | xRigh: odiv.getBoundingClientRect().left + screnWidth - 145,
41 | yTop: odiv.getBoundingClientRect().top,
42 | yBottom: odiv.getBoundingClientRect().top + screnWidth - 145
43 | };
44 | }
45 |
46 | // 获取鼠标坐标
47 | static mousePos(e) {
48 | const ev = e || window.event;
49 | return {
50 | x: ev.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
51 | y: ev.clientY + document.body.scrollTop + document.documentElement.scrollTop
52 | };
53 | }
54 |
55 | // 鼠标按下才初始化
56 | static initDrag(e) {
57 | let oDragHandle = nn6 ? e.target : event.srcElement;
58 | const topElement = 'HTML';
59 | while (oDragHandle.tagName !== topElement && oDragHandle.className !== 'dragAble') {
60 | oDragHandle = nn6 ? oDragHandle.parentNode : oDragHandle.parentElement;
61 | }
62 | if (oDragHandle.className === 'dragAble') {
63 | isdrag = true;
64 | oDragObj = oDragHandle;
65 | nTY = parseInt(oDragObj.style.top + 0, 10);
66 | y = nn6 ? e.clientY : event.clientY;
67 | nTX = parseInt(oDragObj.style.left + 0, 10);
68 | x = nn6 ? e.clientX : event.clientX;
69 | $(document).on('mousemove', PageComponent.moveMouse);
70 | return false;
71 | }
72 | return true;
73 | }
74 |
75 | // 鼠标移动
76 | static moveMouse(e) {
77 | // 鼠标的坐标
78 | const x1 = PageComponent.mousePos(e).x;
79 | const y1 = PageComponent.mousePos(e).y;
80 | // div的四个顶点坐标
81 | const xLeft = PageComponent.getDivPosition().xLeft;
82 | const xRigh = PageComponent.getDivPosition().xRigh;
83 | const yTop = PageComponent.getDivPosition().yTop;
84 | const yBottom = PageComponent.getDivPosition().yBottom;
85 |
86 | if (isdrag && x1 > xLeft && x1 < xRigh && y1 > yTop && y1 < yBottom) {
87 | oDragObj.style.top = `${nn6 ? nTY + e.clientY - y : nTY + event.clientY - y}px`;
88 | oDragObj.style.left = `${nn6 ? nTX + e.clientX - x : nTX + event.clientX - x}px`;
89 | return false;
90 | }
91 | return true;
92 | }
93 |
94 | static offDrag() {
95 | isdrag = false;
96 | }
97 |
98 | static imgScale(status) {
99 | if (status) {
100 | orign += 0.2;
101 | if (orign >= 2) {
102 | orign = 2;
103 | }
104 | $('#imgWrap').css('transform', `scale(${orign})`);
105 | } else {
106 | orign -= 0.2;
107 | if (orign <= 0.1) {
108 | orign = 0.1;
109 | }
110 | $('#imgWrap').css('transform', `scale(${orign})`);
111 | }
112 | }
113 |
114 | static enlarge() {
115 | PageComponent.imgScale(true);
116 | }
117 |
118 | static diminsh() {
119 | PageComponent.imgScale(false);
120 | }
121 |
122 | /* 以下是为了兼容切换到手机模式的拖拽事件 */
123 | static initTouchDrag(e) {
124 | let oDragHandle = nn6 ? e.target : event.srcElement;
125 | const topElement = 'HTML';
126 | while (oDragHandle.tagName !== topElement && oDragHandle.className !== 'dragAble') {
127 | oDragHandle = nn6 ? oDragHandle.parentNode : oDragHandle.parentElement;
128 | }
129 | if (oDragHandle.className === 'dragAble') {
130 | isdrag = true;
131 | oDragObj = oDragHandle;
132 | nTY = parseInt(oDragObj.style.top + 0, 10);
133 | y = nn6 ? e.touches[0].clientY : event.touches[0].clientY;
134 | nTX = parseInt(oDragObj.style.left + 0, 10);
135 | x = nn6 ? e.touches[0].clientX : event.touches[0].clientX;
136 | oDiv.addEventListener('touchmove', PageComponent.touchmoveMouse);
137 | return false;
138 | }
139 | return true;
140 | }
141 |
142 | // touch鼠标移动
143 | static touchmoveMouse(e) {
144 | oDragObj.style.top = `${nn6 ? nTY + e.touches[0].clientY - y : nTY + event.touches[0].clientY - y}px`;
145 | oDragObj.style.left = `${nn6 ? nTX + e.touches[0].clientX - x : nTX + event.touches[0].clientX - x}px`;
146 | return false;
147 | }
148 | /* 以上是为了兼容切换到手机模式的拖拽事件 */
149 |
150 | componentDidMount() {
151 | oDiv = document.getElementById('imgWrap');
152 | const picDiv = $('#picDiv');
153 | let layoutHeight = $(window).height() - 157;
154 | let picHeight = `${layoutHeight - 91.5}px`;
155 | picDiv.css('height', picHeight);
156 | $(window).resize(() => {
157 | layoutHeight = $(window).height() - 157;
158 | picHeight = `${layoutHeight - 91.5}px`;
159 | picDiv.css('height', picHeight);
160 | });
161 | PageComponent.doQuery();
162 | oDiv.addEventListener('touchstart', PageComponent.initTouchDrag);
163 | oDiv.ontouchend = PageComponent.offDrag;
164 |
165 | $(document).on('mousedown', PageComponent.initDrag);
166 | $(document).on('mouseup', PageComponent.offDrag);
167 | }
168 |
169 | componentWillUnmount() {
170 | $(document).off('mousedown');
171 | $(document).off('mouseup');
172 | $(document).off('mousemove');
173 | }
174 |
175 |
176 | render() {
177 | const positionData = store.data.list.slice();
178 | return (
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 | {positionData.length ? positionData.map(value =>
190 | (

)) : ''}
200 |

201 |
202 |
203 |
204 |
205 |
206 | );
207 | }
208 | }
209 |
210 | export default PageComponent;
211 |
--------------------------------------------------------------------------------
/src/pages/item3/item3.less:
--------------------------------------------------------------------------------
1 | .item3 {
2 | position: relative;
3 | .search {
4 | padding-bottom: 30px;
5 | border-bottom: 1px solid #cccccc;
6 | .apart-line {
7 | position: relative;
8 | display: inline-block;
9 | width: 1px;
10 | height: 28px;
11 | top: 9px;
12 | margin: 0 10px;
13 | background: rgb(229, 235, 241);
14 | }
15 | }
16 | .pos {
17 | position: relative;
18 | #picDiv
19 | {
20 | background:#fff;
21 | padding:0;
22 | min-width:420px;
23 | min-height:420px;
24 | width:100%;
25 | overflow:hidden;
26 | position:relative;
27 | cursor:move;
28 | .dragAble {
29 | position: absolute;
30 | cursor: move;
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/pages/item4/item4.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Layout from 'components/layout2/layout2';
3 | import { Map, GroundImage, Markers, Marker, Circle } from 'react-amap';
4 | import srcImg from 'images/dongwuyuan.jpg';
5 | import './item4.less';
6 |
7 |
8 | class PageComponent extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.center = {
12 | longitude: 118.642807,
13 | latitude: 32.036538
14 | };
15 | this.currentPosition = {
16 | longitude: 116.397477,
17 | latitude: 39.908692
18 | };
19 | this.state = {
20 | radius: 600,
21 | visible: true,
22 | style: { strokeColor: '#f00' },
23 | draggable: true
24 | };
25 | this.circleEvents = {
26 | created: (ins) => { console.log(window.circle = ins); },
27 | click: () => { console.log('clicked'); },
28 | mouseover: () => { console.log('mouseover'); }
29 | };
30 | this.markers = [
31 | {
32 | position: {
33 | longitude: 116.333124,
34 | latitude: 39.941849
35 | },
36 | id: '1'
37 | },
38 | {
39 | position: {
40 | longitude: 116.340934,
41 | latitude: 39.944794
42 | },
43 | id: '2'
44 | }
45 | ];
46 | this.bounds = {
47 | sw: {
48 | longitude: 116.327911,
49 | latitude: 39.939229
50 | },
51 | ne: {
52 | longitude: 116.342659,
53 | latitude: 39.946275
54 | }
55 | };
56 | }
57 | componentDidMount() {
58 | // 调用高德地图原生LngLat类,使用distance方法,但需等高德地图加载完成
59 | setTimeout(() => {
60 | console.log(this.calculate(
61 | new window.AMap.LngLat(118.642807, 32.036538),
62 | new window.AMap.LngLat(116.397477, 39.908692)
63 | ));
64 | }, 2000);
65 | }
66 | markersEvents = {
67 | click(e, marker) {
68 | const extData = marker.getExtData();
69 | const deveui = extData.deveui;
70 | console.log(deveui);
71 | }
72 | };
73 | calculate(lnglat1, lnglat2) {
74 | return Math.round(lnglat1.distance(lnglat2));
75 | }
76 |
77 | render() {
78 | return (
79 |
80 |
81 |
82 |
107 |
108 |
109 |
110 | );
111 | }
112 | }
113 |
114 | export default PageComponent;
115 |
--------------------------------------------------------------------------------
/src/pages/item4/item4.less:
--------------------------------------------------------------------------------
1 | .item4{
2 | #container{
3 | width: 100%;
4 | height: 600px;
5 | }
6 | }
--------------------------------------------------------------------------------
/src/pages/item5/item5.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Layout from 'components/layout2/layout2';
3 | import vis from 'vis';
4 | import nodeImage from 'images/computer.png';
5 | import './item5.less';
6 |
7 | class PageComponent extends Component {
8 | componentDidMount() {
9 | const container = document.getElementById('mynetwork');
10 | const nodes = new vis.DataSet([
11 | {
12 | id: 1, label: '网关1', shape: 'image', image: `${nodeImage}`, x: 400, y: 500
13 | },
14 | {
15 | id: 2, label: '网关2', shape: 'image', image: `${nodeImage}`, x: 300, y: 400
16 | },
17 | {
18 | id: 3, label: '网关3', shape: 'image', image: `${nodeImage}`, x: 200, y: 300
19 | },
20 | {
21 | id: 4, label: '网关4', shape: 'image', image: `${nodeImage}`, x: 100, y: 200
22 | },
23 | {
24 | id: 5, label: '网关5', shape: 'image', image: `${nodeImage}`, x: 100, y: 100
25 | }
26 | ]);
27 | const edges = new vis.DataSet([
28 | { from: 1, to: 3, dashes: true },
29 | {
30 | from: 1,
31 | to: 2,
32 | color: {
33 | color: 'red',
34 | highlight: 'blue',
35 | hover: '#faff00',
36 | inherit: false
37 | }
38 | },
39 | { from: 2, to: 4 },
40 | { from: 2, to: 5 }
41 | ]);
42 |
43 | const data = {
44 | nodes,
45 | edges
46 | };
47 | const options = {
48 | interaction: {
49 | hover: true
50 | },
51 | physics: false
52 | };
53 | const network = new vis.Network(container, data, options);
54 | }
55 | render() {
56 | return (
57 |
58 |
59 |
60 | );
61 | }
62 | }
63 |
64 | export default PageComponent;
65 |
--------------------------------------------------------------------------------
/src/pages/item5/item5.less:
--------------------------------------------------------------------------------
1 | #mynetwork {
2 | width: 600px;
3 | height: 400px;
4 | border: 1px solid lightgray;
5 | }
--------------------------------------------------------------------------------
/src/pages/item6/item6.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Layout from 'components/layout2/layout2';
3 | import ReconnectingWebSocket from 'reconnectingwebsocket';
4 |
5 | const url = 'ws://10.47.73.41:31020/';
6 |
7 | class PageComponent extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.socket = null;
11 | this.socketOpen = this.socketOpen.bind(this);
12 | this.socketError = this.socketError.bind(this);
13 | }
14 | componentDidMount() {
15 | this.socketHandle();
16 | }
17 | componentWillUnmount() {
18 | if (this.socket !== null) {
19 | this.socket.close();
20 | this.socket = null;
21 | }
22 | }
23 | socketHandle() {
24 | this.socket = new ReconnectingWebSocket(url, null, {
25 | debug: true,
26 | reconnectInterval: 3000
27 | });
28 | this.socket.onopen = this.socketOpen;
29 | this.socket.onerror = this.socketError;
30 | this.socket.onmessage = this.socketMessage;
31 | }
32 |
33 | socketOpen(event) {
34 | alert('WebSocket connected.');
35 | alert('send hello to server');
36 | this.socket.send(JSON.stringify('hello'));
37 | }
38 |
39 | socketMessage(event) {
40 | console.log(event);
41 | console.log(event.data);
42 | }
43 | socketError(error) {
44 | alert('CONNECTION ERROR!');
45 | }
46 | render() {
47 | return (
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
55 | export default PageComponent;
56 |
--------------------------------------------------------------------------------
/src/pages/item7/item7.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Layout from 'components/layout2/layout2';
3 | import go from 'gojs';
4 |
5 | class PageComponent extends Component {
6 | componentDidMount() {
7 | const $ = go.GraphObject.make; // for conciseness in defining templates in this function
8 |
9 | const myDiagram =
10 | $(
11 | go.Diagram, 'myDiagramDiv', // must be the ID or reference to div
12 | { initialContentAlignment: go.Spot.Center }
13 | );
14 |
15 | // define all of the gradient brushes
16 | const graygrad = $(go.Brush, 'Linear', { 0: '#F5F5F5', 1: '#F1F1F1' });
17 | const bluegrad = $(go.Brush, 'Linear', { 0: '#CDDAF0', 1: '#91ADDD' });
18 | const yellowgrad = $(go.Brush, 'Linear', { 0: '#FEC901', 1: '#FEA200' });
19 | const lavgrad = $(go.Brush, 'Linear', { 0: '#ffffff', 1: '#ffffff' });
20 |
21 | // define the Node template for non-terminal nodes
22 | myDiagram.nodeTemplate =
23 | $(
24 | go.Node, 'Auto',
25 | { isShadowed: true },
26 | // define the node's outer shape
27 | $(
28 | go.Shape, 'RoundedRectangle',
29 | { fill: graygrad, stroke: '#D8D8D8' },
30 | new go.Binding('fill', 'color')
31 | ),
32 | // define the node's text
33 | $(
34 | go.TextBlock,
35 | { margin: 5, font: 'bold 11px Helvetica, bold Arial, sans-serif' },
36 | new go.Binding('text', 'key')
37 | )
38 | );
39 |
40 | // define the Link template
41 | myDiagram.linkTemplate =
42 | $(
43 | go.Link, // the whole link panel
44 | { selectable: false },
45 | $(go.Shape)
46 | ); // the link shape
47 |
48 | // create the model for the double tree
49 | myDiagram.model = new go.TreeModel([
50 | // these node data are indented but not nested according to the depth in the tree
51 | { key: 'Root', color: lavgrad },
52 | {
53 | key: 'Left1', parent: 'Right1', dir: 'left', color: bluegrad
54 | },
55 | { key: 'leaf1', parent: 'Left1' },
56 | { key: 'leaf2', parent: 'Left1' },
57 | { key: 'Left2', parent: 'Left1', color: bluegrad },
58 | { key: 'leaf3', parent: 'Left2' },
59 | { key: 'leaf4', parent: 'Left2' },
60 | {
61 | key: 'Right1', parent: 'Right1', dir: 'right', color: yellowgrad
62 | },
63 | { key: 'Right2', parent: 'Right1', color: yellowgrad },
64 | { key: 'leaf5', parent: 'Right2' },
65 | { key: 'leaf6', parent: 'Right2' },
66 | { key: 'leaf7', parent: 'Right2' },
67 | { key: 'leaf8', parent: 'Right1' },
68 | { key: 'leaf9', parent: 'Right1' }
69 | ]);
70 |
71 | this.doubleTreeLayout(myDiagram);
72 | }
73 | doubleTreeLayout(diagram) {
74 | // Within this function override the definition of '$' from jQuery:
75 | const $ = go.GraphObject.make; // for conciseness in defining templates
76 | diagram.startTransaction('Double Tree Layout');
77 |
78 | // split the nodes and links into two Sets, depending on direction
79 | const leftParts = new go.Set(go.Part);
80 | const rightParts = new go.Set(go.Part);
81 | this.separatePartsByLayout(diagram, leftParts, rightParts);
82 | // but the ROOT node will be in both collections
83 |
84 | // create and perform two TreeLayouts, one in each direction,
85 | // without moving the ROOT node, on the different subsets of nodes and links
86 | const layout1 =
87 | $(
88 | go.TreeLayout,
89 | {
90 | angle: 180,
91 | arrangement: go.TreeLayout.ArrangementFixedRoots,
92 | setsPortSpot: false
93 | }
94 | );
95 |
96 | const layout2 =
97 | $(
98 | go.TreeLayout,
99 | {
100 | angle: 0,
101 | arrangement: go.TreeLayout.ArrangementFixedRoots,
102 | setsPortSpot: false
103 | }
104 | );
105 |
106 | layout1.doLayout(leftParts);
107 | layout2.doLayout(rightParts);
108 |
109 | diagram.commitTransaction('Double Tree Layout');
110 | }
111 | separatePartsByLayout(diagram, leftParts, rightParts) {
112 | const root = diagram.findNodeForKey('Right1');
113 | if (root === null) return;
114 | // the ROOT node is shared by both subtrees!
115 | leftParts.add(root);
116 | rightParts.add(root);
117 | // look at all of the immediate children of the ROOT node
118 | root.findTreeChildrenNodes().each((child) => {
119 | // in what direction is this child growing?
120 | const dir = child.data.dir;
121 | const coll = (dir === 'left') ? leftParts : rightParts;
122 | // add the whole subtree starting with this child node
123 | coll.addAll(child.findTreeParts());
124 | // and also add the link from the ROOT node to this child node
125 | coll.add(child.findTreeParentLink());
126 | });
127 | }
128 | render() {
129 | return (
130 |
131 |
137 |
138 | );
139 | }
140 | }
141 |
142 | export default PageComponent;
143 |
--------------------------------------------------------------------------------
/src/pages/item8/item8.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Layout from 'components/layout2/layout2';
3 | import audioSrc from 'media/tip.mp3';
4 | import './item8.less';
5 |
6 | class PageComponent extends Component {
7 | constructor(props) {
8 | super(props);
9 | this.playAudio = this.playAudio.bind(this);
10 | }
11 | componentDidMount() {
12 | $('.play').bind('click', this.playAudio);
13 | }
14 | playAudio() {
15 | const media = $('#media')[0];
16 | if (media.paused) {
17 | this.play();
18 | } else {
19 | this.pause();
20 | }
21 | }
22 | play() {
23 | const media = $('#media')[0];
24 | media.play();
25 | $('#play').html('Pause music!');
26 | }
27 | pause() {
28 | const media = $('#media')[0];
29 | media.pause();
30 | $('#play').html('Play music!');
31 | }
32 | render() {
33 | return (
34 |
35 |
36 |
37 |
38 | Pause music!
39 |
40 |
41 |
44 |
45 |
46 |
47 | );
48 | }
49 | }
50 | export default PageComponent;
51 |
--------------------------------------------------------------------------------
/src/pages/item8/item8.less:
--------------------------------------------------------------------------------
1 | .item8{
2 | #play{
3 | cursor: pointer;
4 | }
5 | }
--------------------------------------------------------------------------------
/src/store/echartstore.js:
--------------------------------------------------------------------------------
1 | import { observable } from 'mobx';
2 | import Ajax from 'util/ajax';
3 |
4 | export default class Echartstore {
5 | @observable data = {
6 | list: [],
7 | pieList: []
8 | };
9 |
10 | fetchData(param) {
11 | const that = this;
12 | const params = {
13 | successFn(data) {
14 | if (data.list && data.list.length) {
15 | const dataObserve = { ...that.data };
16 | dataObserve.list = data.list;
17 | that.data = dataObserve;
18 | }
19 | },
20 | ...param
21 | };
22 | console.log(params);
23 | Ajax.fetch(params);
24 | }
25 |
26 | fetchPieData(param) {
27 | const that = this;
28 | const params = {
29 | successFn(data) {
30 | if (data.list && data.list.length) {
31 | const dataObserve = { ...that.data };
32 | dataObserve.pieList = data.list;
33 | that.data = dataObserve;
34 | }
35 | },
36 | ...param
37 | };
38 | console.log(params);
39 | Ajax.fetch(params);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/store/menustore.js:
--------------------------------------------------------------------------------
1 | import { observable } from 'mobx';
2 | import Ajax from 'util/ajax';
3 |
4 | const menulistUrl = 'claa/menulist';
5 |
6 | export default class Menustore {
7 | @observable list = [];
8 |
9 | fetchData() {
10 | const that = this;
11 | const param = {
12 | loadingFlag: true,
13 | url: menulistUrl,
14 | method: 'GET',
15 | data: {},
16 | successFn(data) {
17 | that.list = data.list;
18 | }
19 | };
20 | console.log(param);
21 | Ajax.fetch(param);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/store/positionstore.js:
--------------------------------------------------------------------------------
1 | import { observable } from 'mobx';
2 | import Ajax from 'util/ajax';
3 |
4 | export default class Echartstore {
5 | @observable data = {
6 | list: []
7 | };
8 |
9 | fetchDataPosition(param) {
10 | const that = this;
11 | const params = {
12 | successFn(data) {
13 | if (data.list && data.list.length) {
14 | const dataObserve = { ...that.data };
15 | dataObserve.list = data.list;
16 | that.data = dataObserve;
17 | }
18 | },
19 | ...param
20 | };
21 | console.log(params);
22 | Ajax.fetch(params);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/store/tablestore.js:
--------------------------------------------------------------------------------
1 | import { observable } from 'mobx';
2 | import Ajax from 'util/ajax';
3 |
4 | export default class Tablestore {
5 | @observable data = {
6 | list: [],
7 | pagination: {
8 | pageSize: 10,
9 | current: 1,
10 | total: 10
11 | }
12 | };
13 |
14 | fetchData(param) {
15 | const that = this;
16 | const params = {
17 | successFn(data) {
18 | const dataObserve = { ...that.data };
19 | dataObserve.list = data.list;
20 | dataObserve.pagination.total = parseInt(data.total, 10);
21 | that.data = dataObserve;
22 | // 防止数据更新后,当前点击的页码超过了总页码数
23 | if (that.data.pagination.current > Math.ceil(that.data.pagination.total / that.data.pagination.pageSize)) {
24 | that.changeCurrentPage(Math.ceil(that.data.pagination.total / that.data.pagination.pageSize));
25 | }
26 | },
27 | ...param
28 | };
29 | console.log(params);
30 | Ajax.fetch(params);
31 | }
32 |
33 | changeCurrentPage(value) {
34 | this.data.pagination.current = value;
35 | }
36 |
37 | createUser(param) {
38 | const params = {
39 | ...param
40 | };
41 | console.log(params);
42 | Ajax.fetch(params);
43 | }
44 |
45 | deleteUser(param) {
46 | const params = {
47 | ...param
48 | };
49 | console.log(params);
50 | Ajax.fetch(params);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/testdata/localdata/linelist.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "list": [
4 | {
5 | "id": "1",
6 | "name": "平台",
7 | "counttime": "2016-11-08 16:19",
8 | "successrate": 22,
9 | "maxsuccessimagerate": 82,
10 | "maxsuccessregionrate": 56,
11 | "maxfailimagerate": 92,
12 | "maxfailregionrate": 33
13 | },{
14 | "id": "2",
15 | "name": "平台",
16 | "counttime": "2016-11-08 17:19",
17 | "successrate": 32,
18 | "maxsuccessimagerate": 52,
19 | "maxsuccessregionrate": 66,
20 | "maxfailimagerate": 22,
21 | "maxfailregionrate": 23
22 | },{
23 | "id": "3",
24 | "name": "平台",
25 | "counttime": "2016-11-08 18:19",
26 | "successrate": 42,
27 | "maxsuccessimagerate": 32,
28 | "maxsuccessregionrate": 76,
29 | "maxfailimagerate": 32,
30 | "maxfailregionrate": 43
31 | },{
32 | "id": "4",
33 | "name": "平台",
34 | "counttime": "2016-11-08 19:19",
35 | "successrate": 22,
36 | "maxsuccessimagerate": 42,
37 | "maxsuccessregionrate": 6,
38 | "maxfailimagerate": 142,
39 | "maxfailregionrate": 13
40 | },{
41 | "id": "5",
42 | "name": "平台",
43 | "counttime": "2016-11-08 20:19",
44 | "successrate": 62,
45 | "maxsuccessimagerate": 52,
46 | "maxsuccessregionrate": 96,
47 | "maxfailimagerate": 52,
48 | "maxfailregionrate": 73
49 | }
50 | ],
51 | "message": "error"
52 | }
--------------------------------------------------------------------------------
/src/testdata/localdata/menulist.json:
--------------------------------------------------------------------------------
1 | {
2 | "list": [
3 | {
4 | "key": "item1",
5 | "name": "item1",
6 | "sub": [
7 | {
8 | "key": "item1List1",
9 | "name": "item1List1",
10 | "icon": "user",
11 | "sub": [
12 | {
13 | "key": "item1SubList1",
14 | "name": "item1SubList1"
15 | },
16 | {
17 | "key": "item1SubList2",
18 | "name": "item1SubList2"
19 | }
20 | ]
21 | }
22 | ]
23 | },
24 | {
25 | "key": "item2",
26 | "name": "item2",
27 | "sub": [
28 | {
29 | "key": "item2List1",
30 | "name": "item2List1",
31 | "icon": "user",
32 | "sub": [
33 | {
34 | "key": "item2SubList1",
35 | "name": "item2SubList1"
36 | }
37 | ]
38 | }
39 | ]
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/src/testdata/localdata/menulist2.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "list": [
4 | {
5 | "key": "item1",
6 | "name": "item1"
7 | },{
8 | "key": "item2",
9 | "name": "item2"
10 | },{
11 | "key": "item3",
12 | "name": "item3"
13 | },{
14 | "key": "item4",
15 | "name": "item4"
16 | },{
17 | "key": "item5",
18 | "name": "item5"
19 | },{
20 | "key": "item6",
21 | "name": "item6"
22 | },{
23 | "key": "item7",
24 | "name": "item7"
25 | },{
26 | "key": "item8",
27 | "name": "item8"
28 | }
29 | ],
30 | "message": "error"
31 | }
--------------------------------------------------------------------------------
/src/testdata/localdata/pielist.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "list": [
4 | {
5 | "id": "1",
6 | "clusterName": "测试一",
7 | "usableNodes": 9
8 | },
9 | {
10 | "id": "2",
11 | "clusterName": "测试二",
12 | "usableNodes": 19
13 | },
14 | {
15 | "id": "3",
16 | "clusterName": "测试三",
17 | "usableNodes": 29
18 | },
19 | {
20 | "id": "4",
21 | "clusterName": "测试四",
22 | "usableNodes": 39
23 | },
24 | {
25 | "id": "5",
26 | "clusterName": "测试五",
27 | "usableNodes": 49
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/src/testdata/localdata/positionlist.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "list": [
4 | {
5 | "id": "0",
6 | "type": "1",
7 | "left": "133",
8 | "top": "136"
9 | },
10 | {
11 | "id": "1",
12 | "type": "1",
13 | "left": "279",
14 | "top": "609"
15 | },
16 | {
17 | "id": "2",
18 | "type": "2",
19 | "left": "665",
20 | "top": "142"
21 | },
22 | {
23 | "id": "3",
24 | "type": "2",
25 | "left": "658",
26 | "top": "385"
27 | }
28 | ]
29 | }
--------------------------------------------------------------------------------
/src/testdata/localdata/tablelist.json:
--------------------------------------------------------------------------------
1 | {
2 | "code": 0,
3 | "list": [
4 | {
5 | "key": "1",
6 | "username": "胡彦斌",
7 | "rolename": "管理员",
8 | "createTime": "2015-02-20 12:12:05",
9 | "deadTime": "2016-02-20 12:12:05",
10 | "desc": "testtest"
11 | },{
12 | "key": "2",
13 | "username": "岳云鹏",
14 | "rolename": "管理员",
15 | "createTime": "2015-02-20 12:12:05",
16 | "deadTime": "2016-02-20 12:12:05",
17 | "desc": "testtest"
18 | },{
19 | "key": "3",
20 | "username": "郭德纲",
21 | "rolename": "管理员",
22 | "createTime": "2015-02-20 12:12:05",
23 | "deadTime": "2016-02-20 12:12:05",
24 | "desc": "testtest"
25 | },{
26 | "key": "4",
27 | "username": "刘若英",
28 | "rolename": "普通用户",
29 | "createTime": "2015-02-20 12:12:05",
30 | "deadTime": "2016-02-20 12:12:05",
31 | "desc": "testtest"
32 | }
33 | ],
34 | "total": "4",
35 | "message": "error"
36 | }
--------------------------------------------------------------------------------
/src/testdata/mockdata/menulist.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs';
2 |
3 | export default Mock.mock('http://claa/menulist', {
4 | code: 0,
5 | list: [
6 | {
7 | key: 'item1',
8 | name: 'item1'
9 | }, {
10 | key: 'item2',
11 | name: 'item2'
12 | }, {
13 | key: 'item3',
14 | name: 'item3'
15 | }, {
16 | key: 'item4',
17 | name: 'item4'
18 | }
19 | ],
20 | message: 'error'
21 | });
22 |
--------------------------------------------------------------------------------
/src/utils/ajax.js:
--------------------------------------------------------------------------------
1 | import modal from 'components/modal/modal';
2 | import 'util/mockdata';
3 | import ErrorCode from './errorcode';
4 |
5 | export default class AJAX {
6 | static localData = require('util/localdata');
7 |
8 | static getEnvPrefix() {
9 | if (window.isDebug) {
10 | return '';
11 | }
12 | return window.apiUrl;
13 | }
14 |
15 | static fetch(fetchObj) {
16 | const {
17 | loadingFlag,
18 | method,
19 | successFn,
20 | errorFn
21 | } = fetchObj;
22 | let {
23 | url,
24 | data = {}
25 | } = fetchObj;
26 |
27 | if (loadingFlag) {
28 | modal.showModel({
29 | type: 'loading'
30 | });
31 | }
32 |
33 | if (window.isDebug) {
34 | setTimeout(() => {
35 | if (loadingFlag) {
36 | modal.closeModel();
37 | }
38 | const localData = AJAX.localData[url];
39 | // console.log('localData', localData);
40 | if (localData.code === 0) {
41 | successFn(localData);
42 | } else {
43 | const errorMsg = ErrorCode(localData.code) || '服务器异常,请联系运维人员!';
44 | if (errorFn) {
45 | errorFn(errorMsg);
46 | } else {
47 | AJAX.modalError(errorMsg);// ajax错误统一处理
48 | }
49 | }
50 | }, 500);
51 | return;
52 | }
53 |
54 | url = AJAX.getEnvPrefix() + url;
55 |
56 | if (method.toLowerCase() === 'get') {
57 | data = null;
58 | } else {
59 | data = JSON.stringify(data);
60 | }
61 |
62 | $.ajax({
63 | method,
64 | url,
65 | data: AJAX.isExisty(data) ? data : {},
66 | headers: {
67 | Accept: 'application/json',
68 | 'Content-Type': 'application/json'
69 | },
70 | dataType: 'json',
71 | // traditional: true,
72 | // xhrFields: {
73 | // withCredentials: false
74 | // },
75 | crossDomain: true,
76 | success(result) {
77 | if (loadingFlag) {
78 | modal.closeModel();
79 | }
80 | if (result.code === 0) {
81 | successFn(result);
82 | } else {
83 | const errorMsg = ErrorCode(result.code) || '服务器异常,请联系运维人员!';
84 | if (errorFn) {
85 | errorFn(errorMsg);
86 | } else {
87 | AJAX.modalError(errorMsg);
88 | }
89 | }
90 | },
91 | error(...args) {
92 | if (errorFn) {
93 | errorFn(args);
94 | } else {
95 | AJAX.modalError(args);
96 | }
97 | }
98 | });
99 | }
100 |
101 | static isExisty(obj) {
102 | return obj !== null;
103 | }
104 |
105 | static modalError(message) {
106 | return modal.showModel({
107 | type: 'error',
108 | errorMessage: message
109 | });
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/utils/errorcode.js:
--------------------------------------------------------------------------------
1 | const map = {
2 | 4: '服务器异常'
3 | };
4 |
5 | module.exports = function (code) {
6 | return map[code];
7 | };
8 |
--------------------------------------------------------------------------------
/src/utils/localdata.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This module is used for mock testing
3 | * add new mock data if backend haven't implement the logic yet
4 | */
5 |
6 | const localData = {
7 | 'claa/menulist': require('localData/menulist2.json'),
8 | 'claa/tablelist': require('localData/tablelist.json'),
9 | 'claa/linelist': require('localData/linelist.json'),
10 | 'claa/pielist': require('localData/pielist.json'),
11 | 'claa/positionlist': require('localData/positionlist.json')
12 | };
13 |
14 | module.exports = localData;
15 |
--------------------------------------------------------------------------------
/src/utils/mockdata.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This module is used for local testing
3 | * add new mock data if backend haven't implement the logic yet
4 | */
5 |
6 | const mock = {
7 | 'claa/menulist': require('mockData/menulist.js')
8 | };
9 |
10 | module.exports = mock;
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true,
4 | "allowJs": true
5 | }
6 | }
--------------------------------------------------------------------------------