Compare commits

...
159 Commits
Author SHA1 Message Date
Baorong Li f02d39ace0 Merge pull request #891 from Louis-7/bugfix/motion-switch
Bugfix/motion switch
2018-09-04 15:58:00 +08:00
Louis-7 4d32829445 fix motion switch style on Users page 2018-09-04 15:06:48 +08:00
Baorong Li 5438e04fc5 Merge pull request #888 from Louis-7/bugfix/chart-shake
Bugfix/chart shake
2018-09-03 15:38:35 +08:00
Baorong Li 54bbe4d70a 🎉🎉 upgrade umi@2.0.0 2018-09-03 15:38:03 +08:00
Louis 78ece0c9fb Merge pull request #2 from Louis-7/bugfix/chart-shake
fix move mouse into chart will cause chart shake issue.
2018-09-03 15:26:48 +08:00
Louis-7 3407f9a0c1 fix move mouse into chart will cause chart shake issue. 2018-09-03 15:24:15 +08:00
Louis f1b78e8d1f Merge pull request #1 from Louis-7/bugfix/sidebar-shake
Bugfix/sidebar shake
2018-09-03 15:15:40 +08:00
Baorong Li df2fc9c32e Merge pull request #886 from Louis-7/bugfix/sidebar-shake
Bugfix/sidebar shake
2018-09-03 15:11:15 +08:00
Louis-7 cc5c319332 remove useless rule
Signed-off-by: Louis-7 <louisgh.cn@gmail.com>
2018-09-03 14:58:56 +08:00
Louis-7 43ef09dfed Revert "restrict rule"
This reverts commit 843bd1a088.
2018-09-03 14:57:04 +08:00
Louis-7 0c95751b8d restrict rule
Signed-off-by: Louis-7 <louisgh.cn@gmail.com>
2018-09-03 14:56:06 +08:00
Louis-7 843bd1a088 restrict rule
Signed-off-by: Louis-7 <louisgh.cn@gmail.com>
2018-09-03 14:54:20 +08:00
Louis-7 a0db71e571 Revert "fix sidebar shake once mouse over it"
This reverts commit 7fc14eddd9.
2018-09-03 13:28:13 +08:00
Louis-7 7fc14eddd9 fix sidebar shake once mouse over it
Signed-off-by: Louis-7 <louisgh.cn@gmail.com>
2018-09-03 13:18:46 +08:00
Baorong Li 7f2fdc383b upgrade query-string@6 2018-08-22 15:58:12 +08:00
Baorong Li ff2caecb3a Merge pull request #877 from sorrycc/refact/migrate-to-umi-2
[WIP] refact: migrate to umi@2
2018-08-22 15:32:08 +08:00
sorrycc d01df1ef13 refact: migrate to umi@2 2018-08-22 15:12:01 +08:00
Baorong Li cd55df3a15 upgrade antd@3.8.0 2018-08-05 22:46:55 +08:00
Baorong Li ce59f3e7b2 Update README.md 2018-08-02 17:25:18 +08:00
Baorong Li 4d722f103a Update README.md 2018-08-02 17:20:02 +08:00
Baorong Li c1bc6f27b1 upgrade antd@3.7.3 2018-08-02 16:50:34 +08:00
Baorong Li ed88c087bf forgot to remove css part in dashboard/user 2018-07-21 13:15:16 +08:00
Baorong Li 4e337caa07 remove unuse png 2018-07-21 12:49:56 +08:00
Baorong Li ea3929b4c2 cut project size 2018-07-21 12:43:10 +08:00
Baorong Li 9eff4ca129 modify mock method in users delete, fix #859 2018-07-20 11:48:33 +08:00
Baorong Li d6d94e2121 upgrade antd@3.7.0 2018-07-20 11:18:42 +08:00
Baorong Li 737c0236d6 Merge pull request #844 from JChord/master
refactor:修改父ID取值逻辑
2018-06-25 12:42:14 +08:00
DosLin 69571f2916 refactor:修改父ID取值逻辑 2018-06-25 10:53:10 +08:00
Baorong Li 6dffa7378c Merge pull request #842 from JChord/master
fix:进入动态路由下的二级页面菜单栏无法选中问题
2018-06-22 17:02:08 +08:00
DosLin c2a7bc7106 fix:进入动态路由下的二级页面菜单栏无法选中问题 2018-06-22 16:50:58 +08:00
Baorong Li e752750c9e update doc, fix #839 2018-06-20 09:07:52 +08:00
Baorong Li 32bde8f69e Merge pull request #834 from codeif/master
Rename variable name  domin  to domain
2018-06-08 10:26:44 +08:00
codeif b5f9ef51f1 Rename variable name domin
to domain
2018-06-07 21:53:54 +08:00
Baorong Li 8c10be6ee6 upgrade umi@1.3.5 => fix #723 2018-06-01 15:56:37 +08:00
zuiidea c1e3872792 Fix README conflic 2018-05-25 17:37:23 +08:00
zuiidea c3eef53e4d Merge develop and update to 5.0.0-beta 2018-05-25 17:20:20 +08:00
zuiidea a1b9c0c33d Fix the files under the 'public' dicrectoy can't visit after build 2018-05-25 17:13:30 +08:00
Baorong Li c49b0edbe9 update umi@1.3.4 & antd@3.5.3 [use MOCK=none for production] 2018-05-25 13:49:13 +08:00
Baorong Li 0fd8824ad7 fix logout not work #826, #669 2018-05-25 11:52:39 +08:00
Baorong Li 973199135f update umi@1.3.3 antd@3.5.2 [no production for this commit] 2018-05-17 18:32:33 +08:00
Baorong Li 43b7b21ad3 update umi@1.3.1 [no production for this commit] 2018-05-15 22:04:42 +08:00
Baorong Li ba96ebb874 update dep 2018-05-12 14:34:00 +08:00
Baorong Li c66f086f42 fix #372 update navOpenKeys when copy link open 2018-05-05 12:11:03 +08:00
Baorong Li 07b2175e92 upgrade dep antd@3.5.0, umi@1.2.6 2018-05-05 12:05:07 +08:00
Baorong Li d245a1eabc upgrade umi@1.2.1 2018-04-24 23:00:31 +08:00
Baorong Li f1e2fd3b18 fix: alias 2018-04-24 22:51:12 +08:00
Baorong Li a6b3dba92e cut moment locale/lodash size & revert d06ee20 2018-04-13 18:19:22 +08:00
Baorong Li 9fd0abe6ea update dep 2018-04-12 15:21:03 +08:00
Baorong Li d06ee20c47 remove dep highcharts-more/highcharts-exporting 2018-04-12 12:02:59 +08:00
Baorong Li 2ef1fa0367 upgrade dep umi 2018-04-12 12:00:35 +08:00
Baorong Li 9d459106c1 Update README.md 2018-04-10 17:27:19 +08:00
Baorong Li cd5a52a8fc Merge pull request #793 from iversonwool/add_leehow
comfirmLoding
2018-04-10 09:09:40 +08:00
李浩 d89320f578 comfirmLoding 2018-04-10 08:59:16 +08:00
Baorong Li df5ce2991e improve by github.com/sorrycc/blog/issues/66 2018-03-31 15:36:26 +08:00
Baorong Li 668c9c7dfe upgrade umi@1.1.4 (support dll gzip & cache) 2018-03-30 15:25:39 +08:00
Baorong Li 9bd13055c0 5.0.0-beta coming 2018-03-29 11:26:30 +08:00
Baorong Li 9f3adda59d upgrade dependencies 2018-03-29 11:16:11 +08:00
Baorong Li bfa7aaecb8 Merge pull request #770 from umijs/refact/migrate-to-umi
Refact/migrate to umi
2018-03-29 10:17:07 +08:00
Baorong Li 9d4310d8e0 Merge branch 'develop' into refact/migrate-to-umi 2018-03-29 10:16:31 +08:00
Baorong Li b3555b01f3 Merge branch 'master' into develop 2018-03-29 10:08:50 +08:00
chencheng 74895fbb0d fix: uglifyjs problem, use query-string@5 2018-03-26 17:59:22 +08:00
chencheng 5f04d19d2d add lost dep query-string 2018-03-26 17:18:43 +08:00
chencheng 0fef06e0c6 use umi-plugin-dll to enable dll 2018-03-26 17:15:27 +08:00
chencheng 89d22451c5 fix: svg don't work 2018-03-24 18:08:16 +08:00
chencheng fb49056c73 make login work 2018-03-24 14:39:54 +08:00
chencheng a3071819c4 eslint 2018-03-24 09:07:36 +08:00
chencheng d4e10ad5c2 refact the directory structure 2018-03-23 23:31:09 +08:00
chencheng 59e9a1053e refact config files and package.json 2018-03-23 22:51:41 +08:00
Baorong Li 308fc09b33 Merge pull request #767 from iversonwool/add_leehow
refresh bug in router/user
2018-03-16 14:30:42 +08:00
李浩 99ec9facd3 refresh bug 2018-03-16 10:29:32 +08:00
Baorong Li 2a96d7a5f6 Merge pull request #749 from nazarlitvin/remove-async
remove unnecessary async functions
2018-03-10 11:43:00 +08:00
Baorong Li 195e1d17f8 Merge pull request #755 from LizPeng/patch-1
Update Echarts version
2018-03-09 14:00:03 +08:00
Baorong Li 580ff59b3d Create issue_template.md 2018-03-09 11:18:39 +08:00
Baorong Li cfa5aae5da fix #754 add set port guide 2018-03-09 10:58:54 +08:00
Baorong Li 761125735a fix #572, move cross-env to devDependencies 2018-03-08 17:53:12 +08:00
zuiidea d1b12ff0e1 Fix issue resulting User page showing wrong content when delete alll items in last page. 2018-03-01 17:45:34 +08:00
zuiidea a47176a4e5 fix user table 2018-02-27 19:17:59 +08:00
Dustin bc3d7fb39a Update Echarts version
require Echarts  ^4.0.0
2018-02-27 19:02:53 +08:00
zuiidea 458548150c fix popup position 2018-02-26 20:02:46 +08:00
zuiidea f6e11bb464 eslint fix 2018-02-26 19:35:58 +08:00
zuiidea 479fc647c3 Merge branch 'Maple-Ro-master' into develop 2018-02-26 19:19:56 +08:00
zuiidea 9a4c63390d locale example 2018-02-26 19:19:42 +08:00
zuiidea 42cd1221fa logo text fadeIn 2018-02-26 19:13:43 +08:00
zuiidea 98b773fdc3 logo text fadeIn 2018-02-26 19:13:12 +08:00
zuiidea cd54fcbf52 Merge branch 'hiooyUI-master' into develop 2018-02-26 10:58:30 +08:00
nazarlitvin bd68f8c631 remove unnecessary async functions 2018-02-19 22:16:33 +02:00
liutsing 3fde5aaa3c 1、本地化
2、解决侧边栏收起时菜单图标悬浮下无菜单文字显示的问题
2018-02-16 01:22:44 +08:00
Nelson Kuang 2f34de5602 修复左侧菜单合拢时mouseover提示空白视觉bug
当一级菜单没子菜单时,mouseover会弹出tooltips,但提示空白无内容
2018-02-07 17:25:16 +08:00
zuiidea 2de1e81661 Merge pull request #711 from zuiidea/develop
Develop
2017-12-27 15:41:00 +08:00
zuiidea cea60c5683 update Readme 2017-12-27 15:39:45 +08:00
zuiidea f16e104f73 fix all echarts example 2017-12-26 14:14:52 +08:00
zuiidea c397f552c3 fix some style 2017-12-26 11:31:05 +08:00
zuiidea 11c4ac803e fix users pagination 2017-12-25 20:39:48 +08:00
zuiidea 09b9a100de fix header style 2017-12-25 19:54:48 +08:00
zuiidea 0e59df39ee Compatibility upgrade 2017-12-25 18:08:25 +08:00
zuiidea 30254a2ec7 upgrade package 2017-12-25 10:51:36 +08:00
zuiidea cd796a6db9 fix Search style 2017-11-24 11:27:00 +08:00
zuiidea 6ba75de576 add backTop 2017-11-24 11:02:52 +08:00
zuiidea a3637b3a99 user search 2017-11-24 10:32:12 +08:00
zuiidea 85ec09ec9a Merge branch 'weishijun14-patch-1' into develop 2017-11-24 10:28:25 +08:00
zuiidea eb683b98e7 Merge branch 'patch-1' of https://github.com/weishijun14/antd-admin into weishijun14-patch-1 2017-11-24 10:28:17 +08:00
zuiidea 9221173309 Merge branch 'silentred-master' into develop 2017-11-24 10:26:15 +08:00
zuiidea 55a96f41c6 Merge branch 'master' of https://github.com/silentred/antd-admin into silentred-master 2017-11-24 10:25:42 +08:00
zuiidea ce510e79c7 Merge branch 'nazarlitvin-pagination' into develop 2017-11-24 10:24:56 +08:00
zuiidea 3d4f2a8814 Merge branch 'pagination' of https://github.com/nazarlitvin/antd-admin into nazarlitvin-pagination 2017-11-24 10:24:22 +08:00
nazarlitvin 38e24edd7b fix incorrect pagination property 2017-11-22 16:01:49 +02:00
Jason W 841c987a1a Update package.json
update package.json
2017-11-03 04:21:16 -05:00
shijun Wei dc26f7d25e update query to search
history 的 location 属性上不再包含 query。
2017-11-02 13:19:09 +08:00
zuiidea bc754e683e assets 2017-10-30 14:07:09 +08:00
zuiidea c7acc8db4b Merge pull request #649 from zuiidea/develop
Develop
2017-10-30 11:56:42 +08:00
zuiidea 057acc514f Merge branch 'smackgg-master' into develop 2017-10-30 11:52:52 +08:00
zuiidea 53ce7d08fb Merge branch 'xx1595140265-patch-1' into develop 2017-10-30 11:51:27 +08:00
zuiidea 8ffd68a4e2 Merge branch 'dkvirus-patch-1' into develop 2017-10-30 11:50:18 +08:00
zuiidea 766653ee7a merge #640 2017-10-30 11:49:27 +08:00
zuiidea 9dedcc68c3 Merge branch 'the-wang-master' into develop 2017-10-30 11:28:23 +08:00
zuiidea 5ea2b3c9b8 extend chart 2017-10-30 11:25:53 +08:00
汪亚辉 d2ac91839a 面包屑导航支持多级参数
例:
当前router为/:appkey/:packageId
父级router为/:appkey
当前pathname为/com.mock.ly/58

