├── .gitattributes
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── public
└── vite.svg
├── src
├── App.jsx
├── api
│ ├── config.js
│ └── index.js
├── assets
│ ├── font
│ │ ├── demo.html
│ │ ├── webfont.eot
│ │ ├── webfont.svg
│ │ ├── webfont.ttf
│ │ ├── webfont.woff
│ │ └── webfont.woff2
│ └── images
│ │ ├── 404.jpg
│ │ ├── 500.png
│ │ ├── loading.gif
│ │ ├── loading1.gif
│ │ ├── login.jpg
│ │ └── user.jpg
├── components
│ ├── CustomBreadcrumb
│ │ ├── CustomBreadcrumb.jsx
│ │ └── index.js
│ ├── CustomMenu
│ │ ├── CustomMenu.jsx
│ │ └── index.js
│ └── PageLoading
│ │ └── Index.jsx
├── containers
│ ├── AppAside.jsx
│ ├── AppFooter.jsx
│ ├── AppHeader.jsx
│ ├── DefaultLayout.jsx
│ ├── index.js
│ └── menu.js
├── main.jsx
├── routes
│ └── index.js
├── style
│ ├── App.scss
│ ├── base.scss
│ ├── layout.scss
│ └── view-style
│ │ ├── animation.scss
│ │ ├── button.scss
│ │ ├── dropdown.scss
│ │ ├── editor.scss
│ │ ├── form.scss
│ │ ├── icon.scss
│ │ ├── index.scss
│ │ ├── login.scss
│ │ ├── progress.scss
│ │ ├── step.scss
│ │ └── table.scss
├── utils
│ └── util.js
└── views
│ ├── About
│ ├── About.jsx
│ └── index.js
│ ├── FormView
│ ├── FormBaseView
│ │ ├── FormBaseView.jsx
│ │ └── index.js
│ └── FormStepView
│ │ ├── FormStepView.jsx
│ │ └── index.js
│ ├── Index
│ ├── Index.jsx
│ ├── bar.jsx
│ ├── index.js
│ ├── line.jsx
│ ├── pictorialBar.jsx
│ ├── pie.jsx
│ └── scatter.jsx
│ ├── Login
│ ├── Login.jsx
│ └── index.js
│ ├── NavView
│ ├── Dropdown
│ │ ├── Dropdown.jsx
│ │ └── index.js
│ ├── Menu
│ │ ├── Menu.jsx
│ │ └── index.js
│ └── Step
│ │ ├── Step.jsx
│ │ └── index.js
│ ├── Others
│ ├── 404
│ │ ├── 404.jsx
│ │ └── index.js
│ ├── 500
│ │ ├── 500.jsx
│ │ └── index.js
│ ├── Animation
│ │ ├── Animation.jsx
│ │ └── index.js
│ ├── Editor
│ │ ├── Editor.jsx
│ │ └── index.js
│ ├── Progress
│ │ ├── Progress.jsx
│ │ └── index.js
│ └── Upload
│ │ ├── Upload.jsx
│ │ └── index.js
│ ├── PublicView
│ ├── Button
│ │ ├── ButtonView.jsx
│ │ ├── components
│ │ │ └── IconButton.jsx
│ │ └── index.js
│ └── Icon
│ │ ├── IconView.jsx
│ │ └── index.js
│ ├── ShowView
│ ├── Collapse
│ │ ├── Collapse.jsx
│ │ └── index.js
│ ├── Table
│ │ ├── Table.jsx
│ │ └── index.js
│ ├── Tabs
│ │ ├── Tabs.jsx
│ │ ├── components
│ │ │ ├── AddTabs.jsx
│ │ │ ├── BaseTabs.jsx
│ │ │ ├── LocationTabs.jsx
│ │ │ └── SizeTabs.jsx
│ │ └── index.js
│ └── Tree
│ │ ├── Index.scss
│ │ ├── Tree.jsx
│ │ ├── components
│ │ ├── BaseTree.jsx
│ │ ├── ControlledTree.jsx
│ │ ├── DragTree.jsx
│ │ └── SearchTree.jsx
│ │ └── index.js
│ └── TestView
│ ├── TestView.jsx
│ └── index.js
└── vite.config.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | vue.config.js filter=gitignore
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 |
3 | **react-vite-admin**
4 |
5 | 基于 React 生态系统搭建的后台管理系统模板
6 |
7 | > [项目预览地址](https://github.react-vite-admin.zzhvv.com/#/login)
8 |
9 | > ~~[ts 版本](https://github.com/zzhStrive/react-vite-ts-admin)~~
10 |
11 | ## 技术栈
12 |
13 | react@18.2.0 + vite@3.0.7 + antd@4.23.0 + axios@0.19.0
14 |
15 | > `animate.css@3.7.2` 页面动画展示
16 |
17 | > `echarts@4.4.0` 数据可视化
18 |
19 | > `nprogress@0.2.0` 顶部加载条
20 |
21 | > `screenfull@5.0.0` 全屏插件
22 |
23 | > 开发 node 版本 v16.15.0
24 |
25 | ### 基本功能
26 |
27 | - [x] 路由懒加载
28 | - [x] 面包屑导航
29 | - [x] 常用 UI 展示
30 | - [x] echarts 全屏展示
31 | - [x] 登陆/注销功能
32 |
33 | ## 快速启动
34 |
35 | ```
36 | # 克隆项目
37 | git clone git@github.com:zzhStrive/react-vite-admin.git
38 |
39 |
40 |
41 | # 进入项目目录
42 | cd react-vite-admin
43 |
44 | # 安装依赖
45 | npm install
46 |
47 | # 启动服务
48 | npm run dev dev
49 |
50 | # 打包
51 | npm run build build
52 | ```
53 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
226 |
webfont 字体预览
227 |
字体预览,字体演示
228 |
229 |
230 | 第一步:使用font-face声明字体
231 |
232 | @font-face {
233 | font-family: 'webfont';
234 | font-display: swap;
235 | src: url('webfont.eot'); /* IE9 */
236 | src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
237 | url('webfont.woff2') format('woff2'),
238 | url('webfont.woff') format('woff'), /* chrome、firefox */
239 | url('webfont.ttf') format('truetype'), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
240 | url('webfont.svg#webfont') format('svg'); /* iOS 4.1- */
241 | }
242 |
243 | 第二步:定义使用 webfont 的样式
244 |
245 | .web-font {
246 | font-family: "webfont" !important;
247 | font-size: 16px;
248 | font-style: normal;
249 | -webkit-font-smoothing: antialiased;
250 | -moz-osx-font-smoothing: grayscale;
251 | }
252 |
253 | 第三步:为文字加上对应的样式
254 |
255 | <i class="web-font">字体预览,字体演示</i>
256 |
257 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/src/assets/font/webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzwanfeng/react-vite-admin/32486f7316c8ca9867af6828bfe550dc88c6916f/src/assets/font/webfont.eot
--------------------------------------------------------------------------------
/src/assets/font/webfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | props.setCurrent(0)}>
167 | 再发一封
168 | ,
169 |
170 | ]}
171 | />
172 | )
173 | }
174 |
175 |
176 | const FormStepView = props => {
177 | const [current, setCurrent] = useState(0)
178 | const [formData, setFormData] = useState(null)
179 |
180 | return (
181 |
182 |
183 |
184 |
185 |
186 |
何时使用
187 |
188 |
当用户需要分步收集不同信息时
189 |
190 |
191 |
192 |
193 |
194 |
分步表单
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 | {current === 0 && (
203 | setFormData(val)} setCurrent={val => setCurrent(val)} />
204 | )}
205 | {current === 1 && setCurrent(val)} />}
206 | {current === 2 && setCurrent(val)} />}
207 |
208 |
209 |
210 |
211 |
212 | )
213 | }
214 |
215 | export default FormStepView
216 |
--------------------------------------------------------------------------------
/src/views/FormView/FormStepView/index.js:
--------------------------------------------------------------------------------
1 | import FormStepView from './FormStepView.jsx'
2 |
3 | export default FormStepView
4 |
--------------------------------------------------------------------------------
/src/views/Index/Index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Layout, Row, Col, Divider } from 'antd'
3 | import screenfull from 'screenfull'
4 | import '@/style/view-style/index.scss'
5 |
6 | import BarEcharts from './bar.jsx'
7 | import PieEcharts from './pie.jsx'
8 | import LineEcharts from './line.jsx'
9 | import ScatterEcharts from './scatter.jsx'
10 | import PictorialBarEcharts from './pictorialBar.jsx'
11 |
12 | import { iconToElement } from '@/utils/util'
13 |
14 | const Index = () => {
15 | const fullToggle = () => {
16 | if (screenfull.isEnabled) {
17 | screenfull.request(document.getElementById('bar'))
18 | }
19 | }
20 | return (
21 |
22 |
23 |
24 |
25 | {iconToElement('WechatOutlined', { fontSize: '5rem' })}
26 |
30 |
31 |
32 |
33 |
34 |
35 | {iconToElement('QqOutlined', { fontSize: '5rem' })}
36 |
40 |
41 |
42 |
43 |
44 |
45 | {iconToElement('DingdingOutlined', { fontSize: '5rem' })}
46 |
50 |
51 |
52 |
53 |
54 |
55 | {iconToElement('WeiboOutlined', { fontSize: '5rem' })}
56 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
图形全屏展示
69 |
73 | {iconToElement('FullscreenOutlined', { fontSize: '2rem' })}
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
105 |
106 |
107 |
108 | )
109 | }
110 |
111 | export default Index
112 |
--------------------------------------------------------------------------------
/src/views/Index/bar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import echarts from 'echarts/lib/echarts'
3 | import 'echarts/lib/chart/bar'
4 | import 'echarts/lib/component/tooltip'
5 | import 'echarts/lib/component/title'
6 | import 'echarts/lib/component/legend'
7 |
8 | const Bar = () => {
9 | useEffect(() => {
10 | let myChart = echarts.init(document.getElementById('bar'))
11 | myChart.setOption({
12 | tooltip: {
13 | trigger: 'axis',
14 | axisPointer: {
15 | // 坐标轴指示器,坐标轴触发有效
16 | type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
17 | }
18 | },
19 | legend: {
20 | data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎', '百度', '谷歌', '必应', '其他']
21 | },
22 | grid: {
23 | left: '3%',
24 | right: '4%',
25 | bottom: '3%',
26 | containLabel: true
27 | },
28 | xAxis: [
29 | {
30 | type: 'category',
31 | data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
32 | }
33 | ],
34 | yAxis: [
35 | {
36 | type: 'value'
37 | }
38 | ],
39 | series: [
40 | {
41 | name: '直接访问',
42 | type: 'bar',
43 | data: [320, 332, 301, 334, 390, 330, 320]
44 | },
45 | {
46 | name: '邮件营销',
47 | type: 'bar',
48 | stack: '广告',
49 | data: [120, 132, 101, 134, 90, 230, 210]
50 | },
51 | {
52 | name: '联盟广告',
53 | type: 'bar',
54 | stack: '广告',
55 | data: [220, 182, 191, 234, 290, 330, 310]
56 | },
57 | {
58 | name: '视频广告',
59 | type: 'bar',
60 | stack: '广告',
61 | data: [150, 232, 201, 154, 190, 330, 410]
62 | },
63 | {
64 | name: '搜索引擎',
65 | type: 'bar',
66 | data: [862, 1018, 964, 1026, 1679, 1600, 1570],
67 | markLine: {
68 | lineStyle: {
69 | normal: {
70 | type: 'dashed'
71 | }
72 | },
73 | data: [[{ type: 'min' }, { type: 'max' }]]
74 | }
75 | },
76 | {
77 | name: '百度',
78 | type: 'bar',
79 | barWidth: 5,
80 | stack: '搜索引擎',
81 | data: [620, 732, 701, 734, 1090, 1130, 1120]
82 | },
83 | {
84 | name: '谷歌',
85 | type: 'bar',
86 | stack: '搜索引擎',
87 | data: [120, 132, 101, 134, 290, 230, 220]
88 | },
89 | {
90 | name: '必应',
91 | type: 'bar',
92 | stack: '搜索引擎',
93 | data: [60, 72, 71, 74, 190, 130, 110]
94 | },
95 | {
96 | name: '其他',
97 | type: 'bar',
98 | stack: '搜索引擎',
99 | data: [62, 82, 91, 84, 109, 110, 120]
100 | }
101 | ]
102 | })
103 | window.addEventListener('resize', function() {
104 | myChart.resize()
105 | })
106 | }, [])
107 | return
108 | }
109 |
110 | export default Bar
111 |
--------------------------------------------------------------------------------
/src/views/Index/index.js:
--------------------------------------------------------------------------------
1 | import Index from './Index.jsx'
2 |
3 | export default Index
4 |
--------------------------------------------------------------------------------
/src/views/Index/line.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import echarts from 'echarts/lib/echarts'
3 | import 'echarts/lib/chart/line'
4 | import 'echarts/lib/component/tooltip'
5 | import 'echarts/lib/component/title'
6 | import 'echarts/lib/component/legend'
7 |
8 | const Line = () => {
9 | useEffect(() => {
10 | let myChart = echarts.init(document.getElementById('line'))
11 | myChart.setOption({
12 | tooltip: {
13 | trigger: 'axis'
14 | },
15 | legend: {
16 | data: ['邮件营销', '联盟广告', '视频广告']
17 | },
18 | grid: {
19 | left: '3%',
20 | right: '4%',
21 | bottom: '3%',
22 | containLabel: true
23 | },
24 | toolbox: {
25 | feature: {
26 | saveAsImage: {}
27 | }
28 | },
29 | xAxis: {
30 | type: 'category',
31 | boundaryGap: false,
32 | data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
33 | },
34 | yAxis: {
35 | type: 'value'
36 | },
37 | series: [
38 | {
39 | name: '邮件营销',
40 | type: 'line',
41 | data: [120, 132, 101, 134, 90, 230, 210]
42 | },
43 | {
44 | name: '联盟广告',
45 | type: 'line',
46 | data: [220, 182, 191, 234, 290, 330, 310]
47 | },
48 | {
49 | name: '视频广告',
50 | type: 'line',
51 | data: [150, 232, 201, 154, 190, 330, 410]
52 | }
53 | ]
54 | })
55 | window.addEventListener('resize', function() {
56 | myChart.resize()
57 | })
58 | }, [])
59 |
60 | return
61 | }
62 |
63 | export default Line
64 |
--------------------------------------------------------------------------------
/src/views/Index/pictorialBar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import echarts from 'echarts/lib/echarts'
3 | import 'echarts/lib/chart/pictorialBar'
4 | import 'echarts/lib/component/tooltip'
5 | import 'echarts/lib/component/title'
6 | import 'echarts/lib/component/legend'
7 |
8 | let pathSymbols = {
9 | reindeer:
10 | 'path://M-22.788,24.521c2.08-0.986,3.611-3.905,4.984-5.892 c-2.686,2.782-5.047,5.884-9.102,7.312c-0.992,0.005-0.25-2.016,0.34-2.362l1.852-0.41c0.564-0.218,0.785-0.842,0.902-1.347 c2.133-0.727,4.91-4.129,6.031-6.194c1.748-0.7,4.443-0.679,5.734-2.293c1.176-1.468,0.393-3.992,1.215-6.557 c0.24-0.754,0.574-1.581,1.008-2.293c-0.611,0.011-1.348-0.061-1.959-0.608c-1.391-1.245-0.785-2.086-1.297-3.313 c1.684,0.744,2.5,2.584,4.426,2.586C-8.46,3.012-8.255,2.901-8.04,2.824c6.031-1.952,15.182-0.165,19.498-3.937 c1.15-3.933-1.24-9.846-1.229-9.938c0.008-0.062-1.314-0.004-1.803-0.258c-1.119-0.771-6.531-3.75-0.17-3.33 c0.314-0.045,0.943,0.259,1.439,0.435c-0.289-1.694-0.92-0.144-3.311-1.946c0,0-1.1-0.855-1.764-1.98 c-0.836-1.09-2.01-2.825-2.992-4.031c-1.523-2.476,1.367,0.709,1.816,1.108c1.768,1.704,1.844,3.281,3.232,3.983 c0.195,0.203,1.453,0.164,0.926-0.468c-0.525-0.632-1.367-1.278-1.775-2.341c-0.293-0.703-1.311-2.326-1.566-2.711 c-0.256-0.384-0.959-1.718-1.67-2.351c-1.047-1.187-0.268-0.902,0.521-0.07c0.789,0.834,1.537,1.821,1.672,2.023 c0.135,0.203,1.584,2.521,1.725,2.387c0.102-0.259-0.035-0.428-0.158-0.852c-0.125-0.423-0.912-2.032-0.961-2.083 c-0.357-0.852-0.566-1.908-0.598-3.333c0.4-2.375,0.648-2.486,0.549-0.705c0.014,1.143,0.031,2.215,0.602,3.247 c0.807,1.496,1.764,4.064,1.836,4.474c0.561,3.176,2.904,1.749,2.281-0.126c-0.068-0.446-0.109-2.014-0.287-2.862 c-0.18-0.849-0.219-1.688-0.113-3.056c0.066-1.389,0.232-2.055,0.277-2.299c0.285-1.023,0.4-1.088,0.408,0.135 c-0.059,0.399-0.131,1.687-0.125,2.655c0.064,0.642-0.043,1.768,0.172,2.486c0.654,1.928-0.027,3.496,1,3.514 c1.805-0.424,2.428-1.218,2.428-2.346c-0.086-0.704-0.121-0.843-0.031-1.193c0.221-0.568,0.359-0.67,0.312-0.076 c-0.055,0.287,0.031,0.533,0.082,0.794c0.264,1.197,0.912,0.114,1.283-0.782c0.15-0.238,0.539-2.154,0.545-2.522 c-0.023-0.617,0.285-0.645,0.309,0.01c0.064,0.422-0.248,2.646-0.205,2.334c-0.338,1.24-1.105,3.402-3.379,4.712 c-0.389,0.12-1.186,1.286-3.328,2.178c0,0,1.729,0.321,3.156,0.246c1.102-0.19,3.707-0.027,4.654,0.269 c1.752,0.494,1.531-0.053,4.084,0.164c2.26-0.4,2.154,2.391-1.496,3.68c-2.549,1.405-3.107,1.475-2.293,2.984 c3.484,7.906,2.865,13.183,2.193,16.466c2.41,0.271,5.732-0.62,7.301,0.725c0.506,0.333,0.648,1.866-0.457,2.86 c-4.105,2.745-9.283,7.022-13.904,7.662c-0.977-0.194,0.156-2.025,0.803-2.247l1.898-0.03c0.596-0.101,0.936-0.669,1.152-1.139 c3.16-0.404,5.045-3.775,8.246-4.818c-4.035-0.718-9.588,3.981-12.162,1.051c-5.043,1.423-11.449,1.84-15.895,1.111 c-3.105,2.687-7.934,4.021-12.115,5.866c-3.271,3.511-5.188,8.086-9.967,10.414c-0.986,0.119-0.48-1.974,0.066-2.385l1.795-0.618 C-22.995,25.682-22.849,25.035-22.788,24.521z',
11 | plane:
12 | 'path://M1.112,32.559l2.998,1.205l-2.882,2.268l-2.215-0.012L1.112,32.559z M37.803,23.96 c0.158-0.838,0.5-1.509,0.961-1.904c-0.096-0.037-0.205-0.071-0.344-0.071c-0.777-0.005-2.068-0.009-3.047-0.009 c-0.633,0-1.217,0.066-1.754,0.18l2.199,1.804H37.803z M39.738,23.036c-0.111,0-0.377,0.325-0.537,0.924h1.076 C40.115,23.361,39.854,23.036,39.738,23.036z M39.934,39.867c-0.166,0-0.674,0.705-0.674,1.986s0.506,1.986,0.674,1.986 s0.672-0.705,0.672-1.986S40.102,39.867,39.934,39.867z M38.963,38.889c-0.098-0.038-0.209-0.07-0.348-0.073 c-0.082,0-0.174,0-0.268-0.001l-7.127,4.671c0.879,0.821,2.42,1.417,4.348,1.417c0.979,0,2.27-0.006,3.047-0.01 c0.139,0,0.25-0.034,0.348-0.072c-0.646-0.555-1.07-1.643-1.07-2.967C37.891,40.529,38.316,39.441,38.963,38.889z M32.713,23.96 l-12.37-10.116l-4.693-0.004c0,0,4,8.222,4.827,10.121H32.713z M59.311,32.374c-0.248,2.104-5.305,3.172-8.018,3.172H39.629 l-25.325,16.61L9.607,52.16c0,0,6.687-8.479,7.95-10.207c1.17-1.6,3.019-3.699,3.027-6.407h-2.138 c-5.839,0-13.816-3.789-18.472-5.583c-2.818-1.085-2.396-4.04-0.031-4.04h0.039l-3.299-11.371h3.617c0,0,4.352,5.696,5.846,7.5 c2,2.416,4.503,3.678,8.228,3.87h30.727c2.17,0,4.311,0.417,6.252,1.046c3.49,1.175,5.863,2.7,7.199,4.027 C59.145,31.584,59.352,32.025,59.311,32.374z M22.069,30.408c0-0.815-0.661-1.475-1.469-1.475c-0.812,0-1.471,0.66-1.471,1.475 s0.658,1.475,1.471,1.475C21.408,31.883,22.069,31.224,22.069,30.408z M27.06,30.408c0-0.815-0.656-1.478-1.466-1.478 c-0.812,0-1.471,0.662-1.471,1.478s0.658,1.477,1.471,1.477C26.404,31.885,27.06,31.224,27.06,30.408z M32.055,30.408 c0-0.815-0.66-1.475-1.469-1.475c-0.808,0-1.466,0.66-1.466,1.475s0.658,1.475,1.466,1.475 C31.398,31.883,32.055,31.224,32.055,30.408z M37.049,30.408c0-0.815-0.658-1.478-1.467-1.478c-0.812,0-1.469,0.662-1.469,1.478 s0.656,1.477,1.469,1.477C36.389,31.885,37.049,31.224,37.049,30.408z M42.039,30.408c0-0.815-0.656-1.478-1.465-1.478 c-0.811,0-1.469,0.662-1.469,1.478s0.658,1.477,1.469,1.477C41.383,31.885,42.039,31.224,42.039,30.408z M55.479,30.565 c-0.701-0.436-1.568-0.896-2.627-1.347c-0.613,0.289-1.551,0.476-2.73,0.476c-1.527,0-1.639,2.263,0.164,2.316 C52.389,32.074,54.627,31.373,55.479,30.565z',
13 | rocket:
14 | 'path://M-244.396,44.399c0,0,0.47-2.931-2.427-6.512c2.819-8.221,3.21-15.709,3.21-15.709s5.795,1.383,5.795,7.325C-237.818,39.679-244.396,44.399-244.396,44.399z M-260.371,40.827c0,0-3.881-12.946-3.881-18.319c0-2.416,0.262-4.566,0.669-6.517h17.684c0.411,1.952,0.675,4.104,0.675,6.519c0,5.291-3.87,18.317-3.87,18.317H-260.371z M-254.745,18.951c-1.99,0-3.603,1.676-3.603,3.744c0,2.068,1.612,3.744,3.603,3.744c1.988,0,3.602-1.676,3.602-3.744S-252.757,18.951-254.745,18.951z M-255.521,2.228v-5.098h1.402v4.969c1.603,1.213,5.941,5.069,7.901,12.5h-17.05C-261.373,7.373-257.245,3.558-255.521,2.228zM-265.07,44.399c0,0-6.577-4.721-6.577-14.896c0-5.942,5.794-7.325,5.794-7.325s0.393,7.488,3.211,15.708C-265.539,41.469-265.07,44.399-265.07,44.399z M-252.36,45.15l-1.176-1.22L-254.789,48l-1.487-4.069l-1.019,2.116l-1.488-3.826h8.067L-252.36,45.15z',
15 | train:
16 | 'path://M67.335,33.596L67.335,33.596c-0.002-1.39-1.153-3.183-3.328-4.218h-9.096v-2.07h5.371 c-4.939-2.07-11.199-4.141-14.89-4.141H19.72v12.421v5.176h38.373c4.033,0,8.457-1.035,9.142-5.176h-0.027 c0.076-0.367,0.129-0.751,0.129-1.165L67.335,33.596L67.335,33.596z M27.999,30.413h-3.105v-4.141h3.105V30.413z M35.245,30.413 h-3.104v-4.141h3.104V30.413z M42.491,30.413h-3.104v-4.141h3.104V30.413z M49.736,30.413h-3.104v-4.141h3.104V30.413z M14.544,40.764c1.143,0,2.07-0.927,2.07-2.07V35.59V25.237c0-1.145-0.928-2.07-2.07-2.07H-9.265c-1.143,0-2.068,0.926-2.068,2.07 v10.351v3.105c0,1.144,0.926,2.07,2.068,2.07H14.544L14.544,40.764z M8.333,26.272h3.105v4.141H8.333V26.272z M1.087,26.272h3.105 v4.141H1.087V26.272z M-6.159,26.272h3.105v4.141h-3.105V26.272z M-9.265,41.798h69.352v1.035H-9.265V41.798z',
17 | ship:
18 | 'path://M16.678,17.086h9.854l-2.703,5.912c5.596,2.428,11.155,5.575,16.711,8.607c3.387,1.847,6.967,3.75,10.541,5.375 v-6.16l-4.197-2.763v-5.318L33.064,12.197h-11.48L20.43,15.24h-4.533l-1.266,3.286l0.781,0.345L16.678,17.086z M49.6,31.84 l0.047,1.273L27.438,20.998l0.799-1.734L49.6,31.84z M33.031,15.1l12.889,8.82l0.027,0.769L32.551,16.1L33.031,15.1z M22.377,14.045 h9.846l-1.539,3.365l-2.287-1.498h1.371l0.721-1.352h-2.023l-0.553,1.037l-0.541-0.357h-0.34l0.359-0.684h-2.025l-0.361,0.684 h-3.473L22.377,14.045z M23.695,20.678l-0.004,0.004h0.004V20.678z M24.828,18.199h-2.031l-0.719,1.358h2.029L24.828,18.199z M40.385,34.227c-12.85-7.009-25.729-14.667-38.971-12.527c1.26,8.809,9.08,16.201,8.213,24.328 c-0.553,4.062-3.111,0.828-3.303,7.137c15.799,0,32.379,0,48.166,0l0.066-4.195l1.477-7.23 C50.842,39.812,45.393,36.961,40.385,34.227z M13.99,35.954c-1.213,0-2.195-1.353-2.195-3.035c0-1.665,0.98-3.017,2.195-3.017 c1.219,0,2.195,1.352,2.195,3.017C16.186,34.604,15.213,35.954,13.99,35.954z M23.691,20.682h-2.02l-0.588,1.351h2.023 L23.691,20.682z M19.697,18.199l-0.721,1.358h2.025l0.727-1.358H19.697z',
19 | car:
20 | 'path://M49.592,40.883c-0.053,0.354-0.139,0.697-0.268,0.963c-0.232,0.475-0.455,0.519-1.334,0.475 c-1.135-0.053-2.764,0-4.484,0.068c0,0.476,0.018,0.697,0.018,0.697c0.111,1.299,0.697,1.342,0.931,1.342h3.7 c0.326,0,0.628,0,0.861-0.154c0.301-0.196,0.43-0.772,0.543-1.78c0.017-0.146,0.025-0.336,0.033-0.56v-0.01 c0-0.068,0.008-0.154,0.008-0.25V41.58l0,0C49.6,41.348,49.6,41.09,49.592,40.883L49.592,40.883z M6.057,40.883 c0.053,0.354,0.137,0.697,0.268,0.963c0.23,0.475,0.455,0.519,1.334,0.475c1.137-0.053,2.762,0,4.484,0.068 c0,0.476-0.018,0.697-0.018,0.697c-0.111,1.299-0.697,1.342-0.93,1.342h-3.7c-0.328,0-0.602,0-0.861-0.154 c-0.309-0.18-0.43-0.772-0.541-1.78c-0.018-0.146-0.027-0.336-0.035-0.56v-0.01c0-0.068-0.008-0.154-0.008-0.25V41.58l0,0 C6.057,41.348,6.057,41.09,6.057,40.883L6.057,40.883z M49.867,32.766c0-2.642-0.344-5.224-0.482-5.507 c-0.104-0.207-0.766-0.749-2.271-1.773c-1.522-1.042-1.487-0.887-1.766-1.566c0.25-0.078,0.492-0.224,0.639-0.241 c0.326-0.034,0.345,0.274,1.023,0.274c0.68,0,2.152-0.18,2.453-0.48c0.301-0.303,0.396-0.405,0.396-0.672 c0-0.268-0.156-0.818-0.447-1.146c-0.293-0.327-1.541-0.49-2.273-0.585c-0.729-0.095-0.834,0-1.022,0.121 c-0.304,0.189-0.32,1.919-0.32,1.919l-0.713,0.018c-0.465-1.146-1.11-3.452-2.117-5.269c-1.103-1.979-2.256-2.599-2.737-2.754 c-0.474-0.146-0.904-0.249-4.131-0.576c-3.298-0.344-5.922-0.388-8.262-0.388c-2.342,0-4.967,0.052-8.264,0.388 c-3.229,0.336-3.66,0.43-4.133,0.576s-1.633,0.775-2.736,2.754c-1.006,1.816-1.652,4.123-2.117,5.269L9.87,23.109 c0,0-0.008-1.729-0.318-1.919c-0.189-0.121-0.293-0.225-1.023-0.121c-0.732,0.104-1.98,0.258-2.273,0.585 c-0.293,0.327-0.447,0.878-0.447,1.146c0,0.267,0.094,0.379,0.396,0.672c0.301,0.301,1.773,0.48,2.453,0.48 c0.68,0,0.697-0.309,1.023-0.274c0.146,0.018,0.396,0.163,0.637,0.241c-0.283,0.68-0.24,0.524-1.764,1.566 c-1.506,1.033-2.178,1.566-2.271,1.773c-0.139,0.283-0.482,2.865-0.482,5.508s0.189,5.02,0.189,5.86c0,0.354,0,0.976,0.076,1.565 c0.053,0.354,0.129,0.697,0.268,0.966c0.232,0.473,0.447,0.516,1.334,0.473c1.137-0.051,2.779,0,4.477,0.07 c1.135,0.043,2.297,0.086,3.33,0.11c2.582,0.051,1.826-0.379,2.928-0.36c1.102,0.016,5.447,0.196,9.424,0.196 c3.976,0,8.332-0.182,9.423-0.196c1.102-0.019,0.346,0.411,2.926,0.36c1.033-0.018,2.195-0.067,3.332-0.11 c1.695-0.062,3.348-0.121,4.477-0.07c0.886,0.043,1.103,0,1.332-0.473c0.132-0.269,0.218-0.611,0.269-0.966 c0.086-0.592,0.078-1.213,0.078-1.565C49.678,37.793,49.867,35.408,49.867,32.766L49.867,32.766z M13.219,19.735 c0.412-0.964,1.652-2.9,2.256-3.244c0.145-0.087,1.426-0.491,4.637-0.706c2.953-0.198,6.217-0.276,7.73-0.276 c1.513,0,4.777,0.078,7.729,0.276c3.201,0.215,4.502,0.611,4.639,0.706c0.775,0.533,1.842,2.28,2.256,3.244 c0.412,0.965,0.965,2.858,0.861,3.116c-0.104,0.258,0.104,0.388-1.291,0.275c-1.387-0.103-10.088-0.216-14.185-0.216 c-4.088,0-12.789,0.113-14.184,0.216c-1.395,0.104-1.188-0.018-1.291-0.275C12.254,22.593,12.805,20.708,13.219,19.735 L13.219,19.735z M16.385,30.511c-0.619,0.155-0.988,0.491-1.764,0.482c-0.775,0-2.867-0.353-3.314-0.371 c-0.447-0.017-0.842,0.302-1.076,0.362c-0.23,0.06-0.688-0.104-1.377-0.318c-0.688-0.216-1.092-0.155-1.316-1.094 c-0.232-0.93,0-2.264,0-2.264c1.488-0.068,2.928,0.069,5.621,0.826c2.693,0.758,4.191,2.213,4.191,2.213 S17.004,30.357,16.385,30.511L16.385,30.511z M36.629,37.293c-1.23,0.164-6.386,0.207-8.794,0.207c-2.412,0-7.566-0.051-8.799-0.207 c-1.256-0.164-2.891-1.67-1.764-2.865c1.523-1.627,1.24-1.576,4.701-2.023C24.967,32.018,27.239,32,27.834,32 c0.584,0,2.865,0.025,5.859,0.404c3.461,0.447,3.178,0.396,4.699,2.022C39.521,35.623,37.887,37.129,36.629,37.293L36.629,37.293z M48.129,29.582c-0.232,0.93-0.629,0.878-1.318,1.093c-0.688,0.216-1.145,0.371-1.377,0.319c-0.231-0.053-0.627-0.371-1.074-0.361 c-0.448,0.018-2.539,0.37-3.313,0.37c-0.772,0-1.146-0.328-1.764-0.481c-0.621-0.154-0.966-0.154-0.966-0.154 s1.49-1.464,4.191-2.213c2.693-0.758,4.131-0.895,5.621-0.826C48.129,27.309,48.361,28.643,48.129,29.582L48.129,29.582z',
21 | run:
22 | 'path://M13.676,32.955c0.919-0.031,1.843-0.008,2.767-0.008v0.007c0.827,0,1.659,0.041,2.486-0.019 c0.417-0.028,1.118,0.325,1.14-0.545c0.014-0.637-0.156-1.279-0.873-1.367c-1.919-0.241-3.858-0.233-5.774,0.019 c-0.465,0.062-0.998,0.442-0.832,1.069C12.715,32.602,13.045,32.977,13.676,32.955z M14.108,29.013 c1.47-0.007,2.96-0.122,4.414,0.035c1.792,0.192,3.1-0.412,4.273-2.105c-3.044,0-5.882,0.014-8.719-0.01 c-0.768-0.005-1.495,0.118-1.461,1C12.642,28.731,13.329,29.014,14.108,29.013z M23.678,36.593c-0.666-0.69-1.258-1.497-2.483-1.448 c-2.341,0.095-4.689,0.051-7.035,0.012c-0.834-0.014-1.599,0.177-1.569,1.066c0.031,0.854,0.812,1.062,1.636,1.043 c1.425-0.033,2.852-0.01,4.278-0.01v-0.01c1.562,0,3.126,0.008,4.691-0.005C23.614,37.239,24.233,37.174,23.678,36.593z M32.234,42.292h-0.002c-1.075,0.793-2.589,0.345-3.821,1.048c-0.359,0.193-0.663,0.465-0.899,0.799 c-1.068,1.623-2.052,3.301-3.117,4.928c-0.625,0.961-0.386,1.805,0.409,2.395c0.844,0.628,1.874,0.617,2.548-0.299 c1.912-2.573,3.761-5.197,5.621-7.814C33.484,42.619,33.032,42.387,32.234,42.292z M43.527,28.401 c-0.688-1.575-2.012-0.831-3.121-0.895c-1.047-0.058-2.119,1.128-3.002,0.345c-0.768-0.677-1.213-1.804-1.562-2.813 c-0.45-1.305-1.495-2.225-2.329-3.583c2.953,1.139,4.729,0.077,5.592-1.322c0.99-1.61,0.718-3.725-0.627-4.967 c-1.362-1.255-3.414-1.445-4.927-0.452c-1.933,1.268-2.206,2.893-0.899,6.11c-2.098-0.659-3.835-1.654-5.682-2.383 c-0.735-0.291-1.437-1.017-2.293-0.666c-2.263,0.927-4.522,1.885-6.723,2.95c-1.357,0.658-1.649,1.593-1.076,2.638 c0.462,0.851,1.643,1.126,2.806,0.617c0.993-0.433,1.994-0.857,2.951-1.374c1.599-0.86,3.044-0.873,4.604,0.214 c1.017,0.707,0.873,1.137,0.123,1.849c-1.701,1.615-3.516,3.12-4.933,5.006c-1.042,1.388-0.993,2.817,0.255,4.011 c1.538,1.471,3.148,2.869,4.708,4.315c0.485,0.444,0.907,0.896-0.227,1.104c-1.523,0.285-3.021,0.694-4.538,1.006 c-1.109,0.225-2.02,1.259-1.83,2.16c0.223,1.07,1.548,1.756,2.687,1.487c3.003-0.712,6.008-1.413,9.032-2.044 c1.549-0.324,2.273-1.869,1.344-3.115c-0.868-1.156-1.801-2.267-2.639-3.445c-1.964-2.762-1.95-2.771,0.528-5.189 c1.394-1.357,1.379-1.351,2.437,0.417c0.461,0.769,0.854,1.703,1.99,1.613c2.238-0.181,4.407-0.755,6.564-1.331 C43.557,30.447,43.88,29.206,43.527,28.401z',
23 | walk:
24 | 'path://M29.902,23.275c1.86,0,3.368-1.506,3.368-3.365c0-1.859-1.508-3.365-3.368-3.365 c-1.857,0-3.365,1.506-3.365,3.365C26.537,21.769,28.045,23.275,29.902,23.275z M36.867,30.74c-1.666-0.467-3.799-1.6-4.732-4.199 c-0.932-2.6-3.131-2.998-4.797-2.998s-7.098,3.894-7.098,3.894c-1.133,1.001-2.1,6.502-0.967,6.769 c1.133,0.269,1.266-1.533,1.934-3.599c0.666-2.065,3.797-3.466,3.797-3.466s0.201,2.467-0.398,3.866 c-0.599,1.399-1.133,2.866-1.467,6.198s-1.6,3.665-3.799,6.266c-2.199,2.598-0.6,3.797,0.398,3.664 c1.002-0.133,5.865-5.598,6.398-6.998c0.533-1.397,0.668-3.732,0.668-3.732s0,0,2.199,1.867c2.199,1.865,2.332,4.6,2.998,7.73 s2.332,0.934,2.332-0.467c0-1.401,0.269-5.465-1-7.064c-1.265-1.6-3.73-3.465-3.73-5.265s1.199-3.732,1.199-3.732 c0.332,1.667,3.335,3.065,5.599,3.399C38.668,33.206,38.533,31.207,36.867,30.74z'
25 | }
26 |
27 | const PictorialBar = () => {
28 | useEffect(() => {
29 | let myChart = echarts.init(document.getElementById('pictorialBar'))
30 | myChart.setOption({
31 | tooltip: {
32 | trigger: 'axis',
33 | axisPointer: {
34 | type: 'none'
35 | },
36 | formatter: function(params) {
37 | return params[0].name + ': ' + params[0].value
38 | }
39 | },
40 | xAxis: {
41 | data: ['驯鹿', '火箭', '飞机', '高铁', '轮船', '汽车', '跑步', '步行'],
42 | axisTick: { show: false },
43 | axisLine: { show: false },
44 | axisLabel: {
45 | textStyle: {
46 | color: '#e54035'
47 | }
48 | }
49 | },
50 | yAxis: {
51 | splitLine: { show: false },
52 | axisTick: { show: false },
53 | axisLine: { show: false },
54 | axisLabel: { show: false }
55 | },
56 | color: ['#e54035'],
57 | series: [
58 | {
59 | name: 'hill',
60 | type: 'pictorialBar',
61 | barCategoryGap: '-130%',
62 | // symbol: 'path://M0,10 L10,10 L5,0 L0,10 z',
63 | symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z',
64 | itemStyle: {
65 | normal: {
66 | opacity: 0.5
67 | },
68 | emphasis: {
69 | opacity: 1
70 | }
71 | },
72 | data: [123, 60, 25, 18, 12, 9, 2, 1],
73 | z: 10
74 | },
75 | {
76 | name: 'glyph',
77 | type: 'pictorialBar',
78 | barGap: '-100%',
79 | symbolPosition: 'end',
80 | symbolSize: 50,
81 | symbolOffset: [0, '-120%'],
82 | data: [
83 | {
84 | value: 123,
85 | symbol: pathSymbols.reindeer,
86 | symbolSize: [60, 60]
87 | },
88 | {
89 | value: 60,
90 | symbol: pathSymbols.rocket,
91 | symbolSize: [50, 60]
92 | },
93 | {
94 | value: 25,
95 | symbol: pathSymbols.plane,
96 | symbolSize: [65, 35]
97 | },
98 | {
99 | value: 18,
100 | symbol: pathSymbols.train,
101 | symbolSize: [50, 30]
102 | },
103 | {
104 | value: 12,
105 | symbol: pathSymbols.ship,
106 | symbolSize: [50, 35]
107 | },
108 | {
109 | value: 9,
110 | symbol: pathSymbols.car,
111 | symbolSize: [40, 30]
112 | },
113 | {
114 | value: 2,
115 | symbol: pathSymbols.run,
116 | symbolSize: [40, 50]
117 | },
118 | {
119 | value: 1,
120 | symbol: pathSymbols.walk,
121 | symbolSize: [40, 50]
122 | }
123 | ]
124 | }
125 | ]
126 | })
127 | window.addEventListener('resize', function() {
128 | myChart.resize()
129 | })
130 | }, [])
131 |
132 | return
133 | }
134 |
135 | export default PictorialBar
136 |
--------------------------------------------------------------------------------
/src/views/Index/pie.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import echarts from 'echarts/lib/echarts'
3 | import 'echarts/lib/chart/pie'
4 | import 'echarts/lib/component/tooltip'
5 | import 'echarts/lib/component/title'
6 | import 'echarts/lib/component/legend'
7 |
8 | const Pie = () => {
9 | useEffect(() => {
10 | let myChart = echarts.init(document.getElementById('pie'))
11 | myChart.setOption({
12 | tooltip: {
13 | trigger: 'item',
14 | formatter: '{a}
{b} : {c} ({d}%)'
15 | },
16 | legend: {
17 | orient: 'vertical',
18 | left: 'left',
19 | data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
20 | },
21 | series: [
22 | {
23 | name: '访问来源',
24 | type: 'pie',
25 | radius: '55%',
26 | center: ['50%', '60%'],
27 | data: [
28 | { value: 335, name: '直接访问' },
29 | { value: 310, name: '邮件营销' },
30 | { value: 234, name: '联盟广告' },
31 | { value: 135, name: '视频广告' },
32 | { value: 1548, name: '搜索引擎' }
33 | ],
34 | itemStyle: {
35 | emphasis: {
36 | shadowBlur: 10,
37 | shadowOffsetX: 0,
38 | shadowColor: 'rgba(0, 0, 0, 0.5)'
39 | }
40 | }
41 | }
42 | ]
43 | })
44 | window.addEventListener('resize', function() {
45 | myChart.resize()
46 | })
47 | }, [])
48 |
49 | return
50 | }
51 |
52 | export default Pie
53 |
--------------------------------------------------------------------------------
/src/views/Index/scatter.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import echarts from 'echarts/lib/echarts'
3 | import 'echarts/lib/chart/scatter'
4 | import 'echarts/lib/component/tooltip'
5 | import 'echarts/lib/component/title'
6 | import 'echarts/lib/component/legend'
7 |
8 | let data = [
9 | [
10 | [28604, 77, 17096869, 'Australia', 1990],
11 | [31163, 77.4, 27662440, 'Canada', 1990],
12 | [1516, 68, 1154605773, 'China', 1990],
13 | [13670, 74.7, 10582082, 'Cuba', 1990],
14 | [28599, 75, 4986705, 'Finland', 1990],
15 | [29476, 77.1, 56943299, 'France', 1990],
16 | [31476, 75.4, 78958237, 'Germany', 1990],
17 | [28666, 78.1, 254830, 'Iceland', 1990],
18 | [1777, 57.7, 870601776, 'India', 1990],
19 | [29550, 79.1, 122249285, 'Japan', 1990],
20 | [2076, 67.9, 20194354, 'North Korea', 1990],
21 | [12087, 72, 42972254, 'South Korea', 1990],
22 | [24021, 75.4, 3397534, 'New Zealand', 1990],
23 | [43296, 76.8, 4240375, 'Norway', 1990],
24 | [10088, 70.8, 38195258, 'Poland', 1990],
25 | [19349, 69.6, 147568552, 'Russia', 1990],
26 | [10670, 67.3, 53994605, 'Turkey', 1990],
27 | [26424, 75.7, 57110117, 'United Kingdom', 1990],
28 | [37062, 75.4, 252847810, 'United States', 1990]
29 | ],
30 | [
31 | [44056, 81.8, 23968973, 'Australia', 2015],
32 | [43294, 81.7, 35939927, 'Canada', 2015],
33 | [13334, 76.9, 1376048943, 'China', 2015],
34 | [21291, 78.5, 11389562, 'Cuba', 2015],
35 | [38923, 80.8, 5503457, 'Finland', 2015],
36 | [37599, 81.9, 64395345, 'France', 2015],
37 | [44053, 81.1, 80688545, 'Germany', 2015],
38 | [42182, 82.8, 329425, 'Iceland', 2015],
39 | [5903, 66.8, 1311050527, 'India', 2015],
40 | [36162, 83.5, 126573481, 'Japan', 2015],
41 | [1390, 71.4, 25155317, 'North Korea', 2015],
42 | [34644, 80.7, 50293439, 'South Korea', 2015],
43 | [34186, 80.6, 4528526, 'New Zealand', 2015],
44 | [64304, 81.6, 5210967, 'Norway', 2015],
45 | [24787, 77.3, 38611794, 'Poland', 2015],
46 | [23038, 73.13, 143456918, 'Russia', 2015],
47 | [19360, 76.5, 78665830, 'Turkey', 2015],
48 | [38225, 81.4, 64715810, 'United Kingdom', 2015],
49 | [53354, 79.1, 321773631, 'United States', 2015]
50 | ]
51 | ]
52 |
53 | const Scatter = () => {
54 | useEffect(() => {
55 | let myChart = echarts.init(document.getElementById('scatter'))
56 | myChart.setOption({
57 | legend: {
58 | right: 10,
59 | data: ['1990', '2015']
60 | },
61 | xAxis: {
62 | splitLine: {
63 | lineStyle: {
64 | type: 'dashed'
65 | }
66 | }
67 | },
68 | yAxis: {
69 | splitLine: {
70 | lineStyle: {
71 | type: 'dashed'
72 | }
73 | },
74 | scale: true
75 | },
76 | series: [
77 | {
78 | name: '1990',
79 | data: data[0],
80 | type: 'scatter',
81 | symbolSize: function(data) {
82 | return Math.sqrt(data[2]) / 5e2
83 | },
84 | label: {
85 | emphasis: {
86 | show: true,
87 | formatter: function(param) {
88 | return param.data[3]
89 | },
90 | position: 'top'
91 | }
92 | },
93 | itemStyle: {
94 | normal: {
95 | shadowBlur: 10,
96 | shadowColor: 'rgba(120, 36, 50, 0.5)',
97 | shadowOffsetY: 5,
98 | color: new echarts.graphic.RadialGradient(0.4, 0.3, 1, [
99 | {
100 | offset: 0,
101 | color: 'rgb(251, 118, 123)'
102 | },
103 | {
104 | offset: 1,
105 | color: 'rgb(204, 46, 72)'
106 | }
107 | ])
108 | }
109 | }
110 | },
111 | {
112 | name: '2015',
113 | data: data[1],
114 | type: 'scatter',
115 | symbolSize: function(data) {
116 | return Math.sqrt(data[2]) / 5e2
117 | },
118 | label: {
119 | emphasis: {
120 | show: true,
121 | formatter: function(param) {
122 | return param.data[3]
123 | },
124 | position: 'top'
125 | }
126 | },
127 | itemStyle: {
128 | normal: {
129 | shadowBlur: 10,
130 | shadowColor: 'rgba(25, 100, 150, 0.5)',
131 | shadowOffsetY: 5,
132 | color: new echarts.graphic.RadialGradient(0.4, 0.3, 1, [
133 | {
134 | offset: 0,
135 | color: 'rgb(129, 227, 238)'
136 | },
137 | {
138 | offset: 1,
139 | color: 'rgb(25, 183, 207)'
140 | }
141 | ])
142 | }
143 | }
144 | }
145 | ]
146 | })
147 | window.addEventListener('resize', function() {
148 | myChart.resize()
149 | })
150 | }, [])
151 |
152 | return
153 | }
154 |
155 | export default Scatter
156 |
--------------------------------------------------------------------------------
/src/views/Login/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { Layout, Input, Form, Button, Divider, message, notification } from 'antd'
3 | import { withRouter } from 'react-router-dom'
4 | import {
5 | UserOutlined,
6 | UnlockOutlined
7 | } from '@ant-design/icons';
8 | import '@/style/view-style/login.scss'
9 |
10 |
11 | const Login = props => {
12 | const [loading, setLoading] = useState(false)
13 |
14 | const handleSubmit = values => {
15 | // 这里可以做权限校验 模拟接口返回用户权限标识
16 | switch (values.username) {
17 | case 'admin':
18 | values.auth = 0
19 | break
20 | default:
21 | values.auth = 1
22 | }
23 |
24 | localStorage.setItem('user', JSON.stringify(values))
25 | setLoading(true)
26 | setTimeout(() => {
27 | message.success('登录成功!')
28 | props.history.push('/')
29 | }, 2000)
30 | }
31 |
32 | useEffect(() => {
33 | notification.open({
34 | message: '欢迎使用后台管理平台',
35 | duration: null,
36 | description: '账号 admin(管理员) 其他(游客) 密码随意'
37 | })
38 | return () => {
39 | notification.destroy()
40 | }
41 | }, [])
42 |
43 | return (
44 |
45 |
46 |
47 |
后台管理系统
48 |
49 |
51 | }
53 | placeholder='用户名'
54 | />
55 |
56 |
57 | }
59 | type='password'
60 | placeholder='密码'
61 | />
62 |
63 |
64 |
67 |
68 |
69 |
70 |
71 |
72 | )
73 | }
74 |
75 | export default withRouter((Login))
76 |
--------------------------------------------------------------------------------
/src/views/Login/index.js:
--------------------------------------------------------------------------------
1 | import Login from './Login.jsx'
2 |
3 | export default Login
4 |
--------------------------------------------------------------------------------
/src/views/NavView/Dropdown/Dropdown.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Layout, Divider, Menu, Dropdown, Row, Col, message, Button } from 'antd'
3 | import { iconToElement } from '@/utils/util'
4 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
5 | import '@/style/view-style/dropdown.scss'
6 |
7 | const { SubMenu } = Menu
8 |
9 | const menuOnClick = ({ key }) => {
10 | message.info(`Click on item ${key}`)
11 | }
12 |
13 | const items = [
14 | {
15 | label: '1st menu item',
16 | key: '0',
17 | },
18 | {
19 | label: '2st menu item',
20 | key: '1',
21 | },
22 | {
23 | label: '3rd menu item (disabled)',
24 | key: '2',
25 | disabled: true,
26 | },
27 | {
28 | label: 'sub menu',
29 | key: '3',
30 | children: [
31 | {
32 | label: '4rd menu item',
33 | key: '4'
34 | },
35 | {
36 | label: '5rd menu item',
37 | key: '5'
38 | }
39 | ],
40 | },
41 | ];
42 |
43 | const menu = (
44 |
48 | )
49 |
50 | function handleButtonClick (e) {
51 | message.info('Click on left button.')
52 | console.log('click left button', e)
53 | }
54 |
55 | const DropdownView = () => (
56 |
57 |
58 |
59 |
60 |
61 |
何时使用
62 |
63 |
64 | 当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。
65 |
66 |
67 |
68 |
69 |
70 |
71 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | Dropdown
114 |
115 |
116 | Dropdown
117 |
118 |
119 | Dropdown
120 |
121 |
122 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | )
133 |
134 | export default DropdownView
135 |
--------------------------------------------------------------------------------
/src/views/NavView/Dropdown/index.js:
--------------------------------------------------------------------------------
1 | import DropdownView from './Dropdown'
2 |
3 | export default DropdownView
4 |
--------------------------------------------------------------------------------
/src/views/NavView/Menu/Menu.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Layout, Divider, Row, Col, Menu, Button, Switch } from 'antd'
3 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
4 | import {
5 | AppstoreOutlined,
6 | MailOutlined,
7 | SettingOutlined,
8 | ContainerOutlined,
9 | DesktopOutlined,
10 | MenuFoldOutlined,
11 | MenuUnfoldOutlined,
12 | PieChartOutlined,
13 | CalendarOutlined,
14 | LinkOutlined
15 | } from '@ant-design/icons';
16 |
17 | const { SubMenu } = Menu
18 |
19 | const MenuView = () => {
20 | const [current, setCurrent] = useState('mail')
21 | const [collapsed, setCollapsed] = useState(false)
22 | const [openKeys, setOpenKeys] = useState(['sub1'])
23 | const [mode, setMode] = useState('inline')
24 | const [theme, setTheme] = useState('light')
25 |
26 | const rootSubmenuKeys = ['sub1', 'sub2', 'sub4']
27 |
28 | const handleClick = e => {
29 | console.log('click ', e)
30 | setCurrent(e.key)
31 | }
32 |
33 | const onOpenChange = keys => {
34 | const latestOpenKey = keys.find((key) => openKeys.indexOf(key) === -1);
35 |
36 | if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
37 | setOpenKeys(keys);
38 | } else {
39 | setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
40 | }
41 | }
42 |
43 | const itemsTop = [
44 | {
45 | label: 'Navigation One',
46 | key: 'mail',
47 | icon: ,
48 | },
49 | {
50 | label: 'Navigation Two',
51 | key: 'app',
52 | icon: ,
53 | disabled: true,
54 | },
55 | {
56 | label: 'Navigation Three - Submenu',
57 | key: 'SubMenu',
58 | icon: ,
59 | children: [
60 | {
61 | type: 'group',
62 | label: 'Item 1',
63 | children: [
64 | {
65 | label: 'Option 1',
66 | key: 'setting:1',
67 | },
68 | {
69 | label: 'Option 2',
70 | key: 'setting:2',
71 | },
72 | ],
73 | },
74 | {
75 | type: 'group',
76 | label: 'Item 2',
77 | children: [
78 | {
79 | label: 'Option 3',
80 | key: 'setting:3',
81 | },
82 | {
83 | label: 'Option 4',
84 | key: 'setting:4',
85 | },
86 | ],
87 | },
88 | ],
89 | },
90 | {
91 | label: (
92 |
93 | Navigation Four - Link
94 |
95 | ),
96 | key: 'alipay',
97 | },
98 | ];
99 |
100 | function getItem (label, key, icon, children, type) {
101 | return {
102 | key,
103 | icon,
104 | children,
105 | label,
106 | type,
107 | };
108 | }
109 |
110 | // 内嵌菜单
111 | const itemsEmbedded = [
112 | getItem('Navigation One', 'sub1', , [
113 | getItem('Item 1', 'g1', null, [getItem('Option 1', '1'), getItem('Option 2', '2')], 'group'),
114 | getItem('Item 2', 'g2', null, [getItem('Option 3', '3'), getItem('Option 4', '4')], 'group'),
115 | ]),
116 | getItem('Navigation Two', 'sub2', , [
117 | getItem('Option 5', '5'),
118 | getItem('Option 6', '6'),
119 | getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]),
120 | ]),
121 | getItem('Navigation Three', 'sub4', , [
122 | getItem('Option 9', '9'),
123 | getItem('Option 10', '10'),
124 | getItem('Option 11', '11'),
125 | getItem('Option 12', '12'),
126 | ]),
127 | ];
128 |
129 | // 可收缩菜单
130 | const itemsShrink = [
131 | getItem('Option 1', '1', ),
132 | getItem('Option 2', '2', ),
133 | getItem('Option 3', '3', ),
134 | getItem('Navigation One', 'sub1', , [
135 | getItem('Option 5', '5'),
136 | getItem('Option 6', '6'),
137 | getItem('Option 7', '7'),
138 | getItem('Option 8', '8'),
139 | ]),
140 | getItem('Navigation Two', 'sub2', , [
141 | getItem('Option 9', '9'),
142 | getItem('Option 10', '10'),
143 | getItem('Submenu', 'sub3', null, [getItem('Option 11', '11'), getItem('Option 12', '12')]),
144 | ]),
145 | ];
146 |
147 | // 只展开当前父级菜单
148 | const itemsFirstLevel = [
149 | getItem('Navigation One', 'sub1', , [
150 | getItem('Option 1', '1'),
151 | getItem('Option 2', '2'),
152 | getItem('Option 3', '3'),
153 | getItem('Option 4', '4'),
154 | ]),
155 | getItem('Navigation Two', 'sub2', , [
156 | getItem('Option 5', '5'),
157 | getItem('Option 6', '6'),
158 | getItem('Submenu', 'sub3', null, [getItem('Option 7', '7'), getItem('Option 8', '8')]),
159 | ]),
160 | getItem('Navigation Three', 'sub4', , [
161 | getItem('Option 9', '9'),
162 | getItem('Option 10', '10'),
163 | getItem('Option 11', '11'),
164 | getItem('Option 12', '12'),
165 | ]),
166 | ];
167 |
168 | // 可切换动态菜单
169 | const itemsDynamicState = [
170 | getItem('Navigation One', '1', ),
171 | getItem('Navigation Two', '2', ),
172 | getItem('Navigation Two', 'sub1', , [
173 | getItem('Option 3', '3'),
174 | getItem('Option 4', '4'),
175 | getItem('Submenu', 'sub1-2', null, [getItem('Option 5', '5'), getItem('Option 6', '6')]),
176 | ]),
177 | getItem('Navigation Three', 'sub2', , [
178 | getItem('Option 7', '7'),
179 | getItem('Option 8', '8'),
180 | getItem('Option 9', '9'),
181 | getItem('Option 10', '10'),
182 | ]),
183 | getItem(
184 |
185 | Ant Design
186 | ,
187 | 'link',
188 | ,
189 | ),
190 | ];
191 |
192 | return (
193 |
194 |
195 |
196 |
197 |
198 |
何时使用
199 |
200 |
201 | 导航菜单是一个网站的灵魂,用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航,顶部导航提供全局性的类目和功能,侧边导航提供多级结构来收纳和排列网站架构。
202 |
203 |
204 |
205 |
206 |
210 |
211 |
212 |
213 |
226 |
227 |
228 |
229 |
230 |
只展开当前父级菜单
231 |
240 |
241 |
242 |
243 |
244 |
245 |
可收缩菜单
246 |
251 |
260 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
可切换动态菜单
275 |
276 | setMode(() => (val ? 'vertical' : 'inline'))} /> Change Mode
277 |
278 | setTheme(() => (val ? 'dark' : 'light'))} /> Change Theme
279 |
280 |
281 |
291 |
292 |
293 |
294 |
295 |
296 | )
297 | }
298 |
299 | export default MenuView
300 |
--------------------------------------------------------------------------------
/src/views/NavView/Menu/index.js:
--------------------------------------------------------------------------------
1 | import MenuView from './Menu.jsx'
2 |
3 | export default MenuView
4 |
--------------------------------------------------------------------------------
/src/views/NavView/Step/Step.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Layout, Divider, Row, Col, Steps, Button, message } from 'antd'
3 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
4 | import '@/style/view-style/step.scss'
5 | import { iconToElement } from '@/utils/util'
6 |
7 | const { Step } = Steps
8 |
9 | const steps = [
10 | {
11 | title: 'First',
12 | content: 'First-content'
13 | },
14 | {
15 | title: 'Second',
16 | content: 'Second-content'
17 | },
18 | {
19 | title: 'Last',
20 | content: 'Last-content'
21 | }
22 | ]
23 |
24 | const StepView = () => {
25 | const [current, setCurrent] = useState(0)
26 |
27 | return (
28 |
29 |
30 |
31 |
32 |
33 |
何时使用
34 |
35 |
当任务复杂或者存在先后关系时,将其分解成一系列步骤,从而简化任务。
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
setCurrent(current)}>
96 | {steps.map(item => (
97 |
98 | ))}
99 |
100 |
{steps[current].content}
101 |
102 | {current < steps.length - 1 && (
103 |
106 | )}
107 | {current === steps.length - 1 && (
108 |
111 | )}
112 | {current > 0 && (
113 |
116 | )}
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | )
134 | }
135 |
136 | export default StepView
137 |
--------------------------------------------------------------------------------
/src/views/NavView/Step/index.js:
--------------------------------------------------------------------------------
1 | import StepView from './Step.jsx'
2 |
3 | export default StepView
4 |
--------------------------------------------------------------------------------
/src/views/Others/404/404.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import img404 from '@/assets/images/404.jpg'
3 |
4 | const View404 = () => (
5 |
6 |

7 |
8 | )
9 |
10 | export default View404
11 |
--------------------------------------------------------------------------------
/src/views/Others/404/index.js:
--------------------------------------------------------------------------------
1 | import View404 from './404.jsx'
2 |
3 | export default View404
4 |
--------------------------------------------------------------------------------
/src/views/Others/500/500.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import img500 from '@/assets/images/500.png'
3 |
4 | const View500 = () => (
5 |
6 |

7 |
8 | )
9 |
10 | export default View500
11 |
--------------------------------------------------------------------------------
/src/views/Others/500/index.js:
--------------------------------------------------------------------------------
1 | import View500 from './500.jsx'
2 |
3 | export default View500
4 |
--------------------------------------------------------------------------------
/src/views/Others/Animation/Animation.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Layout, Divider, Row, Col, Button, Tabs } from 'antd'
3 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
4 | import '@/style/view-style/animation.scss'
5 |
6 | const { TabPane } = Tabs
7 | const typeIn = [
8 | 'bounceInDown',
9 | 'bounceInLeft',
10 | 'bounceInRight',
11 | 'bounceInUp',
12 | 'fadeIn',
13 | 'fadeInDown',
14 | 'fadeInLeft',
15 | 'fadeInLeftBig',
16 | 'fadeInRight',
17 | 'fadeInRightBig',
18 | 'fadeInUp',
19 | 'fadeInUpBig',
20 | 'flipInX',
21 | 'flipInY',
22 | 'rotateIn'
23 | ]
24 | const typeOut = [
25 | 'bounceOut',
26 | 'bounceOutDown',
27 | 'bounceOutLeft',
28 | 'bounceOutRight',
29 | 'bounceOutUp',
30 | 'fadeInDown',
31 | 'fadeOut',
32 | 'fadeOutDown',
33 | 'fadeOutDownBig',
34 | 'fadeOutLeft',
35 | 'fadeOutLeftBig',
36 | 'fadeOutRight',
37 | 'fadeOutRightBig',
38 | 'fadeOutUp',
39 | 'fadeOutUpBig',
40 | 'rotateOut'
41 | ]
42 | const typeOther = [
43 | 'bounceIn',
44 | 'bounce',
45 | 'flash',
46 | 'pulse',
47 | 'rubberBand',
48 | 'shake',
49 | 'headShake',
50 | 'swing',
51 | 'tada',
52 | 'wobble',
53 | 'jello'
54 | ]
55 |
56 |
57 | const AnimationView = () => {
58 | const [fontType, setFontType] = useState('animated bounceInRight')
59 |
60 |
61 | const Access = () => {
62 | return (
63 |
64 | {
65 | typeIn.map((v, i) => (
66 |
74 | ))
75 | }
76 |
77 | )
78 | }
79 |
80 | const ExitView = () => {
81 | return (
82 |
83 | {typeOut.map((v, i) => (
84 |
92 | ))}
93 |
94 | )
95 | }
96 |
97 | const Other = () => {
98 | return (
99 |
100 | {typeOther.map((v, i) => (
101 |
109 | ))}
110 |
111 | )
112 | }
113 |
114 | return (
115 |
116 |
117 |
118 |
119 |
120 |
何时使用
121 |
122 |
当页面需要动态效果时。
123 |
124 |
125 |
126 |
127 | ,
136 | },
137 | {
138 | label: `退场`,
139 | key: '2',
140 | children: ,
141 | },
142 | {
143 | label: `其它`,
144 | key: '3',
145 | children: ,
146 | },
147 | ]}
148 | />
149 |
150 |
151 |
152 |
153 | Animate.css
154 |
155 |
156 |
157 |
158 | )
159 | }
160 |
161 | export default AnimationView
162 |
--------------------------------------------------------------------------------
/src/views/Others/Animation/index.js:
--------------------------------------------------------------------------------
1 | import AnimationView from './Animation.jsx'
2 |
3 | export default AnimationView
4 |
--------------------------------------------------------------------------------
/src/views/Others/Editor/Editor.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import * as ReactDOM from 'react-dom';
3 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
4 | import { Layout, Divider } from 'antd'
5 | import SimpleMDE from 'react-simplemde-editor';
6 | import 'easymde/dist/easymde.min.css';
7 |
8 | // 其它编辑器 支持node14+
9 | // react-markdown-editor-lite
10 | // https://github.com/HarryChen0506/react-markdown-editor-lite
11 | // braft-editor
12 | // https://github.com/margox/braft-editor
13 |
14 |
15 | // 当前使用 支持node16.15.0
16 | // simplemde - markdown - editor
17 | // https://github.com/sparksuite/simplemde-markdown-editor
18 |
19 |
20 | // Register plugins if required
21 | // MdEditor.use(YOUR_PLUGINS_HERE);
22 |
23 | // Initialize a markdown parser
24 | // const mdParser = new MarkdownIt(/* Markdown-it options */);
25 |
26 | const EditorView = (props) => {
27 | const value = '这是一个富文本编辑器'
28 | const handleChange = (value) => {
29 | console.log('value', value)
30 | }
31 |
32 | return (
33 |
34 |
35 |
36 |
37 |
45 |
46 |
74 |
75 | )
76 | }
77 |
78 | export default EditorView
--------------------------------------------------------------------------------
/src/views/Others/Editor/index.js:
--------------------------------------------------------------------------------
1 | import EditorView from './Editor.jsx'
2 |
3 | export default EditorView
4 |
--------------------------------------------------------------------------------
/src/views/Others/Progress/Progress.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
3 | import { Layout, Row, Col, Progress, Divider, Button } from 'antd'
4 | import '@/style/view-style/progress.scss'
5 | import { iconToElement } from '@/utils/util'
6 |
7 | const ButtonGroup = Button.Group
8 |
9 | const DrawerView = () => {
10 | const [percent, setPercent] = useState(0)
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
何时使用
19 |
在操作需要较长时间才能完成时,为用户显示该操作的当前进度和状态。
20 |
21 |
22 |
23 |
24 |
25 |
基本
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
动态进度条
37 |
38 |
39 |
48 |
49 |
50 |
51 |
52 |
53 |
圆环
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
自定义文字
63 |
66 |
67 |
68 |
69 | )
70 | }
71 |
72 | export default DrawerView
73 |
--------------------------------------------------------------------------------
/src/views/Others/Progress/index.js:
--------------------------------------------------------------------------------
1 | import ProgressView from './Progress.jsx'
2 |
3 | export default ProgressView
4 |
--------------------------------------------------------------------------------
/src/views/Others/Upload/Upload.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { Layout, Row, Col, Upload, message, Button, Divider, Modal } from 'antd'
3 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
4 | import { iconToElement } from '@/utils/util'
5 |
6 | const { Dragger } = Upload
7 |
8 | const props = {
9 | name: 'file',
10 | action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
11 | headers: {
12 | authorization: 'authorization-text'
13 | },
14 | onChange (info) {
15 | if (info.file.status !== 'uploading') {
16 | console.log(info.file, info.fileList)
17 | }
18 | if (info.file.status === 'done') {
19 | message.success(`${info.file.name} file uploaded successfully`)
20 | } else if (info.file.status === 'error') {
21 | message.error(`${info.file.name} file upload failed.`)
22 | }
23 | }
24 | }
25 |
26 | function getBase64 (img, callback) {
27 | const reader = new FileReader()
28 | reader.addEventListener('load', () => callback(reader.result))
29 | reader.readAsDataURL(img)
30 | }
31 |
32 | function getBase_64 (file) {
33 | return new Promise((resolve, reject) => {
34 | const reader = new FileReader()
35 | reader.readAsDataURL(file)
36 | reader.onload = () => resolve(reader.result)
37 | reader.onerror = error => reject(error)
38 | })
39 | }
40 |
41 | function beforeUpload (file) {
42 | const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
43 | if (!isJpgOrPng) {
44 | message.error('You can only upload JPG/PNG file!')
45 | }
46 | const isLt2M = file.size / 1024 / 1024 < 2
47 | if (!isLt2M) {
48 | message.error('Image must smaller than 2MB!')
49 | }
50 | return isJpgOrPng && isLt2M
51 | }
52 |
53 | const UploadView = () => {
54 | const [state, setState] = useState({
55 | previewVisible: false,
56 | previewImage: '',
57 | fileList: [
58 | {
59 | uid: '-1',
60 | name: 'image.png',
61 | status: 'done',
62 | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
63 | },
64 | {
65 | uid: '-2',
66 | name: 'image.png',
67 | status: 'done',
68 | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
69 | },
70 | {
71 | uid: '-3',
72 | name: 'image.png',
73 | status: 'done',
74 | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
75 | },
76 | {
77 | uid: '-4',
78 | name: 'image.png',
79 | status: 'done',
80 | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
81 | },
82 | {
83 | uid: '-5',
84 | name: 'image.png',
85 | status: 'done',
86 | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
87 | }
88 | ]
89 | })
90 |
91 | const [loading, setLoading] = useState(false)
92 | const [imageUrl, setimageUrl] = useState()
93 |
94 | let { previewVisible, previewImage, fileList } = state
95 |
96 | const handleChange = info => {
97 | getBase64(info.file.originFileObj, imageUrl => {
98 | setimageUrl(() => {
99 | if (info.file.status === 'done') {
100 | return imageUrl
101 | }
102 | })
103 | setLoading(() => (info.file.status === 'uploading' ? true : false))
104 | })
105 | }
106 |
107 | const handleCancel = () =>
108 | setState(prevState => {
109 | return { ...prevState, previewVisible: false }
110 | })
111 |
112 | const handlePreview = async file => {
113 | if (!file.url && !file.preview) {
114 | file.preview = await getBase_64(file.originFileObj)
115 | }
116 | setState(prevState => {
117 | return { ...prevState, previewImage: file.url || file.preview, previewVisible: true }
118 | })
119 | }
120 | const handle_Change = ({ fileList }) =>
121 | setState(prevState => {
122 | return { ...prevState, fileList }
123 | })
124 |
125 | const uploadButton = (
126 |
127 | {iconToElement(loading ? 'LoadingOutlined' : 'PlusOutlined', { fontSize: '2rem' })}
128 |
Upload
129 |
130 | )
131 | return (
132 |
133 |
134 |
135 |
136 |
137 |
何时使用
138 |
上传是将信息(网页、文字、图片、视频等)通过网页或者上传工具发布到远程服务器上的过程
139 |
140 |
141 |
142 |
143 |
普通模式
144 |
145 |
146 | {iconToElement('UploadOutlined', { fontSize: '2rem' })}
147 | Click to Upload
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
照片墙
156 |
157 |
163 | {fileList.length >= 8 ? null : uploadButton}
164 |
165 |
166 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
自定义模式
181 |
189 | {imageUrl ?
: uploadButton}
190 |
191 |
192 |
193 |
可拖拽上传
194 |
195 |
196 | {iconToElement('InboxOutlined', { fontSize: '2rem' })}
197 |
198 | Click or drag file to this area to upload
199 |
200 | Support for a single or bulk upload. Strictly prohibit from uploading company data or
201 | other band files
202 |
203 |
204 |
205 |
206 |
207 |
208 | )
209 | }
210 |
211 | export default UploadView
212 |
--------------------------------------------------------------------------------
/src/views/Others/Upload/index.js:
--------------------------------------------------------------------------------
1 | import UploadView from './Upload.jsx'
2 |
3 | export default UploadView
4 |
--------------------------------------------------------------------------------
/src/views/PublicView/Button/ButtonView.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
3 | import { Layout, Row, Col, Button, Divider } from 'antd'
4 | import '@/style/view-style/button.scss'
5 | import { iconToElement } from '@/utils/util'
6 | import IconButton from './components/IconButton'
7 |
8 | const ButtonGroup = Button.Group
9 |
10 | const ButtonView = () => {
11 | const [loading, setloading] = useState(false)
12 | const [iconLoading, setIconLoading] = useState(false)
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
何时使用
20 |
21 |
标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。
22 |
23 |
24 |
25 |
26 |
27 | Primary
28 | Default
29 | Dashed
30 | Danger
31 | Link
32 |
33 |
34 |
35 | Loading
36 |
37 |
38 | Loading
39 |
40 | setloading(true)}>
41 | Click me!
42 |
43 | setIconLoading(true)}>
48 | Click me!
49 |
50 |
51 |
52 |
53 |
54 |
55 |
Basic
56 |
57 | large
58 | small
59 | mini
60 |
61 |
62 | L
63 | M
64 | R
65 |
66 |
67 | With Icon
68 |
69 |
70 | {iconToElement('LeftOutlined')}
71 | Go back
72 |
73 |
74 |
75 | Go forward
76 | {iconToElement('RightOutlined')}
77 |
78 |
79 |
80 |
81 |
85 |
89 |
90 |
91 |
92 |
97 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | Primary
113 |
114 | Primary(disabled)
115 |
116 | Default
117 | Default(disabled)
118 | Dashed
119 |
120 | Dashed(disabled)
121 |
122 |
123 |
124 |
125 | Primary
126 |
127 | Default
128 |
129 | Dashed
130 |
131 |
132 | Danger
133 |
134 |
135 | Link
136 |
137 |
138 |
139 |
140 |
141 |
142 | )
143 | }
144 |
145 | export default ButtonView
146 |
--------------------------------------------------------------------------------
/src/views/PublicView/Button/components/IconButton.jsx:
--------------------------------------------------------------------------------
1 | import { SearchOutlined } from '@ant-design/icons';
2 | import { Button, Tooltip } from 'antd';
3 | import React from 'react';
4 |
5 | const App = () => (
6 | <>
7 |
8 | } />
9 |
10 |
11 |
12 | A
13 |
14 |
15 | }>
16 | Search
17 |
18 |
19 |
20 | } />
21 |
22 |
23 | }>Search
24 |
25 |
26 | } />
27 |
28 |
29 | }>
30 | Search
31 |
32 | } href="https://www.google.com" />
33 | >
34 | );
35 |
36 | export default App;
--------------------------------------------------------------------------------
/src/views/PublicView/Button/index.js:
--------------------------------------------------------------------------------
1 | import ButtonView from './ButtonView.jsx'
2 |
3 | export default ButtonView
4 |
--------------------------------------------------------------------------------
/src/views/PublicView/Icon/index.js:
--------------------------------------------------------------------------------
1 | import IconView from './IconView.jsx'
2 |
3 | export default IconView
4 |
--------------------------------------------------------------------------------
/src/views/ShowView/Collapse/Collapse.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
3 | import { Layout, Divider, Row, Col, Collapse } from 'antd'
4 | import { iconToElement } from '@/utils/util'
5 |
6 | const { Panel } = Collapse
7 |
8 | const text = `
9 | A dog is a type of domesticated animal.
10 | Known for its loyalty and faithfulness,
11 | it can be found as a welcome guest in many households across the world.
12 | `
13 |
14 | function callback (key) {
15 | console.log(key)
16 | }
17 |
18 | const customPanelStyle = {
19 | background: '#f7f7f7',
20 | borderRadius: 4,
21 | marginBottom: 24,
22 | border: 0,
23 | overflow: 'hidden'
24 | }
25 |
26 | const CollapseView = () => {
27 | return (
28 |
29 |
30 |
31 |
32 |
33 |
何时使用
34 |
35 |
对复杂区域进行分组和隐藏,保持页面的整洁。
36 |
手风琴 是一种特殊的折叠面板,只允许单个内容区域展开。
37 |
38 |
39 |
40 |
41 |
42 |
简单使用
43 |
44 |
45 | {text}
46 |
47 |
48 | {text}
49 |
50 |
51 | {text}
52 |
53 |
54 | ,
55 |
56 |
57 |
58 |
59 |
60 |
手风琴
61 |
62 |
63 | {text}
64 |
65 |
66 | {text}
67 |
68 |
69 | {text}
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
自定义样式功能
78 |
iconToElement('WechatOutlined', { fontSize: '2rem' }, { rotate: isActive ? 90 : 0 })}
83 | >
84 |
85 |
86 |
87 | {text}
88 |
89 |
90 |
91 |
92 | {text}
93 |
94 |
95 | {text}
96 |
97 |
98 |
99 |
100 |
101 |
102 | )
103 | }
104 |
105 | export default CollapseView
106 |
--------------------------------------------------------------------------------
/src/views/ShowView/Collapse/index.js:
--------------------------------------------------------------------------------
1 | import CollapseView from './Collapse.jsx'
2 |
3 | export default CollapseView
4 |
--------------------------------------------------------------------------------
/src/views/ShowView/Table/Table.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
3 | import { Layout, Divider, Row, Col, Tag, Table, Button, Anchor } from 'antd'
4 | import '@/style/view-style/table.scss'
5 |
6 | const { Column } = Table
7 | const { Link } = Anchor
8 |
9 | const columns = [
10 | {
11 | title: 'Name',
12 | dataIndex: 'name',
13 | key: 'name',
14 | render: text => {text}
15 | },
16 | {
17 | title: 'Age',
18 | dataIndex: 'age',
19 | key: 'age'
20 | },
21 | {
22 | title: 'Address',
23 | dataIndex: 'address',
24 | key: 'address'
25 | },
26 | {
27 | title: 'Tags',
28 | key: 'tags',
29 | dataIndex: 'tags',
30 | render: tags => (
31 |
32 | {tags.map(tag => {
33 | let color = tag.length > 5 ? 'geekblue' : 'green'
34 | if (tag === 'loser') {
35 | color = 'volcano'
36 | }
37 | return (
38 |
39 | {tag.toUpperCase()}
40 |
41 | )
42 | })}
43 |
44 | )
45 | },
46 | {
47 | title: 'Action',
48 | key: 'action',
49 | render: (text, record) => (
50 |
51 | Invite {record.name}
52 |
53 | Delete
54 |
55 | )
56 | }
57 | ]
58 |
59 | const data = []
60 | for (let i = 0; i < 46; i++) {
61 | data.push({
62 | key: i,
63 | name: `Edward King ${i}`,
64 | age: `${i + 1}`,
65 | address: `London, Park Lane no. ${i}`,
66 | tags: ['nice', 'developer']
67 | })
68 | }
69 |
70 | class Table1 extends Component {
71 | render () {
72 | return
73 | }
74 | }
75 |
76 | class Table2 extends Component {
77 | render () {
78 | return (
79 |
80 |
81 |
82 |
83 | (
88 |
89 | {tags.map(tag => (
90 |
91 | {tag}
92 |
93 | ))}
94 |
95 | )}
96 | />
97 | (
101 |
102 | Invite {record.lastName}
103 |
104 | Delete
105 |
106 | )}
107 | />
108 |
109 | )
110 | }
111 | }
112 |
113 | class Table3 extends Component {
114 | state = {
115 | selectedRowKeys: []
116 | }
117 |
118 | onSelectChange = selectedRowKeys => {
119 | console.log('selectedRowKeys changed: ', selectedRowKeys)
120 | this.setState({ selectedRowKeys })
121 | }
122 |
123 | render () {
124 | const { selectedRowKeys } = this.state
125 | const rowSelection = {
126 | selectedRowKeys,
127 | onChange: this.onSelectChange,
128 | hideDefaultSelections: true,
129 | selections: [
130 | {
131 | key: 'all-data',
132 | text: 'Select All Data',
133 | onSelect: () => {
134 | this.setState({
135 | selectedRowKeys: [...Array(46).keys()] // 0...45
136 | })
137 | }
138 | },
139 | {
140 | key: 'odd',
141 | text: 'Select Odd Row',
142 | onSelect: changableRowKeys => {
143 | let newSelectedRowKeys = []
144 | newSelectedRowKeys = changableRowKeys.filter((key, index) => {
145 | if (index % 2 !== 0) {
146 | return false
147 | }
148 | return true
149 | })
150 | this.setState({ selectedRowKeys: newSelectedRowKeys })
151 | }
152 | },
153 | {
154 | key: 'even',
155 | text: 'Select Even Row',
156 | onSelect: changableRowKeys => {
157 | let newSelectedRowKeys = []
158 | newSelectedRowKeys = changableRowKeys.filter((key, index) => {
159 | if (index % 2 !== 0) {
160 | return true
161 | }
162 | return false
163 | })
164 | this.setState({ selectedRowKeys: newSelectedRowKeys })
165 | }
166 | }
167 | ]
168 | }
169 | return
170 | }
171 | }
172 |
173 | class Table4 extends Component {
174 | state = {
175 | filteredInfo: null,
176 | sortedInfo: null
177 | }
178 | handleChange = (pagination, filters, sorter) => {
179 | console.log('Various parameters', pagination, filters, sorter)
180 | this.setState({
181 | filteredInfo: filters,
182 | sortedInfo: sorter
183 | })
184 | }
185 |
186 | clearFilters = () => {
187 | this.setState({ filteredInfo: null })
188 | }
189 |
190 | clearAll = () => {
191 | this.setState({
192 | filteredInfo: null,
193 | sortedInfo: null
194 | })
195 | }
196 |
197 | setAgeSort = () => {
198 | this.setState({
199 | sortedInfo: {
200 | order: 'descend',
201 | columnKey: 'age'
202 | }
203 | })
204 | }
205 | render () {
206 | let { sortedInfo, filteredInfo } = this.state
207 | sortedInfo = sortedInfo || {}
208 | filteredInfo = filteredInfo || {}
209 | const columns = [
210 | {
211 | title: 'Name',
212 | dataIndex: 'name',
213 | key: 'name',
214 | filters: [
215 | { text: 'Edward King 20', value: 'Edward King 20' },
216 | { text: 'Edward King 25', value: 'Edward King 25' }
217 | ],
218 | filteredValue: filteredInfo.name || null,
219 | onFilter: (value, record) => record.name.includes(value)
220 | },
221 | {
222 | title: 'Age',
223 | dataIndex: 'age',
224 | key: 'age',
225 | sorter: (a, b) => a.age - b.age,
226 | sortOrder: sortedInfo.columnKey === 'age' && sortedInfo.order
227 | },
228 | {
229 | title: 'Address',
230 | dataIndex: 'address',
231 | key: 'address',
232 | filters: [
233 | { text: 'London, Park Lane no. 24', value: 'London, Park Lane no. 24' },
234 | { text: 'London, Park Lane no. 27', value: 'London, Park Lane no. 27' }
235 | ],
236 | filteredValue: filteredInfo.address || null,
237 | onFilter: (value, record) => record.address.includes(value)
238 | }
239 | ]
240 | return (
241 |
242 |
243 | Sort age
244 | Clear filters
245 | Clear filters and sorters
246 |
247 |
248 |
249 | )
250 | }
251 | }
252 |
253 | const handleAnchor = (e, link) => {
254 | e.preventDefault();
255 | };
256 |
257 | class TableView extends Component {
258 | render () {
259 | return (
260 |
261 |
262 |
263 |
264 |
265 |
何时使用
266 |
267 |
当有大量结构化的数据需要展现时;
268 |
当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。
269 |
270 |
271 |
272 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
基础表格
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
JSX表单
294 |
JSX表格
295 |
296 |
297 |
298 |
299 |
300 |
301 |
可选表单
302 |
可选表格
303 |
304 |
305 |
306 |
307 |
308 |
309 |
可筛选排序表单
310 |
可筛选排序表格
311 |
312 |
313 |
314 |
315 |
316 | )
317 | }
318 | }
319 |
320 | export default TableView
321 |
--------------------------------------------------------------------------------
/src/views/ShowView/Table/index.js:
--------------------------------------------------------------------------------
1 | import TableView from './Table.jsx'
2 |
3 | export default TableView
4 |
--------------------------------------------------------------------------------
/src/views/ShowView/Tabs/Tabs.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
3 | import { Layout, Divider, Row, Col } from 'antd'
4 | import BaseTabs from './components/BaseTabs'
5 | import SizeTabs from './components/SizeTabs'
6 | import LocationTabs from './components/LocationTabs'
7 | import AddTabs from './components/AddTabs'
8 |
9 | const TabsViews = () => {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
何时使用
17 |
18 |
提供平级的区域将大块内容进行收纳和展现,保持界面整洁
19 |
Ant Design 依次提供了三级选项卡,分别用于不同的场景
20 |
- 卡片式的页签,提供可关闭的样式,常用于容器顶部。
21 |
- 标准线条式页签,用于容器内部的主功能切换,这是最常用的 Tabs。
22 |
- RadioButton 可作为更次级的页签来使用。
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
52 |
53 |
54 |
55 | )
56 | }
57 |
58 | export default TabsViews
59 |
--------------------------------------------------------------------------------
/src/views/ShowView/Tabs/components/AddTabs.jsx:
--------------------------------------------------------------------------------
1 | import { Tabs } from 'antd';
2 | import React, { useRef, useState } from 'react';
3 | const initialItems = [
4 | {
5 | label: 'Tab 1',
6 | children: 'Content of Tab 1',
7 | key: '1',
8 | },
9 | {
10 | label: 'Tab 2',
11 | children: 'Content of Tab 2',
12 | key: '2',
13 | },
14 | {
15 | label: 'Tab 3',
16 | children: 'Content of Tab 3',
17 | key: '3',
18 | closable: false,
19 | },
20 | ];
21 |
22 | const App = () => {
23 | const [activeKey, setActiveKey] = useState(initialItems[0].key);
24 | const [items, setItems] = useState(initialItems);
25 | const newTabIndex = useRef(0);
26 |
27 | const onChange = (newActiveKey) => {
28 | setActiveKey(newActiveKey);
29 | };
30 |
31 | const add = () => {
32 | const newActiveKey = `newTab${newTabIndex.current++}`;
33 | const newPanes = [...items];
34 | newPanes.push({
35 | label: 'New Tab',
36 | children: 'Content of new Tab',
37 | key: newActiveKey,
38 | });
39 | setItems(newPanes);
40 | setActiveKey(newActiveKey);
41 | };
42 |
43 | const remove = (targetKey) => {
44 | let newActiveKey = activeKey;
45 | let lastIndex = -1;
46 | items.forEach((item, i) => {
47 | if (item.key === targetKey) {
48 | lastIndex = i - 1;
49 | }
50 | });
51 | const newPanes = items.filter((item) => item.key !== targetKey);
52 |
53 | if (newPanes.length && newActiveKey === targetKey) {
54 | if (lastIndex >= 0) {
55 | newActiveKey = newPanes[lastIndex].key;
56 | } else {
57 | newActiveKey = newPanes[0].key;
58 | }
59 | }
60 |
61 | setItems(newPanes);
62 | setActiveKey(newActiveKey);
63 | };
64 |
65 | const onEdit = (targetKey, action) => {
66 | if (action === 'add') {
67 | add();
68 | } else {
69 | remove(targetKey);
70 | }
71 | };
72 |
73 | return (
74 |
81 | );
82 | };
83 |
84 | export default App;
--------------------------------------------------------------------------------
/src/views/ShowView/Tabs/components/BaseTabs.jsx:
--------------------------------------------------------------------------------
1 | import { Tabs } from 'antd';
2 | import React from 'react';
3 |
4 | const onChange = (key) => {
5 | console.log(key);
6 | };
7 |
8 | const App = () => (
9 |
30 | );
31 |
32 | export default App;
--------------------------------------------------------------------------------
/src/views/ShowView/Tabs/components/LocationTabs.jsx:
--------------------------------------------------------------------------------
1 | import { Radio, Space, Tabs } from 'antd';
2 | import React, { useState } from 'react';
3 |
4 | const App = () => {
5 | const [tabPosition, setTabPosition] = useState('left');
6 |
7 | const changeTabPosition = (e) => {
8 | setTabPosition(e.target.value);
9 | };
10 |
11 | return (
12 | <>
13 |
18 | Tab position:
19 |
20 | top
21 | bottom
22 | left
23 | right
24 |
25 |
26 | {
29 | const id = String(i + 1);
30 | return {
31 | label: `Tab ${id}`,
32 | key: id,
33 | children: `Content of Tab ${id}`,
34 | };
35 | })}
36 | />
37 | >
38 | );
39 | };
40 |
41 | export default App;
--------------------------------------------------------------------------------
/src/views/ShowView/Tabs/components/SizeTabs.jsx:
--------------------------------------------------------------------------------
1 | import { Radio, Tabs } from 'antd';
2 | import React, { useState } from 'react';
3 |
4 | const App = () => {
5 | const [size, setSize] = useState('small');
6 |
7 | const onChange = (e) => {
8 | setSize(e.target.value);
9 | };
10 |
11 | return (
12 |
13 |
20 | Small
21 | Middle
22 | Large
23 |
24 | {
31 | const id = String(i + 1);
32 | return {
33 | label: `Tab ${id}`,
34 | key: id,
35 | children: `Content of tab ${id}`,
36 | };
37 | })}
38 | />
39 | {
44 | const id = String(i + 1);
45 | return {
46 | label: `Card Tab ${id}`,
47 | key: id,
48 | children: `Content of card tab ${id}`,
49 | };
50 | })}
51 | />
52 |
53 | );
54 | };
55 |
56 | export default App;
--------------------------------------------------------------------------------
/src/views/ShowView/Tabs/index.js:
--------------------------------------------------------------------------------
1 | import TabsView from './Tabs.jsx'
2 |
3 | export default TabsView
4 |
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/Index.scss:
--------------------------------------------------------------------------------
1 | .site-tree-search-value {
2 | color: #f50;
3 | }
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/Tree.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
3 | import { Layout, Divider, Row, Col } from 'antd'
4 | import { iconToElement } from '@/utils/util'
5 | import BaseTree from './components/BaseTree'
6 | import SearchTree from './components/SearchTree'
7 | import ControlledTree from './components/ControlledTree'
8 | import DragTree from './components/DragTree'
9 |
10 |
11 | const TreeView = () => {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
何时使用
19 |
20 |
21 | 文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用 树控件
22 | 可以完整展现其中的层级关系,并具有展开收起选择等交互功能。
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | export default TreeView
48 |
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/components/BaseTree.jsx:
--------------------------------------------------------------------------------
1 | import { Tree, Divider } from 'antd';
2 | import React from 'react';
3 |
4 | const treeData = [
5 | {
6 | title: '0-0',
7 | key: '0-0',
8 | children: [
9 | {
10 | title: '0-0-0',
11 | key: '0-0-0',
12 | children: [
13 | { title: '0-0-0-0', key: '0-0-0-0' },
14 | { title: '0-0-0-1', key: '0-0-0-1' },
15 | { title: '0-0-0-2', key: '0-0-0-2' }
16 | ]
17 | },
18 | {
19 | title: '0-0-1',
20 | key: '0-0-1',
21 | children: [
22 | { title: '0-0-1-0', key: '0-0-1-0' },
23 | { title: '0-0-1-1', key: '0-0-1-1' },
24 | { title: '0-0-1-2', key: '0-0-1-2' }
25 | ]
26 | },
27 | {
28 | title: '0-0-2',
29 | key: '0-0-2'
30 | }
31 | ]
32 | },
33 | {
34 | title: '0-1',
35 | key: '0-1',
36 | children: [
37 | { title: '0-1-0-0', key: '0-1-0-0' },
38 | { title: '0-1-0-1', key: '0-1-0-1' },
39 | { title: '0-1-0-2', key: '0-1-0-2' }
40 | ]
41 | },
42 | {
43 | title: '0-2',
44 | key: '0-2'
45 | }
46 | ]
47 |
48 | const BaseTree = () => {
49 | const onSelect = (selectedKeys, info) => {
50 | console.log('selected', selectedKeys, info);
51 | };
52 |
53 | const onCheck = (checkedKeys, info) => {
54 | console.log('onCheck', checkedKeys, info);
55 | };
56 |
57 | return (
58 |
70 | );
71 | };
72 |
73 | export default BaseTree;
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/components/ControlledTree.jsx:
--------------------------------------------------------------------------------
1 | import { Tree, Divider } from 'antd';
2 | import React, { useState } from 'react';
3 |
4 | const treeData = [
5 | {
6 | title: '0-0',
7 | key: '0-0',
8 | children: [
9 | {
10 | title: '0-0-0',
11 | key: '0-0-0',
12 | children: [
13 | {
14 | title: '0-0-0-0',
15 | key: '0-0-0-0',
16 | },
17 | {
18 | title: '0-0-0-1',
19 | key: '0-0-0-1',
20 | },
21 | {
22 | title: '0-0-0-2',
23 | key: '0-0-0-2',
24 | },
25 | ],
26 | },
27 | {
28 | title: '0-0-1',
29 | key: '0-0-1',
30 | children: [
31 | {
32 | title: '0-0-1-0',
33 | key: '0-0-1-0',
34 | },
35 | {
36 | title: '0-0-1-1',
37 | key: '0-0-1-1',
38 | },
39 | {
40 | title: '0-0-1-2',
41 | key: '0-0-1-2',
42 | },
43 | ],
44 | },
45 | {
46 | title: '0-0-2',
47 | key: '0-0-2',
48 | },
49 | ],
50 | },
51 | {
52 | title: '0-1',
53 | key: '0-1',
54 | children: [
55 | {
56 | title: '0-1-0-0',
57 | key: '0-1-0-0',
58 | },
59 | {
60 | title: '0-1-0-1',
61 | key: '0-1-0-1',
62 | },
63 | {
64 | title: '0-1-0-2',
65 | key: '0-1-0-2',
66 | },
67 | ],
68 | },
69 | {
70 | title: '0-2',
71 | key: '0-2',
72 | },
73 | ];
74 |
75 | const ControlledTree = () => {
76 | const [expandedKeys, setExpandedKeys] = useState(['0-0-0', '0-0-1']);
77 | const [checkedKeys, setCheckedKeys] = useState(['0-0-0']);
78 | const [selectedKeys, setSelectedKeys] = useState([]);
79 | const [autoExpandParent, setAutoExpandParent] = useState(true);
80 |
81 | const onExpand = (expandedKeysValue) => {
82 | console.log('onExpand', expandedKeysValue); // if not set autoExpandParent to false, if children expanded, parent can not collapse.
83 | // or, you can remove all expanded children keys.
84 |
85 | setExpandedKeys(expandedKeysValue);
86 | setAutoExpandParent(false);
87 | };
88 |
89 | const onCheck = (checkedKeysValue) => {
90 | console.log('onCheck', checkedKeysValue);
91 | setCheckedKeys(checkedKeysValue);
92 | };
93 |
94 | const onSelect = (selectedKeysValue, info) => {
95 | console.log('onSelect', info);
96 | setSelectedKeys(selectedKeysValue);
97 | };
98 |
99 | return (
100 |
114 | );
115 | };
116 |
117 | export default ControlledTree;
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/components/DragTree.jsx:
--------------------------------------------------------------------------------
1 | import { Tree, Divider } from 'antd';
2 | import React, { useState } from 'react';
3 |
4 | const x = 3;
5 | const y = 2;
6 | const z = 1;
7 | const defaultData = [];
8 |
9 | const generateData = (_level, _preKey, _tns) => {
10 | const preKey = _preKey || '0';
11 | const tns = _tns || defaultData;
12 | const children = [];
13 |
14 | for (let i = 0; i < x; i++) {
15 | const key = `${preKey}-${i}`;
16 | tns.push({
17 | title: key,
18 | key,
19 | });
20 |
21 | if (i < y) {
22 | children.push(key);
23 | }
24 | }
25 |
26 | if (_level < 0) {
27 | return tns;
28 | }
29 |
30 | const level = _level - 1;
31 | children.forEach((key, index) => {
32 | tns[index].children = [];
33 | return generateData(level, key, tns[index].children);
34 | });
35 | };
36 |
37 | generateData(z);
38 |
39 | const DragTree = () => {
40 | const [gData, setGData] = useState(defaultData);
41 | const [expandedKeys] = useState(['0-0', '0-0-0', '0-0-0-0']);
42 |
43 | const onDragEnter = (info) => {
44 | console.log(info); // expandedKeys 需要受控时设置
45 | // setExpandedKeys(info.expandedKeys)
46 | };
47 |
48 | const onDrop = (info) => {
49 | console.log(info);
50 | const dropKey = info.node.key;
51 | const dragKey = info.dragNode.key;
52 | const dropPos = info.node.pos.split('-');
53 | const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
54 |
55 | const loop = (data, key, callback) => {
56 | for (let i = 0; i < data.length; i++) {
57 | if (data[i].key === key) {
58 | return callback(data[i], i, data);
59 | }
60 |
61 | if (data[i].children) {
62 | loop(data[i].children, key, callback);
63 | }
64 | }
65 | };
66 |
67 | const data = [...gData]; // Find dragObject
68 |
69 | let dragObj;
70 | loop(data, dragKey, (item, index, arr) => {
71 | arr.splice(index, 1);
72 | dragObj = item;
73 | });
74 |
75 | if (!info.dropToGap) {
76 | // Drop on the content
77 | loop(data, dropKey, (item) => {
78 | item.children = item.children || []; // where to insert 示例添加到头部,可以是随意位置
79 |
80 | item.children.unshift(dragObj);
81 | });
82 | } else if (
83 | (info.node.props.children || []).length > 0 && // Has children
84 | info.node.props.expanded && // Is expanded
85 | dropPosition === 1 // On the bottom gap
86 | ) {
87 | loop(data, dropKey, (item) => {
88 | item.children = item.children || []; // where to insert 示例添加到头部,可以是随意位置
89 |
90 | item.children.unshift(dragObj); // in previous version, we use item.children.push(dragObj) to insert the
91 | // item to the tail of the children
92 | });
93 | } else {
94 | let ar = [];
95 | let i;
96 | loop(data, dropKey, (_item, index, arr) => {
97 | ar = arr;
98 | i = index;
99 | });
100 |
101 | if (dropPosition === -1) {
102 | ar.splice(i, 0, dragObj);
103 | } else {
104 | ar.splice(i + 1, 0, dragObj);
105 | }
106 | }
107 |
108 | setGData(data);
109 | };
110 |
111 | return (
112 |
113 |
125 | );
126 | };
127 |
128 | export default DragTree;
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/components/SearchTree.jsx:
--------------------------------------------------------------------------------
1 | import { Tree, Divider, Input } from 'antd';
2 | import React, { useMemo, useState } from 'react';
3 |
4 | const { Search } = Input;
5 | const x = 3;
6 | const y = 2;
7 | const z = 1;
8 | const defaultData = [];
9 |
10 | const generateData = (_level, _preKey, _tns) => {
11 | const preKey = _preKey || '0';
12 | const tns = _tns || defaultData;
13 | const children = [];
14 |
15 | for (let i = 0; i < x; i++) {
16 | const key = `${preKey}-${i}`;
17 | tns.push({
18 | title: key,
19 | key,
20 | });
21 |
22 | if (i < y) {
23 | children.push(key);
24 | }
25 | }
26 |
27 | if (_level < 0) {
28 | return tns;
29 | }
30 |
31 | const level = _level - 1;
32 | children.forEach((key, index) => {
33 | tns[index].children = [];
34 | return generateData(level, key, tns[index].children);
35 | });
36 | };
37 |
38 | generateData(z);
39 | const dataList = [];
40 |
41 | const generateList = (data) => {
42 | for (let i = 0; i < data.length; i++) {
43 | const node = data[i];
44 | const { key } = node;
45 | dataList.push({
46 | key,
47 | title: key,
48 | });
49 |
50 | if (node.children) {
51 | generateList(node.children);
52 | }
53 | }
54 | };
55 |
56 | generateList(defaultData);
57 |
58 | const getParentKey = (key, tree) => {
59 | let parentKey;
60 |
61 | for (let i = 0; i < tree.length; i++) {
62 | const node = tree[i];
63 |
64 | if (node.children) {
65 | if (node.children.some((item) => item.key === key)) {
66 | parentKey = node.key;
67 | } else if (getParentKey(key, node.children)) {
68 | parentKey = getParentKey(key, node.children);
69 | }
70 | }
71 | }
72 |
73 | return parentKey;
74 | };
75 |
76 | const SearchTree = () => {
77 | const [expandedKeys, setExpandedKeys] = useState([]);
78 | const [searchValue, setSearchValue] = useState('');
79 | const [autoExpandParent, setAutoExpandParent] = useState(true);
80 |
81 | const onExpand = (newExpandedKeys) => {
82 | setExpandedKeys(newExpandedKeys);
83 | setAutoExpandParent(false);
84 | };
85 |
86 | const onChange = (e) => {
87 | const { value } = e.target;
88 | const newExpandedKeys = dataList
89 | .map((item) => {
90 | if (item.title.indexOf(value) > -1) {
91 | return getParentKey(item.key, defaultData);
92 | }
93 |
94 | return null;
95 | })
96 | .filter((item, i, self) => item && self.indexOf(item) === i);
97 | setExpandedKeys(newExpandedKeys);
98 | setSearchValue(value);
99 | setAutoExpandParent(true);
100 | };
101 |
102 | const treeData = useMemo(() => {
103 | const loop = (data) =>
104 | data.map((item) => {
105 | const strTitle = item.title;
106 | const index = strTitle.indexOf(searchValue);
107 | const beforeStr = strTitle.substring(0, index);
108 | const afterStr = strTitle.slice(index + searchValue.length);
109 | const title =
110 | index > -1 ? (
111 |
112 | {beforeStr}
113 | {searchValue}
114 | {afterStr}
115 |
116 | ) : (
117 | {strTitle}
118 | );
119 |
120 | if (item.children) {
121 | return {
122 | title,
123 | key: item.key,
124 | children: loop(item.children),
125 | };
126 | }
127 |
128 | return {
129 | title,
130 | key: item.key,
131 | };
132 | });
133 |
134 | return loop(defaultData);
135 | }, [searchValue]);
136 |
137 | return (
138 |
139 |
可搜索
140 |
147 |
153 |
154 |
155 | );
156 | };
157 |
158 | export default SearchTree;
--------------------------------------------------------------------------------
/src/views/ShowView/Tree/index.js:
--------------------------------------------------------------------------------
1 | import TreeView from './Tree.jsx'
2 | import './index.scss'
3 |
4 | export default TreeView
5 |
--------------------------------------------------------------------------------
/src/views/TestView/TestView.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Layout, Divider } from 'antd'
3 | import CustomBreadcrumb from '@/components/CustomBreadcrumb'
4 |
5 | const TestView = () => (
6 |
7 |
8 |
9 |
10 |
11 |
多级导航
12 |
13 |
这个是多级导航
14 |
15 |
16 | )
17 |
18 | export default TestView
19 |
--------------------------------------------------------------------------------
/src/views/TestView/index.js:
--------------------------------------------------------------------------------
1 | import TestView from './TestView.jsx'
2 |
3 | export default TestView
4 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig, loadEnv } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 | import { resolve } from 'path';
4 |
5 |
6 |
7 | function pathResolve (dir) {
8 | return resolve(__dirname, dir);
9 | }
10 |
11 | export default ({ mode }) => {
12 | process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
13 |
14 | // https://vitejs.dev/config/
15 | return defineConfig({
16 | // 项目根目录
17 | root: process.cwd(),
18 | // 项目部署的基础路径
19 | base: '/',
20 | //环境配置
21 | mode: 'development',
22 | //全局变量替换 Record
23 | define: {
24 | // util: [path.resolve(__dirname, './src/utils/util.ts')],
25 | // aaaa: "123",
26 | },
27 | plugins: [
28 | react(),
29 | ],
30 | //静态资源服务的文件夹
31 | publicDir: "public",
32 | resolve: {
33 | // 别名
34 | // alias: {
35 | // '@': pathResolve('./src'),
36 | // // '@': path.resolve(__dirname, './src'),
37 | // // views: path.resolve(__dirname, './src/views'),
38 | // // components: path.resolve(__dirname, './src/components'),
39 | // // utils: path.resolve(__dirname, './src/utils'),
40 | // // less: path.resolve(__dirname, "./src/less"),
41 | // // assets: path.resolve(__dirname, "./src/assets"),
42 | // // com: path.resolve(__dirname, "./src/components"),
43 | // // store: path.resolve(__dirname, "./src/store"),
44 | // // mixins: path.resolve(__dirname, "./src/mixins")
45 | // },
46 | alias: [
47 | { find: /^~/, replacement: '' },
48 | { find: '@', replacement: pathResolve('./src') }
49 | ],
50 | dedupe: [],
51 | //情景导出package.json配置中的exports 字段
52 | conditions: [],
53 | //解析package.json中的字段
54 | mainFields: ['module', 'jsnext:main', 'jsnext'],
55 | //导入时想要省略的扩展名列表
56 | extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
57 | },
58 | // 依赖优化项
59 | optimizeDeps: {
60 | // include 默认情况下,不在 node_modules 中的,链接的包不会被预构建。使用此选项可强制预构建链接的包。
61 | include: [
62 | '@ant-design/colors',
63 | '@ant-design/icons',
64 | ],
65 | // 设置为 true 强制使依赖预构建
66 | // force: true,
67 | },
68 | // CSS 预处理器
69 | css: {
70 | // modules: {
71 | // localsConvention: 'camelCaseOnly',
72 | // },
73 | preprocessorOptions: {
74 | less: {
75 | javascriptEnabled: true,
76 | // modifyVars是在全局less文件后面添加变量的配置。modifyVars对应的对象属性名会加上@追加到less文件后
77 | modifyVars: {
78 | '@primary-color': '#1890ff',
79 | },
80 | },
81 | },
82 | postcss: {
83 | plugins: [
84 | {
85 | postcssPlugin: 'internal:charset-removal',//vite打包问题(忽略字符集问题)
86 | AtRule: {
87 | charset: (atRule) => {
88 | if (atRule.name === 'charset') {
89 | atRule.remove();
90 | }
91 | }
92 | }
93 | }
94 | ],
95 | },
96 | },
97 | build: {
98 | // 指定输出路径
99 | outDir: 'dist',
100 | //指定生成静态资源的存放路劲
101 | assetsDir: 'static',
102 | //将 CommonJS 模块转换为 ES6 的 Rollup 插件
103 | commonjsOptions: {
104 | requireReturnsDefault: 'namespace'
105 | },
106 | rollupOptions: {
107 | output: {
108 | //分割打包 解决打包时Some chunks are larger警告
109 | manualChunks (id) {
110 | if (id.includes('node_modules')) {
111 | return id.toString().split('node_modules/')[1].split('/')[0].toString();
112 | }
113 | }
114 | }
115 | },
116 | // chunk 大小警告的限制(以 kbs 为单位)
117 | chunkSizeWarningLimit: 1000,
118 | // 启用/禁用 gzip 压缩大小报告
119 | reportCompressedSize: false,
120 | },
121 | //静态资源处理 字符串|正则表达式
122 | assetsInclude: '',
123 | //调整控制台输出的级别 'info' | 'warn' | 'error' | 'silent'
124 | logLevel: 'info',
125 | //设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息
126 | clearScreen: true,
127 | // 服务
128 | server: {
129 | // 服务器主机名,如果允许外部访问,可设置为"0.0.0.0"
130 | host: "localhost",
131 | port: 9527,
132 | // 设为 true ,若端口已被占用则会直接退出,而不是尝试下一个可用端口
133 | strictPort: false,
134 | // 是否自动在浏览器打开
135 | open: false,
136 | // 是否开启 https
137 | https: false,
138 | // 为开发服务器配置 CORS
139 | cors: true,
140 | proxy: {
141 | '/api': {
142 | //#gitignoreline_start
143 | target: 'xxx',
144 | //#gitignoreline_end
145 | changeOrigin: true,
146 | ws: true,
147 | },
148 | },
149 | },
150 | })
151 | }
152 |
153 |
154 |
--------------------------------------------------------------------------------