Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f02d39ace0 | ||
|
|
4d32829445 | ||
|
|
5438e04fc5 | ||
|
|
54bbe4d70a | ||
|
|
78ece0c9fb | ||
|
|
3407f9a0c1 | ||
|
|
f1b78e8d1f | ||
|
|
df2fc9c32e | ||
|
|
cc5c319332 | ||
|
|
43ef09dfed | ||
|
|
0c95751b8d | ||
|
|
843bd1a088 | ||
|
|
a0db71e571 | ||
|
|
7fc14eddd9 | ||
|
|
7f2fdc383b | ||
|
|
ff2caecb3a | ||
|
|
d01df1ef13 | ||
|
|
cd55df3a15 | ||
|
|
ce59f3e7b2 | ||
|
|
4d722f103a | ||
|
|
c1bc6f27b1 | ||
|
|
ed88c087bf | ||
|
|
4e337caa07 | ||
|
|
ea3929b4c2 | ||
|
|
9eff4ca129 | ||
|
|
d6d94e2121 | ||
|
|
737c0236d6 | ||
|
|
69571f2916 | ||
|
|
6dffa7378c | ||
|
|
c2a7bc7106 | ||
|
|
e752750c9e | ||
|
|
32bde8f69e | ||
|
|
b5f9ef51f1 | ||
|
|
8c10be6ee6 | ||
|
|
c1e3872792 | ||
|
|
c3eef53e4d | ||
|
|
a1b9c0c33d | ||
|
|
c49b0edbe9 | ||
|
|
0fd8824ad7 | ||
|
|
973199135f | ||
|
|
43b7b21ad3 | ||
|
|
ba96ebb874 | ||
|
|
c66f086f42 | ||
|
|
07b2175e92 | ||
|
|
d245a1eabc | ||
|
|
f1e2fd3b18 | ||
|
|
a6b3dba92e | ||
|
|
9fd0abe6ea | ||
|
|
d06ee20c47 | ||
|
|
2ef1fa0367 | ||
|
|
9d459106c1 | ||
|
|
cd5a52a8fc | ||
|
|
d89320f578 | ||
|
|
df5ce2991e | ||
|
|
668c9c7dfe | ||
|
|
9bd13055c0 | ||
|
|
9f3adda59d | ||
|
|
bfa7aaecb8 | ||
|
|
9d4310d8e0 | ||
|
|
b3555b01f3 | ||
|
|
74895fbb0d | ||
|
|
5f04d19d2d | ||
|
|
0fef06e0c6 | ||
|
|
89d22451c5 | ||
|
|
fb49056c73 | ||
|
|
a3071819c4 | ||
|
|
d4e10ad5c2 | ||
|
|
59e9a1053e | ||
|
|
308fc09b33 | ||
|
|
99ec9facd3 | ||
|
|
2a96d7a5f6 | ||
|
|
195e1d17f8 | ||
|
|
580ff59b3d | ||
|
|
cfa5aae5da | ||
|
|
761125735a | ||
|
|
d1b12ff0e1 | ||
|
|
a47176a4e5 | ||
|
|
bc3d7fb39a | ||
|
|
458548150c | ||
|
|
f6e11bb464 | ||
|
|
479fc647c3 | ||
|
|
9a4c63390d | ||
|
|
42cd1221fa | ||
|
|
98b773fdc3 | ||
|
|
cd54fcbf52 | ||
|
|
bd68f8c631 | ||
|
|
3fde5aaa3c | ||
|
|
2f34de5602 | ||
|
|
2de1e81661 | ||
|
|
cea60c5683 | ||
|
|
f16e104f73 | ||
|
|
c397f552c3 | ||
|
|
11c4ac803e | ||
|
|
09b9a100de | ||
|
|
0e59df39ee | ||
|
|
30254a2ec7 | ||
|
|
cd796a6db9 | ||
|
|
6ba75de576 | ||
|
|
a3637b3a99 | ||
|
|
85ec09ec9a | ||
|
|
eb683b98e7 | ||
|
|
9221173309 | ||
|
|
55a96f41c6 | ||
|
|
ce510e79c7 | ||
|
|
3d4f2a8814 | ||
|
|
38e24edd7b | ||
|
|
841c987a1a | ||
|
|
dc26f7d25e | ||
|
|
bc754e683e | ||
|
|
c7acc8db4b | ||
|
|
057acc514f | ||
|
|
53ce7d08fb | ||
|
|
8ffd68a4e2 | ||
|
|
766653ee7a | ||
|
|
9dedcc68c3 | ||
|
|
5ea2b3c9b8 | ||
|
|
d2ac91839a | ||
|
|
bfca2746d8 | ||
|
|
b417065ac3 | ||
|
|
abdc97f087 | ||
|
|
07016c6c26 | ||
|
|
b8162060cd | ||
|
|
36fb5d293c | ||
|
|
429280a97a | ||
|
|
7ac36c779e | ||
|
|
d2e7b464e3 | ||
|
|
25839ea99f | ||
|
|
9c99581aa6 | ||
|
|
e42c21f0eb | ||
|
|
782bf214e5 | ||
|
|
a8a4496c7a | ||
|
|
f5f013ff23 | ||
|
|
8cff3af897 | ||
|
|
322d5a6d0e | ||
|
|
2ee26f51a7 | ||
|
|
e670ed2f96 | ||
|
|
601a03b5b4 | ||
|
|
00582e70ff | ||
|
|
fa4385055b | ||
|
|
01f4de55df | ||
|
|
dedd34e8e8 | ||
|
|
d1b373201e | ||
|
|
dbcc90e7ad | ||
|
|
87fce74d5b | ||
|
|
5c51679ad7 | ||
|
|
6d17b5b876 | ||
|
|
1288853112 | ||
|
|
d3e7e17789 | ||
|
|
6077d74f10 | ||
|
|
7bf031699a | ||
|
|
a6eb693636 | ||
|
|
39c377e0e2 | ||
|
|
67b90c4df0 | ||
|
|
0e2727f9c8 | ||
|
|
0cf02e7324 | ||
|
|
68c9f2b65f | ||
|
|
587b1f6b9d | ||
|
|
d94580a253 | ||
|
|
531e3c0fcc | ||
|
|
d68de7a30c | ||
|
|
45cb70f006 | ||
|
|
af85384f11 | ||
|
|
208539134f | ||
|
|
a3f41e3d64 | ||
|
|
3855c402c9 | ||
|
|
6a58d8434b | ||
|
|
d26a92ce79 | ||
|
|
0d20717c3c | ||
|
|
a0d81dcda9 | ||
|
|
4490af8553 | ||
|
|
75cc86152d | ||
|
|
3d9f263330 | ||
|
|
70b5d05f1a | ||
|
|
4da23b9133 | ||
|
|
da1c52e82b | ||
|
|
6ae39bfd55 | ||
|
|
d86f0ebd78 | ||
|
|
ecbd8bf51e | ||
|
|
0c9fabe2b4 | ||
|
|
0f27528d2f | ||
|
|
a36d44d402 | ||
|
|
37deddc911 | ||
|
|
52ee780e40 | ||
|
|
057853cfde | ||
|
|
c0222c3957 | ||
|
|
00d8fc5ea5 | ||
|
|
1e08d7adaa | ||
|
|
b2b0aa872f | ||
|
|
a2b4ee4047 | ||
|
|
c6b477c993 | ||
|
|
548d7a8ddb | ||
|
|
755c1250e5 | ||
|
|
c5ebb91980 | ||
|
|
ae12492887 | ||
|
|
28a5863701 | ||
|
|
bf65aa5478 | ||
|
|
acd3fe8337 | ||
|
|
3ad5a6cfb6 | ||
|
|
c278c8f6f8 | ||
|
|
71c75e15ff | ||
|
|
ec8db0e0fb | ||
|
|
89c58b2f98 | ||
|
|
a320c77ecb | ||
|
|
ce1d957212 | ||
|
|
7f091d7642 | ||
|
|
d8f222f312 | ||
|
|
38637ef167 | ||
|
|
fe8527e72e | ||
|
|
da64cac414 | ||
|
|
f6021cbaa4 |
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"presets": [
|
||||
"umi/babel"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"babel-plugin-module-resolver",
|
||||
{
|
||||
"alias": {
|
||||
"components": "./src/components",
|
||||
"utils": "./src/utils",
|
||||
"config": "./src/utils/config",
|
||||
"enums": "./src/utils/enums",
|
||||
"services": "./src/services",
|
||||
"models": "./src/models",
|
||||
"routes": "./src/routes",
|
||||
"themes": "./src/themes"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -1 +1,4 @@
|
||||
src/**/*-test.js
|
||||
src/public
|
||||
src/routes/chart/ECharts/theme
|
||||
src/routes/chart/highCharts/mapdata
|
||||
|
||||
@@ -1,35 +1,48 @@
|
||||
{
|
||||
"extends": "airbnb",
|
||||
"extends": "umi",
|
||||
"rules": {
|
||||
"semi": [2, "never"],
|
||||
"no-console": 0,
|
||||
"arrow-body-style": [0, "never"],
|
||||
"comma-dangle": [2, "always-multiline"],
|
||||
"global-require": 0,
|
||||
"func-names": 0,
|
||||
"prefer-const": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/extensions": 0,
|
||||
"max-len": 0,
|
||||
"react/jsx-first-prop-new-line": 0,
|
||||
"space-before-function-paren": [2, "always"],
|
||||
"no-unused-expressions": [0, {
|
||||
"allowShortCircuit": true,
|
||||
"allowTernary": true
|
||||
}],
|
||||
"arrow-body-style": [0, "never"],
|
||||
"func-names": 0,
|
||||
"prefer-const": 0,
|
||||
"no-console": 0,
|
||||
"no-extend-native": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-restricted-syntax": 0,
|
||||
"no-eval": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"no-continue": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-unused-vars": [2, { "ignoreRestSiblings": true }],
|
||||
"no-underscore-dangle": 0,
|
||||
"global-require": 0,
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 8,
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
"space-before-function-paren": [2, "always"],
|
||||
"semi": [2, "never"],
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"jsx-a11y/no-static-element-interactions": 0,
|
||||
"jsx-a11y/click-events-have-key-events": 0,
|
||||
"jsx-a11y/href-no-hash": 0,
|
||||
"jsx-a11y/anchor-is-valid": 0,
|
||||
"jsx-a11y/label-has-for": 0,
|
||||
"react/no-array-index-key": 0,
|
||||
"react/require-default-props": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
"react/no-string-refs": 0,
|
||||
"react/no-find-dom-node": 0,
|
||||
"react/prefer-stateless-function": 0,
|
||||
"react/jsx-closing-tag-location": 0,
|
||||
"react/sort-comp": 0,
|
||||
"react/jsx-no-bind": 0,
|
||||
"react/no-danger": 0,
|
||||
"react/jsx-first-prop-new-line": 0,
|
||||
"react/jsx-filename-extension": 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
> 请酌情提供细节,并保持issue精简便于查阅
|
||||
> 1. 功能需求 => 详细说明
|
||||
> 2. Bug反馈
|
||||
> 2.1 简单描述下报错
|
||||
> 2.2 你期望什么结果
|
||||
> 2.3 如何操作导致的
|
||||
> 2.4 可提供运行环境信息
|
||||
> 3. 代码求助 => 可以提,未必及时答复
|
||||
@@ -2,3 +2,15 @@ dist
|
||||
node_modules
|
||||
yarn.lock
|
||||
npm-debug.log
|
||||
|
||||
# ide
|
||||
.idea
|
||||
|
||||
# Mac General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# umi
|
||||
.umi
|
||||
.umi-production
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
const path = require('path')
|
||||
|
||||
const svgSpriteDirs = [
|
||||
path.resolve(__dirname, 'src/svg/'),
|
||||
require.resolve('antd').replace(/index\.js$/, ''),
|
||||
]
|
||||
|
||||
export default {
|
||||
entry: 'src/index.js',
|
||||
svgSpriteLoaderDirs: svgSpriteDirs,
|
||||
"theme": "./theme.config.js",
|
||||
// 接口代理示例
|
||||
// "proxy": {
|
||||
// "/api/v1": {
|
||||
// "target": "http://api.zuiidea.com",
|
||||
// "changeOrigin": true,
|
||||
// "pathRewrite": { "^/api/v1" : "/v1" }
|
||||
// },
|
||||
// "/api/v2": {
|
||||
// "target": "http://192.168.0.110",
|
||||
// "changeOrigin": true,
|
||||
// "pathRewrite": { "^/api/v2" : "/api/v2" }
|
||||
// }
|
||||
// },
|
||||
"env": {
|
||||
"development": {
|
||||
"extraBabelPlugins": [
|
||||
"dva-hmr",
|
||||
"transform-runtime",
|
||||
["import", { "libraryName": "antd", "style": true }]
|
||||
]
|
||||
},
|
||||
"production": {
|
||||
"extraBabelPlugins": [
|
||||
"transform-runtime",
|
||||
["import", { "libraryName": "antd", "style": true}]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
const mock = {}
|
||||
require('fs').readdirSync(require('path').join(__dirname + '/src/mock')).forEach(function(file) {
|
||||
Object.assign(mock, require('./src/mock/' + file))
|
||||
})
|
||||
module.exports = mock
|
||||
@@ -0,0 +1,71 @@
|
||||
import {resolve} from "path";
|
||||
|
||||
export default {
|
||||
// for query-string@6 https://github.com/sorrycc/blog/issues/68
|
||||
es5ImcompatibleVersions: true,
|
||||
plugins: [
|
||||
[
|
||||
'umi-plugin-react',
|
||||
{
|
||||
dva: true,
|
||||
antd: true,
|
||||
routes: {
|
||||
exclude: [
|
||||
/model\.(j|t)sx?$/,
|
||||
/service\.(j|t)sx?$/,
|
||||
/models\//,
|
||||
/components\//,
|
||||
/services\//,
|
||||
/chart\/Container\.js$/,
|
||||
/chart\/ECharts\/.+Component\.js$/,
|
||||
/chart\/ECharts\/.+ComPonent\.js$/,
|
||||
/chart\/ECharts\/theme\/.+\.js$/,
|
||||
/chart\/highCharts\/.+Component\.js$/,
|
||||
/chart\/highCharts\/mapdata\/.+\.js$/,
|
||||
/chart\/Recharts\/.+Component\.js$/,
|
||||
/chart\/Recharts\/Container\.js$/,
|
||||
],
|
||||
},
|
||||
dll: {
|
||||
exclude: [],
|
||||
include: ["dva", "dva/router", "dva/saga", "dva/fetch", "antd/es"],
|
||||
},
|
||||
hardSource: /* isMac */process.platform === 'darwin',
|
||||
},
|
||||
],
|
||||
],
|
||||
theme: "./theme.config.js",
|
||||
// 接口代理示例
|
||||
proxy: {
|
||||
"/api/v1/weather": {
|
||||
"target": "https://api.seniverse.com/",
|
||||
"changeOrigin": true,
|
||||
"pathRewrite": { "^/api/v1/weather": "/v3/weather" }
|
||||
},
|
||||
// "/api/v2": {
|
||||
// "target": "http://192.168.0.110",
|
||||
// "changeOrigin": true,
|
||||
// "pathRewrite": { "^/api/v2" : "/api/v2" }
|
||||
// }
|
||||
},
|
||||
alias: {
|
||||
themes: resolve(__dirname, './src/themes'),
|
||||
components: resolve(__dirname,"./src/components"),
|
||||
utils: resolve(__dirname,"./src/utils"),
|
||||
config: resolve(__dirname,"./src/utils/config"),
|
||||
enums: resolve(__dirname,"./src/utils/enums"),
|
||||
services: resolve(__dirname,"./src/services"),
|
||||
models: resolve(__dirname,"./src/models"),
|
||||
routes: resolve(__dirname,"./src/routes"),
|
||||
},
|
||||
urlLoaderExcludes: [
|
||||
/\.svg$/,
|
||||
],
|
||||
ignoreMomentLocale: true,
|
||||
chainWebpack(config) {
|
||||
config.module.rule('svg')
|
||||
.test(/\.svg$/i)
|
||||
.use('svg-sprite-loader')
|
||||
.loader(require.resolve('svg-sprite-loader'));
|
||||
},
|
||||
}
|
||||
@@ -1,108 +1,136 @@
|
||||
# Antd Admin
|
||||
|
||||
[](https://github.com/facebook/react)
|
||||
[](https://github.com/ant-design/ant-design)
|
||||
[](https://github.com/dvajs/dva)
|
||||
[](https://github.com/facebook/react)
|
||||
[](https://github.com/ant-design/ant-design)
|
||||
[](https://github.com/dvajs/dva)
|
||||
|
||||
[](https://github.com/zuiidea/antd-admin)
|
||||
[](https://github.com/zuiidea/antd-admin/pulls)
|
||||
[](http://opensource.org/licenses/MIT)
|
||||
[](http://standardjs.com)
|
||||
|
||||
演示地址 <http://zuiidea.github.io/antd-admin> \| [备用地址](http://47.92.30.98:8000)
|
||||
演示地址 <http://antd-admin.zuiidea.com>
|
||||
|
||||
## 特性
|
||||
|
||||
- 基于[react](https://github.com/facebook/react),[ant-design](https://github.com/ant-design/ant-design),[dva](https://github.com/dvajs/dva),[Mock](https://github.com/nuysoft/Mock) 企业级后台管理系统最佳实践。
|
||||
- 基于Antd UI 设计语言,提供后台管理系统常见使用场景。
|
||||
- 基于[dva](https://github.com/dvajs/dva)动态加载 Model 和路由,按需加载。
|
||||
- 使用[roadhog](https://github.com/sorrycc/roadhog)本地调试和构建,其中Mock功能实现脱离后端独立开发。
|
||||
- 浅度响应式设计。
|
||||
* 基于[react](https://github.com/facebook/react),[ant-design](https://github.com/ant-design/ant-design),[dva](https://github.com/dvajs/dva),[Mock](https://github.com/nuysoft/Mock) 企业级后台管理系统最佳实践。
|
||||
* 基于 Antd UI 设计语言,提供后台管理系统常见使用场景。
|
||||
* 基于[dva](https://github.com/dvajs/dva)动态加载 Model 和路由,按需加载。
|
||||
* 使用[umi](https://github.com/umijs/umi)本地调试和构建,其中 Mock 功能实现脱离后端独立开发。
|
||||
* 浅度响应式设计。
|
||||
|
||||
## 更新日志
|
||||
|
||||
### 4.2.2
|
||||
### 5.0.0-beta
|
||||
|
||||
`2017-06-01`
|
||||
`2018-6-20`
|
||||
|
||||
- 新增用户管理批量删除。[#320](https://github.com/zuiidea/antd-admin/issues/320)
|
||||
* 感谢@sorrycc、@xiaohuoni [PR](https://github.com/zuiidea/antd-admin/pull/770)
|
||||
|
||||
* 更新`roadhog`至`umi`
|
||||
详见 [使用 umi 改进 dva 项目开发](https://github.com/sorrycc/blog/issues/66#issuecomment-408596579) | [umi model 用法](https://github.com/umijs/umi/issues/171)
|
||||
|
||||
### 4.2.1
|
||||
### 4.3.9
|
||||
|
||||
`2017-05-12`
|
||||
`2017-12-27`
|
||||
|
||||
- 新增IconFont扩展方案,本地使用方案。[#270](https://github.com/zuiidea/antd-admin/issues/270) [Live](http://47.92.30.98:666/UIElement/iconfont)
|
||||
- 新增常见场景使用loading。 [dva-loading](https://github.com/dvajs/dva-loading)
|
||||
* 更新`antd`至`3.0.3`,以及其它主要库,并解决升级带来的兼容问题。
|
||||
* 尽可能的保持`antd`的设计语言。
|
||||
|
||||
### 4.2
|
||||
### 4.3.7
|
||||
|
||||
`2017-04-28`
|
||||
`2017-10-30`
|
||||
|
||||
- 修改user相关API使用`Restful`风格。
|
||||
- 增加user页面多条件查询。[#266](https://github.com/zuiidea/antd-admin/issues/226)
|
||||
- 修复菜单默认高亮。[#201](https://github.com/zuiidea/antd-admin/issues/201)
|
||||
* 更新`chart`,新增[ECharts](https://github.com/ecomfe/echarts),[highCharts](https://github.com/highcharts/highcharts),[Recharts](https://github.com/recharts/recharts)演示。
|
||||
|
||||
[More Change Log](https://github.com/zuiidea/antd-admin/wiki/Change-Log)
|
||||
### 4.3.5
|
||||
|
||||
`2017-09-04`
|
||||
|
||||
* 更新[dva](https://github.com/dvajs/dva)至`2.0.1`,感谢[@yangbin1994](https://github.com/yangbin1994)的[PR](https://github.com/zuiidea/antd-admin/pull/567)。
|
||||
|
||||
### 4.3.4
|
||||
|
||||
`2017-09-04`
|
||||
|
||||
* 更新[roadhog](https://github.com/sorrycc/roadhog)至`1.2.1`,修复闪屏问题。
|
||||
* 修复 build css 未压缩[#529](https://github.com/zuiidea/antd-admin/issues/529),classname 未 Hash[#477](https://github.com/zuiidea/antd-admin/issues/477)。
|
||||
* 更新登录成功使用 router 跳转[#479](https://github.com/zuiidea/antd-admin/issues/479)。
|
||||
|
||||
### 4.3.0
|
||||
|
||||
`2017-07-30`
|
||||
|
||||
* 更新[roadhog](https://github.com/sorrycc/roadhog)至`1.0.0-beta.7`,得益于`webpack@3.4`,编译速度不减。
|
||||
* 基于使用 roadhog 的 dll 插件,开发时编译耗时减半。
|
||||
* 新增打包时按项目版本号生成文件目录。[#449](https://github.com/zuiidea/antd-admin/issues/449)
|
||||
* 更新`eslint`,并适当修改了`.eslintrc`。
|
||||
|
||||
[More Change Log](https://github.com/zuiidea/antd-admin/wiki/Change-Log)
|
||||
|
||||
## 开发构建
|
||||
|
||||
### 目录结构
|
||||
### 目录结构
|
||||
|
||||
```bash
|
||||
├── /dist/ # 项目输出目录
|
||||
├── /mock/ # 数据mock
|
||||
├── /public/ # 公共文件,编译时copy至dist目录
|
||||
├── /src/ # 项目源码目录
|
||||
│ ├── /components/ # UI组件及UI相关方法
|
||||
│ │ ├── skin.less # 全局样式
|
||||
│ │ └── vars.less # 全局样式变量
|
||||
│ ├── /routes/ # 路由组件
|
||||
│ │ └── app.js # 路由入口
|
||||
│ ├── /layouts/ # 全局组件
|
||||
│ │ └── app.js # 页面入口
|
||||
│ │ └── index.js # 入口文件
|
||||
│ ├── /models/ # 数据模型
|
||||
│ ├── /pages/ # 页面组件
|
||||
│ │ └── document.ejs # html模版
|
||||
│ ├── /services/ # 数据接口
|
||||
│ ├── /themes/ # 项目样式
|
||||
│ ├── /mock/ # 数据mock
|
||||
│ │ ├── default.less # 全局样式
|
||||
│ │ └── vars.less # 全局样式变量
|
||||
│ ├── /utils/ # 工具函数
|
||||
│ │ ├── config.js # 项目常规配置
|
||||
│ │ ├── menu.js # 菜单及面包屑配置
|
||||
│ │ ├── config.js # 项目常规配置
|
||||
│ │ ├── request.js # 异步请求函数
|
||||
│ │ ├── request.js # 异步请求函数(axios)
|
||||
│ │ └── theme.js # 项目需要在js中使用到样式变量
|
||||
│ ├── route.js # 路由配置
|
||||
│ ├── index.js # 入口文件
|
||||
│ └── index.html
|
||||
├── package.json # 项目信息
|
||||
├── .eslintrc # Eslint配置
|
||||
└── .roadhogrc.js # roadhog配置
|
||||
└── .umirc.js # umi配置
|
||||
└── .umirc.mock.js # mock配置
|
||||
└── .theme.config.js # 主题less编译配置
|
||||
```
|
||||
pages中可参考 [duck 模式](https://medium.freecodecamp.org/scaling-your-redux-app-with-ducks-6115955638be)
|
||||
|
||||
文件夹命名说明:
|
||||
|
||||
- components:组件(方法)为单位以文件夹保存,文件夹名组件首字母大写(如`DataTable`),方法首字母小写(如`layer`),文件夹内主文件与文件夹同名,多文件以`index.js`导出对象(如`./src/components/Layout`)。
|
||||
- routes:页面为单位以文件夹保存,文件夹名首字母小写(特殊除外,如`UIElement`),文件夹内主文件以`index.js`导出,多文件时可建立`components`文件夹(如`./src/routes/dashboard`),如果有子路由,依次按照路由层次建立文件夹(如`./src/routes/UIElement`)。
|
||||
* components:组件(方法)为单位以文件夹保存,文件夹名组件首字母大写(如`DataTable`),方法首字母小写(如`layer`),文件夹内主文件与文件夹同名,多文件以`index.js`导出对象(如`./src/components/Layout`)。
|
||||
* routes:页面为单位以文件夹保存,文件夹名首字母小写(特殊除外,如`UIElement`),文件夹内主文件以`index.js`导出,多文件时可建立`components`文件夹(如`./src/routes/dashboard`),如果有子路由,依次按照路由层次建立文件夹(如`./src/routes/UIElement`)。
|
||||
|
||||
### 快速开始
|
||||
|
||||
克隆项目文件:
|
||||
|
||||
git clone https://github.com/zuiidea/antd-admin.git
|
||||
```bash
|
||||
git clone https://github.com/zuiidea/antd-admin.git
|
||||
```
|
||||
|
||||
进入目录安装依赖:
|
||||
|
||||
npm i 或者 yarn install
|
||||
```bash
|
||||
#开始前请确保没有安装roadhog、webpack到NPM全局目录, 国内用户推荐yarn或者cnpm
|
||||
npm i 或者 yarn install
|
||||
```
|
||||
|
||||
开发:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
打开 http://localhost:8000
|
||||
npm run start
|
||||
打开 http://localhost:8000 #端口在package.json中cross-env后加上 PORT=8000指定
|
||||
```
|
||||
|
||||
构建:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
|
||||
将会生成dist目录
|
||||
```
|
||||
[详情](https://github.com/zuiidea/antd-admin/issues/269)
|
||||
|
||||
代码检测:
|
||||
|
||||
@@ -110,20 +138,35 @@ npm run build
|
||||
npm run lint
|
||||
```
|
||||
|
||||
项目部署 [#269](https://github.com/zuiidea/antd-admin/issues/269)
|
||||
## FAQ
|
||||
|
||||
* 项目打包后如何部署? [#269](https://github.com/zuiidea/antd-admin/issues/269)
|
||||
* 如何做权限管理? [#384](https://github.com/zuiidea/antd-admin/issues/384)
|
||||
* 如何使用 mock.js 模拟接口,怎么使用线上接口? [#348](https://github.com/zuiidea/antd-admin/issues/348)
|
||||
* 如何使用 Iconfont,如何使用本地的 svg 图标? [#270](https://github.com/zuiidea/antd-admin/issues/270)
|
||||
* 怎么按版本打包,上线时不影响正在访问的用户? [#449](https://github.com/zuiidea/antd-admin/issues/449)
|
||||
* windows 处理 CRLF?[参考](http://blog.csdn.net/lysc_forever/article/details/42835203)
|
||||
|
||||
```bash
|
||||
git config --global core.autocrlf false
|
||||
```
|
||||
|
||||
## 参考
|
||||
|
||||
用户列表:<https://github.com/dvajs/dva/tree/master/examples/user-dashboard>
|
||||
|
||||
dashboard设计稿:<https://dribbble.com/shots/3108122-Dashboard-Admin> (已征得作者同意)
|
||||
dashboard 设计稿:<https://dribbble.com/shots/3108122-Dashboard-Admin> (已征得作者同意)
|
||||
|
||||
## 截屏
|
||||
|
||||
web
|
||||
|
||||

|
||||

|
||||
|
||||
移动
|
||||
|
||||

|
||||

|
||||
|
||||
效果图
|
||||
|
||||

|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 MiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 645 KiB |
@@ -1,5 +1,5 @@
|
||||
const Mock = require('mockjs')
|
||||
const config = require('../utils/config')
|
||||
const config = require('../src/utils/config')
|
||||
|
||||
const queryArray = (array, key, keyAlias = 'key') => {
|
||||
if (!(array instanceof Array)) {
|
||||
@@ -1,6 +1,8 @@
|
||||
import { color } from '../utils/theme'
|
||||
import { color } from '../src/utils/theme'
|
||||
|
||||
const Mock = require('mockjs')
|
||||
const config = require('../utils/config')
|
||||
const config = require('../src/utils/config')
|
||||
|
||||
const { apiPrefix } = config
|
||||
|
||||
const Dashboard = Mock.mock({
|
||||
@@ -4,7 +4,7 @@ const { apiPrefix } = config
|
||||
let database = [
|
||||
{
|
||||
id: '1',
|
||||
icon: 'laptop',
|
||||
icon: 'dashboard',
|
||||
name: 'Dashboard',
|
||||
route: '/dashboard',
|
||||
},
|
||||
@@ -78,7 +78,7 @@ let database = [
|
||||
id: '45',
|
||||
bpid: '4',
|
||||
mpid: '4',
|
||||
name: 'Editor',
|
||||
name: '56pxor',
|
||||
icon: 'edit',
|
||||
route: '/UIElement/editor',
|
||||
},
|
||||
@@ -93,32 +93,32 @@ let database = [
|
||||
{
|
||||
id: '5',
|
||||
bpid: '1',
|
||||
name: 'Recharts',
|
||||
name: 'Charts',
|
||||
icon: 'code-o',
|
||||
},
|
||||
{
|
||||
id: '51',
|
||||
bpid: '5',
|
||||
mpid: '5',
|
||||
name: 'LineChart',
|
||||
name: 'ECharts',
|
||||
icon: 'line-chart',
|
||||
route: '/chart/lineChart',
|
||||
route: '/chart/ECharts',
|
||||
},
|
||||
{
|
||||
id: '52',
|
||||
bpid: '5',
|
||||
mpid: '5',
|
||||
name: 'BarChart',
|
||||
name: 'highCharts',
|
||||
icon: 'bar-chart',
|
||||
route: '/chart/barChart',
|
||||
route: '/chart/highCharts',
|
||||
},
|
||||
{
|
||||
id: '53',
|
||||
bpid: '5',
|
||||
mpid: '5',
|
||||
name: 'AreaChart',
|
||||
name: 'Rechartst',
|
||||
icon: 'area-chart',
|
||||
route: '/chart/areaChart',
|
||||
route: '/chart/Recharts',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
@@ -1,6 +1,7 @@
|
||||
const qs = require('qs')
|
||||
const Mock = require('mockjs')
|
||||
const config = require('../utils/config')
|
||||
const config = require('../src/utils/config')
|
||||
|
||||
const { apiPrefix } = config
|
||||
|
||||
let usersListData = Mock.mock({
|
||||
@@ -91,7 +92,7 @@ module.exports = {
|
||||
|
||||
[`POST ${apiPrefix}/user/login`] (req, res) {
|
||||
const { username, password } = req.body
|
||||
const user = adminUsers.filter((item) => item.username === username)
|
||||
const user = adminUsers.filter(item => item.username === username)
|
||||
|
||||
if (user.length > 0 && user[0].password === password) {
|
||||
const now = new Date()
|
||||
@@ -172,9 +173,9 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
[`DELETE ${apiPrefix}/users`] (req, res) {
|
||||
[`POST ${apiPrefix}/users/delete`] (req, res) {
|
||||
const { ids } = req.body
|
||||
database = database.filter((item) => !ids.some(_ => _ === item.id))
|
||||
database = database.filter(item => !ids.some(_ => _ === item.id))
|
||||
res.status(204).end()
|
||||
},
|
||||
|
||||
@@ -204,7 +205,7 @@ module.exports = {
|
||||
const { id } = req.params
|
||||
const data = queryArray(database, id, 'id')
|
||||
if (data) {
|
||||
database = database.filter((item) => item.id !== id)
|
||||
database = database.filter(item => item.id !== id)
|
||||
res.status(204).end()
|
||||
} else {
|
||||
res.status(404).json(NOTFOUND)
|
||||
@@ -1,52 +1,63 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "antd-admin",
|
||||
"version": "5.0.0-beta",
|
||||
"dependencies": {
|
||||
"antd": "^2.11.2",
|
||||
"classnames": "^2.2.5",
|
||||
"draftjs-to-markdown": "^0.4.0",
|
||||
"dva": "^1.2.0",
|
||||
"dva-loading": "^0.2.0",
|
||||
"lodash": "^4.17.4",
|
||||
"@babel/polyfill": "^7.0.0",
|
||||
"antd": "^3.9.0",
|
||||
"axios": "^0.18.0",
|
||||
"classnames": "^2.2.6",
|
||||
"d3-shape": "^1.2.2",
|
||||
"draftjs-to-html": "^0.8.4",
|
||||
"draftjs-to-markdown": "^0.5.1",
|
||||
"dva-model-extend": "^0.1.2",
|
||||
"echarts": "^4.1.0",
|
||||
"echarts-for-react": "^2.0.14",
|
||||
"echarts-gl": "^1.1.1",
|
||||
"echarts-liquidfill": "^2.0.2",
|
||||
"highcharts-exporting": "^0.1.7",
|
||||
"highcharts-more": "^0.1.7",
|
||||
"jsonp": "^0.2.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"qs": "^6.5.0",
|
||||
"react": "^15.6.1",
|
||||
"react-countup": "^2.1.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-draft-wysiwyg": "^1.10.0",
|
||||
"react-helmet": "^5.1.3",
|
||||
"recharts": "^0.22.4"
|
||||
"path-to-regexp": "^2.4.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"qs": "^6.5.2",
|
||||
"query-string": "^6.1.0",
|
||||
"rc-tween-one": "^2.2.3",
|
||||
"react-adsense": "^0.0.6",
|
||||
"react-countup": "^4.0.0-alpha.6",
|
||||
"react-draft-wysiwyg": "^1.12.13",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-highcharts": "^16.0.2",
|
||||
"recharts": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.16.2",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-plugin-dev-expression": "^0.2.1",
|
||||
"babel-plugin-dva-hmr": "^0.3.2",
|
||||
"babel-plugin-import": "^1.1.1",
|
||||
"babel-plugin-transform-runtime": "^6.9.0",
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"babel-runtime": "^6.9.2",
|
||||
"draftjs-to-html": "^0.7.0",
|
||||
"dva-model-extend": "^0.1.1",
|
||||
"eslint": "^4.1.1",
|
||||
"eslint-config-airbnb": "^15.0.2",
|
||||
"eslint-loader": "^1.9.0",
|
||||
"eslint-plugin-import": "^2.6.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.2",
|
||||
"eslint-plugin-react": "^7.1.0",
|
||||
"jsonp": "^0.2.1",
|
||||
"less-vars-to-js": "^1.1.2",
|
||||
"babel-plugin-module-resolver": "^3.1.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"eslint": "^5.5.0",
|
||||
"eslint-config-umi": "^0.1.5",
|
||||
"eslint-plugin-flowtype": "^2.50.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.1.1",
|
||||
"eslint-plugin-react": "^7.11.1",
|
||||
"js-beautify": "^1.8.1",
|
||||
"less-vars-to-js": "^1.3.0",
|
||||
"mockjs": "^1.0.1-beta3",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"rc-tween-one": "^1.0.0",
|
||||
"redbox-react": "^1.2.10",
|
||||
"roadhog": "0.6.0"
|
||||
"svg-sprite-loader": "^3.9.2",
|
||||
"umi": "^2.0.0",
|
||||
"umi-plugin-react": "^1.0.0"
|
||||
},
|
||||
"pre-commit": [
|
||||
"lint"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "set BROWSER=none&&set HOST=0.0.0.0&&roadhog server",
|
||||
"analyze": "cross-env ANALYZE=1 umi build",
|
||||
"start": "umi dev",
|
||||
"lint": "eslint --fix --ext .js src",
|
||||
"build": "roadhog build"
|
||||
"build": "umi build",
|
||||
"test": "umi test"
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 28 Copy 5</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<linearGradient x1="62.1023273%" y1="0%" x2="108.19718%" y2="37.8635764%" id="linearGradient-1">
|
||||
<stop stop-color="#4285EB" offset="0%"></stop>
|
||||
<stop stop-color="#2EC7FF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="69.644116%" y1="0%" x2="54.0428975%" y2="108.456714%" id="linearGradient-2">
|
||||
<stop stop-color="#29CDFF" offset="0%"></stop>
|
||||
<stop stop-color="#148EFF" offset="37.8600687%"></stop>
|
||||
<stop stop-color="#0A60FF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="69.6908165%" y1="-12.9743587%" x2="16.7228981%" y2="117.391248%" id="linearGradient-3">
|
||||
<stop stop-color="#FA816E" offset="0%"></stop>
|
||||
<stop stop-color="#F74A5C" offset="41.472606%"></stop>
|
||||
<stop stop-color="#F51D2C" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-4">
|
||||
<stop stop-color="#FA8E7D" offset="0%"></stop>
|
||||
<stop stop-color="#F74A5C" offset="51.2635191%"></stop>
|
||||
<stop stop-color="#F51D2C" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="logo" transform="translate(-20.000000, -20.000000)">
|
||||
<g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)">
|
||||
<g id="Group-27-Copy-3">
|
||||
<g id="Group-25" fill-rule="nonzero">
|
||||
<g id="2">
|
||||
<path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-1)"></path>
|
||||
<path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-2)"></path>
|
||||
</g>
|
||||
<path d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z" id="Shape" fill="url(#linearGradient-3)"></path>
|
||||
</g>
|
||||
<ellipse id="Combined-Shape" fill="url(#linearGradient-4)" cx="100.519339" cy="100.436681" rx="23.6001926" ry="23.580786"></ellipse>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -1,5 +1,4 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { TweenOneGroup } from 'rc-tween-one'
|
||||
|
||||
const enterAnim = [
|
||||
@@ -40,28 +39,12 @@ const leaveAnim = [
|
||||
},
|
||||
]
|
||||
|
||||
const AnimTableBody = ({ body, page = 1, current }) => {
|
||||
if (current !== +page) {
|
||||
return body
|
||||
}
|
||||
|
||||
return (
|
||||
<TweenOneGroup
|
||||
component="tbody"
|
||||
className={body.props.className}
|
||||
enter={enterAnim}
|
||||
leave={leaveAnim}
|
||||
appear={false}
|
||||
>
|
||||
{body.props.children}
|
||||
</TweenOneGroup>
|
||||
)
|
||||
}
|
||||
|
||||
AnimTableBody.propTypes = {
|
||||
body: PropTypes.element,
|
||||
page: PropTypes.any,
|
||||
current: PropTypes.number.isRequired,
|
||||
}
|
||||
const AnimTableBody = props => (<TweenOneGroup
|
||||
component="tbody"
|
||||
{...props}
|
||||
enter={enterAnim}
|
||||
leave={leaveAnim}
|
||||
appear={false}
|
||||
/>)
|
||||
|
||||
export default AnimTableBody
|
||||
|
||||
@@ -2,18 +2,21 @@ import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Table } from 'antd'
|
||||
import { request } from 'utils'
|
||||
import lodash from 'lodash'
|
||||
import cloneDeep from 'lodash.clonedeep'
|
||||
import isEqual from 'lodash.isequal'
|
||||
import './DataTable.less'
|
||||
|
||||
class DataTable extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
const { dataSource, pagination = {
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: total => `共 ${total} 条`,
|
||||
current: 1,
|
||||
total: 100 },
|
||||
const {
|
||||
dataSource, pagination = {
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: total => `共 ${total} 条`,
|
||||
current: 1,
|
||||
total: 100,
|
||||
},
|
||||
} = props
|
||||
this.state = {
|
||||
loading: false,
|
||||
@@ -29,12 +32,12 @@ class DataTable extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
const staticNextProps = lodash.cloneDeep(nextProps)
|
||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||
const staticNextProps = cloneDeep(nextProps)
|
||||
delete staticNextProps.columns
|
||||
const { columns, ...otherProps } = this.props
|
||||
|
||||
if (!lodash.isEqual(staticNextProps, otherProps)) {
|
||||
if (!isEqual(staticNextProps, otherProps)) {
|
||||
this.props = nextProps
|
||||
this.fetch()
|
||||
}
|
||||
@@ -97,13 +100,12 @@ class DataTable extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DataTable.propTypes = {
|
||||
fetch: PropTypes.object,
|
||||
rowKey: PropTypes.string,
|
||||
pagination: React.PropTypes.oneOfType([
|
||||
React.PropTypes.bool,
|
||||
React.PropTypes.object,
|
||||
pagination: PropTypes.oneOfType([
|
||||
PropTypes.bool,
|
||||
PropTypes.object,
|
||||
]),
|
||||
columns: PropTypes.array,
|
||||
dataSource: PropTypes.array,
|
||||
|
||||
@@ -2,7 +2,9 @@ import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Dropdown, Button, Icon, Menu } from 'antd'
|
||||
|
||||
const DropOption = ({ onMenuClick, menuOptions = [], buttonStyle, dropdownProps }) => {
|
||||
const DropOption = ({
|
||||
onMenuClick, menuOptions = [], buttonStyle, dropdownProps,
|
||||
}) => {
|
||||
const menu = menuOptions.map(item => <Menu.Item key={item.key}>{item.name}</Menu.Item>)
|
||||
return (<Dropdown
|
||||
overlay={<Menu onClick={onMenuClick}>{menu}</Menu>}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Editor } from 'react-draft-wysiwyg'
|
||||
import styles from './Editor.less'
|
||||
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'
|
||||
import styles from './Editor.less'
|
||||
|
||||
|
||||
const DraftEditor = (props) => {
|
||||
|
||||
@@ -11,7 +11,7 @@ const FilterItem = ({
|
||||
<div className={styles.filterItem}>
|
||||
{labelArray.length > 0
|
||||
? <div className={styles.labelWrap}>
|
||||
{labelArray.map((item, index) => <span className="labelText" key={index}>{item}</span>)}
|
||||
{labelArray.map((item, index) => <span className="labelText" key={index}>{item}</span>)}
|
||||
</div>
|
||||
: ''}
|
||||
<div className={styles.item}>
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import './iconfont.less'
|
||||
|
||||
const Iconfont = ({ type, colorful }) => {
|
||||
const Iconfont = ({ type, colorful = false, className }) => {
|
||||
if (colorful) {
|
||||
return (<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `<svg class="colorful-icon" aria-hidden="true"><use xlink:href="#${type.startsWith('#') ? type.replace(/#/, '') : type}"></use></svg>`,
|
||||
}}
|
||||
/>)
|
||||
return (
|
||||
<svg className={classnames('colorful-icon', className)} aria-hidden="true">
|
||||
<use xlinkHref={`#${type.startsWith('#') ? type.replace(/#/, '') : type}`} />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
return <i className={`antdadmin icon-${type}`} />
|
||||
|
||||
return <i className={classnames('antdadmin', [`icon-${type}`], className)} />
|
||||
}
|
||||
|
||||
Iconfont.propTypes = {
|
||||
type: PropTypes.string,
|
||||
type: PropTypes.string.isRequired,
|
||||
colorful: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
export default Iconfont
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Breadcrumb, Icon } from 'antd'
|
||||
import { Link } from 'dva/router'
|
||||
import styles from './Bread.less'
|
||||
import { Link } from 'react-router-dom'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import { queryArray } from 'utils'
|
||||
import styles from './Layout.less'
|
||||
|
||||
const Bread = ({ menu }) => {
|
||||
const Bread = ({ menu, location }) => {
|
||||
// 匹配当前路由
|
||||
let pathArray = []
|
||||
let current
|
||||
@@ -24,6 +24,7 @@ const Bread = ({ menu }) => {
|
||||
}
|
||||
}
|
||||
|
||||
let paramMap = {}
|
||||
if (!current) {
|
||||
pathArray.push(menu[0] || {
|
||||
id: 1,
|
||||
@@ -36,20 +37,31 @@ const Bread = ({ menu }) => {
|
||||
})
|
||||
} else {
|
||||
getPathArray(current)
|
||||
|
||||
let keys = []
|
||||
let values = pathToRegexp(current.route, keys).exec(location.pathname.replace('#', ''))
|
||||
if (keys.length) {
|
||||
keys.forEach((currentValue, index) => {
|
||||
if (typeof currentValue.name !== 'string') {
|
||||
return
|
||||
}
|
||||
paramMap[currentValue.name] = values[index + 1]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 递归查找父级
|
||||
const breads = pathArray.map((item, key) => {
|
||||
const content = (
|
||||
<span>{item.icon
|
||||
? <Icon type={item.icon} style={{ marginRight: 4 }} />
|
||||
: ''}{item.name}</span>
|
||||
? <Icon type={item.icon} style={{ marginRight: 4 }} />
|
||||
: ''}{item.name}</span>
|
||||
)
|
||||
return (
|
||||
<Breadcrumb.Item key={key}>
|
||||
{((pathArray.length - 1) !== key)
|
||||
? <Link to={item.route}>
|
||||
{content}
|
||||
? <Link to={pathToRegexp.compile(item.route || '')(paramMap) || '#'}>
|
||||
{content}
|
||||
</Link>
|
||||
: content}
|
||||
</Breadcrumb.Item>
|
||||
@@ -67,6 +79,7 @@ const Bread = ({ menu }) => {
|
||||
|
||||
Bread.propTypes = {
|
||||
menu: PropTypes.array,
|
||||
location: PropTypes.object,
|
||||
}
|
||||
|
||||
export default Bread
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
@import "../../themes/vars.less";
|
||||
|
||||
.bread {
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
padding: 0 24px;
|
||||
margin-bottom: -24px;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import React from 'react'
|
||||
import styles from './Footer.less'
|
||||
import { config } from 'utils'
|
||||
|
||||
const Footer = () => <div className={styles.footer}>
|
||||
{config.footerText}
|
||||
</div>
|
||||
|
||||
export default Footer
|
||||
@@ -1,12 +0,0 @@
|
||||
@import "../../themes/vars.less";
|
||||
|
||||
.footer {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
background: #fff;
|
||||
box-shadow: @shadow-2;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Menu, Icon, Popover } from 'antd'
|
||||
import { Menu, Icon, Popover, Layout } from 'antd'
|
||||
import classnames from 'classnames'
|
||||
import styles from './Header.less'
|
||||
import Menus from './Menu'
|
||||
|
||||
const SubMenu = Menu.SubMenu
|
||||
const { SubMenu } = Menu
|
||||
|
||||
const Header = ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVisible, location, switchMenuPopover, navOpenKeys, changeOpenKeys, menu }) => {
|
||||
const Header = ({
|
||||
user, logout, switchSider, siderFold, isNavbar, menuPopoverVisible, location, switchMenuPopover, navOpenKeys, changeOpenKeys, menu,
|
||||
}) => {
|
||||
let handleClickMenu = e => e.key === 'logout' && logout()
|
||||
const menusProps = {
|
||||
menu,
|
||||
@@ -19,25 +22,32 @@ const Header = ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVis
|
||||
changeOpenKeys,
|
||||
}
|
||||
return (
|
||||
<div className={styles.header}>
|
||||
<Layout.Header className={styles.header}>
|
||||
{isNavbar
|
||||
? <Popover placement="bottomLeft" onVisibleChange={switchMenuPopover} visible={menuPopoverVisible} overlayClassName={styles.popovermenu} trigger="click" content={<Menus {...menusProps} />}>
|
||||
<div className={styles.button}>
|
||||
<Icon type="bars" />
|
||||
</div>
|
||||
</Popover>
|
||||
: <div className={styles.button} onClick={switchSider}>
|
||||
<Icon type={siderFold ? 'menu-unfold' : 'menu-fold'} />
|
||||
: <div
|
||||
className={styles.button}
|
||||
onClick={switchSider}
|
||||
>
|
||||
<Icon type={classnames({ 'menu-unfold': siderFold, 'menu-fold': !siderFold })} />
|
||||
</div>}
|
||||
<div className={styles.rightWarpper}>
|
||||
<div className={styles.button}>
|
||||
<Icon type="mail" />
|
||||
</div>
|
||||
<Menu mode="horizontal" onClick={handleClickMenu}>
|
||||
<SubMenu style={{
|
||||
float: 'right',
|
||||
}} title={< span > <Icon type="user" />
|
||||
{user.username} < /span>}
|
||||
<SubMenu
|
||||
style={{
|
||||
float: 'right',
|
||||
}}
|
||||
title={<span>
|
||||
<Icon type="user" />
|
||||
{user.username}
|
||||
</span>}
|
||||
>
|
||||
<Menu.Item key="logout">
|
||||
Sign out
|
||||
@@ -45,7 +55,7 @@ const Header = ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVis
|
||||
</SubMenu>
|
||||
</Menu>
|
||||
</div>
|
||||
</div>
|
||||
</Layout.Header>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,55 @@
|
||||
@import "../../themes/vars.less";
|
||||
@import "~themes/vars.less";
|
||||
|
||||
.header {
|
||||
:global .ant-menu-horizontal {
|
||||
& > .ant-menu-submenu {
|
||||
float: right;
|
||||
:global {
|
||||
.ant-menu-submenu-title {
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal {
|
||||
line-height: 56px;
|
||||
|
||||
& > .ant-menu-submenu:hover {
|
||||
color: #1890ff;
|
||||
background-color: rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
border-bottom: none;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal > .ant-menu-submenu {
|
||||
top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal > .ant-menu-item,
|
||||
.ant-menu-horizontal > .ant-menu-submenu {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal > .ant-menu-item-active,
|
||||
.ant-menu-horizontal > .ant-menu-item-open,
|
||||
.ant-menu-horizontal > .ant-menu-item-selected,
|
||||
.ant-menu-horizontal > .ant-menu-item:hover,
|
||||
.ant-menu-horizontal > .ant-menu-submenu-active,
|
||||
.ant-menu-horizontal > .ant-menu-submenu-open,
|
||||
.ant-menu-horizontal > .ant-menu-submenu-selected,
|
||||
.ant-menu-horizontal > .ant-menu-submenu:hover {
|
||||
border-bottom: none;
|
||||
}
|
||||
border: none;
|
||||
display: inline-block;
|
||||
}
|
||||
box-shadow: @shadow-2;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 47px;
|
||||
height: 56px;
|
||||
z-index: 9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
z-index: 999;
|
||||
|
||||
.rightWarpper {
|
||||
display: flex;
|
||||
@@ -22,9 +57,9 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 47px;
|
||||
height: 47px;
|
||||
line-height: 47px;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
@@ -47,8 +82,6 @@
|
||||
.ant-menu-inline .ant-menu-item,
|
||||
.ant-menu-vertical .ant-menu-item {
|
||||
border-right: 0;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.ant-menu-inline .ant-menu-item-selected,
|
||||
|
||||
@@ -1,292 +1,191 @@
|
||||
@import "../../themes/vars.less";
|
||||
@import "~themes/vars.less";
|
||||
|
||||
.layout {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
|
||||
&.withnavbar {
|
||||
.main {
|
||||
margin-left: 0;
|
||||
}
|
||||
:global {
|
||||
.ant-layout-header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&.fold {
|
||||
.sider {
|
||||
width: 42px;
|
||||
.ant-layout-sider {
|
||||
transition: all 0.3s;
|
||||
|
||||
.logo {
|
||||
img {
|
||||
width: 28px;
|
||||
margin: 6px 7px;
|
||||
}
|
||||
.ant-menu-root {
|
||||
height: ~"calc(100vh - 144px)";
|
||||
overflow-x: hidden;
|
||||
border-right: none;
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-menu-root {
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
|
||||
& > .ant-menu-item {
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
|
||||
.anticon {
|
||||
font-size: 14px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& > .ant-menu-submenu {
|
||||
& > .ant-menu-submenu-title {
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
|
||||
.anticon {
|
||||
font-size: 14px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-left: 42px;
|
||||
}
|
||||
}
|
||||
|
||||
.sider {
|
||||
width: 224px;
|
||||
background: #3e3e3e;
|
||||
position: absolute;
|
||||
overflow: visible;
|
||||
padding-bottom: 24px;
|
||||
height: 100vh;
|
||||
transition: @transition-ease-out;
|
||||
box-shadow: @shadow-1;
|
||||
color: #999;
|
||||
|
||||
&.light {
|
||||
background: #fff;
|
||||
|
||||
.switchtheme {
|
||||
background: #fff;
|
||||
border-top: solid 1px #f8f8f8;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
text-align: center;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
cursor: pointer;
|
||||
margin: 28px 0;
|
||||
transition: @transition-ease-out;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
margin-right: 8px;
|
||||
transition: @transition-ease-out;
|
||||
}
|
||||
|
||||
span {
|
||||
vertical-align: text-bottom;
|
||||
font-size: 16px;
|
||||
text-transform: uppercase;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
transition: @transition-ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
.switchtheme {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 48px;
|
||||
background-color: @dark-half;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 16px 0 24px;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:global {
|
||||
.anticon {
|
||||
min-width: 14px;
|
||||
margin-right: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-menu-dark,
|
||||
.ant-menu-dark .ant-menu-sub {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ant-menu-root {
|
||||
height: ~"calc(100vh - 144px)";
|
||||
overflow-x: hidden;
|
||||
border-right: none;
|
||||
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-menu-vertical {
|
||||
.ant-menu-sub {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.ant-menu-submenu-active {
|
||||
.ant-menu-sub {
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu {
|
||||
transition: @transition-ease-out;
|
||||
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu-title {
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
}
|
||||
.ant-menu {
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu-title {
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-left: 224px;
|
||||
overflow: auto;
|
||||
height: 100vh;
|
||||
transition: @transition-ease-out;
|
||||
.ant-layout-content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
:global {
|
||||
.content-inner {
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
box-shadow: @shadow-1;
|
||||
min-height: e("calc(100vh - 184px)");
|
||||
}
|
||||
.ant-layout-footer {
|
||||
text-align: center;
|
||||
padding: 0 24px;
|
||||
height: 40px;
|
||||
font-size: 12px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.ant-back-top {
|
||||
right: 50px;
|
||||
}
|
||||
|
||||
.ant-switch.ant-switch-large {
|
||||
line-height: 24px;
|
||||
height: 26px;
|
||||
|
||||
&:after,
|
||||
&:before {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 24px;
|
||||
}
|
||||
.flex-vertical-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: e("calc(100vh - 184px)");
|
||||
position: relative;
|
||||
.ant-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.logo {
|
||||
height: 96px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span {
|
||||
vertical-align: text-bottom;
|
||||
font-size: 16px;
|
||||
text-transform: uppercase;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
color: @primary-color;
|
||||
white-space: nowrap;
|
||||
:local {
|
||||
animation: fadeLeftIn 500ms linear;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global .ant-menu-dark {
|
||||
color: #999;
|
||||
background-color: #3e3e3e;
|
||||
.sidemenu {
|
||||
:global{
|
||||
.ant-menu-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-submenu-title:hover,
|
||||
.ant-menu-submenu:hover {
|
||||
color: @primary-color;
|
||||
.switchtheme {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 48px;
|
||||
background-color: #fff;
|
||||
border-top: solid 1px #f8f8f8;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
overflow: hidden;
|
||||
z-index: 9;
|
||||
transition: all 0.3s;
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ant-menu-sub {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ant-menu-submenu-selected {
|
||||
color: @primary-color;
|
||||
|
||||
&:not(.ant-menu-submenu-open) {
|
||||
background-color: @dark-half;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item,
|
||||
.ant-menu-submenu-title {
|
||||
& > a {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&:hover > a {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-menu-inline {
|
||||
.ant-menu-item-selected {
|
||||
background-color: @dark-half;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
color: @primary-color;
|
||||
background-color: @dark-half;
|
||||
|
||||
& > a {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @dark-half;
|
||||
:global {
|
||||
.anticon {
|
||||
min-width: 14px;
|
||||
margin-right: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.spin {
|
||||
:global .ant-spin-container {
|
||||
height: 100vh;
|
||||
.bread {
|
||||
margin-bottom: 24px;
|
||||
|
||||
:global {
|
||||
.ant-breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.switchtheme {
|
||||
background-color: #000d18;
|
||||
border-color: #001629;
|
||||
}
|
||||
}
|
||||
|
||||
.light {
|
||||
:global {
|
||||
.ant-layout-sider {
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.layout {
|
||||
.main {
|
||||
.container {
|
||||
margin: 12px;
|
||||
}
|
||||
.bread {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.bread {
|
||||
padding: 0 12px;
|
||||
}
|
||||
:global {
|
||||
.ant-layout-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: e("calc(100vh - 160px)");
|
||||
}
|
||||
|
||||
:global {
|
||||
.content-inner {
|
||||
padding: 12px;
|
||||
min-height: e("calc(100vh - 160px)");
|
||||
}
|
||||
}
|
||||
.ant-back-top {
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeLeftIn {
|
||||
0% {
|
||||
transform: translateX(5px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Menu, Icon } from 'antd'
|
||||
import { Link } from 'dva/router'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { arrayToTree, queryArray } from 'utils'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import styles from './Layout.less'
|
||||
|
||||
const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOpenKeys, menu }) => {
|
||||
const { SubMenu } = Menu
|
||||
let openKeysFlag = false
|
||||
|
||||
const Menus = ({
|
||||
siderFold, darkTheme, navOpenKeys, changeOpenKeys, menu, location,
|
||||
}) => {
|
||||
// 生成树状
|
||||
const menuTree = arrayToTree(menu.filter(_ => _.mpid !== '-1'), 'id', 'mpid')
|
||||
const levelMap = {}
|
||||
|
||||
// 递归生成菜单
|
||||
const getMenus = (menuTreeN, siderFoldN) => {
|
||||
return menuTreeN.map(item => {
|
||||
return menuTreeN.map((item) => {
|
||||
if (item.children) {
|
||||
if (item.mpid) {
|
||||
levelMap[item.id] = item.mpid
|
||||
}
|
||||
return (
|
||||
<Menu.SubMenu
|
||||
<SubMenu
|
||||
key={item.id}
|
||||
title={<span>
|
||||
{item.icon && <Icon type={item.icon} />}
|
||||
@@ -26,14 +32,14 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
|
||||
</span>}
|
||||
>
|
||||
{getMenus(item.children, siderFoldN)}
|
||||
</Menu.SubMenu>
|
||||
</SubMenu>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Menu.Item key={item.id}>
|
||||
<Link to={item.route}>
|
||||
<Link to={item.route || '#'} style={siderFoldN ? { width: 10 } : {}}>
|
||||
{item.icon && <Icon type={item.icon} />}
|
||||
{(!siderFoldN || !menuTree.includes(item)) && item.name}
|
||||
{item.name}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
)
|
||||
@@ -60,6 +66,7 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
|
||||
}
|
||||
|
||||
const onOpenChange = (openKeys) => {
|
||||
if (navOpenKeys.length) changeOpenKeys([]), openKeysFlag = true
|
||||
const latestOpenKey = openKeys.find(key => !navOpenKeys.includes(key))
|
||||
const latestCloseKey = navOpenKeys.find(key => !openKeys.includes(key))
|
||||
let nextOpenKeys = []
|
||||
@@ -83,6 +90,7 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
|
||||
let defaultSelectedKeys
|
||||
for (let item of menu) {
|
||||
if (item.route && pathToRegexp(item.route).exec(location.pathname)) {
|
||||
if (!navOpenKeys.length && item.mpid && !openKeysFlag) changeOpenKeys([String(item.mpid)])
|
||||
currentMenu = item
|
||||
break
|
||||
}
|
||||
@@ -91,8 +99,12 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
|
||||
let result = [String(current[id])]
|
||||
const getPath = (item) => {
|
||||
if (item && item[pid]) {
|
||||
result.unshift(String(item[pid]))
|
||||
getPath(queryArray(array, item[pid], id))
|
||||
if (item[pid] === '-1') {
|
||||
result.unshift(String(item['bpid']))
|
||||
} else {
|
||||
result.unshift(String(item[pid]))
|
||||
getPath(queryArray(array, item[pid], id))
|
||||
}
|
||||
}
|
||||
}
|
||||
getPath(current)
|
||||
@@ -102,13 +114,17 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
|
||||
defaultSelectedKeys = getPathArray(menu, currentMenu, 'mpid', 'id')
|
||||
}
|
||||
|
||||
if (!defaultSelectedKeys) {
|
||||
defaultSelectedKeys = ['1']
|
||||
}
|
||||
|
||||
return (
|
||||
<Menu
|
||||
{...menuProps}
|
||||
mode={siderFold ? 'vertical' : 'inline'}
|
||||
theme={darkTheme ? 'dark' : 'light'}
|
||||
onClick={handleClickNavMenu}
|
||||
defaultSelectedKeys={defaultSelectedKeys}
|
||||
selectedKeys={defaultSelectedKeys}
|
||||
className={styles.sidemenu}
|
||||
>
|
||||
{menuItems}
|
||||
</Menu>
|
||||
@@ -119,10 +135,9 @@ Menus.propTypes = {
|
||||
menu: PropTypes.array,
|
||||
siderFold: PropTypes.bool,
|
||||
darkTheme: PropTypes.bool,
|
||||
isNavbar: PropTypes.bool,
|
||||
handleClickNavMenu: PropTypes.func,
|
||||
navOpenKeys: PropTypes.array,
|
||||
changeOpenKeys: PropTypes.func,
|
||||
location: PropTypes.object,
|
||||
}
|
||||
|
||||
export default Menus
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Icon, Switch } from 'antd'
|
||||
import styles from './Layout.less'
|
||||
import { config } from 'utils'
|
||||
import styles from './Layout.less'
|
||||
import Menus from './Menu'
|
||||
|
||||
const Sider = ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, changeOpenKeys, menu }) => {
|
||||
const Sider = ({
|
||||
siderFold, darkTheme, location, changeTheme, navOpenKeys, changeOpenKeys, menu,
|
||||
}) => {
|
||||
const menusProps = {
|
||||
menu,
|
||||
siderFold,
|
||||
@@ -17,7 +19,7 @@ const Sider = ({ siderFold, darkTheme, location, changeTheme, navOpenKeys, chang
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.logo}>
|
||||
<img alt={'logo'} src={config.logo} />
|
||||
<img alt="logo" src={config.logo} />
|
||||
{siderFold ? '' : <span>{config.name}</span>}
|
||||
</div>
|
||||
<Menus {...menusProps} />
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
@import "../../themes/vars.less";
|
||||
@@ -2,7 +2,6 @@ import Header from './Header'
|
||||
import Menu from './Menu'
|
||||
import Bread from './Bread'
|
||||
import Sider from './Sider'
|
||||
import Footer from './Footer'
|
||||
import styles from './Layout.less'
|
||||
|
||||
export { Header, Menu, Bread, Sider, Footer, styles }
|
||||
export { Header, Menu, Bread, Sider, styles }
|
||||
|
||||
@@ -3,8 +3,12 @@ import PropTypes from 'prop-types'
|
||||
import classNames from 'classnames'
|
||||
import styles from './Loader.less'
|
||||
|
||||
const Loader = ({ spinning }) => {
|
||||
return (<div className={classNames(styles.loader, { [styles.hidden]: !spinning })}>
|
||||
const Loader = ({ spinning, fullScreen }) => {
|
||||
return (<div className={classNames(styles.loader, {
|
||||
[styles.hidden]: !spinning,
|
||||
[styles.fullScreen]: fullScreen,
|
||||
})}
|
||||
>
|
||||
<div className={styles.warpper}>
|
||||
<div className={styles.inner} />
|
||||
<div className={styles.text} >LOADING</div>
|
||||
@@ -15,6 +19,7 @@ const Loader = ({ spinning }) => {
|
||||
|
||||
Loader.propTypes = {
|
||||
spinning: PropTypes.bool,
|
||||
fullScreen: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default Loader
|
||||
|
||||
@@ -1,64 +1,68 @@
|
||||
.loader {
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 1;
|
||||
text-align: center;
|
||||
|
||||
.warpper {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.inner {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin: 0 auto;
|
||||
text-indent: -12345px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.7);
|
||||
border-radius: 50%;
|
||||
z-index: 100001;
|
||||
|
||||
:local {
|
||||
animation: spinner 600ms infinite linear;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 100px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
letter-spacing: 4px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
transition: opacity 1s ease 0.5s, z-index 0.1s ease 1.5s;
|
||||
}
|
||||
}
|
||||
@keyframes spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.loader {
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 1;
|
||||
text-align: center;
|
||||
|
||||
&.fullScreen {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.warpper {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.inner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto;
|
||||
text-indent: -12345px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.7);
|
||||
border-radius: 50%;
|
||||
z-index: 100001;
|
||||
|
||||
:local {
|
||||
animation: spinner 600ms infinite linear;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 100px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
letter-spacing: 4px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
transition: opacity 1s ease 0.5s, z-index 0.1s ease 1.5s;
|
||||
}
|
||||
}
|
||||
@keyframes spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import Loader from '../Loader'
|
||||
import styles from './Page.less'
|
||||
|
||||
export default class Page extends Component {
|
||||
render () {
|
||||
const {
|
||||
className, children, loading = false, inner = false,
|
||||
} = this.props
|
||||
const loadingStyle = {
|
||||
height: 'calc(100vh - 184px)',
|
||||
overflow: 'hidden',
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={classnames(className, {
|
||||
[styles.contentInner]: inner,
|
||||
})}
|
||||
style={loading ? loadingStyle : null}
|
||||
>
|
||||
{loading ? <Loader spinning /> : ''}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Page.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
loading: PropTypes.bool,
|
||||
inner: PropTypes.bool,
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
@import "~themes/vars.less";
|
||||
|
||||
.contentInner{
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
box-shadow: @shadow-1;
|
||||
min-height: ~"calc(100vh - 198px)";
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.contentInner {
|
||||
padding: 12px;
|
||||
min-height: ~"calc(100vh - 160px)";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "Page",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"main": "./Page.js"
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ReactDOM from 'react-dom'
|
||||
import styles from './Search.less'
|
||||
import { Input, Select, Button, Icon } from 'antd'
|
||||
import styles from './Search.less'
|
||||
|
||||
class Search extends React.Component {
|
||||
state = {
|
||||
@@ -18,13 +18,13 @@ class Search extends React.Component {
|
||||
}
|
||||
if (this.props.onSearch) this.props.onSearch(data)
|
||||
}
|
||||
handleInputChange = e => {
|
||||
handleInputChange = (e) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
clearVisible: e.target.value !== '',
|
||||
})
|
||||
}
|
||||
handleSelectChange = value => {
|
||||
handleSelectChange = (value) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
selectValue: value,
|
||||
@@ -38,7 +38,9 @@ class Search extends React.Component {
|
||||
this.handleSearch()
|
||||
}
|
||||
render () {
|
||||
const { size, select, selectOptions, selectProps, style, keyword } = this.props
|
||||
const {
|
||||
size, select, selectOptions, selectProps, style, keyword,
|
||||
} = this.props
|
||||
const { clearVisible } = this.state
|
||||
return (
|
||||
<Input.Group compact size={size} className={styles.search} style={style}>
|
||||
|
||||
@@ -1,55 +1,54 @@
|
||||
.no-highlight() {
|
||||
border-color: #e5e5e5;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
:global {
|
||||
.anticon-cross {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
right: 84px;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
line-height: 18px;
|
||||
border-radius: 50%!important;
|
||||
background-color: rgba(0, 0, 0, .16);
|
||||
top: 7px;
|
||||
// opacity:
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
|
||||
&.ant-select-focused .ant-select-selection,
|
||||
&.ant-select-open .ant-select-selection,
|
||||
.ant-select-selection:active,
|
||||
.ant-select-selection:focus,
|
||||
.ant-select-selection:hover {
|
||||
.no-highlight();
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
&:focus,
|
||||
&:hover {
|
||||
.no-highlight();
|
||||
}
|
||||
flex-shrink: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.no-highlight() {
|
||||
border-color: #e5e5e5;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex !important;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
:global {
|
||||
.anticon-cross {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
right: 84px;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
line-height: 18px;
|
||||
border-radius: 50%!important;
|
||||
background-color: rgba(0, 0, 0, .16);
|
||||
top: 7px;
|
||||
}
|
||||
|
||||
.ant-select {
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
|
||||
&.ant-select-focused .ant-select-selection,
|
||||
&.ant-select-open .ant-select-selection,
|
||||
.ant-select-selection:active,
|
||||
.ant-select-selection:focus,
|
||||
.ant-select-selection:hover {
|
||||
.no-highlight();
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
&:focus,
|
||||
&:hover {
|
||||
.no-highlight();
|
||||
}
|
||||
flex-shrink: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import Search from './Search'
|
||||
import Editor from './Editor'
|
||||
import FilterItem from './FilterItem'
|
||||
import Loader from './Loader'
|
||||
import * as Layout from './Layout/index.js'
|
||||
import * as MyLayout from './Layout/index.js'
|
||||
import Page from './Page'
|
||||
|
||||
import layer from './layer'
|
||||
|
||||
export {
|
||||
Layout,
|
||||
MyLayout,
|
||||
DataTable,
|
||||
DropOption,
|
||||
Iconfont,
|
||||
@@ -19,4 +20,5 @@ export {
|
||||
FilterItem,
|
||||
Loader,
|
||||
layer,
|
||||
}
|
||||
Page,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
/* global document */
|
||||
import { Modal, message } from 'antd'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import classnames from 'classnames'
|
||||
import styles from './layer.less'
|
||||
const { info, success, error, warning, confirm } = Modal
|
||||
|
||||
const {
|
||||
info, success, error, warning, confirm,
|
||||
} = Modal
|
||||
|
||||
const layer = {
|
||||
prefixCls: 'ant-layer',
|
||||
@@ -15,7 +19,7 @@ const layer = {
|
||||
confirm,
|
||||
}
|
||||
|
||||
layer.close = (index) => new Promise((resolve, reject) => {
|
||||
layer.close = index => new Promise((resolve, reject) => {
|
||||
const { prefixCls } = layer
|
||||
let div = document.getElementById(`${prefixCls}-reference-${index}`)
|
||||
if (index === undefined) {
|
||||
@@ -41,7 +45,7 @@ layer.closeAll = () => {
|
||||
let i = 0
|
||||
while (i < references.length) {
|
||||
layer.close()
|
||||
i++
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,32 +54,32 @@ layer.open = (config) => {
|
||||
const { content, ...modalProps } = props
|
||||
const { className, wrapClassName = '', verticalCenter = true } = modalProps
|
||||
const { prefixCls } = layer
|
||||
const index = layer.index++
|
||||
layer.index += 1
|
||||
const { index } = layer
|
||||
let div = document.createElement('div')
|
||||
div.id = `${prefixCls}-reference-${index}`
|
||||
div.className = `${prefixCls}-reference`
|
||||
document.body.appendChild(div)
|
||||
|
||||
ReactDOM.render(
|
||||
<Modal
|
||||
visible
|
||||
title="Title"
|
||||
transitionName="zoom"
|
||||
maskTransitionName="fade"
|
||||
onCancel={() => {
|
||||
ReactDOM.render(<Modal
|
||||
visible
|
||||
title="Title"
|
||||
transitionName="zoom"
|
||||
maskTransitionName="fade"
|
||||
onCancel={() => {
|
||||
layer.close(index)
|
||||
}}
|
||||
onOk={() => {
|
||||
onOk={() => {
|
||||
layer.close(index)
|
||||
}}
|
||||
{...modalProps}
|
||||
wrapClassName={classnames({ [styles.verticalCenter]: verticalCenter, [wrapClassName]: true })}
|
||||
className={classnames(prefixCls, className, [`${prefixCls}-${index}`])}
|
||||
>
|
||||
<div className={`${prefixCls}-body-wrapper`} style={{ maxHeight: document.body.clientHeight - 256 }}>
|
||||
{content}
|
||||
</div>
|
||||
</Modal>, div)
|
||||
{...modalProps}
|
||||
wrapClassName={classnames({ [styles.verticalCenter]: verticalCenter, [wrapClassName]: true })}
|
||||
className={classnames(prefixCls, className, [`${prefixCls}-${index}`])}
|
||||
>
|
||||
<div className={`${prefixCls}-body-wrapper`} style={{ maxHeight: document.body.clientHeight - 256 }}>
|
||||
{content}
|
||||
</div>
|
||||
</Modal>, div)
|
||||
|
||||
return index
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import '@babel/polyfill'
|
||||
@@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<!--[if lte IE 10]>
|
||||
<script
|
||||
src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,media-match/2.0.2/media.match.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var __oldConsoleError = window.console.error.bind(console)
|
||||
window.console.error = function(message, b) {
|
||||
if (message === "Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead." ||
|
||||
"Warning: A Component: React.createClass is deprecated and will be removed in version 16. Use plain JavaScript classes instead. If you're not yet ready to migrate, create-react-class is available on npm as a drop-in replacement.") {
|
||||
return false
|
||||
}
|
||||
__oldConsoleError(message)
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
<script src="/index.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,26 +0,0 @@
|
||||
import './index.html'
|
||||
import 'babel-polyfill'
|
||||
import dva from 'dva'
|
||||
import createLoading from 'dva-loading'
|
||||
import { browserHistory } from 'dva/router'
|
||||
import { message } from 'antd'
|
||||
|
||||
// 1. Initialize
|
||||
const app = dva({
|
||||
...createLoading({
|
||||
effects: true,
|
||||
}),
|
||||
history: browserHistory,
|
||||
onError (error) {
|
||||
message.error(error.message)
|
||||
},
|
||||
})
|
||||
|
||||
// 2. Model
|
||||
app.model(require('./models/app'))
|
||||
|
||||
// 3. Router
|
||||
app.router(require('./router'))
|
||||
|
||||
// 4. Start
|
||||
app.start('#root')
|
||||
@@ -1,27 +1,37 @@
|
||||
/* global window */
|
||||
/* global document */
|
||||
import React from 'react'
|
||||
import NProgress from 'nprogress'
|
||||
import PropTypes from 'prop-types'
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
import { connect } from 'dva'
|
||||
import { Layout, Loader } from 'components'
|
||||
import { Loader, MyLayout } from 'components'
|
||||
import { BackTop, Layout } from 'antd'
|
||||
import { classnames, config } from 'utils'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { withRouter } from 'dva/router'
|
||||
import Error from '../pages/404'
|
||||
import '../themes/index.less'
|
||||
import './app.less'
|
||||
import NProgress from 'nprogress'
|
||||
import Error from './error'
|
||||
|
||||
const { Content, Footer, Sider } = Layout
|
||||
const { Header, Bread, styles } = MyLayout
|
||||
const { prefix, openPages } = config
|
||||
|
||||
const { Header, Bread, Footer, Sider, styles } = Layout
|
||||
let lastHref
|
||||
|
||||
const App = ({ children, dispatch, app, loading, location }) => {
|
||||
const { user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys, menu, permissions } = app
|
||||
const App = ({
|
||||
children, dispatch, app, loading, location,
|
||||
}) => {
|
||||
const {
|
||||
user, siderFold, darkTheme, isNavbar, menuPopoverVisible, navOpenKeys, menu, permissions,
|
||||
} = app
|
||||
let { pathname } = location
|
||||
pathname = pathname.startsWith('/') ? pathname : `/${pathname}`
|
||||
const { iconFontJS, iconFontCSS, logo } = config
|
||||
const current = menu.filter(item => pathToRegexp(item.route || '').exec(pathname))
|
||||
const hasPermission = current.length ? permissions.visit.includes(current[0].id) : false
|
||||
const href = window.location.href
|
||||
const { href } = window.location
|
||||
|
||||
if (lastHref !== href) {
|
||||
NProgress.start()
|
||||
@@ -34,6 +44,7 @@ const App = ({ children, dispatch, app, loading, location }) => {
|
||||
const headerProps = {
|
||||
menu,
|
||||
user,
|
||||
location,
|
||||
siderFold,
|
||||
isNavbar,
|
||||
menuPopoverVisible,
|
||||
@@ -54,6 +65,7 @@ const App = ({ children, dispatch, app, loading, location }) => {
|
||||
|
||||
const siderProps = {
|
||||
menu,
|
||||
location,
|
||||
siderFold,
|
||||
darkTheme,
|
||||
navOpenKeys,
|
||||
@@ -61,44 +73,54 @@ const App = ({ children, dispatch, app, loading, location }) => {
|
||||
dispatch({ type: 'app/switchTheme' })
|
||||
},
|
||||
changeOpenKeys (openKeys) {
|
||||
localStorage.setItem(`${prefix}navOpenKeys`, JSON.stringify(openKeys))
|
||||
window.localStorage.setItem(`${prefix}navOpenKeys`, JSON.stringify(openKeys))
|
||||
dispatch({ type: 'app/handleNavOpenKeys', payload: { navOpenKeys: openKeys } })
|
||||
},
|
||||
}
|
||||
|
||||
const breadProps = {
|
||||
menu,
|
||||
location,
|
||||
}
|
||||
|
||||
if (openPages && openPages.includes(pathname)) {
|
||||
return (<div>
|
||||
<Loader spinning={loading.effects['app/query']} />
|
||||
<Loader fullScreen spinning={loading.effects['app/query']} />
|
||||
{children}
|
||||
</div>)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Loader fullScreen spinning={loading.effects['app/query']} />
|
||||
<Helmet>
|
||||
<title>ANTD ADMIN</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href={logo} type="image/x-icon" />
|
||||
{iconFontJS && <script src={iconFontJS}></script>}
|
||||
{iconFontJS && <script src={iconFontJS} />}
|
||||
{iconFontCSS && <link rel="stylesheet" href={iconFontCSS} />}
|
||||
</Helmet>
|
||||
<div className={classnames(styles.layout, { [styles.fold]: isNavbar ? false : siderFold }, { [styles.withnavbar]: isNavbar })}>
|
||||
{!isNavbar ? <aside className={classnames(styles.sider, { [styles.light]: !darkTheme })}>
|
||||
<Sider {...siderProps} />
|
||||
</aside> : ''}
|
||||
<div className={styles.main}>
|
||||
|
||||
<Layout className={classnames({ [styles.dark]: darkTheme, [styles.light]: !darkTheme })}>
|
||||
{!isNavbar && <Sider
|
||||
trigger={null}
|
||||
collapsible
|
||||
collapsed={siderFold}
|
||||
>
|
||||
{siderProps.menu.length === 0 ? null : <MyLayout.Sider {...siderProps} />}
|
||||
</Sider>}
|
||||
<Layout style={{ height: '100vh', overflow: 'scroll' }} id="mainContainer">
|
||||
<BackTop target={() => document.getElementById('mainContainer')} />
|
||||
<Header {...headerProps} />
|
||||
<Bread {...breadProps} />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
{hasPermission ? children : <Error />}
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
<Content>
|
||||
<Bread {...breadProps} />
|
||||
{hasPermission ? children : <Error />}
|
||||
</Content>
|
||||
<Footer >
|
||||
{config.footerText}
|
||||
</Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -111,4 +133,4 @@ App.propTypes = {
|
||||
loading: PropTypes.object,
|
||||
}
|
||||
|
||||
export default connect(({ app, loading }) => ({ app, loading }))(App)
|
||||
export default withRouter(connect(({ app, loading }) => ({ app, loading }))(App))
|
||||
@@ -1,4 +1,4 @@
|
||||
@import "../themes/vars.less";
|
||||
@import "~themes/vars.less";
|
||||
|
||||
:global {
|
||||
#nprogress {
|
||||
@@ -0,0 +1,14 @@
|
||||
import { LocaleProvider } from 'antd'
|
||||
import enUS from 'antd/lib/locale-provider/en_US'
|
||||
import withRouter from 'umi/withRouter'
|
||||
import App from './app'
|
||||
|
||||
export default withRouter((props) => {
|
||||
return (
|
||||
<LocaleProvider locale={enUS}>
|
||||
<App>
|
||||
{ props.children }
|
||||
</App>
|
||||
</LocaleProvider>
|
||||
)
|
||||
})
|
||||
@@ -1,9 +1,16 @@
|
||||
import { query, logout } from '../services/app'
|
||||
import * as menusService from '../services/menus'
|
||||
/* global window */
|
||||
/* global document */
|
||||
/* global location */
|
||||
/* eslint no-restricted-globals: ["error", "event"] */
|
||||
|
||||
import { routerRedux } from 'dva/router'
|
||||
import { parse } from 'qs'
|
||||
import config from 'config'
|
||||
import { EnumRoleType } from 'enums'
|
||||
import { query, logout } from 'services/app'
|
||||
import * as menusService from 'services/menus'
|
||||
import queryString from 'query-string'
|
||||
|
||||
const { prefix } = config
|
||||
|
||||
export default {
|
||||
@@ -22,13 +29,27 @@ export default {
|
||||
},
|
||||
],
|
||||
menuPopoverVisible: false,
|
||||
siderFold: localStorage.getItem(`${prefix}siderFold`) === 'true',
|
||||
darkTheme: localStorage.getItem(`${prefix}darkTheme`) === 'true',
|
||||
siderFold: window.localStorage.getItem(`${prefix}siderFold`) === 'true',
|
||||
darkTheme: window.localStorage.getItem(`${prefix}darkTheme`) === 'true',
|
||||
isNavbar: document.body.clientWidth < 769,
|
||||
navOpenKeys: JSON.parse(localStorage.getItem(`${prefix}navOpenKeys`)) || [],
|
||||
navOpenKeys: JSON.parse(window.localStorage.getItem(`${prefix}navOpenKeys`)) || [],
|
||||
locationPathname: '',
|
||||
locationQuery: {},
|
||||
},
|
||||
subscriptions: {
|
||||
|
||||
setupHistory ({ dispatch, history }) {
|
||||
history.listen((location) => {
|
||||
dispatch({
|
||||
type: 'updateState',
|
||||
payload: {
|
||||
locationPathname: location.pathname,
|
||||
locationQuery: location.query,
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
setup ({ dispatch }) {
|
||||
dispatch({ type: 'query' })
|
||||
let tid
|
||||
@@ -43,58 +64,73 @@ export default {
|
||||
},
|
||||
effects: {
|
||||
|
||||
*query ({
|
||||
* query ({
|
||||
payload,
|
||||
}, { call, put }) {
|
||||
}, { call, put, select }) {
|
||||
const { success, user } = yield call(query, payload)
|
||||
const { locationPathname } = yield select(_ => _.app)
|
||||
if (success && user) {
|
||||
const { list } = yield call(menusService.query)
|
||||
const { permissions } = user
|
||||
let menu = list
|
||||
if (permissions.role === EnumRoleType.ADMIN || permissions.role === EnumRoleType.DEVELOPER) {
|
||||
permissions.visit = list.map(item => item.id)
|
||||
} else {
|
||||
menu = list.filter((item) => {
|
||||
const cases = [
|
||||
permissions.visit.includes(item.id),
|
||||
item.mpid ? permissions.visit.includes(item.mpid) || item.mpid === '-1' : true,
|
||||
item.bpid ? permissions.visit.includes(item.bpid) : true,
|
||||
]
|
||||
return cases.every(_ => _)
|
||||
})
|
||||
}
|
||||
yield put({
|
||||
type: 'updateState',
|
||||
payload: {
|
||||
user,
|
||||
permissions,
|
||||
menu: list.filter(item => {
|
||||
if (permissions.role === EnumRoleType.ADMIN || permissions.role === EnumRoleType.DEVELOPER) {
|
||||
return true
|
||||
}
|
||||
const cases = [
|
||||
permissions.visit.includes(item.id),
|
||||
item.mpid ? permissions.visit.includes(item.mpid) || item.mpid === '-1' : true,
|
||||
item.bpid ? permissions.visit.includes(item.bpid) : true,
|
||||
]
|
||||
return cases.every(_ => _)
|
||||
}
|
||||
),
|
||||
menu,
|
||||
},
|
||||
})
|
||||
if (location.pathname === '/login') {
|
||||
yield put(routerRedux.push('/dashboard'))
|
||||
}
|
||||
} else {
|
||||
if (config.openPages && config.openPages.indexOf(location.pathname) < 0) {
|
||||
let from = location.pathname
|
||||
window.location = `${location.origin}/login?from=${from}`
|
||||
yield put(routerRedux.push({
|
||||
pathname: '/dashboard',
|
||||
}))
|
||||
}
|
||||
} else if (config.openPages && config.openPages.indexOf(locationPathname) < 0) {
|
||||
yield put(routerRedux.push({
|
||||
pathname: '/login',
|
||||
search: queryString.stringify({
|
||||
from: locationPathname,
|
||||
}),
|
||||
}))
|
||||
}
|
||||
},
|
||||
|
||||
*logout ({
|
||||
* logout ({
|
||||
payload,
|
||||
}, { call, put }) {
|
||||
const data = yield call(logout, parse(payload))
|
||||
if (data.success) {
|
||||
yield put({ type: 'updateState', payload: {
|
||||
user: {},
|
||||
permissions: { visit: [] },
|
||||
menu: [{
|
||||
id: 1,
|
||||
icon: 'laptop',
|
||||
name: 'Dashboard',
|
||||
router: '/dashboard',
|
||||
}],
|
||||
}})
|
||||
yield put({ type: 'query' })
|
||||
} else {
|
||||
throw (data)
|
||||
}
|
||||
},
|
||||
|
||||
*changeNavbar ({
|
||||
payload,
|
||||
}, { put, select }) {
|
||||
const { app } = yield(select(_ => _))
|
||||
* changeNavbar (action, { put, select }) {
|
||||
const { app } = yield (select(_ => _))
|
||||
const isNavbar = document.body.clientWidth < 769
|
||||
if (isNavbar !== app.isNavbar) {
|
||||
yield put({ type: 'handleNavbar', payload: isNavbar })
|
||||
@@ -111,7 +147,7 @@ export default {
|
||||
},
|
||||
|
||||
switchSider (state) {
|
||||
localStorage.setItem(`${prefix}siderFold`, !state.siderFold)
|
||||
window.localStorage.setItem(`${prefix}siderFold`, !state.siderFold)
|
||||
return {
|
||||
...state,
|
||||
siderFold: !state.siderFold,
|
||||
@@ -119,7 +155,7 @@ export default {
|
||||
},
|
||||
|
||||
switchTheme (state) {
|
||||
localStorage.setItem(`${prefix}darkTheme`, !state.darkTheme)
|
||||
window.localStorage.setItem(`${prefix}darkTheme`, !state.darkTheme)
|
||||
return {
|
||||
...state,
|
||||
darkTheme: !state.darkTheme,
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
import { myCity, queryWeather, query } from '../services/dashboard'
|
||||
import { parse } from 'qs'
|
||||
|
||||
// zuimei 摘自 http://www.zuimeitianqi.com/res/js/index.js
|
||||
let zuimei = {
|
||||
parseActualData (actual) {
|
||||
let weather = {
|
||||
icon: `http://www.zuimeitianqi.com/res/icon/${zuimei.getIconName(actual.wea, 'big')}`,
|
||||
name: zuimei.getWeatherName(actual.wea),
|
||||
temperature: actual.tmp,
|
||||
dateTime: new Date(actual.PTm).format('MM-dd hh:mm'),
|
||||
}
|
||||
return weather
|
||||
},
|
||||
|
||||
getIconName (wea, flg) {
|
||||
let myDate = new Date()
|
||||
let hour = myDate.getHours()
|
||||
let num = 0
|
||||
if (wea.indexOf('/') !== -1) {
|
||||
let weas = wea.split('/')
|
||||
if (hour < 12) {
|
||||
num = zuimei.replaceIcon(weas[0])
|
||||
if (num < 6) {
|
||||
num = `${num}_${flg}_night.png`
|
||||
} else {
|
||||
num = `${num}_${flg}.png`
|
||||
}
|
||||
} else if (hour >= 12) {
|
||||
num = zuimei.replaceIcon(weas[1])
|
||||
if (hour >= 18) {
|
||||
num = `${num}_${flg}_night.png`
|
||||
} else {
|
||||
num = `${num}_${flg}.png`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((hour >= 18 && hour <= 23) || (hour >= 0 && hour <= 6)) {
|
||||
num = `${num}_${flg}_night.png`
|
||||
} else {
|
||||
num = `${num}_${flg}.png`
|
||||
}
|
||||
}
|
||||
|
||||
return num
|
||||
},
|
||||
|
||||
replaceIcon (num) {
|
||||
if (num === 21) {
|
||||
num = 7
|
||||
} else if (num === 22) {
|
||||
num = 8
|
||||
} else if (num === 10 || num === 11 || num === 12 || num === 23 || num === 24 || num === 25) {
|
||||
num = 9
|
||||
} else if (num === 13 || num === 15 || num === 26 || num === 27 || num === 34) {
|
||||
num = 14
|
||||
} else if (num === 17 || num === 28) {
|
||||
num = 16
|
||||
} else if (num === 35) {
|
||||
num = 18
|
||||
} else if (num === 31 || num === 32 || num === 33) {
|
||||
num = 20
|
||||
} else if (num === 30) {
|
||||
num = 29
|
||||
}
|
||||
|
||||
return num
|
||||
},
|
||||
|
||||
getWeatherName (wea) {
|
||||
let name = ''
|
||||
if (wea.indexOf('/') !== -1) {
|
||||
let weas = wea.split('/')
|
||||
name = `${zuimei.getWeatherByCode(weas[0])}转${zuimei.getWeatherByCode(weas[1])}`
|
||||
} else {
|
||||
name = zuimei.getWeatherByCode(wea)
|
||||
}
|
||||
|
||||
return name
|
||||
},
|
||||
|
||||
getWeatherByCode (number) {
|
||||
let wea = ''
|
||||
let num = Number(number)
|
||||
if (num === 0) {
|
||||
wea = '晴'
|
||||
} else if (num === 1) {
|
||||
wea = '多云'
|
||||
} else if (num === 2) {
|
||||
wea = '阴'
|
||||
} else if (num === 3) {
|
||||
wea = '阵雨'
|
||||
} else if (num === 4) {
|
||||
wea = '雷阵雨'
|
||||
} else if (num === 5) {
|
||||
wea = '雷阵雨并伴有冰雹'
|
||||
} else if (num === 6) {
|
||||
wea = '雨夹雪'
|
||||
} else if (num === 7) {
|
||||
wea = '小雨'
|
||||
} else if (num === 8) {
|
||||
wea = '中雨'
|
||||
} else if (num === 9) {
|
||||
wea = '大雨'
|
||||
} else if (num === 10) {
|
||||
wea = '暴雨'
|
||||
} else if (num === 11) {
|
||||
wea = '大暴雨'
|
||||
} else if (num === 12) {
|
||||
wea = '特大暴雨'
|
||||
} else if (num === 13) {
|
||||
wea = '阵雪'
|
||||
} else if (num === 14) {
|
||||
wea = '小雪'
|
||||
} else if (num === 15) {
|
||||
wea = '中雪'
|
||||
} else if (num === 16) {
|
||||
wea = '大雪'
|
||||
} else if (num === 17) {
|
||||
wea = '暴雪'
|
||||
} else if (num === 18) {
|
||||
wea = '雾'
|
||||
} else if (num === 19) {
|
||||
wea = '冻雨'
|
||||
} else if (num === 20) {
|
||||
wea = '沙尘暴'
|
||||
} else if (num === 21) {
|
||||
wea = '小雨-中雨'
|
||||
} else if (num === 22) {
|
||||
wea = '中雨-大雨'
|
||||
} else if (num === 23) {
|
||||
wea = '大雨-暴雨'
|
||||
} else if (num === 24) {
|
||||
wea = '暴雨-大暴雨'
|
||||
} else if (num === 25) {
|
||||
wea = '大暴雨-特大暴雨'
|
||||
} else if (num === 26) {
|
||||
wea = '小雪-中雪'
|
||||
} else if (num === 27) {
|
||||
wea = '中雪-大雪'
|
||||
} else if (num === 28) {
|
||||
wea = '大雪-暴雪'
|
||||
} else if (num === 29) {
|
||||
wea = '浮沉'
|
||||
} else if (num === 30) {
|
||||
wea = '扬沙'
|
||||
} else if (num === 31) {
|
||||
wea = '强沙尘暴'
|
||||
} else if (num === 32) {
|
||||
wea = '飑'
|
||||
} else if (num === 33) {
|
||||
wea = '龙卷风'
|
||||
} else if (num === 34) {
|
||||
wea = '若高吹雪'
|
||||
} else if (num === 35) {
|
||||
wea = '轻雾'
|
||||
} else if (num === 53) {
|
||||
wea = '霾'
|
||||
} else if (num === 99) {
|
||||
wea = '未知'
|
||||
}
|
||||
|
||||
return wea
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
namespace: 'dashboard',
|
||||
state: {
|
||||
weather: {
|
||||
city: '成都',
|
||||
temperature: '5',
|
||||
name: '晴',
|
||||
icon: 'http://www.zuimeitianqi.com/res/icon/0_big.png',
|
||||
dateTime: new Date().format('MM-dd hh:mm'),
|
||||
},
|
||||
sales: [],
|
||||
quote: {
|
||||
avatar: 'http://img.hb.aicdn.com/bc442cf0cc6f7940dcc567e465048d1a8d634493198c4-sPx5BR_fw236',
|
||||
},
|
||||
numbers: [],
|
||||
recentSales: [],
|
||||
comments: [],
|
||||
completed: [],
|
||||
browser: [],
|
||||
cpu: {},
|
||||
user: {
|
||||
avatar: 'http://img.hb.aicdn.com/bc442cf0cc6f7940dcc567e465048d1a8d634493198c4-sPx5BR_fw236',
|
||||
},
|
||||
},
|
||||
subscriptions: {
|
||||
setup ({ dispatch }) {
|
||||
dispatch({ type: 'query' })
|
||||
dispatch({ type: 'queryWeather' })
|
||||
},
|
||||
},
|
||||
effects: {
|
||||
*query ({
|
||||
payload,
|
||||
}, { call, put }) {
|
||||
const data = yield call(query, parse(payload))
|
||||
yield put({ type: 'queryWeather', payload: { ...data } })
|
||||
},
|
||||
*queryWeather ({
|
||||
payload,
|
||||
}, { call, put }) {
|
||||
const myCityResult = yield call(myCity, { flg: 0 })
|
||||
const result = yield call(queryWeather, { cityCode: myCityResult.selectCityCode })
|
||||
const weather = zuimei.parseActualData(result.data.actual)
|
||||
weather.city = myCityResult.selectCityName
|
||||
yield put({ type: 'queryWeatherSuccess', payload: {
|
||||
weather,
|
||||
} })
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
queryWeatherSuccess (state, action) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
}
|
||||
},
|
||||
queryWeather (state, action) {
|
||||
return {
|
||||
...state,
|
||||
...action.payload,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { login } from '../services/login'
|
||||
import { routerRedux } from 'dva/router'
|
||||
import { queryURL } from 'utils'
|
||||
|
||||
export default {
|
||||
namespace: 'login',
|
||||
state: {
|
||||
loginLoading: false,
|
||||
},
|
||||
|
||||
effects: {
|
||||
*login ({
|
||||
payload,
|
||||
}, { put, call }) {
|
||||
yield put({ type: 'showLoginLoading' })
|
||||
const data = yield call(login, payload)
|
||||
yield put({ type: 'hideLoginLoading' })
|
||||
if (data.success) {
|
||||
const from = queryURL('from')
|
||||
yield put({ type: 'app/query' })
|
||||
if (from) {
|
||||
yield put(routerRedux.push(from))
|
||||
} else {
|
||||
yield put(routerRedux.push('/dashboard'))
|
||||
}
|
||||
} else {
|
||||
throw data
|
||||
}
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
showLoginLoading (state) {
|
||||
return {
|
||||
...state,
|
||||
loginLoading: true,
|
||||
}
|
||||
},
|
||||
hideLoginLoading (state) {
|
||||
return {
|
||||
...state,
|
||||
loginLoading: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
import React from 'react'
|
||||
import { Icon } from 'antd'
|
||||
import styles from './index.less'
|
||||
import { Page } from 'components'
|
||||
import styles from './404.less'
|
||||
|
||||
const Error = () => <div className="content-inner">
|
||||
const Error = () => (<Page inner>
|
||||
<div className={styles.error}>
|
||||
<Icon type="frown-o" />
|
||||
<h1>404 Not Found</h1>
|
||||
</div>
|
||||
</div>
|
||||
</Page>)
|
||||
|
||||
export default Error
|
||||
@@ -5,9 +5,11 @@ import { Table, Row, Col, Card, Select } from 'antd'
|
||||
class DataTablePage extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.state = { filterCase: {
|
||||
gender: '',
|
||||
} }
|
||||
this.state = {
|
||||
filterCase: {
|
||||
gender: '',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
handleSelectChange = (gender) => {
|
||||
@@ -20,7 +22,11 @@ class DataTablePage extends React.Component {
|
||||
render () {
|
||||
const { filterCase } = this.state
|
||||
const staticDataTableProps = {
|
||||
dataSource: [{ key: '1', name: 'John Brown', age: 24, address: 'New York' }, { key: '2', name: 'Jim Green', age: 23, address: 'London' }],
|
||||
dataSource: [{
|
||||
key: '1', name: 'John Brown', age: 24, address: 'New York',
|
||||
}, {
|
||||
key: '2', name: 'Jim Green', age: 23, address: 'London',
|
||||
}],
|
||||
columns: [{ title: 'name', dataIndex: 'name' }, { title: 'Age', dataIndex: 'age' }, { title: 'Address', dataIndex: 'address' }],
|
||||
pagination: false,
|
||||
}
|
||||
@@ -35,11 +41,11 @@ class DataTablePage extends React.Component {
|
||||
dataKey: 'results',
|
||||
},
|
||||
columns: [
|
||||
{ title: 'Name', dataIndex: 'name', render: (text) => `${text.first} ${text.last}` },
|
||||
{ title: 'Name', dataIndex: 'name', render: text => `${text.first} ${text.last}` },
|
||||
{ title: 'Phone', dataIndex: 'phone' },
|
||||
{ title: 'Gender', dataIndex: 'gender' },
|
||||
],
|
||||
rowKey: 'registered',
|
||||
rowKey: 'email',
|
||||
}
|
||||
|
||||
const caseChangeDataTableProps = {
|
||||
@@ -53,11 +59,11 @@ class DataTablePage extends React.Component {
|
||||
dataKey: 'results',
|
||||
},
|
||||
columns: [
|
||||
{ title: 'Name', dataIndex: 'name', render: (text) => `${text.first} ${text.last}` },
|
||||
{ title: 'Name', dataIndex: 'name', render: text => `${text.first} ${text.last}` },
|
||||
{ title: 'Phone', dataIndex: 'phone' },
|
||||
{ title: 'Gender', dataIndex: 'gender' },
|
||||
],
|
||||
rowKey: 'registered',
|
||||
rowKey: 'email',
|
||||
}
|
||||
|
||||
return (<div className="content-inner">
|
||||
@@ -125,6 +131,7 @@ class DataTablePage extends React.Component {
|
||||
desciption: '远程获取数据的参数',
|
||||
type: 'Object',
|
||||
default: '后面有空加上',
|
||||
key: 'basetable'
|
||||
}]}
|
||||
/>
|
||||
</Col>
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react'
|
||||
import { DropOption } from 'components'
|
||||
import { DropOption, Page } from 'components'
|
||||
import { Table, Row, Col, Card, message } from 'antd'
|
||||
|
||||
const DropOptionPage = () => <div className="content-inner">
|
||||
const DropOptionPage = () => (<Page inner>
|
||||
<Row gutter={32}>
|
||||
<Col lg={8} md={12}>
|
||||
<Card title="默认">
|
||||
@@ -90,6 +90,6 @@ const DropOptionPage = () => <div className="content-inner">
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Page>)
|
||||
|
||||
export default DropOptionPage
|
||||
@@ -4,7 +4,6 @@ import { convertToRaw } from 'draft-js'
|
||||
import { Row, Col, Card } from 'antd'
|
||||
import draftToHtml from 'draftjs-to-html'
|
||||
import draftToMarkdown from 'draftjs-to-markdown'
|
||||
// https://github.com/jpuri/react-draft-wysiwyg/blob/master/docs/src/components/Demo/index.js
|
||||
|
||||
export default class EditorPage extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react'
|
||||
import { Iconfont } from 'components'
|
||||
import { Iconfont, Page } from 'components'
|
||||
import { Table, Row, Col, Icon } from 'antd'
|
||||
import styles from './index.less'
|
||||
import './emoji.js'
|
||||
import './emoji'
|
||||
|
||||
const colorfulIcons = ['boluo', 'baixiangguo', 'chengzi', 'boluomei', 'caomei', 'dayouzi', 'chelizi', 'fanqie', 'hamigua', 'ganlan',
|
||||
'juzi', 'heimei', 'huolongguo', 'hongmei', 'lizi', 'lanmei', 'mangguo', 'mihoutao', 'longyan', 'mugua', 'lizi1', 'ningmeng']
|
||||
@@ -24,35 +24,35 @@ const localRequireSVGIcons = [
|
||||
require('../../../svg/cute/think.svg'),
|
||||
]
|
||||
|
||||
const IcoPage = () => <div className="content-inner">
|
||||
const IcoPage = () => (<Page inner>
|
||||
<Icon type="star-oo" />
|
||||
<h2 style={{ margin: '16px 0' }}>Colorful Icon</h2>
|
||||
<ul className={styles.list}>
|
||||
{colorfulIcons.map(item => <li key={item}>
|
||||
{colorfulIcons.map(item => (<li key={item}>
|
||||
<Iconfont className={styles.icon} colorful type={item} />
|
||||
<span className={styles.name}>{item}</span>
|
||||
</li>)}
|
||||
</li>))}
|
||||
</ul>
|
||||
<h2 style={{ margin: '16px 0' }}>Flat Icon</h2>
|
||||
<ul className={styles.list}>
|
||||
{flatIcons.map(item => <li key={item}>
|
||||
{flatIcons.map(item => (<li key={item}>
|
||||
<Iconfont className={styles.icon} type={item} />
|
||||
<span className={styles.name}>{item}</span>
|
||||
</li>)}
|
||||
</li>))}
|
||||
</ul>
|
||||
<h2 style={{ margin: '16px 0' }}>Local SVG</h2>
|
||||
<ul className={styles.list}>
|
||||
{localSVGIcons.map(item => <li key={item}>
|
||||
{localSVGIcons.map(item => (<li key={item}>
|
||||
<Iconfont className={styles.icon} colorful type={item} />
|
||||
<span className={styles.name}>{item}</span>
|
||||
</li>)}
|
||||
</li>))}
|
||||
</ul>
|
||||
<h2 style={{ margin: '16px 0' }}>Local Require SVG</h2>
|
||||
<ul className={styles.list}>
|
||||
{localRequireSVGIcons.map(item => <li key={item}>
|
||||
<Iconfont className={styles.icon} colorful type={item} />
|
||||
<span className={styles.name}>{item}</span>
|
||||
</li>)}
|
||||
{localRequireSVGIcons.map(item => (<li key={item.default.id}>
|
||||
<Iconfont className={styles.icon} colorful type={item.default.id} />
|
||||
<span className={styles.name}>{item.default.id}</span>
|
||||
</li>))}
|
||||
</ul>
|
||||
<h2 style={{ margin: '16px 0' }}>API</h2>
|
||||
<Row>
|
||||
@@ -100,17 +100,17 @@ const IcoPage = () => <div className="content-inner">
|
||||
<div style={{ margin: '16px 0', lineHeight: 2 }}>
|
||||
<p>
|
||||
<a href="http://www.iconfont.cn/user/detail?uid=116813">何阿酥</a> colorful fruit icon
|
||||
<a href="http://www.iconfont.cn/collections/detail?cid=4014" target="_blank"> http://www.iconfont.cn/collections/detail?cid=4014</a>
|
||||
<a href="http://www.iconfont.cn/collections/detail?cid=4014" target="_blank" rel="noopener noreferrer"> http://www.iconfont.cn/collections/detail?cid=4014</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://www.iconfont.cn/user/detail?uid=496384">ColinXu</a> colorful 'tsundere' emoji icon
|
||||
<a href="http://www.iconfont.cn/collections/detail?cid=4116" target="_blank"> http://www.iconfont.cn/collections/detail?cid=4116</a>
|
||||
<a href="http://www.iconfont.cn/user/detail?uid=496384">ColinXu</a> colorful 'tsundere' emoji icon
|
||||
<a href="http://www.iconfont.cn/collections/detail?cid=4116" target="_blank" rel="noopener noreferrer"> http://www.iconfont.cn/collections/detail?cid=4116</a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="http://www.iconfont.cn/user/detail?uid=116813">咕噜小莫莫</a> colorful 'face cute' emoji icon
|
||||
<a href="http://www.iconfont.cn/collections/detail?cid=4268" target="_blank"> http://www.iconfont.cn/collections/detail?cid=4268</a>
|
||||
<a href="http://www.iconfont.cn/user/detail?uid=116813">咕噜小莫莫</a> colorful 'face cute' emoji icon
|
||||
<a href="http://www.iconfont.cn/collections/detail?cid=4268" target="_blank" rel="noopener noreferrer"> http://www.iconfont.cn/collections/detail?cid=4268</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Page>)
|
||||
|
||||
export default IcoPage
|
||||
@@ -1,53 +1,47 @@
|
||||
.list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
li {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
height: 100px;
|
||||
transition: all 0.5s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
box-sizing: border-box;
|
||||
border: solid 1px transparent;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
border: solid 1px #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
:global {
|
||||
.colorful-icon {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
.antdadmin {
|
||||
font-size: 32px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
.list {
|
||||
li {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.list {
|
||||
li {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
li {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
height: 100px;
|
||||
transition: all 0.5s ease;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
box-sizing: border-box;
|
||||
border: solid 1px transparent;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
border: solid 1px #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 32px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
.list {
|
||||
li {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.list {
|
||||
li {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ const IcoPage = () => {
|
||||
<h2 style={{ margin: '16px 0' }}>API</h2>
|
||||
<div style={{ margin: '16px 0' }}>
|
||||
<h2 style={{ margin: '4px 0' }}>layer.open(config)</h2>
|
||||
config对象与<a href="https://ant.design/components/modal-cn/#API" target="_blank">Modal</a>的参数基本一致,config属性如下。
|
||||
config对象与<a href="https://ant.design/components/modal-cn/#API" target="_blank" rel="noopener noreferrer">Modal</a>的参数基本一致,config属性如下。
|
||||
注意:1.visible属性一般不需要设置;2.afterClose无效,layer.close()可代替;3.layer.open()返回一个唯一的layer Id
|
||||
</div>
|
||||
<Row>
|
||||
@@ -69,7 +69,7 @@ const IcoPage = () => {
|
||||
},
|
||||
{
|
||||
props: 'confirmLoading',
|
||||
desciption: '确定按钮 loading ',
|
||||
desciption: '确定按钮 loading',
|
||||
type: 'boolean',
|
||||
default: '无',
|
||||
},
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react'
|
||||
import { Search } from 'components'
|
||||
import { Search, Page } from 'components'
|
||||
import { Table, Row, Col, Card } from 'antd'
|
||||
|
||||
const SearchPage = () => <div className="content-inner">
|
||||
const SearchPage = () => (<Page inner>
|
||||
<Row gutter={32}>
|
||||
<Col lg={8} md={12}>
|
||||
<Card title="默认">
|
||||
@@ -27,7 +27,7 @@ const SearchPage = () => <div className="content-inner">
|
||||
</Col>
|
||||
<Col lg={8} md={12}>
|
||||
<Card title="大小">
|
||||
<Search size="large" style={{ marginBottom: 16 }} />
|
||||
<Search style={{ marginBottom: 16 }} />
|
||||
<Search size="small" />
|
||||
</Card>
|
||||
</Col>
|
||||
@@ -93,6 +93,6 @@ const SearchPage = () => <div className="content-inner">
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Page>)
|
||||
|
||||
export default SearchPage
|
||||
@@ -1,16 +1,18 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import styles from './Container.less'
|
||||
import { ResponsiveContainer } from 'recharts'
|
||||
import styles from './Container.less'
|
||||
|
||||
const Container = ({ children, ratio = 5 / 2, minHeight = 250, maxHeight = 350 }) => <div className={styles.container} style={{ minHeight, maxHeight }}>
|
||||
<div style={{ marginTop: `${100 / ratio}%` || '100%' }}></div>
|
||||
const Container = ({
|
||||
children, ratio = 5 / 2, minHeight = 250, maxHeight = 350,
|
||||
}) => (<div className={styles.container} style={{ minHeight, maxHeight }}>
|
||||
<div style={{ marginTop: `${100 / ratio}%` || '100%' }} />
|
||||
<div className={styles.content} style={{ minHeight, maxHeight }}>
|
||||
<ResponsiveContainer>
|
||||
{children}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
|
||||
Container.propTypes = {
|
||||
children: PropTypes.element.isRequired,
|
||||
@@ -0,0 +1,321 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
require('echarts/map/js/china.js')
|
||||
|
||||
const AirportCoordComponent = () => {
|
||||
let geoCoordMap = {
|
||||
上海: [121.4648, 31.2891],
|
||||
东莞: [113.8953, 22.901],
|
||||
东营: [118.7073, 37.5513],
|
||||
中山: [113.4229, 22.478],
|
||||
临汾: [111.4783, 36.1615],
|
||||
临沂: [118.3118, 35.2936],
|
||||
丹东: [124.541, 40.4242],
|
||||
丽水: [119.5642, 28.1854],
|
||||
乌鲁木齐: [87.9236, 43.5883],
|
||||
佛山: [112.8955, 23.1097],
|
||||
保定: [115.0488, 39.0948],
|
||||
兰州: [103.5901, 36.3043],
|
||||
包头: [110.3467, 41.4899],
|
||||
北京: [116.4551, 40.2539],
|
||||
北海: [109.314, 21.6211],
|
||||
南京: [118.8062, 31.9208],
|
||||
南宁: [108.479, 23.1152],
|
||||
南昌: [116.0046, 28.6633],
|
||||
南通: [121.1023, 32.1625],
|
||||
厦门: [118.1689, 24.6478],
|
||||
台州: [121.1353, 28.6688],
|
||||
合肥: [117.29, 32.0581],
|
||||
呼和浩特: [111.4124, 40.4901],
|
||||
咸阳: [108.4131, 34.8706],
|
||||
哈尔滨: [127.9688, 45.368],
|
||||
唐山: [118.4766, 39.6826],
|
||||
嘉兴: [120.9155, 30.6354],
|
||||
大同: [113.7854, 39.8035],
|
||||
大连: [122.2229, 39.4409],
|
||||
天津: [117.4219, 39.4189],
|
||||
太原: [112.3352, 37.9413],
|
||||
威海: [121.9482, 37.1393],
|
||||
宁波: [121.5967, 29.6466],
|
||||
宝鸡: [107.1826, 34.3433],
|
||||
宿迁: [118.5535, 33.7775],
|
||||
常州: [119.4543, 31.5582],
|
||||
广州: [113.5107, 23.2196],
|
||||
廊坊: [116.521, 39.0509],
|
||||
延安: [109.1052, 36.4252],
|
||||
张家口: [115.1477, 40.8527],
|
||||
徐州: [117.5208, 34.3268],
|
||||
德州: [116.6858, 37.2107],
|
||||
惠州: [114.6204, 23.1647],
|
||||
成都: [103.9526, 30.7617],
|
||||
扬州: [119.4653, 32.8162],
|
||||
承德: [117.5757, 41.4075],
|
||||
拉萨: [91.1865, 30.1465],
|
||||
无锡: [120.3442, 31.5527],
|
||||
日照: [119.2786, 35.5023],
|
||||
昆明: [102.9199, 25.4663],
|
||||
杭州: [119.5313, 29.8773],
|
||||
枣庄: [117.323, 34.8926],
|
||||
柳州: [109.3799, 24.9774],
|
||||
株洲: [113.5327, 27.0319],
|
||||
武汉: [114.3896, 30.6628],
|
||||
汕头: [117.1692, 23.3405],
|
||||
江门: [112.6318, 22.1484],
|
||||
沈阳: [123.1238, 42.1216],
|
||||
沧州: [116.8286, 38.2104],
|
||||
河源: [114.917, 23.9722],
|
||||
泉州: [118.3228, 25.1147],
|
||||
泰安: [117.0264, 36.0516],
|
||||
泰州: [120.0586, 32.5525],
|
||||
济南: [117.1582, 36.8701],
|
||||
济宁: [116.8286, 35.3375],
|
||||
海口: [110.3893, 19.8516],
|
||||
淄博: [118.0371, 36.6064],
|
||||
淮安: [118.927, 33.4039],
|
||||
深圳: [114.5435, 22.5439],
|
||||
清远: [112.9175, 24.3292],
|
||||
温州: [120.498, 27.8119],
|
||||
渭南: [109.7864, 35.0299],
|
||||
湖州: [119.8608, 30.7782],
|
||||
湘潭: [112.5439, 27.7075],
|
||||
滨州: [117.8174, 37.4963],
|
||||
潍坊: [119.0918, 36.524],
|
||||
烟台: [120.7397, 37.5128],
|
||||
玉溪: [101.9312, 23.8898],
|
||||
珠海: [113.7305, 22.1155],
|
||||
盐城: [120.2234, 33.5577],
|
||||
盘锦: [121.9482, 41.0449],
|
||||
石家庄: [114.4995, 38.1006],
|
||||
福州: [119.4543, 25.9222],
|
||||
秦皇岛: [119.2126, 40.0232],
|
||||
绍兴: [120.564, 29.7565],
|
||||
聊城: [115.9167, 36.4032],
|
||||
肇庆: [112.1265, 23.5822],
|
||||
舟山: [122.2559, 30.2234],
|
||||
苏州: [120.6519, 31.3989],
|
||||
莱芜: [117.6526, 36.2714],
|
||||
菏泽: [115.6201, 35.2057],
|
||||
营口: [122.4316, 40.4297],
|
||||
葫芦岛: [120.1575, 40.578],
|
||||
衡水: [115.8838, 37.7161],
|
||||
衢州: [118.6853, 28.8666],
|
||||
西宁: [101.4038, 36.8207],
|
||||
西安: [109.1162, 34.2004],
|
||||
贵阳: [106.6992, 26.7682],
|
||||
连云港: [119.1248, 34.552],
|
||||
邢台: [114.8071, 37.2821],
|
||||
邯郸: [114.4775, 36.535],
|
||||
郑州: [113.4668, 34.6234],
|
||||
鄂尔多斯: [108.9734, 39.2487],
|
||||
重庆: [107.7539, 30.1904],
|
||||
金华: [120.0037, 29.1028],
|
||||
铜川: [109.0393, 35.1947],
|
||||
银川: [106.3586, 38.1775],
|
||||
镇江: [119.4763, 31.9702],
|
||||
长春: [125.8154, 44.2584],
|
||||
长沙: [113.0823, 28.2568],
|
||||
长治: [112.8625, 36.4746],
|
||||
阳泉: [113.4778, 38.0951],
|
||||
青岛: [120.4651, 36.3373],
|
||||
韶关: [113.7964, 24.7028],
|
||||
}
|
||||
|
||||
let BJData = [
|
||||
[{ name: '北京' }, { name: '上海', value: 95 }],
|
||||
[{ name: '北京' }, { name: '广州', value: 90 }],
|
||||
[{ name: '北京' }, { name: '大连', value: 80 }],
|
||||
[{ name: '北京' }, { name: '南宁', value: 70 }],
|
||||
[{ name: '北京' }, { name: '南昌', value: 60 }],
|
||||
[{ name: '北京' }, { name: '拉萨', value: 50 }],
|
||||
[{ name: '北京' }, { name: '长春', value: 40 }],
|
||||
[{ name: '北京' }, { name: '包头', value: 30 }],
|
||||
[{ name: '北京' }, { name: '重庆', value: 20 }],
|
||||
[{ name: '北京' }, { name: '常州', value: 10 }],
|
||||
]
|
||||
|
||||
let SHData = [
|
||||
[{ name: '上海' }, { name: '包头', value: 95 }],
|
||||
[{ name: '上海' }, { name: '昆明', value: 90 }],
|
||||
[{ name: '上海' }, { name: '广州', value: 80 }],
|
||||
[{ name: '上海' }, { name: '郑州', value: 70 }],
|
||||
[{ name: '上海' }, { name: '长春', value: 60 }],
|
||||
[{ name: '上海' }, { name: '重庆', value: 50 }],
|
||||
[{ name: '上海' }, { name: '长沙', value: 40 }],
|
||||
[{ name: '上海' }, { name: '北京', value: 30 }],
|
||||
[{ name: '上海' }, { name: '丹东', value: 20 }],
|
||||
[{ name: '上海' }, { name: '大连', value: 10 }],
|
||||
]
|
||||
|
||||
let GZData = [
|
||||
[{ name: '广州' }, { name: '福州', value: 95 }],
|
||||
[{ name: '广州' }, { name: '太原', value: 90 }],
|
||||
[{ name: '广州' }, { name: '长春', value: 80 }],
|
||||
[{ name: '广州' }, { name: '重庆', value: 70 }],
|
||||
[{ name: '广州' }, { name: '西安', value: 60 }],
|
||||
[{ name: '广州' }, { name: '成都', value: 50 }],
|
||||
[{ name: '广州' }, { name: '常州', value: 40 }],
|
||||
[{ name: '广州' }, { name: '北京', value: 30 }],
|
||||
[{ name: '广州' }, { name: '北海', value: 20 }],
|
||||
[{ name: '广州' }, { name: '海口', value: 10 }],
|
||||
]
|
||||
|
||||
let planePath = 'path://M1705.06,1318.313v-89.254l-319.9-221.799l0.073-208.063c0.521-84.662-26.629-121.796-63.961-121.491c-37.332-0.305-64.482,36.829-63.961,121.491l0.073,208.063l-319.9,221.799v89.254l330.343-157.288l12.238,241.308l-134.449,92.931l0.531,42.034l175.125-42.917l175.125,42.917l0.531-42.034l-134.449-92.931l12.238-241.308L1705.06,1318.313z'
|
||||
|
||||
let convertData = function (data) {
|
||||
let res = []
|
||||
for (let i = 0; i < data.length; i += 1) {
|
||||
let dataItem = data[i]
|
||||
let fromCoord = geoCoordMap[dataItem[0].name]
|
||||
let toCoord = geoCoordMap[dataItem[1].name]
|
||||
if (fromCoord && toCoord) {
|
||||
res.push({
|
||||
fromName: dataItem[0].name,
|
||||
toName: dataItem[1].name,
|
||||
coords: [fromCoord, toCoord],
|
||||
})
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
let color = ['#a6c84c', '#ffa022', '#46bee9']
|
||||
let series = [];
|
||||
[['北京', BJData], ['上海', SHData], ['广州', GZData]].forEach((item, i) => {
|
||||
series.push(
|
||||
{
|
||||
name: `${item[0]} Top10`,
|
||||
type: 'lines',
|
||||
zlevel: 1,
|
||||
effect: {
|
||||
show: true,
|
||||
period: 6,
|
||||
trailLength: 0.7,
|
||||
color: '#fff',
|
||||
symbolSize: 3,
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
color: color[i],
|
||||
width: 0,
|
||||
curveness: 0.2,
|
||||
},
|
||||
},
|
||||
data: convertData(item[1]),
|
||||
},
|
||||
{
|
||||
name: `${item[0]} Top10`,
|
||||
type: 'lines',
|
||||
zlevel: 2,
|
||||
symbol: ['none', 'arrow'],
|
||||
symbolSize: 10,
|
||||
effect: {
|
||||
show: true,
|
||||
period: 6,
|
||||
trailLength: 0,
|
||||
symbol: planePath,
|
||||
symbolSize: 15,
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
color: color[i],
|
||||
width: 1,
|
||||
opacity: 0.6,
|
||||
curveness: 0.2,
|
||||
},
|
||||
},
|
||||
data: convertData(item[1]),
|
||||
},
|
||||
{
|
||||
name: `${item[0]} Top10`,
|
||||
type: 'effectScatter',
|
||||
coordinateSystem: 'geo',
|
||||
zlevel: 2,
|
||||
rippleEffect: {
|
||||
brushType: 'stroke',
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
formatter: '{b}',
|
||||
},
|
||||
},
|
||||
symbolSize (val) {
|
||||
return val[2] / 8
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: color[i],
|
||||
},
|
||||
},
|
||||
data: item[1].map((dataItem) => {
|
||||
return {
|
||||
name: dataItem[1].name,
|
||||
value: geoCoordMap[dataItem[1].name].concat([dataItem[1].value]),
|
||||
}
|
||||
}),
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
let option = {
|
||||
backgroundColor: '#404a59',
|
||||
title: {
|
||||
text: '模拟迁徙',
|
||||
subtext: '数据纯属虚构',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
top: 'bottom',
|
||||
left: 'right',
|
||||
data: ['北京 Top10', '上海 Top10', '广州 Top10'],
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
selectedMode: 'single',
|
||||
},
|
||||
geo: {
|
||||
map: 'china',
|
||||
label: {
|
||||
emphasis: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
roam: true,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
areaColor: '#323c48',
|
||||
borderColor: '#404a59',
|
||||
},
|
||||
emphasis: {
|
||||
areaColor: '#2a333d',
|
||||
},
|
||||
},
|
||||
},
|
||||
series,
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a airport chart. </label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '700px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AirportCoordComponent
|
||||
@@ -0,0 +1,111 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import echarts from 'echarts'
|
||||
|
||||
const currentData = [
|
||||
[[28604, 77, 17096869, 'Australia', 1990], [31163, 77.4, 27662440, 'Canada', 1990], [1516, 68, 1154605773, 'China', 1990], [13670, 74.7, 10582082, 'Cuba', 1990], [28599, 75, 4986705, 'Finland', 1990], [29476, 77.1, 56943299, 'France', 1990], [31476, 75.4, 78958237, 'Germany', 1990], [28666, 78.1, 254830, 'Iceland', 1990], [1777, 57.7, 870601776, 'India', 1990], [29550, 79.1, 122249285, 'Japan', 1990], [2076, 67.9, 20194354, 'North Korea', 1990], [12087, 72, 42972254, 'South Korea', 1990], [24021, 75.4, 3397534, 'New Zealand', 1990], [43296, 76.8, 4240375, 'Norway', 1990], [10088, 70.8, 38195258, 'Poland', 1990], [19349, 69.6, 147568552, 'Russia', 1990], [10670, 67.3, 53994605, 'Turkey', 1990], [26424, 75.7, 57110117, 'United Kingdom', 1990], [37062, 75.4, 252847810, 'United States', 1990]],
|
||||
[[44056, 81.8, 23968973, 'Australia', 2015], [43294, 81.7, 35939927, 'Canada', 2015], [13334, 76.9, 1376048943, 'China', 2015], [21291, 78.5, 11389562, 'Cuba', 2015], [38923, 80.8, 5503457, 'Finland', 2015], [37599, 81.9, 64395345, 'France', 2015], [44053, 81.1, 80688545, 'Germany', 2015], [42182, 82.8, 329425, 'Iceland', 2015], [5903, 66.8, 1311050527, 'India', 2015], [36162, 83.5, 126573481, 'Japan', 2015], [1390, 71.4, 25155317, 'North Korea', 2015], [34644, 80.7, 50293439, 'South Korea', 2015], [34186, 80.6, 4528526, 'New Zealand', 2015], [64304, 81.6, 5210967, 'Norway', 2015], [24787, 77.3, 38611794, 'Poland', 2015], [23038, 73.13, 143456918, 'Russia', 2015], [19360, 76.5, 78665830, 'Turkey', 2015], [38225, 81.4, 64715810, 'United Kingdom', 2015], [53354, 79.1, 321773631, 'United States', 2015]],
|
||||
]
|
||||
|
||||
const option = {
|
||||
backgroundColor: new echarts.graphic.RadialGradient(0.3, 0.3, 0.8, [{
|
||||
offset: 0,
|
||||
color: '#f7f8fa',
|
||||
}, {
|
||||
offset: 1,
|
||||
color: '#cdd0d5',
|
||||
}]),
|
||||
title: {
|
||||
text: '1990 与 2015 年各国家人均寿命与 GDP',
|
||||
},
|
||||
legend: {
|
||||
right: 10,
|
||||
data: ['1990', '2015'],
|
||||
},
|
||||
xAxis: {
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
scale: true,
|
||||
},
|
||||
series: [{
|
||||
name: '1990',
|
||||
data: currentData[0],
|
||||
type: 'scatter',
|
||||
symbolSize (data) {
|
||||
return Math.sqrt(data[2]) / 5e2
|
||||
},
|
||||
label: {
|
||||
emphasis: {
|
||||
show: true,
|
||||
formatter (param) {
|
||||
return param.data[3]
|
||||
},
|
||||
position: 'top',
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
shadowBlur: 10,
|
||||
shadowColor: 'rgba(120, 36, 50, 0.5)',
|
||||
shadowOffsetY: 5,
|
||||
color: new echarts.graphic.RadialGradient(0.4, 0.3, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgb(251, 118, 123)',
|
||||
}, {
|
||||
offset: 1,
|
||||
color: 'rgb(204, 46, 72)',
|
||||
}]),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: '2015',
|
||||
data: currentData[1],
|
||||
type: 'scatter',
|
||||
symbolSize (data) {
|
||||
return Math.sqrt(data[2]) / 5e2
|
||||
},
|
||||
label: {
|
||||
emphasis: {
|
||||
show: true,
|
||||
formatter (param) {
|
||||
return param.data[3]
|
||||
},
|
||||
position: 'top',
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
shadowBlur: 10,
|
||||
shadowColor: 'rgba(25, 100, 150, 0.5)',
|
||||
shadowOffsetY: 5,
|
||||
color: new echarts.graphic.RadialGradient(0.4, 0.3, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgb(129, 227, 238)',
|
||||
}, {
|
||||
offset: 1,
|
||||
color: 'rgb(25, 183, 207)',
|
||||
}]),
|
||||
},
|
||||
},
|
||||
}],
|
||||
}
|
||||
|
||||
const BubbleGradientComponent = () => {
|
||||
return (<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '700px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>)
|
||||
}
|
||||
|
||||
export default BubbleGradientComponent
|
||||
@@ -0,0 +1,197 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import echarts from 'echarts'
|
||||
|
||||
const CalendarComponent = () => {
|
||||
const getVirtulData = (year) => {
|
||||
year = year || '2017'
|
||||
let date = +echarts.number.parseDate(`${year}-01-01`)
|
||||
let end = +echarts.number.parseDate(`${+year + 1}-01-01`)
|
||||
let dayTime = 3600 * 24 * 1000
|
||||
let data = []
|
||||
for (let time = date; time < end; time += dayTime) {
|
||||
data.push([
|
||||
echarts.format.formatTime('yyyy-MM-dd', time),
|
||||
Math.floor(Math.random() * 1000),
|
||||
])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
let graphData = [[
|
||||
1485878400000,
|
||||
260,
|
||||
], [
|
||||
1486137600000,
|
||||
200,
|
||||
], [
|
||||
1486569600000,
|
||||
279,
|
||||
], [
|
||||
1486915200000,
|
||||
847,
|
||||
], [
|
||||
1487347200000,
|
||||
241,
|
||||
], [
|
||||
1487779200000,
|
||||
411,
|
||||
], [
|
||||
1488124800000,
|
||||
985,
|
||||
],
|
||||
]
|
||||
|
||||
let links = graphData.map((item, idx) => {
|
||||
return {
|
||||
source: idx,
|
||||
target: idx + 1,
|
||||
}
|
||||
})
|
||||
links.pop()
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
position: 'top',
|
||||
},
|
||||
visualMap: [{
|
||||
min: 0,
|
||||
max: 1000,
|
||||
calculable: true,
|
||||
seriesIndex: [2, 3, 4],
|
||||
orient: 'horizontal',
|
||||
left: '55%',
|
||||
bottom: 20,
|
||||
}, {
|
||||
min: 0,
|
||||
max: 1000,
|
||||
inRange: {
|
||||
color: ['grey'],
|
||||
opacity: [0, 0.3],
|
||||
},
|
||||
controller: {
|
||||
inRange: {
|
||||
opacity: [0.3, 0.6],
|
||||
},
|
||||
outOfRange: {
|
||||
color: '#ccc',
|
||||
},
|
||||
},
|
||||
calculable: true,
|
||||
seriesIndex: [1],
|
||||
orient: 'horizontal',
|
||||
left: '10%',
|
||||
bottom: 20,
|
||||
}],
|
||||
|
||||
calendar: [
|
||||
{
|
||||
orient: 'vertical',
|
||||
yearLabel: {
|
||||
margin: 40,
|
||||
},
|
||||
monthLabel: {
|
||||
nameMap: 'cn',
|
||||
margin: 20,
|
||||
},
|
||||
dayLabel: {
|
||||
firstDay: 1,
|
||||
nameMap: 'cn',
|
||||
},
|
||||
cellSize: 40,
|
||||
range: '2017-02',
|
||||
},
|
||||
{
|
||||
orient: 'vertical',
|
||||
yearLabel: {
|
||||
margin: 40,
|
||||
},
|
||||
monthLabel: {
|
||||
margin: 20,
|
||||
},
|
||||
cellSize: 40,
|
||||
left: 460,
|
||||
range: '2017-01',
|
||||
},
|
||||
{
|
||||
orient: 'vertical',
|
||||
yearLabel: {
|
||||
margin: 40,
|
||||
},
|
||||
monthLabel: {
|
||||
margin: 20,
|
||||
},
|
||||
cellSize: 40,
|
||||
top: 350,
|
||||
range: '2017-03',
|
||||
},
|
||||
{
|
||||
orient: 'vertical',
|
||||
yearLabel: {
|
||||
margin: 40,
|
||||
},
|
||||
dayLabel: {
|
||||
firstDay: 1,
|
||||
nameMap: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
|
||||
},
|
||||
monthLabel: {
|
||||
nameMap: 'cn',
|
||||
margin: 20,
|
||||
},
|
||||
cellSize: 40,
|
||||
top: 350,
|
||||
left: 460,
|
||||
range: '2017-04',
|
||||
}],
|
||||
|
||||
series: [{
|
||||
type: 'graph',
|
||||
edgeSymbol: ['none', 'arrow'],
|
||||
coordinateSystem: 'calendar',
|
||||
links,
|
||||
symbolSize: 10,
|
||||
calendarIndex: 0,
|
||||
data: graphData,
|
||||
}, {
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
data: getVirtulData(2017),
|
||||
}, {
|
||||
type: 'effectScatter',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 1,
|
||||
symbolSize (val) {
|
||||
return val[1] / 40
|
||||
},
|
||||
data: getVirtulData(2017),
|
||||
}, {
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 2,
|
||||
symbolSize (val) {
|
||||
return val[1] / 60
|
||||
},
|
||||
data: getVirtulData(2017),
|
||||
}, {
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 3,
|
||||
data: getVirtulData(2017),
|
||||
}],
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a calendar-charts </label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '700px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CalendarComponent
|
||||
@@ -0,0 +1,117 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
class ChartAPIComponent extends React.Component {
|
||||
render () {
|
||||
const option = {
|
||||
title: {
|
||||
text: '漏斗图',
|
||||
subtext: '纯属虚构',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c}%',
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
dataView: { readOnly: false },
|
||||
restore: {},
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ['展现', '点击', '访问', '咨询', '订单'],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '预期',
|
||||
type: 'funnel',
|
||||
left: '10%',
|
||||
width: '80%',
|
||||
label: {
|
||||
normal: {
|
||||
formatter: '{b}预期',
|
||||
},
|
||||
emphasis: {
|
||||
position: 'inside',
|
||||
formatter: '{b}预期: {c}%',
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
normal: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ value: 60, name: '访问' },
|
||||
{ value: 40, name: '咨询' },
|
||||
{ value: 20, name: '订单' },
|
||||
{ value: 80, name: '点击' },
|
||||
{ value: 100, name: '展现' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '实际',
|
||||
type: 'funnel',
|
||||
left: '10%',
|
||||
width: '80%',
|
||||
maxSize: '80%',
|
||||
label: {
|
||||
normal: {
|
||||
position: 'inside',
|
||||
formatter: '{c}%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
position: 'inside',
|
||||
formatter: '{b}实际: {c}%',
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
opacity: 0.5,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ value: 30, name: '访问' },
|
||||
{ value: 10, name: '咨询' },
|
||||
{ value: 5, name: '订单' },
|
||||
{ value: 50, name: '点击' },
|
||||
{ value: 80, name: '展现' },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
let code = '<ReactEcharts ref={(e) => { this.echarts_react = e; }} \n' +
|
||||
' option={this.getOtion()} /> \n' +
|
||||
'\n' +
|
||||
'// use echarts API: http://echarts.baidu.com/api.html#echartsInstance' +
|
||||
'this.echarts_react.getEchartsInstance().getDataURL();'
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> use echarts API With <strong> getEchartsInstance() </strong>: (the API will return the echarts instance, then you can use any API of echarts.)</label>
|
||||
<ReactEcharts ref={(e) => { this.echarts_react = e }}
|
||||
option={option}
|
||||
/>
|
||||
<label> code below: (echarts API list see: http://echarts.baidu.com/api.html#echartsInstance)</label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ChartAPIComponent
|
||||
@@ -0,0 +1,97 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
class ChartShowLoadingComponent extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
this._t = null
|
||||
this.onChartReady = this.onChartReady.bind(this)
|
||||
}
|
||||
componentWillUnmount () {
|
||||
clearTimeout(this._t)
|
||||
}
|
||||
|
||||
onChartReady (chart) {
|
||||
this._t = setTimeout(() => {
|
||||
chart.hideLoading()
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
render () {
|
||||
const getOtion = () => {
|
||||
const option = {
|
||||
title: {
|
||||
text: '基础雷达图',
|
||||
},
|
||||
tooltip: {},
|
||||
legend: {
|
||||
data: ['预算分配(Allocated Budget)', '实际开销(Actual Spending)'],
|
||||
},
|
||||
radar: {
|
||||
indicator: [
|
||||
{ name: '销售(sales)', max: 6500 },
|
||||
{ name: '管理(Administration)', max: 16000 },
|
||||
{ name: '信息技术(Information Techology)', max: 30000 },
|
||||
{ name: '客服(Customer Support)', max: 38000 },
|
||||
{ name: '研发(Development)', max: 52000 },
|
||||
{ name: '市场(Marketing)', max: 25000 },
|
||||
],
|
||||
},
|
||||
series: [{
|
||||
name: '预算 vs 开销(Budget vs spending)',
|
||||
type: 'radar',
|
||||
data: [
|
||||
{
|
||||
value: [4300, 10000, 28000, 35000, 50000, 19000],
|
||||
name: '预算分配(Allocated Budget)',
|
||||
},
|
||||
{
|
||||
value: [5000, 14000, 28000, 31000, 42000, 21000],
|
||||
name: '实际开销(Actual Spending)',
|
||||
},
|
||||
],
|
||||
}],
|
||||
}
|
||||
return option
|
||||
}
|
||||
const getLoadingOption = () => {
|
||||
const option = {
|
||||
text: '加载中...',
|
||||
color: '#4413c2',
|
||||
textColor: '#270240',
|
||||
maskColor: 'rgba(194, 88, 86, 0.3)',
|
||||
zlevel: 0,
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
let code = 'onChartReady: function(chart) {\n' +
|
||||
" 'chart.hideLoading();\n" +
|
||||
'}\n\n' +
|
||||
'<ReactEcharts \n' +
|
||||
' option={this.getOtion()} \n' +
|
||||
' onChartReady={this.onChartReady} \n' +
|
||||
' loadingOption={this.getLoadingOption()} \n' +
|
||||
' showLoading={true} />'
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> Chart loading With <strong> showLoading </strong>: (when chart ready, hide the loading mask.)</label>
|
||||
<ReactEcharts
|
||||
option={getOtion()}
|
||||
onChartReady={this.onChartReady}
|
||||
loadingOption={getLoadingOption()}
|
||||
showLoading
|
||||
/>
|
||||
<label> code below: </label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ChartShowLoadingComponent
|
||||
@@ -0,0 +1,89 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
const ChartWithEventComponent = () => {
|
||||
const onChartReady = (echart) => {
|
||||
console.log('echart is ready', echart)
|
||||
}
|
||||
const onChartLegendselectchanged = (param, echart) => {
|
||||
console.log(param, echart)
|
||||
}
|
||||
const onChartClick = (param, echart) => {
|
||||
console.log(param, echart)
|
||||
}
|
||||
const getOtion = () => {
|
||||
const option = {
|
||||
title: {
|
||||
text: '某站点用户访问来源',
|
||||
subtext: '纯属虚构',
|
||||
x: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c} ({d}%)',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: '55%',
|
||||
center: ['50%', '60%'],
|
||||
data: [
|
||||
{ value: 335, name: '直接访问' },
|
||||
{ value: 310, name: '邮件营销' },
|
||||
{ value: 234, name: '联盟广告' },
|
||||
{ value: 135, name: '视频广告' },
|
||||
{ value: 1548, name: '搜索引擎' },
|
||||
],
|
||||
itemStyle: {
|
||||
emphasis: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
let onEvents = {
|
||||
click: onChartClick,
|
||||
legendselectchanged: onChartLegendselectchanged,
|
||||
}
|
||||
let code = 'let onEvents = {\n' +
|
||||
" 'click': onChartClick,\n" +
|
||||
" 'legendselectchanged': onChartLegendselectchanged\n" +
|
||||
'}\n\n' +
|
||||
'<ReactEcharts \n' +
|
||||
' option={getOtion()} \n' +
|
||||
' style={{height: 300}} \n' +
|
||||
' onChartReady={onChartReady} \n' +
|
||||
' onEvents={onEvents} />'
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> Chart With event <strong> onEvents </strong>: (Click the chart, and watch the console)</label>
|
||||
<ReactEcharts
|
||||
option={getOtion()}
|
||||
style={{ height: 300 }}
|
||||
onChartReady={onChartReady}
|
||||
onEvents={onEvents}
|
||||
/>
|
||||
<label> code below: </label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ChartWithEventComponent
|
||||
@@ -0,0 +1,195 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
class DynamicChartComponent extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
this.timeTicket = null
|
||||
this.count = 51
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
text: 'Hello Echarts-for-react.',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
legend: {
|
||||
data: ['最新成交价', '预购队列'],
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
feature: {
|
||||
dataView: { readOnly: false },
|
||||
restore: {},
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: 60,
|
||||
left: 30,
|
||||
right: 60,
|
||||
bottom: 30,
|
||||
},
|
||||
dataZoom: {
|
||||
show: false,
|
||||
start: 0,
|
||||
end: 100,
|
||||
},
|
||||
visualMap: {
|
||||
show: false,
|
||||
min: 0,
|
||||
max: 1000,
|
||||
color: ['#BE002F', '#F20C00', '#F00056', '#FF2D51', '#FF2121', '#FF4C00', '#FF7500',
|
||||
'#FF8936', '#FFA400', '#F0C239', '#FFF143', '#FAFF72', '#C9DD22', '#AFDD22',
|
||||
'#9ED900', '#00E500', '#0EB83A', '#0AA344', '#0C8918', '#057748', '#177CB0'],
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: true,
|
||||
data: (function () {
|
||||
let now = new Date()
|
||||
let res = []
|
||||
let len = 50
|
||||
while (len--) {
|
||||
res.unshift(now.toLocaleTimeString().replace(/^\D*/, ''))
|
||||
now = new Date(now - 2000)
|
||||
}
|
||||
return res
|
||||
}()),
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: true,
|
||||
data: (function () {
|
||||
let res = []
|
||||
let len = 50
|
||||
while (len--) {
|
||||
res.push(50 - len + 1)
|
||||
}
|
||||
return res
|
||||
}()),
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
scale: true,
|
||||
name: '价格',
|
||||
max: 20,
|
||||
min: 0,
|
||||
boundaryGap: [0.2, 0.2],
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
scale: true,
|
||||
name: '预购量',
|
||||
max: 1200,
|
||||
min: 0,
|
||||
boundaryGap: [0.2, 0.2],
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '预购队列',
|
||||
type: 'bar',
|
||||
xAxisIndex: 1,
|
||||
yAxisIndex: 1,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
barBorderRadius: 4,
|
||||
},
|
||||
},
|
||||
animationEasing: 'elasticOut',
|
||||
animationDelay (idx) {
|
||||
return idx * 10
|
||||
},
|
||||
animationDelayUpdate (idx) {
|
||||
return idx * 10
|
||||
},
|
||||
data: (function () {
|
||||
let res = []
|
||||
let len = 50
|
||||
while (len--) {
|
||||
res.push(Math.round(Math.random() * 1000))
|
||||
}
|
||||
return res
|
||||
}()),
|
||||
},
|
||||
{
|
||||
name: '最新成交价',
|
||||
type: 'line',
|
||||
data: (function () {
|
||||
let res = []
|
||||
let len = 0
|
||||
while (len < 50) {
|
||||
res.push((Math.random() * 10 + 5).toFixed(1) - 0)
|
||||
len++
|
||||
}
|
||||
return res
|
||||
}()),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
this.state = {
|
||||
option,
|
||||
}
|
||||
|
||||
this.fetchNewDate = this.fetchNewDate.bind(this)
|
||||
}
|
||||
|
||||
fetchNewDate () {
|
||||
let axisData = (new Date()).toLocaleTimeString().replace(/^\D*/, '')
|
||||
let { option } = this.state
|
||||
option.title.text = `Hello Echarts-for-react.${new Date().getSeconds()}`
|
||||
let data0 = option.series[0].data
|
||||
let data1 = option.series[1].data
|
||||
data0.shift()
|
||||
data0.push(Math.round(Math.random() * 1000))
|
||||
data1.shift()
|
||||
data1.push((Math.random() * 10 + 5).toFixed(1) - 0)
|
||||
|
||||
option.xAxis[0].data.shift()
|
||||
option.xAxis[0].data.push(axisData)
|
||||
option.xAxis[1].data.shift()
|
||||
option.xAxis[1].data.push(this.count += 1)
|
||||
this.setState({ option })
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.timeTicket) {
|
||||
clearInterval(this.timeTicket)
|
||||
}
|
||||
this.timeTicket = setInterval(this.fetchNewDate, 1000)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.timeTicket) {
|
||||
clearInterval(this.timeTicket)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
let code = "<ReactEcharts ref='echartsInstance' \n" +
|
||||
' option={this.state.option} />\n'
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> use React state to render dynamic chart</label>
|
||||
<ReactEcharts ref="echarts_react"
|
||||
option={this.state.option}
|
||||
style={{ height: 400 }}
|
||||
/>
|
||||
<label> code below: use state of react to render dynamic chart</label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default DynamicChartComponent
|
||||
@@ -0,0 +1,51 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import SimpleChartComponent from './SimpleChartComponent'
|
||||
import ChartWithEventComponent from './ChartWithEventComponent'
|
||||
import ThemeChartComponent from './ThemeChartComponent'
|
||||
import ChartShowLoadingComponent from './ChartShowLoadingComponent'
|
||||
import ChartAPIComponent from './ChartAPIComponent'
|
||||
import DynamicChartComponent from './DynamicChartComponent'
|
||||
import MapChartComponent from './MapChartComponent'
|
||||
|
||||
// v1.2.0 add 7 demo.
|
||||
import AirportCoordComponent from './AirportCoordComponent'
|
||||
import CalendarComponent from './CalendarComponent'
|
||||
import GaugeComponent from './GaugeComponent'
|
||||
import GCalendarComponent from './GCalendarComponent'
|
||||
import GraphComponent from './GraphComponent'
|
||||
import LunarCalendarComponent from './LunarCalendarComponent'
|
||||
import TreemapComponent from './TreemapComponent'
|
||||
import LiquidfillComponent from './LiquidfillComponent'
|
||||
import BubbleGradientComponent from './BubbleGradientComponent'
|
||||
import TransparentBar3DComPonent from './TransparentBar3DComPonent'
|
||||
import MoonComponent from './MoonComponent'
|
||||
|
||||
const EchartsComponent = ({ type }) => {
|
||||
if (type === 'simple') return (<SimpleChartComponent />)
|
||||
if (type === 'loading') return (<ChartShowLoadingComponent />)
|
||||
if (type === 'api') return (<ChartAPIComponent />)
|
||||
if (type === 'events') return (<ChartWithEventComponent />)
|
||||
if (type === 'theme') return (<ThemeChartComponent />)
|
||||
if (type === 'dynamic') return (<DynamicChartComponent />)
|
||||
if (type === 'map') return (<MapChartComponent />)
|
||||
if (type === 'airport') return (<AirportCoordComponent />)
|
||||
if (type === 'graph') return (<GraphComponent />)
|
||||
if (type === 'calendar') return (<CalendarComponent />)
|
||||
if (type === 'treemap') return (<TreemapComponent />)
|
||||
if (type === 'gauge') return (<GaugeComponent />)
|
||||
if (type === 'gcalendar') return (<GCalendarComponent />)
|
||||
if (type === 'lunar') return (<LunarCalendarComponent />)
|
||||
if (type === 'liquid') return (<LiquidfillComponent />)
|
||||
if (type === 'BubbleGradientComponent') return (<BubbleGradientComponent />)
|
||||
if (type === 'TransparentBar3DComPonent') return (<TransparentBar3DComPonent />)
|
||||
if (type === 'MoonComponent') return (<MoonComponent />)
|
||||
return (<DynamicChartComponent />)
|
||||
}
|
||||
|
||||
EchartsComponent.propTypes = {
|
||||
type: PropTypes.string,
|
||||
}
|
||||
|
||||
export default EchartsComponent
|
||||
@@ -0,0 +1,70 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import echarts from 'echarts'
|
||||
|
||||
const GCalendarComponent = () => {
|
||||
const getVirtulData = (year) => {
|
||||
year = year || '2017'
|
||||
let date = +echarts.number.parseDate(`${year}-01-01`)
|
||||
let end = +echarts.number.parseDate(`${+year + 1}-01-01`)
|
||||
let dayTime = 3600 * 24 * 1000
|
||||
let data = []
|
||||
for (let time = date; time < end; time += dayTime) {
|
||||
data.push([
|
||||
echarts.format.formatTime('yyyy-MM-dd', time),
|
||||
Math.floor(Math.random() * 1000),
|
||||
])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
position: 'top',
|
||||
},
|
||||
visualMap: {
|
||||
min: 0,
|
||||
max: 1000,
|
||||
calculable: true,
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
top: 'top',
|
||||
},
|
||||
|
||||
calendar: [{
|
||||
range: '2017',
|
||||
cellSize: ['auto', 20],
|
||||
}, {
|
||||
top: 260,
|
||||
range: '2016',
|
||||
cellSize: ['auto', 20],
|
||||
}],
|
||||
|
||||
series: [{
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 0,
|
||||
data: getVirtulData(2017),
|
||||
}, {
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
calendarIndex: 1,
|
||||
data: getVirtulData(2016),
|
||||
}],
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a calendar like github commit history. </label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '500px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default GCalendarComponent
|
||||
@@ -0,0 +1,328 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
class GaugeComponent extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
const option = {
|
||||
backgroundColor: '#1b1b1b',
|
||||
tooltip: {
|
||||
formatter: '{a} <br/>{c} {b}',
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
feature: {
|
||||
mark: { show: true },
|
||||
restore: { show: true },
|
||||
saveAsImage: { show: true },
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '速度',
|
||||
type: 'gauge',
|
||||
min: 0,
|
||||
max: 220,
|
||||
splitNumber: 11,
|
||||
radius: '50%',
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: [[0.09, 'lime'], [0.82, '#1e90ff'], [1, '#ff4500']],
|
||||
width: 3,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisLabel: { // 坐标轴小标记
|
||||
textStyle: { // 属性lineStyle控制线条样式
|
||||
fontWeight: 'bolder',
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisTick: { // 坐标轴小标记
|
||||
length: 15, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: 'auto',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
length: 25, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
width: 3,
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
pointer: { // 分隔线
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 5,
|
||||
},
|
||||
title: {
|
||||
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||||
fontWeight: 'bolder',
|
||||
fontSize: 20,
|
||||
fontStyle: 'italic',
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
backgroundColor: 'rgba(30,144,255,0.8)',
|
||||
borderWidth: 1,
|
||||
borderColor: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 5,
|
||||
offsetCenter: [0, '50%'], // x, y,单位px
|
||||
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||||
fontWeight: 'bolder',
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
data: [{ value: 40, name: 'km/h' }],
|
||||
},
|
||||
{
|
||||
name: '转速',
|
||||
type: 'gauge',
|
||||
center: ['25%', '55%'], // 默认全局居中
|
||||
radius: '30%',
|
||||
min: 0,
|
||||
max: 7,
|
||||
endAngle: 45,
|
||||
splitNumber: 7,
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: [[0.29, 'lime'], [0.86, '#1e90ff'], [1, '#ff4500']],
|
||||
width: 2,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisLabel: { // 坐标轴小标记
|
||||
textStyle: { // 属性lineStyle控制线条样式
|
||||
fontWeight: 'bolder',
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisTick: { // 坐标轴小标记
|
||||
length: 12, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: 'auto',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
length: 20, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
width: 3,
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
pointer: {
|
||||
width: 5,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 5,
|
||||
},
|
||||
title: {
|
||||
offsetCenter: [0, '-30%'], // x, y,单位px
|
||||
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||||
fontWeight: 'bolder',
|
||||
fontStyle: 'italic',
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
detail: {
|
||||
// backgroundColor: 'rgba(30,144,255,0.8)',
|
||||
// borderWidth: 1,
|
||||
borderColor: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 5,
|
||||
width: 80,
|
||||
height: 30,
|
||||
offsetCenter: [25, '20%'], // x, y,单位px
|
||||
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||||
fontWeight: 'bolder',
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
data: [{ value: 1.5, name: 'x1000 r/min' }],
|
||||
},
|
||||
{
|
||||
name: '油表',
|
||||
type: 'gauge',
|
||||
center: ['75%', '50%'], // 默认全局居中
|
||||
radius: '30%',
|
||||
min: 0,
|
||||
max: 2,
|
||||
startAngle: 135,
|
||||
endAngle: 45,
|
||||
splitNumber: 2,
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: [[0.2, 'lime'], [0.8, '#1e90ff'], [1, '#ff4500']],
|
||||
width: 2,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisTick: { // 坐标轴小标记
|
||||
length: 12, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: 'auto',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: { // 属性lineStyle控制线条样式
|
||||
fontWeight: 'bolder',
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
formatter (v) {
|
||||
switch (`${v}`) {
|
||||
case '0': return 'E'
|
||||
case '1': return 'Gas'
|
||||
case '2': return 'F'
|
||||
default: return null
|
||||
}
|
||||
},
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
length: 15, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
width: 3,
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
pointer: {
|
||||
width: 2,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 5,
|
||||
},
|
||||
title: {
|
||||
show: false,
|
||||
},
|
||||
detail: {
|
||||
show: false,
|
||||
},
|
||||
data: [{ value: 0.5, name: 'gas' }],
|
||||
},
|
||||
{
|
||||
name: '水表',
|
||||
type: 'gauge',
|
||||
center: ['75%', '50%'], // 默认全局居中
|
||||
radius: '30%',
|
||||
min: 0,
|
||||
max: 2,
|
||||
startAngle: 315,
|
||||
endAngle: 225,
|
||||
splitNumber: 2,
|
||||
axisLine: { // 坐标轴线
|
||||
lineStyle: { // 属性lineStyle控制线条样式
|
||||
color: [[0.2, 'lime'], [0.8, '#1e90ff'], [1, '#ff4500']],
|
||||
width: 2,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
axisTick: { // 坐标轴小标记
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: { // 属性lineStyle控制线条样式
|
||||
fontWeight: 'bolder',
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
formatter (v) {
|
||||
switch (`${v}`) {
|
||||
case '0': return 'H'
|
||||
case '1': return 'Water'
|
||||
case '2': return 'C'
|
||||
default: return null
|
||||
}
|
||||
},
|
||||
},
|
||||
splitLine: { // 分隔线
|
||||
length: 15, // 属性length控制线长
|
||||
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||||
width: 3,
|
||||
color: '#fff',
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
pointer: {
|
||||
width: 2,
|
||||
shadowColor: '#fff', // 默认透明
|
||||
shadowBlur: 5,
|
||||
},
|
||||
title: {
|
||||
show: false,
|
||||
},
|
||||
detail: {
|
||||
show: false,
|
||||
},
|
||||
data: [{ value: 0.5, name: 'gas' }],
|
||||
},
|
||||
],
|
||||
}
|
||||
this.state = {
|
||||
option,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.timeTicket) {
|
||||
clearInterval(this.timeTicket)
|
||||
}
|
||||
this.timeTicket = setInterval(() => {
|
||||
let { option } = this.state
|
||||
option.series[0].data[0].value = (Math.random() * 100).toFixed(2) - 0
|
||||
option.series[1].data[0].value = (Math.random() * 7).toFixed(2) - 0
|
||||
option.series[2].data[0].value = (Math.random() * 2).toFixed(2) - 0
|
||||
option.series[3].data[0].value = (Math.random() * 2).toFixed(2) - 0
|
||||
this.setState({ option })
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.timeTicket) {
|
||||
clearInterval(this.timeTicket)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a car gauge chart. </label>
|
||||
<ReactEcharts
|
||||
option={this.state.option}
|
||||
style={{ height: '500px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default GaugeComponent
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
require('echarts-liquidfill')
|
||||
|
||||
const LiquidfillComponent = () => {
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
type: 'liquidFill',
|
||||
data: [0.6],
|
||||
},
|
||||
],
|
||||
}
|
||||
return (<div className="examples">
|
||||
<div className="parent">
|
||||
<label>
|
||||
render a Liquidfill chart:
|
||||
</label>
|
||||
<ReactEcharts option={option}
|
||||
style={{
|
||||
height: '400px',
|
||||
width: '100%',
|
||||
}}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default LiquidfillComponent
|
||||
@@ -0,0 +1,492 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import echarts from 'echarts'
|
||||
|
||||
const LunarCalendarComponent = () => {
|
||||
const getOtion = () => {
|
||||
let dateList = [
|
||||
['2017-1-1', '初四'],
|
||||
['2017-1-2', '初五'],
|
||||
['2017-1-3', '初六'],
|
||||
['2017-1-4', '初七'],
|
||||
['2017-1-5', '初八', '小寒'],
|
||||
['2017-1-6', '初九'],
|
||||
['2017-1-7', '初十'],
|
||||
['2017-1-8', '十一'],
|
||||
['2017-1-9', '十二'],
|
||||
['2017-1-10', '十三'],
|
||||
['2017-1-11', '十四'],
|
||||
['2017-1-12', '十五'],
|
||||
['2017-1-13', '十六'],
|
||||
['2017-1-14', '十七'],
|
||||
['2017-1-15', '十八'],
|
||||
['2017-1-16', '十九'],
|
||||
['2017-1-17', '二十'],
|
||||
['2017-1-18', '廿一'],
|
||||
['2017-1-19', '廿二'],
|
||||
['2017-1-20', '廿三', '大寒'],
|
||||
['2017-1-21', '廿四'],
|
||||
['2017-1-22', '廿五'],
|
||||
['2017-1-23', '廿六'],
|
||||
['2017-1-24', '廿七'],
|
||||
['2017-1-25', '廿八'],
|
||||
['2017-1-26', '廿九'],
|
||||
['2017-1-27', '三十'],
|
||||
['2017-1-28', '正月'],
|
||||
['2017-1-29', '初二'],
|
||||
['2017-1-30', '初三'],
|
||||
['2017-1-31', '初四'],
|
||||
['2017-2-1', '初五'],
|
||||
['2017-2-2', '初六'],
|
||||
['2017-2-3', '初七', '立春'],
|
||||
['2017-2-4', '初八'],
|
||||
['2017-2-5', '初九'],
|
||||
['2017-2-6', '初十'],
|
||||
['2017-2-7', '十一'],
|
||||
['2017-2-8', '十二'],
|
||||
['2017-2-9', '十三'],
|
||||
['2017-2-10', '十四'],
|
||||
['2017-2-11', '十五'],
|
||||
['2017-2-12', '十六'],
|
||||
['2017-2-13', '十七'],
|
||||
['2017-2-14', '十八'],
|
||||
['2017-2-15', '十九'],
|
||||
['2017-2-16', '二十'],
|
||||
['2017-2-17', '廿一'],
|
||||
['2017-2-18', '廿二', '雨水'],
|
||||
['2017-2-19', '廿三'],
|
||||
['2017-2-20', '廿四'],
|
||||
['2017-2-21', '廿五'],
|
||||
['2017-2-22', '廿六'],
|
||||
['2017-2-23', '廿七'],
|
||||
['2017-2-24', '廿八'],
|
||||
['2017-2-25', '廿九'],
|
||||
['2017-2-26', '二月'],
|
||||
['2017-2-27', '初二'],
|
||||
['2017-2-28', '初三'],
|
||||
['2017-3-1', '初四'],
|
||||
['2017-3-2', '初五'],
|
||||
['2017-3-3', '初六'],
|
||||
['2017-3-4', '初七'],
|
||||
['2017-3-5', '初八', '驚蟄'],
|
||||
['2017-3-6', '初九'],
|
||||
['2017-3-7', '初十'],
|
||||
['2017-3-8', '十一'],
|
||||
['2017-3-9', '十二'],
|
||||
['2017-3-10', '十三'],
|
||||
['2017-3-11', '十四'],
|
||||
['2017-3-12', '十五'],
|
||||
['2017-3-13', '十六'],
|
||||
['2017-3-14', '十七'],
|
||||
['2017-3-15', '十八'],
|
||||
['2017-3-16', '十九'],
|
||||
['2017-3-17', '二十'],
|
||||
['2017-3-18', '廿一'],
|
||||
['2017-3-19', '廿二'],
|
||||
['2017-3-20', '廿三', '春分'],
|
||||
['2017-3-21', '廿四'],
|
||||
['2017-3-22', '廿五'],
|
||||
['2017-3-23', '廿六'],
|
||||
['2017-3-24', '廿七'],
|
||||
['2017-3-25', '廿八'],
|
||||
['2017-3-26', '廿九'],
|
||||
['2017-3-27', '三十'],
|
||||
['2017-3-28', '三月'],
|
||||
['2017-3-29', '初二'],
|
||||
['2017-3-30', '初三'],
|
||||
['2017-3-31', '初四'],
|
||||
['2017-4-1', '初五'],
|
||||
['2017-4-2', '初六'],
|
||||
['2017-4-3', '初七'],
|
||||
['2017-4-4', '初八', '清明'],
|
||||
['2017-4-5', '初九'],
|
||||
['2017-4-6', '初十'],
|
||||
['2017-4-7', '十一'],
|
||||
['2017-4-8', '十二'],
|
||||
['2017-4-9', '十三'],
|
||||
['2017-4-10', '十四'],
|
||||
['2017-4-11', '十五'],
|
||||
['2017-4-12', '十六'],
|
||||
['2017-4-13', '十七'],
|
||||
['2017-4-14', '十八'],
|
||||
['2017-4-15', '十九'],
|
||||
['2017-4-16', '二十'],
|
||||
['2017-4-17', '廿一'],
|
||||
['2017-4-18', '廿二'],
|
||||
['2017-4-19', '廿三'],
|
||||
['2017-4-20', '廿四', '穀雨'],
|
||||
['2017-4-21', '廿五'],
|
||||
['2017-4-22', '廿六'],
|
||||
['2017-4-23', '廿七'],
|
||||
['2017-4-24', '廿八'],
|
||||
['2017-4-25', '廿九'],
|
||||
['2017-4-26', '四月'],
|
||||
['2017-4-27', '初二'],
|
||||
['2017-4-28', '初三'],
|
||||
['2017-4-29', '初四'],
|
||||
['2017-4-30', '初五'],
|
||||
['2017-5-1', '初六'],
|
||||
['2017-5-2', '初七'],
|
||||
['2017-5-3', '初八'],
|
||||
['2017-5-4', '初九'],
|
||||
['2017-5-5', '初十', '立夏'],
|
||||
['2017-5-6', '十一'],
|
||||
['2017-5-7', '十二'],
|
||||
['2017-5-8', '十三'],
|
||||
['2017-5-9', '十四'],
|
||||
['2017-5-10', '十五'],
|
||||
['2017-5-11', '十六'],
|
||||
['2017-5-12', '十七'],
|
||||
['2017-5-13', '十八'],
|
||||
['2017-5-14', '十九'],
|
||||
['2017-5-15', '二十'],
|
||||
['2017-5-16', '廿一'],
|
||||
['2017-5-17', '廿二'],
|
||||
['2017-5-18', '廿三'],
|
||||
['2017-5-19', '廿四'],
|
||||
['2017-5-20', '廿五'],
|
||||
['2017-5-21', '廿六', '小滿'],
|
||||
['2017-5-22', '廿七'],
|
||||
['2017-5-23', '廿八'],
|
||||
['2017-5-24', '廿九'],
|
||||
['2017-5-25', '三十'],
|
||||
['2017-5-26', '五月'],
|
||||
['2017-5-27', '初二'],
|
||||
['2017-5-28', '初三'],
|
||||
['2017-5-29', '初四'],
|
||||
['2017-5-30', '初五'],
|
||||
['2017-5-31', '初六'],
|
||||
['2017-6-1', '初七'],
|
||||
['2017-6-2', '初八'],
|
||||
['2017-6-3', '初九'],
|
||||
['2017-6-4', '初十'],
|
||||
['2017-6-5', '十一', '芒種'],
|
||||
['2017-6-6', '十二'],
|
||||
['2017-6-7', '十三'],
|
||||
['2017-6-8', '十四'],
|
||||
['2017-6-9', '十五'],
|
||||
['2017-6-10', '十六'],
|
||||
['2017-6-11', '十七'],
|
||||
['2017-6-12', '十八'],
|
||||
['2017-6-13', '十九'],
|
||||
['2017-6-14', '二十'],
|
||||
['2017-6-15', '廿一'],
|
||||
['2017-6-16', '廿二'],
|
||||
['2017-6-17', '廿三'],
|
||||
['2017-6-18', '廿四'],
|
||||
['2017-6-19', '廿五'],
|
||||
['2017-6-20', '廿六'],
|
||||
['2017-6-21', '廿七', '夏至'],
|
||||
['2017-6-22', '廿八'],
|
||||
['2017-6-23', '廿九'],
|
||||
['2017-6-24', '六月'],
|
||||
['2017-6-25', '初二'],
|
||||
['2017-6-26', '初三'],
|
||||
['2017-6-27', '初四'],
|
||||
['2017-6-28', '初五'],
|
||||
['2017-6-29', '初六'],
|
||||
['2017-6-30', '初七'],
|
||||
['2017-7-1', '初八'],
|
||||
['2017-7-2', '初九'],
|
||||
['2017-7-3', '初十'],
|
||||
['2017-7-4', '十一'],
|
||||
['2017-7-5', '十二'],
|
||||
['2017-7-6', '十三'],
|
||||
['2017-7-7', '十四', '小暑'],
|
||||
['2017-7-8', '十五'],
|
||||
['2017-7-9', '十六'],
|
||||
['2017-7-10', '十七'],
|
||||
['2017-7-11', '十八'],
|
||||
['2017-7-12', '十九'],
|
||||
['2017-7-13', '二十'],
|
||||
['2017-7-14', '廿一'],
|
||||
['2017-7-15', '廿二'],
|
||||
['2017-7-16', '廿三'],
|
||||
['2017-7-17', '廿四'],
|
||||
['2017-7-18', '廿五'],
|
||||
['2017-7-19', '廿六'],
|
||||
['2017-7-20', '廿七'],
|
||||
['2017-7-21', '廿八'],
|
||||
['2017-7-22', '廿九', '大暑'],
|
||||
['2017-7-23', '閏六'],
|
||||
['2017-7-24', '初二'],
|
||||
['2017-7-25', '初三'],
|
||||
['2017-7-26', '初四'],
|
||||
['2017-7-27', '初五'],
|
||||
['2017-7-28', '初六'],
|
||||
['2017-7-29', '初七'],
|
||||
['2017-7-30', '初八'],
|
||||
['2017-7-31', '初九'],
|
||||
['2017-8-1', '初十'],
|
||||
['2017-8-2', '十一'],
|
||||
['2017-8-3', '十二'],
|
||||
['2017-8-4', '十三'],
|
||||
['2017-8-5', '十四'],
|
||||
['2017-8-6', '十五'],
|
||||
['2017-8-7', '十六', '立秋'],
|
||||
['2017-8-8', '十七'],
|
||||
['2017-8-9', '十八'],
|
||||
['2017-8-10', '十九'],
|
||||
['2017-8-11', '二十'],
|
||||
['2017-8-12', '廿一'],
|
||||
['2017-8-13', '廿二'],
|
||||
['2017-8-14', '廿三'],
|
||||
['2017-8-15', '廿四'],
|
||||
['2017-8-16', '廿五'],
|
||||
['2017-8-17', '廿六'],
|
||||
['2017-8-18', '廿七'],
|
||||
['2017-8-19', '廿八'],
|
||||
['2017-8-20', '廿九'],
|
||||
['2017-8-21', '三十'],
|
||||
['2017-8-22', '七月'],
|
||||
['2017-8-23', '初二', '處暑'],
|
||||
['2017-8-24', '初三'],
|
||||
['2017-8-25', '初四'],
|
||||
['2017-8-26', '初五'],
|
||||
['2017-8-27', '初六'],
|
||||
['2017-8-28', '初七'],
|
||||
['2017-8-29', '初八'],
|
||||
['2017-8-30', '初九'],
|
||||
['2017-8-31', '初十'],
|
||||
['2017-9-1', '十一'],
|
||||
['2017-9-2', '十二'],
|
||||
['2017-9-3', '十三'],
|
||||
['2017-9-4', '十四'],
|
||||
['2017-9-5', '十五'],
|
||||
['2017-9-6', '十六'],
|
||||
['2017-9-7', '十七', '白露'],
|
||||
['2017-9-8', '十八'],
|
||||
['2017-9-9', '十九'],
|
||||
['2017-9-10', '二十'],
|
||||
['2017-9-11', '廿一'],
|
||||
['2017-9-12', '廿二'],
|
||||
['2017-9-13', '廿三'],
|
||||
['2017-9-14', '廿四'],
|
||||
['2017-9-15', '廿五'],
|
||||
['2017-9-16', '廿六'],
|
||||
['2017-9-17', '廿七'],
|
||||
['2017-9-18', '廿八'],
|
||||
['2017-9-19', '廿九'],
|
||||
['2017-9-20', '八月'],
|
||||
['2017-9-21', '初二'],
|
||||
['2017-9-22', '初三'],
|
||||
['2017-9-23', '初四', '秋分'],
|
||||
['2017-9-24', '初五'],
|
||||
['2017-9-25', '初六'],
|
||||
['2017-9-26', '初七'],
|
||||
['2017-9-27', '初八'],
|
||||
['2017-9-28', '初九'],
|
||||
['2017-9-29', '初十'],
|
||||
['2017-9-30', '十一'],
|
||||
['2017-10-1', '十二'],
|
||||
['2017-10-2', '十三'],
|
||||
['2017-10-3', '十四'],
|
||||
['2017-10-4', '十五'],
|
||||
['2017-10-5', '十六'],
|
||||
['2017-10-6', '十七'],
|
||||
['2017-10-7', '十八'],
|
||||
['2017-10-8', '十九', '寒露'],
|
||||
['2017-10-9', '二十'],
|
||||
['2017-10-10', '廿一'],
|
||||
['2017-10-11', '廿二'],
|
||||
['2017-10-12', '廿三'],
|
||||
['2017-10-13', '廿四'],
|
||||
['2017-10-14', '廿五'],
|
||||
['2017-10-15', '廿六'],
|
||||
['2017-10-16', '廿七'],
|
||||
['2017-10-17', '廿八'],
|
||||
['2017-10-18', '廿九'],
|
||||
['2017-10-19', '三十'],
|
||||
['2017-10-20', '九月'],
|
||||
['2017-10-21', '初二'],
|
||||
['2017-10-22', '初三'],
|
||||
['2017-10-23', '初四', '霜降'],
|
||||
['2017-10-24', '初五'],
|
||||
['2017-10-25', '初六'],
|
||||
['2017-10-26', '初七'],
|
||||
['2017-10-27', '初八'],
|
||||
['2017-10-28', '初九'],
|
||||
['2017-10-29', '初十'],
|
||||
['2017-10-30', '十一'],
|
||||
['2017-10-31', '十二'],
|
||||
['2017-11-1', '十三'],
|
||||
['2017-11-2', '十四'],
|
||||
['2017-11-3', '十五'],
|
||||
['2017-11-4', '十六'],
|
||||
['2017-11-5', '十七'],
|
||||
['2017-11-6', '十八'],
|
||||
['2017-11-7', '十九', '立冬'],
|
||||
['2017-11-8', '二十'],
|
||||
['2017-11-9', '廿一'],
|
||||
['2017-11-10', '廿二'],
|
||||
['2017-11-11', '廿三'],
|
||||
['2017-11-12', '廿四'],
|
||||
['2017-11-13', '廿五'],
|
||||
['2017-11-14', '廿六'],
|
||||
['2017-11-15', '廿七'],
|
||||
['2017-11-16', '廿八'],
|
||||
['2017-11-17', '廿九'],
|
||||
['2017-11-18', '十月'],
|
||||
['2017-11-19', '初二'],
|
||||
['2017-11-20', '初三'],
|
||||
['2017-11-21', '初四'],
|
||||
['2017-11-22', '初五', '小雪'],
|
||||
['2017-11-23', '初六'],
|
||||
['2017-11-24', '初七'],
|
||||
['2017-11-25', '初八'],
|
||||
['2017-11-26', '初九'],
|
||||
['2017-11-27', '初十'],
|
||||
['2017-11-28', '十一'],
|
||||
['2017-11-29', '十二'],
|
||||
['2017-11-30', '十三'],
|
||||
['2017-12-1', '十四'],
|
||||
['2017-12-2', '十五'],
|
||||
['2017-12-3', '十六'],
|
||||
['2017-12-4', '十七'],
|
||||
['2017-12-5', '十八'],
|
||||
['2017-12-6', '十九'],
|
||||
['2017-12-7', '二十', '大雪'],
|
||||
['2017-12-8', '廿一'],
|
||||
['2017-12-9', '廿二'],
|
||||
['2017-12-10', '廿三'],
|
||||
['2017-12-11', '廿四'],
|
||||
['2017-12-12', '廿五'],
|
||||
['2017-12-13', '廿六'],
|
||||
['2017-12-14', '廿七'],
|
||||
['2017-12-15', '廿八'],
|
||||
['2017-12-16', '廿九'],
|
||||
['2017-12-17', '三十'],
|
||||
['2017-12-18', '十一月'],
|
||||
['2017-12-19', '初二'],
|
||||
['2017-12-20', '初三'],
|
||||
['2017-12-21', '初四'],
|
||||
['2017-12-22', '初五', '冬至'],
|
||||
['2017-12-23', '初六'],
|
||||
['2017-12-24', '初七'],
|
||||
['2017-12-25', '初八'],
|
||||
['2017-12-26', '初九'],
|
||||
['2017-12-27', '初十'],
|
||||
['2017-12-28', '十一'],
|
||||
['2017-12-29', '十二'],
|
||||
['2017-12-30', '十三'],
|
||||
['2017-12-31', '十四'],
|
||||
]
|
||||
|
||||
let heatmapData = []
|
||||
let lunarData = []
|
||||
for (let i = 0; i < dateList.length; i++) {
|
||||
heatmapData.push([
|
||||
dateList[i][0],
|
||||
Math.random() * 300,
|
||||
])
|
||||
lunarData.push([
|
||||
dateList[i][0],
|
||||
1,
|
||||
dateList[i][1],
|
||||
dateList[i][2],
|
||||
])
|
||||
}
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
formatter (params) {
|
||||
return `降雨量: ${params.value[1].toFixed(2)}`
|
||||
},
|
||||
},
|
||||
|
||||
visualMap: {
|
||||
show: false,
|
||||
min: 0,
|
||||
max: 300,
|
||||
calculable: true,
|
||||
seriesIndex: [2],
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
bottom: 20,
|
||||
inRange: {
|
||||
color: ['#e0ffff', '#006edd'],
|
||||
opacity: 0.3,
|
||||
},
|
||||
controller: {
|
||||
inRange: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
calendar: [{
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
cellSize: [70, 70],
|
||||
yearLabel: { show: false },
|
||||
orient: 'vertical',
|
||||
dayLabel: {
|
||||
firstDay: 1,
|
||||
nameMap: 'cn',
|
||||
},
|
||||
monthLabel: {
|
||||
show: false,
|
||||
},
|
||||
range: '2017-03',
|
||||
}],
|
||||
|
||||
series: [{
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'calendar',
|
||||
symbolSize: 1,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
formatter (params) {
|
||||
let d = echarts.number.parseDate(params.value[0])
|
||||
return `${d.getDate()}\n\n${params.value[2]}\n\n`
|
||||
},
|
||||
textStyle: {
|
||||
color: '#000',
|
||||
},
|
||||
},
|
||||
},
|
||||
data: lunarData,
|
||||
}, {
|
||||
type: 'scatter',
|
||||
coordinateSystem: 'calendar',
|
||||
symbolSize: 1,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
formatter (params) {
|
||||
return `\n\n\n${params.value[3] || ''}`
|
||||
},
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
fontWeight: 700,
|
||||
color: '#a00',
|
||||
},
|
||||
},
|
||||
},
|
||||
data: lunarData,
|
||||
}, {
|
||||
name: '降雨量',
|
||||
type: 'heatmap',
|
||||
coordinateSystem: 'calendar',
|
||||
data: heatmapData,
|
||||
}],
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a lunar calendar chart. </label>
|
||||
<ReactEcharts
|
||||
option={getOtion()}
|
||||
style={{ height: '500px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LunarCalendarComponent
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from 'react'
|
||||
import AdSense from 'react-adsense'
|
||||
import { Link } from 'react-router'
|
||||
import DynamicChartComponent from './DynamicChartComponent.js'
|
||||
|
||||
|
||||
const MainPageComponent = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1> echarts-for-react {this.props.params.type} </h1>
|
||||
<h3> A very simple echarts(v3.0) wrapper for React. <a href="https://github.com/hustcc/echarts-for-react">hustcc/echarts-for-react</a></h3>
|
||||
|
||||
<AdSense.Google client="ca-pub-7292810486004926"
|
||||
slot="7806394673"
|
||||
/>
|
||||
|
||||
<h4>
|
||||
<Link to="/echarts/simple">Simple demo</Link> |
|
||||
<Link to="/echarts/loading">Echarts loading</Link> |
|
||||
<Link to="/echarts/api">Echarts API</Link> |
|
||||
<Link to="/echarts/events">Echarts events</Link> |
|
||||
<Link to="/echarts/theme">Echarts theme</Link> |
|
||||
<Link to="/echarts/dynamic">Dynamic chart</Link> |
|
||||
<Link to="/echarts/map">Map chart</Link>
|
||||
</h4>
|
||||
<h4>
|
||||
<span style={{ color: 'red' }}>New</span>:
|
||||
<Link to="/echarts/airport">Airport</Link> |
|
||||
<Link to="/echarts/graph">Graph</Link> |
|
||||
<Link to="/echarts/calendar">Calendar</Link> |
|
||||
<Link to="/echarts/treemap">Treemap</Link> |
|
||||
<Link to="/echarts/gauge">Gauge</Link> |
|
||||
<Link to="/echarts/gcalendar">GCalendar</Link> |
|
||||
<Link to="/echarts/lunar">Lunar</Link> |
|
||||
<Link to="/echarts/liquid">Liquidfill</Link>
|
||||
</h4>
|
||||
{this.props.children || <DynamicChartComponent />}
|
||||
|
||||
<h3>Get it on GitHub! <a href="https://github.com/hustcc/echarts-for-react">hustcc/echarts-for-react</a></h3>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MainPageComponent
|
||||
@@ -0,0 +1,205 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
require('echarts/map/js/china.js')
|
||||
|
||||
class MapChartComponent extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
this.timeTicket = null
|
||||
const randomData = () => {
|
||||
return Math.round(Math.random() * 1000)
|
||||
}
|
||||
const option = {
|
||||
title: {
|
||||
text: 'iphone销量',
|
||||
subtext: '纯属虚构',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: ['iphone3', 'iphone4', 'iphone5'],
|
||||
},
|
||||
visualMap: {
|
||||
min: 0,
|
||||
max: 2500,
|
||||
left: 'left',
|
||||
top: 'bottom',
|
||||
text: ['高', '低'], // 文本,默认为数值文本
|
||||
calculable: true,
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
orient: 'vertical',
|
||||
left: 'right',
|
||||
top: 'center',
|
||||
feature: {
|
||||
dataView: { readOnly: false },
|
||||
restore: {},
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'iphone3',
|
||||
type: 'map',
|
||||
mapType: 'china',
|
||||
roam: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ name: '北京', value: randomData() },
|
||||
{ name: '天津', value: randomData() },
|
||||
{ name: '上海', value: randomData() },
|
||||
{ name: '重庆', value: randomData() },
|
||||
{ name: '河北', value: randomData() },
|
||||
{ name: '河南', value: randomData() },
|
||||
{ name: '云南', value: randomData() },
|
||||
{ name: '辽宁', value: randomData() },
|
||||
{ name: '黑龙江', value: randomData() },
|
||||
{ name: '湖南', value: randomData() },
|
||||
{ name: '安徽', value: randomData() },
|
||||
{ name: '山东', value: randomData() },
|
||||
{ name: '新疆', value: randomData() },
|
||||
{ name: '江苏', value: randomData() },
|
||||
{ name: '浙江', value: randomData() },
|
||||
{ name: '江西', value: randomData() },
|
||||
{ name: '湖北', value: randomData() },
|
||||
{ name: '广西', value: randomData() },
|
||||
{ name: '甘肃', value: randomData() },
|
||||
{ name: '山西', value: randomData() },
|
||||
{ name: '内蒙古', value: randomData() },
|
||||
{ name: '陕西', value: randomData() },
|
||||
{ name: '吉林', value: randomData() },
|
||||
{ name: '福建', value: randomData() },
|
||||
{ name: '贵州', value: randomData() },
|
||||
{ name: '广东', value: randomData() },
|
||||
{ name: '青海', value: randomData() },
|
||||
{ name: '西藏', value: randomData() },
|
||||
{ name: '四川', value: randomData() },
|
||||
{ name: '宁夏', value: randomData() },
|
||||
{ name: '海南', value: randomData() },
|
||||
{ name: '台湾', value: randomData() },
|
||||
{ name: '香港', value: randomData() },
|
||||
{ name: '澳门', value: randomData() },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'iphone4',
|
||||
type: 'map',
|
||||
mapType: 'china',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ name: '北京', value: randomData() },
|
||||
{ name: '天津', value: randomData() },
|
||||
{ name: '上海', value: randomData() },
|
||||
{ name: '重庆', value: randomData() },
|
||||
{ name: '河北', value: randomData() },
|
||||
{ name: '安徽', value: randomData() },
|
||||
{ name: '新疆', value: randomData() },
|
||||
{ name: '浙江', value: randomData() },
|
||||
{ name: '江西', value: randomData() },
|
||||
{ name: '山西', value: randomData() },
|
||||
{ name: '内蒙古', value: randomData() },
|
||||
{ name: '吉林', value: randomData() },
|
||||
{ name: '福建', value: randomData() },
|
||||
{ name: '广东', value: randomData() },
|
||||
{ name: '西藏', value: randomData() },
|
||||
{ name: '四川', value: randomData() },
|
||||
{ name: '宁夏', value: randomData() },
|
||||
{ name: '香港', value: randomData() },
|
||||
{ name: '澳门', value: randomData() },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'iphone5',
|
||||
type: 'map',
|
||||
mapType: 'china',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ name: '北京', value: randomData() },
|
||||
{ name: '天津', value: randomData() },
|
||||
{ name: '上海', value: randomData() },
|
||||
{ name: '广东', value: randomData() },
|
||||
{ name: '台湾', value: randomData() },
|
||||
{ name: '香港', value: randomData() },
|
||||
{ name: '澳门', value: randomData() },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
this.state = {
|
||||
option,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.timeTicket) {
|
||||
clearInterval(this.timeTicket)
|
||||
}
|
||||
this.timeTicket = setInterval(() => {
|
||||
const { option } = this.state
|
||||
const r = new Date().getSeconds()
|
||||
option.title.text = `iphone销量${r}`
|
||||
option.series[0].name = `iphone销量${r}`
|
||||
option.legend.data[0] = `iphone销量${r}`
|
||||
this.setState({ option })
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.timeTicket) {
|
||||
clearInterval(this.timeTicket)
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
let code = "require('echarts/map/js/china.js'); \n" +
|
||||
'<ReactEcharts \n' +
|
||||
' option={this.state.option || {}} \n' +
|
||||
" style={{height: '350px', width: '100%'}} \n" +
|
||||
" className='react_for_echarts' />"
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a china map. <strong>MAP charts</strong>: </label>
|
||||
<ReactEcharts
|
||||
option={this.state.option}
|
||||
style={{ height: '500px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
<label> code below: </label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MapChartComponent
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
const ModuleLoadChartComponent = () => {
|
||||
const option = {
|
||||
title: { text: 'ECharts 入门示例' },
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
|
||||
},
|
||||
yAxis: {},
|
||||
series: [{
|
||||
name: '销量',
|
||||
type: 'bar',
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
}],
|
||||
}
|
||||
|
||||
let code = '<ReactEcharts \n' +
|
||||
' option={this.getOtion()} \n' +
|
||||
" style={{height: '350px', width: '100%'}} \n" +
|
||||
" modules={['echarts/lib/chart/bar', 'echarts/lib/component/tooltip', 'echarts/lib/component/title']} \n" +
|
||||
" className='react_for_echarts' />"
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> load echarts module as you wish <strong>reduce the file size</strong>: </label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '350px', width: '100%' }}
|
||||
modules={['echarts/lib/chart/bar', 'echarts/lib/component/tooltip', 'echarts/lib/component/title']}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
<label> code below: </label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModuleLoadChartComponent
|
||||
@@ -0,0 +1,62 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import 'echarts-gl'
|
||||
|
||||
const option = {
|
||||
globe: {
|
||||
baseTexture: '/assets/data-1493804606544-r1PBU7D1W.jpg',
|
||||
heightTexture: '/assets/data-1493804610896-SJoBIXPkW.jpg',
|
||||
|
||||
displacementScale: 0.05,
|
||||
displacementQuality: 'medium',
|
||||
|
||||
environment: '/assets/data-1491837999815-H1_44Qtal.jpg',
|
||||
|
||||
shading: 'realistic',
|
||||
realisticMaterial: {
|
||||
roughness: 0.8,
|
||||
metalness: 0,
|
||||
},
|
||||
|
||||
postEffect: {
|
||||
enable: true,
|
||||
SSAO: {
|
||||
enable: true,
|
||||
radius: 2,
|
||||
intensity: 1,
|
||||
quality: 'high',
|
||||
},
|
||||
},
|
||||
temporalSuperSampling: {
|
||||
enable: true,
|
||||
},
|
||||
light: {
|
||||
ambient: {
|
||||
intensity: 0,
|
||||
},
|
||||
main: {
|
||||
intensity: 2,
|
||||
shadow: true,
|
||||
},
|
||||
ambientCubemap: {
|
||||
texture: '/asset/data-1491838644249-ry33I7YTe.hdr',
|
||||
exposure: 0,
|
||||
diffuseIntensity: 0.02,
|
||||
},
|
||||
},
|
||||
viewControl: {
|
||||
autoRotate: false,
|
||||
},
|
||||
},
|
||||
series: [],
|
||||
}
|
||||
|
||||
const MoonComponent = () => {
|
||||
return (<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '700px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>)
|
||||
}
|
||||
|
||||
export default MoonComponent
|
||||
@@ -0,0 +1,87 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import './theme/macarons.js'
|
||||
|
||||
const SimpleChartComponent = () => {
|
||||
const option = {
|
||||
title: {
|
||||
text: '堆叠区域图',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
legend: {
|
||||
data: ['邮件营销', '联盟广告', '视频广告'],
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '邮件营销',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: { normal: {} },
|
||||
data: [120, 132, 101, 134, 90, 230, 210],
|
||||
},
|
||||
{
|
||||
name: '联盟广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: { normal: {} },
|
||||
data: [220, 182, 191, 234, 290, 330, 310],
|
||||
},
|
||||
{
|
||||
name: '视频广告',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: { normal: {} },
|
||||
data: [150, 232, 201, 154, 190, 330, 410],
|
||||
},
|
||||
],
|
||||
}
|
||||
let code = '<ReactEcharts \n' +
|
||||
' option={this.getOtion()} \n' +
|
||||
" style={{height: '350px', width: '100%'}} \n" +
|
||||
" className='react_for_echarts' />"
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a Simple echart With <strong>option and height</strong>: </label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '350px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
theme="macarons"
|
||||
/>
|
||||
<label> code below: </label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default SimpleChartComponent
|
||||
@@ -0,0 +1,108 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
|
||||
import echarts from 'echarts'
|
||||
|
||||
const ThemeChartComponent = () => {
|
||||
const option = {
|
||||
title: {
|
||||
text: '阶梯瀑布图',
|
||||
subtext: 'From ExcelHome',
|
||||
sublink: 'http://e.weibo.com/1341556070/Aj1J2x5a5',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { // 坐标轴指示器,坐标轴触发有效
|
||||
type: 'shadow', // 默认为直线,可选为:'line' | 'shadow'
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ['支出', '收入'],
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
splitLine: { show: false },
|
||||
data: ['11月1日', '11月2日', '11月3日', '11月4日', '11月5日', '11月6日', '11月7日', '11月8日', '11月9日', '11月10日', '11月11日'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '辅助',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
barBorderColor: 'rgba(0,0,0,0)',
|
||||
color: 'rgba(0,0,0,0)',
|
||||
},
|
||||
emphasis: {
|
||||
barBorderColor: 'rgba(0,0,0,0)',
|
||||
color: 'rgba(0,0,0,0)',
|
||||
},
|
||||
},
|
||||
data: [0, 900, 1245, 1530, 1376, 1376, 1511, 1689, 1856, 1495, 1292],
|
||||
},
|
||||
{
|
||||
name: '收入',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
},
|
||||
},
|
||||
data: [900, 345, 393, '-', '-', 135, 178, 286, '-', '-', '-'],
|
||||
},
|
||||
{
|
||||
name: '支出',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'bottom',
|
||||
},
|
||||
},
|
||||
data: ['-', '-', '-', 108, 154, '-', '-', '-', 119, 361, 203],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
echarts.registerTheme('my_theme', {
|
||||
backgroundColor: '#f4cccc',
|
||||
})
|
||||
|
||||
let code = "echarts.registerTheme('my_theme', {\n" +
|
||||
" backgroundColor: '#f4cccc'\n" +
|
||||
'});\n\n' +
|
||||
'<ReactEcharts \n' +
|
||||
' option={this.getOtion()} \n' +
|
||||
" theme='my_theme' />"
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a echart With <strong>theme</strong>, should <strong>echarts.registerTheme(themeName, themeObj)</strong> before use.</label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
theme="my_theme"
|
||||
/>
|
||||
<label> the theme object format: https://github.com/ecomfe/echarts/blob/master/theme/dark.js</label>
|
||||
<pre>
|
||||
<code>{code}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeChartComponent
|
||||
@@ -0,0 +1,88 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import 'echarts-gl'
|
||||
|
||||
const hours = ['12a', '1a', '2a', '3a', '4a', '5a', '6a',
|
||||
'7a', '8a', '9a', '10a', '11a',
|
||||
'12p', '1p', '2p', '3p', '4p', '5p',
|
||||
'6p', '7p', '8p', '9p', '10p', '11p']
|
||||
const days = ['Saturday', 'Friday', 'Thursday',
|
||||
'Wednesday', 'Tuesday', 'Monday', 'Sunday']
|
||||
|
||||
const data = [[0, 0, 5], [0, 1, 1], [0, 2, 0], [0, 3, 0], [0, 4, 0], [0, 5, 0], [0, 6, 0], [0, 7, 0], [0, 8, 0], [0, 9, 0], [0, 10, 0], [0, 11, 2], [0, 12, 4], [0, 13, 1], [0, 14, 1], [0, 15, 3], [0, 16, 4], [0, 17, 6], [0, 18, 4], [0, 19, 4], [0, 20, 3], [0, 21, 3], [0, 22, 2], [0, 23, 5], [1, 0, 7], [1, 1, 0], [1, 2, 0], [1, 3, 0], [1, 4, 0], [1, 5, 0], [1, 6, 0], [1, 7, 0], [1, 8, 0], [1, 9, 0], [1, 10, 5], [1, 11, 2], [1, 12, 2], [1, 13, 6], [1, 14, 9], [1, 15, 11], [1, 16, 6], [1, 17, 7], [1, 18, 8], [1, 19, 12], [1, 20, 5], [1, 21, 5], [1, 22, 7], [1, 23, 2], [2, 0, 1], [2, 1, 1], [2, 2, 0], [2, 3, 0], [2, 4, 0], [2, 5, 0], [2, 6, 0], [2, 7, 0], [2, 8, 0], [2, 9, 0], [2, 10, 3], [2, 11, 2], [2, 12, 1], [2, 13, 9], [2, 14, 8], [2, 15, 10], [2, 16, 6], [2, 17, 5], [2, 18, 5], [2, 19, 5], [2, 20, 7], [2, 21, 4], [2, 22, 2], [2, 23, 4], [3, 0, 7], [3, 1, 3], [3, 2, 0], [3, 3, 0], [3, 4, 0], [3, 5, 0], [3, 6, 0], [3, 7, 0], [3, 8, 1], [3, 9, 0], [3, 10, 5], [3, 11, 4], [3, 12, 7], [3, 13, 14], [3, 14, 13], [3, 15, 12], [3, 16, 9], [3, 17, 5], [3, 18, 5], [3, 19, 10], [3, 20, 6], [3, 21, 4], [3, 22, 4], [3, 23, 1], [4, 0, 1], [4, 1, 3], [4, 2, 0], [4, 3, 0], [4, 4, 0], [4, 5, 1], [4, 6, 0], [4, 7, 0], [4, 8, 0], [4, 9, 2], [4, 10, 4], [4, 11, 4], [4, 12, 2], [4, 13, 4], [4, 14, 4], [4, 15, 14], [4, 16, 12], [4, 17, 1], [4, 18, 8], [4, 19, 5], [4, 20, 3], [4, 21, 7], [4, 22, 3], [4, 23, 0], [5, 0, 2], [5, 1, 1], [5, 2, 0], [5, 3, 3], [5, 4, 0], [5, 5, 0], [5, 6, 0], [5, 7, 0], [5, 8, 2], [5, 9, 0], [5, 10, 4], [5, 11, 1], [5, 12, 5], [5, 13, 10], [5, 14, 5], [5, 15, 7], [5, 16, 11], [5, 17, 6], [5, 18, 0], [5, 19, 5], [5, 20, 3], [5, 21, 4], [5, 22, 2], [5, 23, 0], [6, 0, 1], [6, 1, 0], [6, 2, 0], [6, 3, 0], [6, 4, 0], [6, 5, 0], [6, 6, 0], [6, 7, 0], [6, 8, 0], [6, 9, 0], [6, 10, 1], [6, 11, 0], [6, 12, 2], [6, 13, 1], [6, 14, 3], [6, 15, 4], [6, 16, 0], [6, 17, 0], [6, 18, 0], [6, 19, 0], [6, 20, 1], [6, 21, 2], [6, 22, 2], [6, 23, 6]]
|
||||
|
||||
const option = {
|
||||
tooltip: {},
|
||||
visualMap: {
|
||||
max: 20,
|
||||
inRange: {
|
||||
color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026'],
|
||||
},
|
||||
},
|
||||
xAxis3D: {
|
||||
type: 'category',
|
||||
data: hours,
|
||||
},
|
||||
yAxis3D: {
|
||||
type: 'category',
|
||||
data: days,
|
||||
},
|
||||
zAxis3D: {
|
||||
type: 'value',
|
||||
},
|
||||
grid3D: {
|
||||
boxWidth: 200,
|
||||
boxDepth: 80,
|
||||
light: {
|
||||
main: {
|
||||
intensity: 1.2,
|
||||
},
|
||||
ambient: {
|
||||
intensity: 0.3,
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [{
|
||||
type: 'bar3D',
|
||||
data: data.map((item) => {
|
||||
return {
|
||||
value: [item[1], item[0], item[2]],
|
||||
}
|
||||
}),
|
||||
shading: 'color',
|
||||
|
||||
label: {
|
||||
show: false,
|
||||
textStyle: {
|
||||
fontSize: 16,
|
||||
borderWidth: 1,
|
||||
},
|
||||
},
|
||||
|
||||
itemStyle: {
|
||||
opacity: 0.4,
|
||||
},
|
||||
|
||||
emphasis: {
|
||||
label: {
|
||||
textStyle: {
|
||||
fontSize: 20,
|
||||
color: '#900',
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#900',
|
||||
},
|
||||
},
|
||||
}],
|
||||
}
|
||||
|
||||
const TransparentBar3DComPonent = () => {
|
||||
return (<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '700px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>)
|
||||
}
|
||||
|
||||
export default TransparentBar3DComPonent
|
||||
@@ -0,0 +1,261 @@
|
||||
import React from 'react'
|
||||
import ReactEcharts from 'echarts-for-react'
|
||||
import echarts from 'echarts'
|
||||
|
||||
const TreemapComponent = () => {
|
||||
let diskData = [
|
||||
{
|
||||
value: 180,
|
||||
name: 'Accounts',
|
||||
path: 'Accounts',
|
||||
children: [
|
||||
{
|
||||
value: 76,
|
||||
name: 'Access',
|
||||
path: 'Accounts/Access',
|
||||
children: [
|
||||
{
|
||||
value: 12,
|
||||
name: 'DefaultAccessPlugin.bundle',
|
||||
path: 'Accounts/Access/DefaultAccessPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 28,
|
||||
name: 'FacebookAccessPlugin.bundle',
|
||||
path: 'Accounts/Access/FacebookAccessPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 20,
|
||||
name: 'LinkedInAccessPlugin.bundle',
|
||||
path: 'Accounts/Access/LinkedInAccessPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
name: 'TencentWeiboAccessPlugin.bundle',
|
||||
path: 'Accounts/Access/TencentWeiboAccessPlugin.bundle',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 92,
|
||||
name: 'Authentication',
|
||||
path: 'Accounts/Authentication',
|
||||
children: [
|
||||
{
|
||||
value: 24,
|
||||
name: 'FacebookAuthenticationPlugin.bundle',
|
||||
path: 'Accounts/Authentication/FacebookAuthenticationPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
name: 'LinkedInAuthenticationPlugin.bundle',
|
||||
path: 'Accounts/Authentication/LinkedInAuthenticationPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 20,
|
||||
name: 'TencentWeiboAuthenticationPlugin.bundle',
|
||||
path: 'Accounts/Authentication/TencentWeiboAuthenticationPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
name: 'TwitterAuthenticationPlugin.bundle',
|
||||
path: 'Accounts/Authentication/TwitterAuthenticationPlugin.bundle',
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
name: 'WeiboAuthenticationPlugin.bundle',
|
||||
path: 'Accounts/Authentication/WeiboAuthenticationPlugin.bundle',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 12,
|
||||
name: 'Notification',
|
||||
path: 'Accounts/Notification',
|
||||
children: [
|
||||
{
|
||||
value: 12,
|
||||
name: 'SPAAccountsNotificationPlugin.bundle',
|
||||
path: 'Accounts/Notification/SPAAccountsNotificationPlugin.bundle',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 1904,
|
||||
name: 'AddressBook Plug-Ins',
|
||||
path: 'AddressBook Plug-Ins',
|
||||
children: [
|
||||
{
|
||||
value: 744,
|
||||
name: 'CardDAVPlugin.sourcebundle',
|
||||
path: 'AddressBook Plug-Ins/CardDAVPlugin.sourcebundle',
|
||||
children: [
|
||||
{
|
||||
value: 744,
|
||||
name: 'Contents',
|
||||
path: 'AddressBook Plug-Ins/CardDAVPlugin.sourcebundle/Contents',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 28,
|
||||
name: 'DirectoryServices.sourcebundle',
|
||||
path: 'AddressBook Plug-Ins/DirectoryServices.sourcebundle',
|
||||
children: [
|
||||
{
|
||||
value: 28,
|
||||
name: 'Contents',
|
||||
path: 'AddressBook Plug-Ins/DirectoryServices.sourcebundle/Contents',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 680,
|
||||
name: 'Exchange.sourcebundle',
|
||||
path: 'AddressBook Plug-Ins/Exchange.sourcebundle',
|
||||
children: [
|
||||
{
|
||||
value: 680,
|
||||
name: 'Contents',
|
||||
path: 'AddressBook Plug-Ins/Exchange.sourcebundle/Contents',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 432,
|
||||
name: 'LDAP.sourcebundle',
|
||||
path: 'AddressBook Plug-Ins/LDAP.sourcebundle',
|
||||
children: [
|
||||
{
|
||||
value: 432,
|
||||
name: 'Contents',
|
||||
path: 'AddressBook Plug-Ins/LDAP.sourcebundle/Contents',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 20,
|
||||
name: 'LocalSource.sourcebundle',
|
||||
path: 'AddressBook Plug-Ins/LocalSource.sourcebundle',
|
||||
children: [
|
||||
{
|
||||
value: 20,
|
||||
name: 'Contents',
|
||||
path: 'AddressBook Plug-Ins/LocalSource.sourcebundle/Contents',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 36,
|
||||
name: 'Assistant',
|
||||
path: 'Assistant',
|
||||
children: [
|
||||
{
|
||||
value: 36,
|
||||
name: 'Plugins',
|
||||
path: 'Assistant/Plugins',
|
||||
children: [
|
||||
{
|
||||
value: 36,
|
||||
name: 'AddressBook.assistantBundle',
|
||||
path: 'Assistant/Plugins/AddressBook.assistantBundle',
|
||||
},
|
||||
{
|
||||
value: 8,
|
||||
name: 'GenericAddressHandler.addresshandler',
|
||||
path: 'Recents/Plugins/GenericAddressHandler.addresshandler',
|
||||
},
|
||||
{
|
||||
value: 12,
|
||||
name: 'MapsRecents.addresshandler',
|
||||
path: 'Recents/Plugins/MapsRecents.addresshandler',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
let formatUtil = echarts.format
|
||||
function getLevelOption () {
|
||||
return [{
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 0,
|
||||
gapWidth: 5,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
itemStyle: {
|
||||
normal: {
|
||||
gapWidth: 1,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
colorSaturation: [0.35, 0.5],
|
||||
itemStyle: {
|
||||
normal: {
|
||||
gapWidth: 1,
|
||||
borderColorSaturation: 0.6,
|
||||
},
|
||||
},
|
||||
}]
|
||||
}
|
||||
const option = {
|
||||
title: {
|
||||
text: 'Disk Usage',
|
||||
left: 'center',
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
formatter (info) {
|
||||
let { value, treePathInfo } = info
|
||||
let treePath = []
|
||||
|
||||
for (let i = 1; i < treePathInfo.length; i++) {
|
||||
treePath.push(treePathInfo[i].name)
|
||||
}
|
||||
|
||||
return [
|
||||
`<div class="tooltip-title">${formatUtil.encodeHTML(treePath.join('/'))}</div>`,
|
||||
`Disk Usage: ${formatUtil.addCommas(value)} KB`,
|
||||
].join('')
|
||||
},
|
||||
},
|
||||
|
||||
series: [{
|
||||
name: 'Disk Usage',
|
||||
type: 'treemap',
|
||||
visibleMin: 300,
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b}',
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderColor: '#fff',
|
||||
},
|
||||
},
|
||||
levels: getLevelOption(),
|
||||
data: diskData,
|
||||
}],
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="examples">
|
||||
<div className="parent">
|
||||
<label> render a disk usage treemap. </label>
|
||||
<ReactEcharts
|
||||
option={option}
|
||||
style={{ height: '500px', width: '100%' }}
|
||||
className="react_for_echarts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TreemapComponent
|
||||
@@ -0,0 +1,111 @@
|
||||
import React from 'react'
|
||||
import { Radio } from 'antd'
|
||||
import { Page } from 'components'
|
||||
import EchartsComponent from './EchartsComponent'
|
||||
import styles from './index.less'
|
||||
|
||||
const RadioGroup = Radio.Group
|
||||
|
||||
const chartList = [
|
||||
{
|
||||
label: 'SimpleChart',
|
||||
value: 'simple',
|
||||
},
|
||||
{
|
||||
label: 'ChartShowLoading',
|
||||
value: 'loading',
|
||||
},
|
||||
{
|
||||
label: 'ChartAPI',
|
||||
value: 'api',
|
||||
},
|
||||
{
|
||||
label: 'ChartWithEvent',
|
||||
value: 'events',
|
||||
},
|
||||
{
|
||||
label: 'ThemeChart',
|
||||
value: 'theme',
|
||||
},
|
||||
{
|
||||
label: 'DynamicChart',
|
||||
value: 'dynamic',
|
||||
},
|
||||
{
|
||||
label: 'MapChart',
|
||||
value: 'map',
|
||||
},
|
||||
{
|
||||
label: 'AirportCoord',
|
||||
value: 'airport',
|
||||
},
|
||||
{
|
||||
label: 'Graph',
|
||||
value: 'graph',
|
||||
},
|
||||
{
|
||||
label: 'Calendar',
|
||||
value: 'calendar',
|
||||
},
|
||||
{
|
||||
label: 'Treemap',
|
||||
value: 'treemap',
|
||||
},
|
||||
{
|
||||
label: 'Gauge',
|
||||
value: 'gauge',
|
||||
},
|
||||
{
|
||||
label: 'GCalendar',
|
||||
value: 'gcalendar',
|
||||
},
|
||||
{
|
||||
label: 'LunarCalendar',
|
||||
value: 'lunar',
|
||||
},
|
||||
{
|
||||
label: 'Liquidfill',
|
||||
value: 'liquid',
|
||||
},
|
||||
{
|
||||
label: 'BubbleGradient',
|
||||
value: 'BubbleGradientComponent',
|
||||
},
|
||||
{
|
||||
label: 'TransparentBar3D',
|
||||
value: 'TransparentBar3DComPonent',
|
||||
},
|
||||
{
|
||||
label: 'MoonComponent',
|
||||
value: 'MoonComponent',
|
||||
},
|
||||
]
|
||||
|
||||
class Chart extends React.Component {
|
||||
constructor () {
|
||||
super()
|
||||
this.state = {
|
||||
type: '',
|
||||
}
|
||||
this.handleRadioGroupChange = this.handleRadioGroupChange.bind(this)
|
||||
}
|
||||
handleRadioGroupChange (e) {
|
||||
this.setState({
|
||||
type: e.target.value,
|
||||
})
|
||||
}
|
||||
render () {
|
||||
return (<Page inner id="EChartsMain">
|
||||
<RadioGroup options={chartList} defaultValue="dynamic" onChange={this.handleRadioGroupChange} />
|
||||
<div className={styles.chart}>
|
||||
<EchartsComponent type={this.state.type} />
|
||||
</div>
|
||||
<div style={{ pading: 24, marginTop: 24 }}>
|
||||
All demos from <a href="https://github.com/hustcc/echarts-for-react">https://github.com/hustcc/echarts-for-react</a>
|
||||
</div>
|
||||
</Page>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Chart
|
||||