可以看出appkey=com.mock.ly, packageId=58
目前这种场景下,面包屑中父级连接直接展示为/:appkey,没有解析

本次commit支持根据当前多param去填充面包屑中父级页面连接
2017-10-24 18:55:06 +08:00
the-wang bfca2746d8 Merge pull request #1 from zuiidea/master
up
2017-10-24 18:54:10 +08:00
dkvirus b417065ac3 Update Menu.js
在 Slider.js 中调用 Menu 组件,并没有传入 handleClickNavMenu 属性的值,代码优化。
2017-10-12 16:27:52 +08:00
xuxue abdc97f087 Update index.js
取错值,修正
2017-10-10 04:23:34 -05:00
smackxu 07016c6c26 Fixed dark theme menu bug 2017-09-12 16:27:22 +08:00
zuiidea b8162060cd Merge pull request #581 from zuiidea/develop
Develop
2017-09-11 10:27:01 +08:00
zuiidea 36fb5d293c delete extra code 2017-09-11 10:19:43 +08:00
zuiidea 429280a97a Merge branch 'DiroKate-master' into develop 2017-09-11 10:18:37 +08:00
zuiidea 7ac36c779e merge #332 2017-09-11 10:18:20 +08:00
zuiidea d2e7b464e3 megre #563 2017-09-11 10:00:25 +08:00
zuiidea 25839ea99f Merge branch 'akliyiping-develop' into develop 2017-09-11 09:55:27 +08:00
zuiidea 9c99581aa6 Merge branch 'develop' of https://github.com/akliyiping/antd-admin into akliyiping-develop 2017-09-11 09:55:05 +08:00
zuiidea e42c21f0eb fix #574 2017-09-11 09:53:22 +08:00
zuiidea 782bf214e5 Merge branch 'dong894-master' into develop 2017-09-11 09:47:45 +08:00
zuiidea a8a4496c7a Merge branch 'master' of https://github.com/dong894/antd-admin into dong894-master 2017-09-11 09:47:29 +08:00
zuiidea f5f013ff23 Merge branch 'develop' 2017-09-11 09:35:39 +08:00
zuiidea 8cff3af897 Merge branch 'master' of https://github.com/zuiidea/antd-admin 2017-09-11 09:35:32 +08:00
zuiidea 322d5a6d0e merge #576 2017-09-11 09:35:09 +08:00
zuiidea 2ee26f51a7 Merge branch 'yangbin1994-bug575' into develop 2017-09-11 09:27:00 +08:00
zuiidea e670ed2f96 Merge branch 'bug575' of https://github.com/yangbin1994/antd-admin into yangbin1994-bug575 2017-09-11 09:26:36 +08:00
杨斌 601a03b5b4 fix bug#575 2017-09-10 02:26:27 +08:00
dongyulei 00582e70ff 修复 4.3.5 中用户画面翻页无效的问题 2017-09-10 00:02:10 +08:00
zuiidea fa4385055b Update README.md 2017-09-09 14:54:18 +08:00
zuiidea 01f4de55df Merge pull request #571 from zuiidea/develop
Develop
2017-09-09 14:52:50 +08:00
zuiidea dedd34e8e8 4.3.5 2017-09-09 14:50:47 +08:00
zuiidea d1b373201e fix some grammar and details 2017-09-09 14:20:51 +08:00
zuiidea dbcc90e7ad 出去吃烧烤,回来接着看 2017-09-08 16:41:05 +08:00
zuiidea 87fce74d5b Update app.js
fix mobile Header menu
2017-09-08 15:45:38 +08:00
zuiidea 5c51679ad7 Merge branch 'yangbin1994-dva2.0' into develop 2017-09-08 14:56:35 +08:00
zuiidea 6d17b5b876 Merge branch 'yangbin1994-dva2.0' 2017-09-08 14:51:51 +08:00
杨斌 1288853112 解决冲突 2017-09-08 14:19:40 +08:00
杨斌 d3e7e17789 query-string 2017-09-08 13:27:07 +08:00
eric 6077d74f10 .gitignore 增加排除项 2017-09-07 11:00:00 +08:00
杨斌 7bf031699a add LoadingComponent 2017-09-06 20:36:14 +08:00
杨斌 a6eb693636 dva@2.0 2017-09-06 11:13:26 +08:00
zuiidea 39c377e0e2 Merge pull request #552 from zuiidea/develop
add entry.ejs and add lte IE10 polyfill
2017-09-06 09:56:25 +08:00
zuiidea 67b90c4df0 add entry.ejs and add lte IE10 polyfill 2017-09-06 09:55:41 +08:00
zuiidea 0e2727f9c8 Merge pull request #542 from zuiidea/develop
4.3.4
2017-09-04 11:48:32 +08:00
zuiidea 0cf02e7324 4.3.4 2017-09-04 11:47:24 +08:00
zuiidea 68c9f2b65f Merge pull request #540 from zuiidea/develop
fix login success redirect;fix css load delay
2017-09-04 11:03:13 +08:00
diro 38637ef167 Example for the ”custom className iconfont” 2017-06-06 21:10:45 +08:00
diro fe8527e72e enable the custom ClassName 2017-06-06 21:08:42 +08:00
diro da64cac414 fix the wrong iconName 2017-06-06 20:45:56 +08:00
179 changed files with 5503 additions and 1781 deletions
+22
View File
@@ -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"
}
}
]
]
}
+2
View File
@@ -0,0 +1,2 @@
BROWSER=none
HOST=0.0.0.0
+2
View File
@@ -1,2 +1,4 @@
src/**/*-test.js
src/public
src/routes/chart/ECharts/theme
src/routes/chart/highCharts/mapdata
+25 -29
View File
@@ -1,52 +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,
"react/jsx-filename-extension": 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,
"no-continue": 0,
"react/jsx-no-bind": 0,
"no-mixed-operators": 0,
"no-plusplus": 0,
"no-unused-vars": [2, { "ignoreRestSiblings": true }],
"no-underscore-dangle": 0,
"global-require": 0,
"import/no-unresolved": 0,
"import/extensions": 0,
"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,
"import/no-extraneous-dependencies": 0,
"import/prefer-default-export": 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,
"jsx-a11y/no-static-element-interactions": 0,
},
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 8,
"ecmaFeatures": {
"jsx": true,
"experimentalObjectRestSpread": true
}
},
"settings": {
"import/resolver": "node"
}
"react/jsx-first-prop-new-line": 0,
"react/jsx-filename-extension": 0
}
}
+8
View File
@@ -0,0 +1,8 @@
> 请酌情提供细节,并保持issue精简便于查阅
> 1. 功能需求 => 详细说明
> 2. Bug反馈
> 2.1 简单描述下报错
> 2.2 你期望什么结果
> 2.3 如何操作导致的
> 2.4 可提供运行环境信息
> 3. 代码求助 => 可以提,未必及时答复
+16 -4
View File
@@ -1,4 +1,16 @@
dist
node_modules
yarn.lock
npm-debug.log
dist
node_modules
yarn.lock
npm-debug.log
# ide
.idea
# Mac General
.DS_Store
.AppleDouble
.LSOverride
# umi
.umi
.umi-production
-57
View File
@@ -1,57 +0,0 @@
const path = require('path')
const { version } = require('./package.json')
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",
publicPath : `/${version}/`,
outputPath : `./dist/${version}`,
// 接口代理示例
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" }
// }
},
env : {
development: {
extraBabelPlugins: [
"dva-hmr",
"transform-runtime",
[
"import", {
"libraryName": "antd",
"style": true
}
]
]
},
production: {
extraBabelPlugins: [
"transform-runtime",
[
"import", {
"libraryName": "antd",
"style": true
}
]
]
}
},
dllPlugin : {
exclude: ["babel-runtime"],
include: ["dva/router", "dva/saga", "dva/fetch"]
}
}
-5
View File
@@ -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
+71
View File
@@ -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'));
},
}
+85 -80
View File
@@ -1,8 +1,8 @@
# Antd Admin
[![React](https://img.shields.io/badge/react-^15.6.1-brightgreen.svg?style=flat-square)](https://github.com/facebook/react)
[![Ant Design](https://img.shields.io/badge/ant--design-^2.11.2-yellowgreen.svg?style=flat-square)](https://github.com/ant-design/ant-design)
[![dva](https://img.shields.io/badge/dva-^1.2.0-orange.svg?style=flat-square)](https://github.com/dvajs/dva)
[![React](https://img.shields.io/badge/react-^16.2.0-brightgreen.svg?style=flat-square)](https://github.com/facebook/react)
[![Ant Design](https://img.shields.io/badge/ant--design-^3.0.3-yellowgreen.svg?style=flat-square)](https://github.com/ant-design/ant-design)
[![dva](https://img.shields.io/badge/dva-^2.1.0-orange.svg?style=flat-square)](https://github.com/dvajs/dva)
[![GitHub issues](https://img.shields.io/github/issues/zuiidea/antd-admin.svg?style=flat-square)](https://github.com/zuiidea/antd-admin)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/zuiidea/antd-admin/pulls)
@@ -13,87 +13,99 @@
## 特性
- 基于[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 功能实现脱离后端独立开发。
* 浅度响应式设计。
## 更新日志
### 5.0.0-beta
`2018-6-20`
* 感谢@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.3.9
`2017-12-27`
* 更新`antd`至`3.0.3`,以及其它主要库,并解决升级带来的兼容问题。
* 尽可能的保持`antd`的设计语言。
### 4.3.7
`2017-10-30`
* 更新`chart`,新增[ECharts](https://github.com/ecomfe/echarts),[highCharts](https://github.com/highcharts/highcharts),[Recharts](https://github.com/recharts/recharts)演示。
### 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`。
* 更新[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`。
### 4.2.3
`2017-07-07`
-   新增用户按权限访问。[#384](https://github.com/zuiidea/antd-admin/issues/384)
### 4.2.2
`2017-06-01`
-   新增用户管理批量删除。[#320](https://github.com/zuiidea/antd-admin/issues/320)
### 4.2.1
`2017-05-12`
-   新增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)
### 4.2
`2017-04-28`
- 修改user相关API使用`Restful`风格。
- 增加user页面多条件查询。[#266](https://github.com/zuiidea/antd-admin/issues/226)
- 修复菜单默认高亮。[#201](https://github.com/zuiidea/antd-admin/issues/201)
[More Change Log](https://github.com/zuiidea/antd-admin/wiki/Change-Log)
[More Change Log](https://github.com/zuiidea/antd-admin/wiki/Change-Log)
## 开发构建
### 目录结构
### 目录结构
```bash
├── /dist/ # 项目输出目录
├── /mock/ # 数据mock
├── /public/ # 公共文件,编译时copy至dist目录
├── /src/ # 项目源码目录
│ ├── /public/ # 公共文件,编译时copy至dist目录
│ ├── /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`)。
### 快速开始
@@ -106,31 +118,20 @@ git clone https://github.com/zuiidea/antd-admin.git
进入目录安装依赖:
```bash
#开始前请确保没有安装roadhog、webpack到NPM全局目录
#开始前请确保没有安装roadhog、webpack到NPM全局目录, 国内用户推荐yarn或者cnpm
npm i 或者 yarn install
```
开发:
```bash
npm run build:dll #第一次npm run dev时需运行此命令,使开发时编译更快
npm run dev
打开 http://localhost:8000
npm run start
打开 http://localhost:8000 #端口在package.json中cross-env后加上 PORT=8000指定
```
构建:
[详情](https://github.com/zuiidea/antd-admin/issues/269)
```bash
npm run build
将会打包至dist/{version}目录 #package.json里version字段
npm run build:new
将会打包至dist/{version增加1}目录 #package.json里version字段
```
代码检测:
```bash
@@ -139,29 +140,33 @@ npm run lint
## 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)
* 项目打包后如何部署? [#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
```
```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
![](assets/4.2.1-demo-1.gif)
![](https://user-images.githubusercontent.com/8142164/43032162-37db46e2-8ce3-11e8-9c7e-73a773bc0545.gif)
移动
![](assets/4.2.1-demo-2.gif)
![](https://user-images.githubusercontent.com/8142164/43032163-3a1f2838-8ce3-11e8-89c5-8e1ae077d34a.gif)
效果图
![](https://user-images.githubusercontent.com/8142164/43032165-5d151bae-8ce3-11e8-9bfd-8a121620ea78.jpg)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 645 KiB

+1 -1
View File
@@ -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)) {
+2 -2
View File
@@ -1,7 +1,7 @@
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
+9 -9
View File
@@ -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',
View File
+2 -2
View File
@@ -1,6 +1,6 @@
const qs = require('qs')
const Mock = require('mockjs')
const config = require('../utils/config')
const config = require('../src/utils/config')
const { apiPrefix } = config
@@ -173,7 +173,7 @@ 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))
res.status(204).end()
+50 -50
View File
@@ -1,63 +1,63 @@
{
"private": true,
"name": "antd-admin",
"version": "4.3.3",
"version": "5.0.0-beta",
"dependencies": {
"antd": "^2.11.2",
"axios": "^0.16.2",
"babel-polyfill": "^6.23.0",
"classnames": "^2.2.5",
"d3-shape": "^1.2.0",
"draftjs-to-markdown": "^0.4.0",
"dva": "^1.2.0",
"dva-loading": "^0.2.0",
"ejs-loader": "^0.3.0",
"js-beautify": "^1.6.14",
"@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",
"less-vars-to-js": "^1.1.2",
"lodash": "^4.17.4",
"mockjs": "^1.0.1-beta3",
"lodash.clonedeep": "^4.5.0",
"lodash.isequal": "^4.5.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.5.10",
"qs": "^6.5.0",
"rc-tween-one": "^1.3.1",
"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",
"roadhog": "^1.2.1"
"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": {
"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-runtime": "^6.9.2",
"copy-webpack-plugin": "^4.0.1",
"draftjs-to-html": "^0.7.0",
"dva-model-extend": "^0.1.1",
"eslint": "^4.1.1",
"eslint-config-airbnb": "^15.0.2",
"eslint-import-resolver-node": "^0.3.1",
"eslint-loader": "^1.9.0",
"eslint-plugin-import": "^2.6.1",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.1.0",
"html-webpack-plugin": "^2.29.0",
"html-webpack-template": "^5.6.0",
"redbox-react": "^1.2.10",
"roadhog": "1.0.0-beta.7"
"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",
"svg-sprite-loader": "^3.9.2",
"umi": "^2.0.0",
"umi-plugin-react": "^1.0.0"
},
"pre-commit": ["lint"],
"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:dll": "roadhog buildDll",
"build:new": "node version && roadhog build"
"build": "umi build",
"test": "umi test"
}
}
}

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

+43
View File
@@ -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

+7 -24
View File
@@ -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
+16 -14
View File
@@ -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,
+3 -1
View File
@@ -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>}
+11 -8
View File
@@ -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
+15 -3
View File
@@ -1,10 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Breadcrumb, Icon } from 'antd'
import { Link } from 'dva/router'
import { Link } from 'react-router-dom'
import pathToRegexp from 'path-to-regexp'
import { queryArray } from 'utils'
import styles from './Bread.less'
import styles from './Layout.less'
const Bread = ({ menu, location }) => {
// 匹配当前路由
@@ -24,6 +24,7 @@ const Bread = ({ menu, location }) => {
}
}
let paramMap = {}
if (!current) {
pathArray.push(menu[0] || {
id: 1,
@@ -36,6 +37,17 @@ const Bread = ({ menu, location }) => {
})
} 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]
})
}
}
// 递归查找父级
@@ -48,7 +60,7 @@ const Bread = ({ menu, location }) => {
return (
<Breadcrumb.Item key={key}>
{((pathArray.length - 1) !== key)
? <Link to={item.route}>
? <Link to={pathToRegexp.compile(item.route || '')(paramMap) || '#'}>
{content}
</Link>
: content}
-8
View File
@@ -1,8 +0,0 @@
@import "~themes/vars";
.bread {
height: 64px;
line-height: 64px;
padding: 0 24px;
margin-bottom: -24px;
}
-9
View File
@@ -1,9 +0,0 @@
import React from 'react'
import { config } from 'utils'
import styles from './Footer.less'
const Footer = () => (<div className={styles.footer}>
{config.footerText}
</div>)
export default Footer
-12
View File
@@ -1,12 +0,0 @@
@import "~themes/vars";
.footer {
height: 48px;
line-height: 48px;
text-align: center;
font-size: 12px;
color: #999;
background: #fff;
box-shadow: @shadow-2;
width: 100%;
}
+7 -5
View File
@@ -1,13 +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,
@@ -20,7 +22,7 @@ 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}>
@@ -53,7 +55,7 @@ const Header = ({ user, logout, switchSider, siderFold, isNavbar, menuPopoverVis
</SubMenu>
</Menu>
</div>
</div>
</Layout.Header>
)
}
+92 -59
View File
@@ -1,59 +1,92 @@
@import "~themes/vars";
.header {
:global .ant-menu-horizontal {
& > .ant-menu-submenu {
float: right;
}
border: none;
display: inline-block;
}
box-shadow: @shadow-2;
position: relative;
display: flex;
justify-content: space-between;
height: 47px;
background-color: #fff;
z-index: 999;
.rightWarpper {
display: flex;
padding-right: 16px;
}
.button {
width: 47px;
height: 47px;
line-height: 47px;
text-align: center;
font-size: 18px;
cursor: pointer;
transition: @transition-ease-in;
&:hover {
color: @primary-color;
background-color: fade(@primary-color, 15%);
}
}
}
.popovermenu {
width: 280px;
margin-left: 6px;
:global .ant-popover-inner-content {
padding: 0;
.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,
.ant-menu-inline .ant-menu-selected {
border-right: 0;
}
}
}
@import "~themes/vars.less";
.header {
: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;
}
}
box-shadow: @shadow-2;
position: relative;
display: flex;
justify-content: space-between;
height: 56px;
z-index: 9;
display: flex;
align-items: center;
background-color: #fff;
.rightWarpper {
display: flex;
padding-right: 16px;
}
.button {
width: 56px;
height: 56px;
line-height: 56px;
text-align: center;
font-size: 18px;
cursor: pointer;
transition: @transition-ease-in;
&:hover {
color: @primary-color;
background-color: fade(@primary-color, 15%);
}
}
}
.popovermenu {
width: 280px;
margin-left: 6px;
:global .ant-popover-inner-content {
padding: 0;
.ant-menu-inline .ant-menu-item,
.ant-menu-vertical .ant-menu-item {
border-right: 0;
}
.ant-menu-inline .ant-menu-item-selected,
.ant-menu-inline .ant-menu-selected {
border-right: 0;
}
}
}
+191 -292
View File
@@ -1,292 +1,191 @@
@import "~themes/vars";
.layout {
position: relative;
height: 100vh;
&.withnavbar {
.main {
margin-left: 0;
}
}
&.fold {
.sider {
width: 42px;
.logo {
img {
width: 28px;
margin: 6px 7px;
}
}
: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;
&::-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;
}
}
}
}
.ant-menu {
transition: @transition-ease-out;
.ant-menu-item,
.ant-menu-submenu-title {
overflow: hidden;
white-space: normal;
}
}
}
}
.main {
margin-left: 224px;
overflow: auto;
height: 100vh;
transition: @transition-ease-out;
:global {
.content-inner {
background: #fff;
padding: 24px;
box-shadow: @shadow-1;
min-height: e("calc(100vh - 184px)");
}
}
.container {
margin: 24px;
}
.content {
min-height: e("calc(100vh - 184px)");
position: relative;
}
}
}
:global .ant-menu-dark {
color: #999;
background-color: #3e3e3e;
.ant-menu-submenu-title:hover,
.ant-menu-submenu:hover {
color: @primary-color;
}
.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;
}
}
}
.spin {
:global .ant-spin-container {
height: 100vh;
}
}
@media (max-width: 767px) {
.layout {
.main {
.container {
margin: 12px;
}
.bread {
padding: 0 12px;
}
.content {
min-height: e("calc(100vh - 160px)");
}
:global {
.content-inner {
padding: 12px;
min-height: e("calc(100vh - 160px)");
}
}
}
}
}
@import "~themes/vars.less";
:global {
.ant-layout-header {
padding: 0;
}
.ant-layout-sider {
transition: all 0.3s;
.ant-menu-root {
height: ~"calc(100vh - 144px)";
overflow-x: hidden;
border-right: none;
&::-webkit-scrollbar-thumb {
background-color: transparent;
}
&:hover {
&::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
}
}
}
.ant-menu {
.ant-menu-item,
.ant-menu-submenu-title {
overflow: hidden;
white-space: normal;
}
}
}
.ant-layout-content {
padding: 24px;
}
.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;
}
}
.flex-vertical-center {
display: flex;
align-items: center;
}
.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;
}
}
}
.sidemenu {
:global{
.ant-menu-item {
width: 100%;
}
}
}
.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;
}
:global {
.anticon {
min-width: 14px;
margin-right: 4px;
font-size: 14px;
}
}
}
.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) {
.bread {
margin-bottom: 12px;
}
:global {
.ant-layout-content {
padding: 12px;
}
.ant-back-top {
right: 20px;
bottom: 20px;
}
}
}
@keyframes fadeLeftIn {
0% {
transform: translateX(5px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
+22 -11
View File
@@ -1,11 +1,17 @@
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, location }) => {
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 = {}
@@ -18,7 +24,7 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
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)
@@ -111,8 +123,8 @@ const Menus = ({ siderFold, darkTheme, handleClickNavMenu, navOpenKeys, changeOp
{...menuProps}
mode={siderFold ? 'vertical' : 'inline'}
theme={darkTheme ? 'dark' : 'light'}
onClick={handleClickNavMenu}
defaultSelectedKeys={defaultSelectedKeys}
selectedKeys={defaultSelectedKeys}
className={styles.sidemenu}
>
{menuItems}
</Menu>
@@ -123,7 +135,6 @@ Menus.propTypes = {
menu: PropTypes.array,
siderFold: PropTypes.bool,
darkTheme: PropTypes.bool,
handleClickNavMenu: PropTypes.func,
navOpenKeys: PropTypes.array,
changeOpenKeys: PropTypes.func,
location: PropTypes.object,
+4 -2
View File
@@ -5,7 +5,9 @@ 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
View File
@@ -1 +0,0 @@
@import "~themes/vars";
+1 -2
View File
@@ -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 }
+7 -2
View File
@@ -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
+68 -64
View File
@@ -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);
}
}
+36
View File
@@ -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,
}
+16
View File
@@ -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)";
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"name": "Page",
"version": "0.0.0",
"private": true,
"main": "./Page.js"
}
+3 -1
View File
@@ -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}>
+54 -55
View File
@@ -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;
}
}
}
+4 -2
View File
@@ -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,
}
+19 -18
View File
@@ -5,7 +5,9 @@ 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',
@@ -53,32 +55,31 @@ layer.open = (config) => {
const { className, wrapClassName = '', verticalCenter = true } = modalProps
const { prefixCls } = layer
layer.index += 1
const index = layer.index
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
}
+1
View File
@@ -0,0 +1 @@
import '@babel/polyfill'
-25
View File
@@ -1,25 +0,0 @@
import { message } from 'antd'
import dva from 'dva'
import createLoading from 'dva-loading'
import { browserHistory } from 'dva/router'
import 'babel-polyfill'
// 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')
+40 -23
View File
@@ -1,29 +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 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()
@@ -36,6 +44,7 @@ const App = ({ children, dispatch, app, loading, location }) => {
const headerProps = {
menu,
user,
location,
siderFold,
isNavbar,
menuPopoverVisible,
@@ -73,15 +82,17 @@ const App = ({ children, dispatch, app, loading, location }) => {
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 spinning={loading.effects['app/query']} />
<Loader fullScreen spinning={loading.effects['app/query']} />
<Helmet>
<title>ANTD ADMIN</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -89,21 +100,27 @@ const App = ({ children, dispatch, app, loading, location }) => {
{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 })}>
{siderProps.menu.length === 0 ? null : <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>
)
}
@@ -116,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))
+72 -72
View File
@@ -1,72 +1,72 @@
@import "~themes/vars";
:global {
#nprogress {
pointer-events: none;
.bar {
background: @primary-color;
position: fixed;
z-index: 1024;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 2px;
}
.peg {
display: block;
position: absolute;
right: 0;
width: 100px;
height: 100%;
box-shadow: 0 0 10px @primary-color,0 0 5px @primary-color;
opacity: 1.0;
transform: rotate(3deg) translate(0px,-4px);
}
.spinner {
display: block;
position: fixed;
z-index: 1031;
top: 15px;
right: 15px;
}
.spinner-icon {
width: 18px;
height: 18px;
box-sizing: border-box;
border: solid 2px transparent;
border-top-color: @primary-color;
border-left-color: @primary-color;
border-radius: 50%;
:local {
animation: nprogress-spinner 400ms linear infinite;
}
}
}
.nprogress-custom-parent {
overflow: hidden;
position: relative;
#nprogress {
.bar,
.spinner {
position: absolute;
}
}
}
}
@keyframes nprogress-spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@import "~themes/vars.less";
:global {
#nprogress {
pointer-events: none;
.bar {
background: @primary-color;
position: fixed;
z-index: 1024;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 2px;
}
.peg {
display: block;
position: absolute;
right: 0;
width: 100px;
height: 100%;
box-shadow: 0 0 10px @primary-color,0 0 5px @primary-color;
opacity: 1.0;
transform: rotate(3deg) translate(0px,-4px);
}
.spinner {
display: block;
position: fixed;
z-index: 1031;
top: 15px;
right: 15px;
}
.spinner-icon {
width: 18px;
height: 18px;
box-sizing: border-box;
border: solid 2px transparent;
border-top-color: @primary-color;
border-left-color: @primary-color;
border-radius: 50%;
:local {
animation: nprogress-spinner 400ms linear infinite;
}
}
}
.nprogress-custom-parent {
overflow: hidden;
position: relative;
#nprogress {
.bar,
.spinner {
position: absolute;
}
}
}
}
@keyframes nprogress-spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
+14
View File
@@ -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>
)
})
+16 -3
View File
@@ -1,12 +1,15 @@
/* 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
@@ -97,10 +100,10 @@ export default {
}
} else if (config.openPages && config.openPages.indexOf(locationPathname) < 0) {
yield put(routerRedux.push({
pathname: 'login',
query: {
pathname: '/login',
search: queryString.stringify({
from: locationPathname,
},
}),
}))
}
},
@@ -110,6 +113,16 @@ export default {
}, { 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)
@@ -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,
}
@@ -39,7 +45,7 @@ class DataTablePage extends React.Component {
{ title: 'Phone', dataIndex: 'phone' },
{ title: 'Gender', dataIndex: 'gender' },
],
rowKey: 'registered',
rowKey: 'email',
}
const caseChangeDataTableProps = {
@@ -57,7 +63,7 @@ class DataTablePage extends React.Component {
{ 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,5 +1,5 @@
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'
@@ -24,7 +24,7 @@ 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}>
@@ -111,6 +111,6 @@ const IcoPage = () => (<div className="content-inner">
<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;
}
}
}
@@ -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
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types'
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 }}>
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>
@@ -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
+328
View File
@@ -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
File diff suppressed because one or more lines are too long
@@ -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>:&nbsp;&nbsp;
<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
+62
View File
@@ -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
+261
View File
@@ -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
+111
View File
@@ -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
+34
View File
@@ -0,0 +1,34 @@
.chart {
label {
margin: 24px 0;
display: block;
font-size: 14px;
}
pre {
padding: 16px;
overflow: auto;
font-size: 12px;
line-height: 2;
background-color: #f6f8fa;
border-radius: 3px;
code {
display: inline;
max-width: auto;
padding: 0;
margin: 0;
overflow: visible;
line-height: inherit;
word-wrap: normal;
background-color: transparent;
border: 0;
}
}
}
:global {
.ant-radio-wrapper {
margin-bottom: 16px;
}
}
+198
View File
@@ -0,0 +1,198 @@
(function (root, factory) {
if (typeof define === 'function' && define.amd) { // eslint-disable-line
// AMD. Register as an anonymous module.
define(['exports', 'echarts'], factory) // eslint-disable-line
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
// CommonJS
factory(exports, require('echarts'))
} else {
// Browser globals
factory({}, root.echarts)
}
}(this, (exports, echarts) => {
let log = function (msg) {
if (typeof console !== 'undefined') {
console && console.error && console.error(msg)
}
}
if (!echarts) {
log('ECharts is not Loaded')
return
}
let colorPalette = [
'#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80',
'#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa',
'#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050',
'#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089',
]
let theme = {
color: colorPalette,
title: {
textStyle: {
fontWeight: 'normal',
color: '#008acd',
},
},
visualMap: {
itemWidth: 15,
color: ['#5ab1ef', '#e0ffff'],
},
toolbox: {
iconStyle: {
normal: {
borderColor: colorPalette[0],
},
},
},
tooltip: {
backgroundColor: 'rgba(50,50,50,0.5)',
axisPointer: {
type: 'line',
lineStyle: {
color: '#008acd',
},
crossStyle: {
color: '#008acd',
},
shadowStyle: {
color: 'rgba(200,200,200,0.2)',
},
},
},
dataZoom: {
dataBackgroundColor: '#efefff',
fillerColor: 'rgba(182,162,222,0.2)',
handleColor: '#008acd',
},
grid: {
borderColor: '#eee',
},
categoryAxis: {
axisLine: {
lineStyle: {
color: '#008acd',
},
},
splitLine: {
lineStyle: {
color: ['#eee'],
},
},
},
valueAxis: {
axisLine: {
lineStyle: {
color: '#008acd',
},
},
splitArea: {
show: true,
areaStyle: {
color: ['rgba(250,250,250,0.1)', 'rgba(200,200,200,0.1)'],
},
},
splitLine: {
lineStyle: {
color: ['#eee'],
},
},
},
timeline: {
lineStyle: {
color: '#008acd',
},
controlStyle: {
normal: { color: '#008acd' },
emphasis: { color: '#008acd' },
},
symbol: 'emptyCircle',
symbolSize: 3,
},
line: {
smooth: true,
symbol: 'emptyCircle',
symbolSize: 3,
},
candlestick: {
itemStyle: {
normal: {
color: '#d87a80',
color0: '#2ec7c9',
lineStyle: {
color: '#d87a80',
color0: '#2ec7c9',
},
},
},
},
scatter: {
symbol: 'circle',
symbolSize: 4,
},
map: {
label: {
normal: {
textStyle: {
color: '#d87a80',
},
},
},
itemStyle: {
normal: {
borderColor: '#eee',
areaColor: '#ddd',
},
emphasis: {
areaColor: '#fe994e',
},
},
},
graph: {
color: colorPalette,
},
gauge: {
axisLine: {
lineStyle: {
color: [[0.2, '#2ec7c9'], [0.8, '#5ab1ef'], [1, '#d87a80']],
width: 10,
},
},
axisTick: {
splitNumber: 10,
length: 15,
lineStyle: {
color: 'auto',
},
},
splitLine: {
length: 22,
lineStyle: {
color: 'auto',
},
},
pointer: {
width: 5,
},
},
}
echarts.registerTheme('macarons', theme)
}))
+158
View File
@@ -0,0 +1,158 @@
(function (root, factory) {
if (typeof define === 'function' && define.amd) { // eslint-disable-line
// AMD. Register as an anonymous module.
define(['exports', 'echarts'], factory) // eslint-disable-line
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
// CommonJS
factory(exports, require('echarts'))
} else {
// Browser globals
factory({}, root.echarts)
}
}(this, (exports, echarts) => {
let log = function (msg) {
if (typeof console !== 'undefined') {
console && console.error && console.error(msg)
}
}
if (!echarts) {
log('ECharts is not Loaded')
return
}
let colorPalette = [
'#c12e34', '#e6b600', '#0098d9', '#2b821d',
'#005eaa', '#339ca8', '#cda819', '#32a487',
]
let theme = {
color: colorPalette,
title: {
textStyle: {
fontWeight: 'normal',
},
},
visualMap: {
color: ['#1790cf', '#a2d4e6'],
},
toolbox: {
iconStyle: {
normal: {
borderColor: '#06467c',
},
},
},
tooltip: {
backgroundColor: 'rgba(0,0,0,0.6)',
},
dataZoom: {
dataBackgroundColor: '#dedede',
fillerColor: 'rgba(154,217,247,0.2)',
handleColor: '#005eaa',
},
timeline: {
lineStyle: {
color: '#005eaa',
},
controlStyle: {
normal: {
color: '#005eaa',
borderColor: '#005eaa',
},
},
},
candlestick: {
itemStyle: {
normal: {
color: '#c12e34',
color0: '#2b821d',
lineStyle: {
width: 1,
color: '#c12e34',
color0: '#2b821d',
},
},
},
},
graph: {
color: colorPalette,
},
map: {
label: {
normal: {
textStyle: {
color: '#c12e34',
},
},
emphasis: {
textStyle: {
color: '#c12e34',
},
},
},
itemStyle: {
normal: {
borderColor: '#eee',
areaColor: '#ddd',
},
emphasis: {
areaColor: '#e6b600',
},
},
},
gauge: {
axisLine: {
show: true,
lineStyle: {
color: [[0.2, '#2b821d'], [0.8, '#005eaa'], [1, '#c12e34']],
width: 5,
},
},
axisTick: {
splitNumber: 10,
length: 8,
lineStyle: {
color: 'auto',
},
},
axisLabel: {
textStyle: {
color: 'auto',
},
},
splitLine: {
length: 12,
lineStyle: {
color: 'auto',
},
},
pointer: {
length: '90%',
width: 3,
color: 'auto',
},
title: {
textStyle: {
color: '#333',
},
},
detail: {
textStyle: {
color: 'auto',
},
},
},
}
echarts.registerTheme('shine', theme)
}))
@@ -1,6 +1,6 @@
import React from 'react'
import * as d3 from 'd3-shape'
import { Row, Col, Card, Button } from 'antd'
import * as d3 from 'd3-shape'
import {
AreaChart,
Area,
@@ -9,7 +9,8 @@ import {
CartesianGrid,
Tooltip,
} from 'recharts'
import Container from '../Container'
import Container from './Container'
const data = [
{
@@ -253,10 +254,9 @@ const CardinalAreaChart = () => (
</Container>
)
const EditorPage = () => (
const AreaChartPage = () => (
<div className="content-inner">
<Button type="primary"
size="large"
style={{
position: 'absolute',
right: 0,
@@ -290,4 +290,4 @@ const EditorPage = () => (
</div>
)
export default EditorPage
export default AreaChartPage
@@ -10,7 +10,8 @@ import {
Tooltip,
Legend,
} from 'recharts'
import Container from '../Container'
import Container from './Container'
const data = [
{
@@ -161,13 +162,15 @@ const MixBarChart = () => (
// CustomShapeBarChart
const getPath = (x, y, width, height) => {
return `M${x},${y + height}
C${x + (width / 3)},${y + height} ${x + (width / 2)},${y + (height / 3)} ${x + (width / 2)}, ${y}
C${x + (width / 2)},${y + (height / 3)} ${x + (2 * (width / 3))},${y + height} ${x + width}, ${y + height}
C${x + width / 3},${y + height} ${x + width / 2},${y + height / 3} ${x + width / 2}, ${y}
C${x + width / 2},${y + height / 3} ${x + 2 * width / 3},${y + height} ${x + width}, ${y + height}
Z`
}
const TriangleBar = (props) => {
const { fill, x, y, width, height } = props
const {
fill, x, y, width, height,
} = props
return <path d={getPath(x, y, width, height)} stroke="none" fill={fill} />
}
@@ -197,10 +200,9 @@ const CustomShapeBarChart = () => (
</Container>
)
const EditorPage = () => (
const BarChartPage = () => (
<div className="content-inner">
<Button type="primary"
size="large"
style={{
position: 'absolute',
right: 0,
@@ -234,4 +236,4 @@ const EditorPage = () => (
</div>
)
export default EditorPage
export default BarChartPage
+24
View File
@@ -0,0 +1,24 @@
import React from 'react'
import PropTypes from 'prop-types'
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 className={styles.content} style={{ minHeight, maxHeight }}>
<ResponsiveContainer>
{children}
</ResponsiveContainer>
</div>
</div>)
Container.propTypes = {
children: PropTypes.element.isRequired,
ratio: PropTypes.number,
minHeight: PropTypes.number,
maxHeight: PropTypes.number,
}
export default Container

Some files were not shown because too many files have changed in this diff Show More