├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── package.json
├── public
├── favicon.ico
└── index.html
└── src
├── App.vue
├── assets
├── base
│ └── index.css
├── iconFont
│ ├── demo.css
│ ├── demo_index.html
│ ├── iconfont.css
│ ├── iconfont.eot
│ ├── iconfont.js
│ ├── iconfont.json
│ ├── iconfont.svg
│ ├── iconfont.ttf
│ ├── iconfont.woff
│ └── iconfont.woff2
└── logo.png
├── components
├── charts
│ ├── bar.vue
│ └── line.vue
└── layout
│ ├── Aside.vue
│ ├── Head.vue
│ └── Main.vue
├── docs
├── 前端解析.xlsx
├── 前端解析的副本.xlsx
├── 前端解析的副本2.xlsx
└── 前端解析的副本3.xlsx
├── main.js
├── mock
├── charts
│ ├── bar.js
│ ├── index.js
│ └── line.js
└── icon
│ ├── icon.js
│ └── index.js
├── router
├── config.js
├── index.js
└── layout.js
├── store
└── index.js
├── utils
├── color.js
├── config.js
├── getAsyncData.js
├── goRepeat.js
├── isArrToObj.js
└── verification.js
└── views
├── Charts
├── Bar
│ └── index.vue
└── Line
│ └── index.vue
├── Docs
├── Drag
│ └── index.vue
└── Xlsx
│ ├── components
│ ├── handleHeads.js
│ ├── handleTbody.js
│ └── handleXlsx.js
│ └── index.vue
├── Found
└── index.vue
├── Game
└── GreedySnake
│ ├── components
│ ├── food.js
│ ├── index.js
│ └── snake.js
│ └── index.vue
├── Home
└── index.vue
├── Icon
└── index.vue
├── Layout
└── index.vue
├── Login
└── index.vue
└── Personal
└── index.vue
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: false,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/vue3-essential',
8 | 'eslint:recommended'
9 | ],
10 | parserOptions: {
11 | parser: 'babel-eslint'
12 | },
13 | rules: {
14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | yarn.lock*
8 | package-lock.json*
9 | # Editor directories and files
10 | .idea
11 | .vscode
12 | *.suo
13 | *.ntvs*
14 | *.njsproj
15 | *.sln
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Tyf2345
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue3.x-admin
2 |
3 | ### 前言
4 | 这是一个完全使用 vue3.x 语法开发的后台管理系统,页面主要包括 CSS3特效, 前端解析xlsx,前端文件下载,可拖拽的div,图表,益智小游戏,vuex4.x 存储用户信息等功能,该项目基本覆盖了vue3.x全家桶的方方面面。 功能丰富,注释多多, 近期会更新D3.js图表,并会进行一些代码优化,欢迎大家提意见。
5 | 使用vue3.x开发项目 `真香!!!`
6 |
7 | ### demo: [传送阵](http://114.215.147.221:8086/login)
8 | ### 技术栈
9 | ```js
10 | Vue3.x + vue-router4.x + vuex4.x + Less + Echarts
11 | ```
12 |
13 | ### 项目运行
14 | ```js
15 | git clone https://github.com/Tyf2345/vue3.x-admin.git
16 | cd vue-admin-ele
17 | yarn install
18 | yarn serve
19 | ```
20 |
21 | ### vue2.x版本传送地址 (https://github.com/Tyf2345/vue-admin-ele)
22 |
23 |
24 | ### 说明
25 |
26 | > 如果对您有帮助,您可以点右上角 "Star" 支持一下 谢谢! ^_^
27 |
28 | > 或者您可以 "follow" 一下,我会不断开源更多的有趣的项目
29 |
30 | > 如有问题请直接在 Issues 中提
31 |
32 | ### 目标功能
33 | - [x] 登录/登出 -- 完成
34 | - [x] 首页 -- 完成
35 | - [x] icon -- 完成
36 | - [x] table -- 完成
37 | - [x] 柱图 -- 完成
38 | - [x] 折线图 -- 完成
39 | - [x] 拖拽div -- 完成
40 | - [x] 前端解析xlsx -- 完成
41 | - [x] 个贪吃蛇小游戏 -- 完成
42 | - [x] 人中心 -- 完成
43 |
44 | ### 结构目录
45 |
46 | ├── build // webpack配置文件
47 | ├── config // 项目打包路径
48 | ├── src // 源码目录
49 | │ ├── assets // 公共资源, 公共css
50 | │ ├── components // 公共组件
51 | │ ├── docs // 前端上传 解析xlsx文件
52 | │ ├── mock // 异步模拟ajax调用接口
53 | │ ├── router // 路由相关
54 | │ ├── vuex // 状态管理相关
55 | │ ├── utils // 工具类,方法
56 | │ ├── views // 页面相关
57 | │ ├── App.vue // 页面入口文件
58 | │ ├── main.js // 程序入口文件,加载各种公共组件
59 | ├── index.html // 入口html文件
60 |
61 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend-vue3",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^3.6.5",
12 | "dayjs": "^1.8.28",
13 | "echarts": "^4.8.0",
14 | "mock": "^0.1.1",
15 | "vue": "^3.0.0-beta.15",
16 | "vue-router": "^4.0.0-alpha.12",
17 | "vuex": "^4.0.0-beta.2",
18 | "xlsx": "^0.16.2"
19 | },
20 | "devDependencies": {
21 | "@vue/cli-plugin-babel": "~4.4.0",
22 | "@vue/cli-plugin-eslint": "~4.4.0",
23 | "@vue/cli-plugin-router": "~4.4.0",
24 | "@vue/cli-service": "~4.4.0",
25 | "@vue/compiler-sfc": "^3.0.0-beta.1",
26 | "babel-eslint": "^10.1.0",
27 | "eslint": "^6.7.2",
28 | "eslint-plugin-vue": "^7.0.0-alpha.0",
29 | "less": "^3.11.3",
30 | "less-loader": "^6.1.0",
31 | "vue-cli-plugin-vue-next": "~0.1.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/src/assets/base/index.css:
--------------------------------------------------------------------------------
1 | html,body,div,p,ul,li,span,a,button,input{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 | html,body,#app{
7 | height: 100%;
8 | }
9 | li{
10 | list-style: none;
11 | }
12 | .ontline{
13 | outline:0;
14 | }
15 | .cursorP{
16 | cursor: pointer;
17 | }
18 | .ovflowHide{
19 | overflow: hidden;
20 | }
21 | .positionR{
22 | position: relative;
23 | }
24 | .positionA{
25 | position: absolute;
26 | }
27 | .TRBL{
28 | top: 0;
29 | right: 0;
30 | bottom: 0;
31 | left: 0;
32 | }
33 | .opacity0{
34 | opacity: 0;
35 | }
36 | .w100{
37 | width: 100%;
38 | }
39 | .h100{
40 | height: 100vh;
41 | }
42 | .w80px{
43 | width: 80px;
44 | }
45 | .w120px{
46 | width: 120px;
47 | }
48 | .flx{
49 | display: flex;
50 | }
51 | .flx1{
52 | flex:1;
53 | }
54 | .border4px{
55 | border-radius: 4px;
56 | }
57 |
58 | .pd0-20{
59 | padding: 0 20px;
60 | }
61 | .pd0-40{
62 | padding: 0 40px;
63 | }
64 | .mr15{
65 | margin-right: 15px;
66 | }
67 | .mb15{
68 | margin-bottom: 15px;
69 | }
70 |
71 |
72 |
73 | .colorfff {
74 | color: #fff;
75 | }
76 |
77 | .charts{
78 | height: 400px;
79 | border: 1px solid #b3c0d1;
80 | border-radius: 6px;
81 | }
--------------------------------------------------------------------------------
/src/assets/iconFont/demo.css:
--------------------------------------------------------------------------------
1 | /* Logo 字体 */
2 | @font-face {
3 | font-family: "iconfont logo";
4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
9 | }
10 |
11 | .logo {
12 | font-family: "iconfont logo";
13 | font-size: 160px;
14 | font-style: normal;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | /* tabs */
20 | .nav-tabs {
21 | position: relative;
22 | }
23 |
24 | .nav-tabs .nav-more {
25 | position: absolute;
26 | right: 0;
27 | bottom: 0;
28 | height: 42px;
29 | line-height: 42px;
30 | color: #666;
31 | }
32 |
33 | #tabs {
34 | border-bottom: 1px solid #eee;
35 | }
36 |
37 | #tabs li {
38 | cursor: pointer;
39 | width: 100px;
40 | height: 40px;
41 | line-height: 40px;
42 | text-align: center;
43 | font-size: 16px;
44 | border-bottom: 2px solid transparent;
45 | position: relative;
46 | z-index: 1;
47 | margin-bottom: -1px;
48 | color: #666;
49 | }
50 |
51 |
52 | #tabs .active {
53 | border-bottom-color: #f00;
54 | color: #222;
55 | }
56 |
57 | .tab-container .content {
58 | display: none;
59 | }
60 |
61 | /* 页面布局 */
62 | .main {
63 | padding: 30px 100px;
64 | width: 960px;
65 | margin: 0 auto;
66 | }
67 |
68 | .main .logo {
69 | color: #333;
70 | text-align: left;
71 | margin-bottom: 30px;
72 | line-height: 1;
73 | height: 110px;
74 | margin-top: -50px;
75 | overflow: hidden;
76 | *zoom: 1;
77 | }
78 |
79 | .main .logo a {
80 | font-size: 160px;
81 | color: #333;
82 | }
83 |
84 | .helps {
85 | margin-top: 40px;
86 | }
87 |
88 | .helps pre {
89 | padding: 20px;
90 | margin: 10px 0;
91 | border: solid 1px #e7e1cd;
92 | background-color: #fffdef;
93 | overflow: auto;
94 | }
95 |
96 | .icon_lists {
97 | width: 100% !important;
98 | overflow: hidden;
99 | *zoom: 1;
100 | }
101 |
102 | .icon_lists li {
103 | width: 100px;
104 | margin-bottom: 10px;
105 | margin-right: 20px;
106 | text-align: center;
107 | list-style: none !important;
108 | cursor: default;
109 | }
110 |
111 | .icon_lists li .code-name {
112 | line-height: 1.2;
113 | }
114 |
115 | .icon_lists .icon {
116 | display: block;
117 | height: 100px;
118 | line-height: 100px;
119 | font-size: 42px;
120 | margin: 10px auto;
121 | color: #333;
122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear;
123 | -moz-transition: font-size 0.25s linear, width 0.25s linear;
124 | transition: font-size 0.25s linear, width 0.25s linear;
125 | }
126 |
127 | .icon_lists .icon:hover {
128 | font-size: 100px;
129 | }
130 |
131 | .icon_lists .svg-icon {
132 | /* 通过设置 font-size 来改变图标大小 */
133 | width: 1em;
134 | /* 图标和文字相邻时,垂直对齐 */
135 | vertical-align: -0.15em;
136 | /* 通过设置 color 来改变 SVG 的颜色/fill */
137 | fill: currentColor;
138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
139 | normalize.css 中也包含这行 */
140 | overflow: hidden;
141 | }
142 |
143 | .icon_lists li .name,
144 | .icon_lists li .code-name {
145 | color: #666;
146 | }
147 |
148 | /* markdown 样式 */
149 | .markdown {
150 | color: #666;
151 | font-size: 14px;
152 | line-height: 1.8;
153 | }
154 |
155 | .highlight {
156 | line-height: 1.5;
157 | }
158 |
159 | .markdown img {
160 | vertical-align: middle;
161 | max-width: 100%;
162 | }
163 |
164 | .markdown h1 {
165 | color: #404040;
166 | font-weight: 500;
167 | line-height: 40px;
168 | margin-bottom: 24px;
169 | }
170 |
171 | .markdown h2,
172 | .markdown h3,
173 | .markdown h4,
174 | .markdown h5,
175 | .markdown h6 {
176 | color: #404040;
177 | margin: 1.6em 0 0.6em 0;
178 | font-weight: 500;
179 | clear: both;
180 | }
181 |
182 | .markdown h1 {
183 | font-size: 28px;
184 | }
185 |
186 | .markdown h2 {
187 | font-size: 22px;
188 | }
189 |
190 | .markdown h3 {
191 | font-size: 16px;
192 | }
193 |
194 | .markdown h4 {
195 | font-size: 14px;
196 | }
197 |
198 | .markdown h5 {
199 | font-size: 12px;
200 | }
201 |
202 | .markdown h6 {
203 | font-size: 12px;
204 | }
205 |
206 | .markdown hr {
207 | height: 1px;
208 | border: 0;
209 | background: #e9e9e9;
210 | margin: 16px 0;
211 | clear: both;
212 | }
213 |
214 | .markdown p {
215 | margin: 1em 0;
216 | }
217 |
218 | .markdown>p,
219 | .markdown>blockquote,
220 | .markdown>.highlight,
221 | .markdown>ol,
222 | .markdown>ul {
223 | width: 80%;
224 | }
225 |
226 | .markdown ul>li {
227 | list-style: circle;
228 | }
229 |
230 | .markdown>ul li,
231 | .markdown blockquote ul>li {
232 | margin-left: 20px;
233 | padding-left: 4px;
234 | }
235 |
236 | .markdown>ul li p,
237 | .markdown>ol li p {
238 | margin: 0.6em 0;
239 | }
240 |
241 | .markdown ol>li {
242 | list-style: decimal;
243 | }
244 |
245 | .markdown>ol li,
246 | .markdown blockquote ol>li {
247 | margin-left: 20px;
248 | padding-left: 4px;
249 | }
250 |
251 | .markdown code {
252 | margin: 0 3px;
253 | padding: 0 5px;
254 | background: #eee;
255 | border-radius: 3px;
256 | }
257 |
258 | .markdown strong,
259 | .markdown b {
260 | font-weight: 600;
261 | }
262 |
263 | .markdown>table {
264 | border-collapse: collapse;
265 | border-spacing: 0px;
266 | empty-cells: show;
267 | border: 1px solid #e9e9e9;
268 | width: 95%;
269 | margin-bottom: 24px;
270 | }
271 |
272 | .markdown>table th {
273 | white-space: nowrap;
274 | color: #333;
275 | font-weight: 600;
276 | }
277 |
278 | .markdown>table th,
279 | .markdown>table td {
280 | border: 1px solid #e9e9e9;
281 | padding: 8px 16px;
282 | text-align: left;
283 | }
284 |
285 | .markdown>table th {
286 | background: #F7F7F7;
287 | }
288 |
289 | .markdown blockquote {
290 | font-size: 90%;
291 | color: #999;
292 | border-left: 4px solid #e9e9e9;
293 | padding-left: 0.8em;
294 | margin: 1em 0;
295 | }
296 |
297 | .markdown blockquote p {
298 | margin: 0;
299 | }
300 |
301 | .markdown .anchor {
302 | opacity: 0;
303 | transition: opacity 0.3s ease;
304 | margin-left: 8px;
305 | }
306 |
307 | .markdown .waiting {
308 | color: #ccc;
309 | }
310 |
311 | .markdown h1:hover .anchor,
312 | .markdown h2:hover .anchor,
313 | .markdown h3:hover .anchor,
314 | .markdown h4:hover .anchor,
315 | .markdown h5:hover .anchor,
316 | .markdown h6:hover .anchor {
317 | opacity: 1;
318 | display: inline-block;
319 | }
320 |
321 | .markdown>br,
322 | .markdown>p>br {
323 | clear: both;
324 | }
325 |
326 |
327 | .hljs {
328 | display: block;
329 | background: white;
330 | padding: 0.5em;
331 | color: #333333;
332 | overflow-x: auto;
333 | }
334 |
335 | .hljs-comment,
336 | .hljs-meta {
337 | color: #969896;
338 | }
339 |
340 | .hljs-string,
341 | .hljs-variable,
342 | .hljs-template-variable,
343 | .hljs-strong,
344 | .hljs-emphasis,
345 | .hljs-quote {
346 | color: #df5000;
347 | }
348 |
349 | .hljs-keyword,
350 | .hljs-selector-tag,
351 | .hljs-type {
352 | color: #a71d5d;
353 | }
354 |
355 | .hljs-literal,
356 | .hljs-symbol,
357 | .hljs-bullet,
358 | .hljs-attribute {
359 | color: #0086b3;
360 | }
361 |
362 | .hljs-section,
363 | .hljs-name {
364 | color: #63a35c;
365 | }
366 |
367 | .hljs-tag {
368 | color: #333333;
369 | }
370 |
371 | .hljs-title,
372 | .hljs-attr,
373 | .hljs-selector-id,
374 | .hljs-selector-class,
375 | .hljs-selector-attr,
376 | .hljs-selector-pseudo {
377 | color: #795da3;
378 | }
379 |
380 | .hljs-addition {
381 | color: #55a532;
382 | background-color: #eaffea;
383 | }
384 |
385 | .hljs-deletion {
386 | color: #bd2c00;
387 | background-color: #ffecec;
388 | }
389 |
390 | .hljs-link {
391 | text-decoration: underline;
392 | }
393 |
394 | /* 代码高亮 */
395 | /* PrismJS 1.15.0
396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
397 | /**
398 | * prism.js default theme for JavaScript, CSS and HTML
399 | * Based on dabblet (http://dabblet.com)
400 | * @author Lea Verou
401 | */
402 | code[class*="language-"],
403 | pre[class*="language-"] {
404 | color: black;
405 | background: none;
406 | text-shadow: 0 1px white;
407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
408 | text-align: left;
409 | white-space: pre;
410 | word-spacing: normal;
411 | word-break: normal;
412 | word-wrap: normal;
413 | line-height: 1.5;
414 |
415 | -moz-tab-size: 4;
416 | -o-tab-size: 4;
417 | tab-size: 4;
418 |
419 | -webkit-hyphens: none;
420 | -moz-hyphens: none;
421 | -ms-hyphens: none;
422 | hyphens: none;
423 | }
424 |
425 | pre[class*="language-"]::-moz-selection,
426 | pre[class*="language-"] ::-moz-selection,
427 | code[class*="language-"]::-moz-selection,
428 | code[class*="language-"] ::-moz-selection {
429 | text-shadow: none;
430 | background: #b3d4fc;
431 | }
432 |
433 | pre[class*="language-"]::selection,
434 | pre[class*="language-"] ::selection,
435 | code[class*="language-"]::selection,
436 | code[class*="language-"] ::selection {
437 | text-shadow: none;
438 | background: #b3d4fc;
439 | }
440 |
441 | @media print {
442 |
443 | code[class*="language-"],
444 | pre[class*="language-"] {
445 | text-shadow: none;
446 | }
447 | }
448 |
449 | /* Code blocks */
450 | pre[class*="language-"] {
451 | padding: 1em;
452 | margin: .5em 0;
453 | overflow: auto;
454 | }
455 |
456 | :not(pre)>code[class*="language-"],
457 | pre[class*="language-"] {
458 | background: #f5f2f0;
459 | }
460 |
461 | /* Inline code */
462 | :not(pre)>code[class*="language-"] {
463 | padding: .1em;
464 | border-radius: .3em;
465 | white-space: normal;
466 | }
467 |
468 | .token.comment,
469 | .token.prolog,
470 | .token.doctype,
471 | .token.cdata {
472 | color: slategray;
473 | }
474 |
475 | .token.punctuation {
476 | color: #999;
477 | }
478 |
479 | .namespace {
480 | opacity: .7;
481 | }
482 |
483 | .token.property,
484 | .token.tag,
485 | .token.boolean,
486 | .token.number,
487 | .token.constant,
488 | .token.symbol,
489 | .token.deleted {
490 | color: #905;
491 | }
492 |
493 | .token.selector,
494 | .token.attr-name,
495 | .token.string,
496 | .token.char,
497 | .token.builtin,
498 | .token.inserted {
499 | color: #690;
500 | }
501 |
502 | .token.operator,
503 | .token.entity,
504 | .token.url,
505 | .language-css .token.string,
506 | .style .token.string {
507 | color: #9a6e3a;
508 | background: hsla(0, 0%, 100%, .5);
509 | }
510 |
511 | .token.atrule,
512 | .token.attr-value,
513 | .token.keyword {
514 | color: #07a;
515 | }
516 |
517 | .token.function,
518 | .token.class-name {
519 | color: #DD4A68;
520 | }
521 |
522 | .token.regex,
523 | .token.important,
524 | .token.variable {
525 | color: #e90;
526 | }
527 |
528 | .token.important,
529 | .token.bold {
530 | font-weight: bold;
531 | }
532 |
533 | .token.italic {
534 | font-style: italic;
535 | }
536 |
537 | .token.entity {
538 | cursor: help;
539 | }
540 |
--------------------------------------------------------------------------------
/src/assets/iconFont/demo_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IconFont Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | - Unicode
22 | - Font class
23 | - Symbol
24 |
25 |
26 |
查看项目
27 |
28 |
29 |
30 |
31 |
32 |
33 | -
34 |
35 |
文档
36 | 
37 |
38 |
39 | -
40 |
41 |
游戏
42 | 
43 |
44 |
45 | -
46 |
47 |
图表
48 | 
49 |
50 |
51 | -
52 |
53 |
图标
54 | 
55 |
56 |
57 | -
58 |
59 |
shouye
60 | 
61 |
62 |
63 | -
64 |
65 |
collapse-right
66 | 
67 |
68 |
69 | -
70 |
71 |
collapse-left
72 | 
73 |
74 |
75 | -
76 |
77 |
xiala
78 | 
79 |
80 |
81 |
82 |
83 |
Unicode 引用
84 |
85 |
86 |
Unicode 是字体在网页端最原始的应用方式,特点是:
87 |
88 | - 兼容性最好,支持 IE6+,及所有现代浏览器。
89 | - 支持按字体的方式去动态调整图标大小,颜色等等。
90 | - 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
91 |
92 |
93 | 注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式
94 |
95 |
Unicode 使用步骤如下:
96 |
第一步:拷贝项目下面生成的 @font-face
97 |
@font-face {
99 | font-family: 'iconfont';
100 | src: url('iconfont.eot');
101 | src: url('iconfont.eot?#iefix') format('embedded-opentype'),
102 | url('iconfont.woff2') format('woff2'),
103 | url('iconfont.woff') format('woff'),
104 | url('iconfont.ttf') format('truetype'),
105 | url('iconfont.svg#iconfont') format('svg');
106 | }
107 |
108 |
第二步:定义使用 iconfont 的样式
109 |
.iconfont {
111 | font-family: "iconfont" !important;
112 | font-size: 16px;
113 | font-style: normal;
114 | -webkit-font-smoothing: antialiased;
115 | -moz-osx-font-smoothing: grayscale;
116 | }
117 |
118 |
第三步:挑选相应图标并获取字体编码,应用于页面
119 |
120 | <span class="iconfont">3</span>
122 |
123 |
124 | "iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。
125 |
126 |
127 |
128 |
129 |
130 |
131 | -
132 |
133 |
134 | 文档
135 |
136 | .icon-ziyuan
137 |
138 |
139 |
140 | -
141 |
142 |
143 | 游戏
144 |
145 | .icon-youxi-yuanshijituantubiao
146 |
147 |
148 |
149 | -
150 |
151 |
152 | 图表
153 |
154 | .icon-tubiao
155 |
156 |
157 |
158 | -
159 |
160 |
161 | 图标
162 |
163 | .icon-tubiao1
164 |
165 |
166 |
167 | -
168 |
169 |
170 | shouye
171 |
172 | .icon-shouye
173 |
174 |
175 |
176 | -
177 |
178 |
179 | collapse-right
180 |
181 | .icon-collapseright
182 |
183 |
184 |
185 | -
186 |
187 |
188 | collapse-left
189 |
190 | .icon-collapse-left
191 |
192 |
193 |
194 | -
195 |
196 |
197 | xiala
198 |
199 | .icon-xiala
200 |
201 |
202 |
203 |
204 |
205 |
font-class 引用
206 |
207 |
208 |
font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。
209 |
与 Unicode 使用方式相比,具有如下特点:
210 |
211 | - 兼容性良好,支持 IE8+,及所有现代浏览器。
212 | - 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
213 | - 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
214 | - 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
215 |
216 |
使用步骤如下:
217 |
第一步:引入项目下面生成的 fontclass 代码:
218 |
<link rel="stylesheet" href="./iconfont.css">
219 |
220 |
第二步:挑选相应图标并获取类名,应用于页面:
221 |
<span class="iconfont icon-xxx"></span>
222 |
223 |
224 | "
225 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。
226 |
227 |
228 |
229 |
230 |
297 |
298 |
Symbol 引用
299 |
300 |
301 |
这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章
302 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:
303 |
304 | - 支持多色图标了,不再受单色限制。
305 | - 通过一些技巧,支持像字体那样,通过
font-size
, color
来调整样式。
306 | - 兼容性较差,支持 IE9+,及现代浏览器。
307 | - 浏览器渲染 SVG 的性能一般,还不如 png。
308 |
309 |
使用步骤如下:
310 |
第一步:引入项目下面生成的 symbol 代码:
311 |
<script src="./iconfont.js"></script>
312 |
313 |
第二步:加入通用 CSS 代码(引入一次就行):
314 |
<style>
315 | .icon {
316 | width: 1em;
317 | height: 1em;
318 | vertical-align: -0.15em;
319 | fill: currentColor;
320 | overflow: hidden;
321 | }
322 | </style>
323 |
324 |
第三步:挑选相应图标并获取类名,应用于页面:
325 |
<svg class="icon" aria-hidden="true">
326 | <use xlink:href="#icon-xxx"></use>
327 | </svg>
328 |
329 |
330 |
331 |
332 |
333 |
334 |
353 |
354 |
355 |
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('iconfont.eot?t=1592300743808'); /* IE9 */
3 | src: url('iconfont.eot?t=1592300743808#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
5 | url('iconfont.woff?t=1592300743808') format('woff'),
6 | url('iconfont.ttf?t=1592300743808') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('iconfont.svg?t=1592300743808#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-ziyuan:before {
19 | content: "\e608";
20 | }
21 |
22 | .icon-youxi-yuanshijituantubiao:before {
23 | content: "\e620";
24 | }
25 |
26 | .icon-tubiao:before {
27 | content: "\e6d8";
28 | }
29 |
30 | .icon-tubiao1:before {
31 | content: "\e606";
32 | }
33 |
34 | .icon-shouye:before {
35 | content: "\e607";
36 | }
37 |
38 | .icon-collapseright:before {
39 | content: "\e94e";
40 | }
41 |
42 | .icon-collapse-left:before {
43 | content: "\e60e";
44 | }
45 |
46 | .icon-xiala:before {
47 | content: "\e659";
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/assets/iconFont/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.js:
--------------------------------------------------------------------------------
1 | !function(c){var t,e,l,o,i,n,a,s='',h=(t=document.getElementsByTagName("script"))[t.length-1].getAttribute("data-injectcss");if(h&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}function d(){n||(n=!0,o())}e=function(){var c,t,e,l,o,i=document.createElement("div");i.innerHTML=s,s=null,(c=i.getElementsByTagName("svg")[0])&&(c.setAttribute("aria-hidden","true"),c.style.position="absolute",c.style.width=0,c.style.height=0,c.style.overflow="hidden",t=c,(e=document.body).firstChild?(l=t,(o=e.firstChild).parentNode.insertBefore(l,o)):e.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(e,0):(l=function(){document.removeEventListener("DOMContentLoaded",l,!1),e()},document.addEventListener("DOMContentLoaded",l,!1)):document.attachEvent&&(o=e,i=c.document,n=!1,(a=function(){try{i.documentElement.doScroll("left")}catch(c){return void setTimeout(a,50)}d()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,d())})}(window);
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "1879252",
3 | "name": "myBacnend",
4 | "font_family": "iconfont",
5 | "css_prefix_text": "icon-",
6 | "description": "",
7 | "glyphs": [
8 | {
9 | "icon_id": "11177590",
10 | "name": "文档",
11 | "font_class": "ziyuan",
12 | "unicode": "e608",
13 | "unicode_decimal": 58888
14 | },
15 | {
16 | "icon_id": "3696033",
17 | "name": "游戏",
18 | "font_class": "youxi-yuanshijituantubiao",
19 | "unicode": "e620",
20 | "unicode_decimal": 58912
21 | },
22 | {
23 | "icon_id": "6851550",
24 | "name": "图表",
25 | "font_class": "tubiao",
26 | "unicode": "e6d8",
27 | "unicode_decimal": 59096
28 | },
29 | {
30 | "icon_id": "7533297",
31 | "name": "图标",
32 | "font_class": "tubiao1",
33 | "unicode": "e606",
34 | "unicode_decimal": 58886
35 | },
36 | {
37 | "icon_id": "8221830",
38 | "name": "shouye",
39 | "font_class": "shouye",
40 | "unicode": "e607",
41 | "unicode_decimal": 58887
42 | },
43 | {
44 | "icon_id": "142287",
45 | "name": "collapse-right",
46 | "font_class": "collapseright",
47 | "unicode": "e94e",
48 | "unicode_decimal": 59726
49 | },
50 | {
51 | "icon_id": "14364270",
52 | "name": "collapse-left",
53 | "font_class": "collapse-left",
54 | "unicode": "e60e",
55 | "unicode_decimal": 58894
56 | },
57 | {
58 | "icon_id": "630037",
59 | "name": "xiala",
60 | "font_class": "xiala",
61 | "unicode": "e659",
62 | "unicode_decimal": 58969
63 | }
64 | ]
65 | }
66 |
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
51 |
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/assets/iconFont/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/assets/iconFont/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/iconFont/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/assets/iconFont/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/charts/bar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
49 |
--------------------------------------------------------------------------------
/src/components/charts/line.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
49 |
--------------------------------------------------------------------------------
/src/components/layout/Aside.vue:
--------------------------------------------------------------------------------
1 |
2 |
47 |
48 |
103 |
--------------------------------------------------------------------------------
/src/components/layout/Head.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 | 后台管理系统
9 |
10 |
11 |
12 |
{{user.userName}}
13 |
登出
14 |

19 |
20 |
21 |
22 |
23 |
49 |
--------------------------------------------------------------------------------
/src/components/layout/Main.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
112 |
--------------------------------------------------------------------------------
/src/docs/前端解析.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/docs/前端解析.xlsx
--------------------------------------------------------------------------------
/src/docs/前端解析的副本.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/docs/前端解析的副本.xlsx
--------------------------------------------------------------------------------
/src/docs/前端解析的副本2.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/docs/前端解析的副本2.xlsx
--------------------------------------------------------------------------------
/src/docs/前端解析的副本3.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tyf2345/vue3.x-admin/a555f5e8e119a06eefaa39348d4d99555efcc452/src/docs/前端解析的副本3.xlsx
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue";
2 | import App from "./App.vue";
3 | import router from "./router";
4 | import store from './store'
5 | //公共css
6 | import "./assets/base/index.css";
7 | // iconfont
8 | import './assets/iconFont/iconfont.css'
9 | const app = createApp(App)
10 | app.use(router)
11 | app.use(store)
12 | app.mount("#app");
13 |
--------------------------------------------------------------------------------
/src/mock/charts/bar.js:
--------------------------------------------------------------------------------
1 | const barData = [
2 | {
3 | title: "服装销量",
4 | x: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
5 | y: [5, 20, 36, 10, 10, 20]
6 | },
7 | {
8 | title:'周出勤',
9 | name:'出勤次数',
10 | x: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
11 | y: [120, 200, 150, 80, 70, 110, 130]
12 | },
13 | {
14 | title:'周出勤',
15 | name:'出勤次数',
16 | x: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
17 | y: [120, 200, 150, 80, 70, 110, 130]
18 | },{
19 | title: "服装销量",
20 | x: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
21 | y: [5, 20, 36, 10, 10, 20]
22 | },{
23 | title: "服装销量",
24 | x: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"],
25 | y: [5, 20, 36, 10, 10, 20]
26 | }
27 | ]
28 | export default barData
--------------------------------------------------------------------------------
/src/mock/charts/index.js:
--------------------------------------------------------------------------------
1 | // 异步模拟ajax请求
2 | import barData from './bar'
3 | import lineData from './line'
4 | import getAsyncData from '../../utils/getAsyncData'
5 |
6 | //柱状图数据
7 | const getBarData = getAsyncData(barData)
8 |
9 | //折线图数据
10 | const getLineData = getAsyncData(lineData)
11 | export {
12 | getBarData,
13 | getLineData
14 | }
--------------------------------------------------------------------------------
/src/mock/charts/line.js:
--------------------------------------------------------------------------------
1 | let lineData = [
2 | {
3 | title: '周堆叠图',
4 | x: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
5 | y: [
6 | {
7 | name: '邮件营销',
8 | type: 'line',
9 | stack: '总量',
10 | data: [120, 132, 101, 134, 90, 230, 210]
11 | },
12 | {
13 | name: '联盟广告',
14 | type: 'line',
15 | stack: '总量',
16 | data: [220, 182, 191, 234, 290, 330, 310]
17 | },
18 | {
19 | name: '视频广告',
20 | type: 'line',
21 | stack: '总量',
22 | data: [150, 232, 201, 154, 190, 330, 410]
23 | },
24 | {
25 | name: '直接访问',
26 | type: 'line',
27 | stack: '总量',
28 | data: [320, 332, 301, 334, 390, 330, 320]
29 | },
30 | {
31 | name: '搜索引擎',
32 | type: 'line',
33 | stack: '总量',
34 | data: [820, 932, 901, 934, 1290, 1330, 1320]
35 | }
36 | ]
37 | },
38 | {
39 | title: '单条折线图',
40 | x: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
41 | y: [{
42 | type: 'line',
43 | data: [820, 932, 901, 934, 1290, 1330, 1320]
44 | }],
45 | }
46 | ]
47 | for (let i = 0; i < 2; i++) {
48 | lineData.push(...lineData)
49 |
50 | }
51 | export default lineData
--------------------------------------------------------------------------------
/src/mock/icon/icon.js:
--------------------------------------------------------------------------------
1 |
2 | const iconData = [
3 | {
4 | id: 0,
5 | name:'文档',
6 | icon: "icon-ziyuan"
7 | },
8 | {
9 | id: 1,
10 | name:'游戏',
11 | icon: "icon-youxi-yuanshijituantubiao"
12 | },
13 | {
14 | id: 2,
15 | name:'图表',
16 | icon: " ion-tubiao"
17 | },
18 | {
19 | id: 3,
20 | name:"图标",
21 | icon: "icon-tubiao1"
22 | },
23 | {
24 | id: 4,
25 | name:"shouye",
26 | icon: "icon-shouye"
27 | },
28 | {
29 | id: 5,
30 | name:'collapse-right',
31 | icon: "icon-collapseright"
32 | },
33 | {
34 | id: 6,
35 | name:'collapse-left',
36 | icon: "icon-collapse-left"
37 | },
38 | {
39 | id: 7,
40 | name:'xiala',
41 | icon: "icon-xiala"
42 | }
43 | ]
44 |
45 |
46 | export default iconData
--------------------------------------------------------------------------------
/src/mock/icon/index.js:
--------------------------------------------------------------------------------
1 | import iconData from './icon'
2 | import getAsyncData from '../../utils/getAsyncData'
3 |
4 | const getIconData = getAsyncData(iconData)
5 |
6 | export {
7 | getIconData
8 | }
--------------------------------------------------------------------------------
/src/router/config.js:
--------------------------------------------------------------------------------
1 | import layout from './layout'
2 |
3 | let LayoutData = []
4 | // 多维数据变一纬数组 ==》递归
5 | layout.forEach(_forEach)
6 | function _forEach(data) {
7 | if (data.children) {
8 | data.children.forEach(_forEach)
9 | } else {
10 | delete data.flag;
11 | LayoutData.push(data)
12 | }
13 | }
14 |
15 | const routes = [
16 | {
17 | path: "/login",
18 | component: () => import("../views/Login"),
19 | },
20 | {
21 | path: '/layout',
22 | component: () => import('../views/Layout'),
23 | children: [
24 | {
25 | path: '',
26 | redirect: LayoutData[0].path,
27 | },
28 | ...LayoutData
29 | ]
30 | },
31 | {
32 | path: '/:catchAll(.*)',
33 | component: () => import('../views/Found')
34 | }
35 | ]
36 |
37 | export default routes
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from "vue-router";
2 | import routes from './config'
3 |
4 |
5 | const router = createRouter({
6 | history: createWebHistory(process.env.BASE_URL),
7 | routes,
8 | });
9 | router.beforeEach((to, from, next) => {
10 | if (to.path === '/login') {
11 | next()
12 | return
13 | }
14 | let user = JSON.parse(localStorage.getItem('user'))
15 | if (user && user.userName && user.pwd) {
16 | next()
17 | return
18 | }
19 | next('/login')
20 | })
21 | export default router;
22 |
--------------------------------------------------------------------------------
/src/router/layout.js:
--------------------------------------------------------------------------------
1 | const layout = [
2 | {
3 | path: '/layout/home',
4 | name: '首页',
5 | icon:'shouye icon-shouye',
6 | component: () => import('../views/Home')
7 | },
8 | {
9 | path: '/layout/icon',
10 | name: '图标',
11 | icon:'图标 icon-tubiao1',
12 | component: () => import('../views/Icon')
13 | },
14 | {
15 | name: '图表',
16 | icon:'图表 icon-tubiao',
17 | children:[
18 | {
19 | path:'/layout/charts/bar',
20 | name:'柱状图',
21 | component: () => import('../views/Charts/Bar')
22 | }, {
23 | path:'/layout/charts/line',
24 | name:'折线图',
25 | component: () => import('../views/Charts/Line')
26 | }
27 | ]
28 | },
29 | {
30 | name: '文档',
31 | icon:'文档 icon-ziyuan',
32 | children:[
33 | {
34 | path:'/layout/docs/drag',
35 | name:'拖拽',
36 | component:() =>import('../views/Docs/Drag')
37 | },
38 | {
39 | path:'/layout/docs/xlsx',
40 | name:'解析xlsx',
41 | component: () =>import('../views/Docs/Xlsx')
42 | }
43 | ]
44 | },
45 | {
46 | name: '游戏',
47 | icon:'游戏 icon-youxi-yuanshijituantubiao',
48 | children:[
49 | {
50 | path:'/layout/game/greedysnake',
51 | name:"贪吃 🐍",
52 | component: ()=>import('../views/Game/GreedySnake')
53 | }
54 | ]
55 | },
56 | {
57 | path:'/layout/personal',
58 | name:'个人中心',
59 | icon:'shouye icon-shouye',
60 | component: () => import ('../views/Personal')
61 | }
62 | ]
63 |
64 | export default layout
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore } from 'vuex'
2 |
3 | // 用户信息
4 | const store = createStore({
5 | state(){
6 | return {
7 | user:{}
8 | }
9 | },
10 | mutations:{
11 | userFun({user},{userName, pwd, time}) {
12 | user.userName = userName
13 | user.pwd = pwd
14 | user.time = time
15 | }
16 | }
17 | })
18 |
19 | export default store
--------------------------------------------------------------------------------
/src/utils/color.js:
--------------------------------------------------------------------------------
1 | // 随机获取十六进制颜色
2 | function getColor() {
3 | var str = "#";
4 | var arr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];
5 | for (var i = 0; i < 6; i++) {
6 | //产生的每个随机数都是一个索引,根据索引找到数组中对应的值,拼接到一起
7 | str += arr[parseInt(Math.random() * 16)];
8 |
9 | }
10 | return str;
11 | }
12 | export default getColor
--------------------------------------------------------------------------------
/src/utils/config.js:
--------------------------------------------------------------------------------
1 | export const time = 300
--------------------------------------------------------------------------------
/src/utils/getAsyncData.js:
--------------------------------------------------------------------------------
1 | import { time } from './config'
2 | //模拟ajax异步请求
3 | const getAsyncData = data => {
4 | return new Promise(res => setTimeout(() => res(data), time))
5 | }
6 | export default getAsyncData
--------------------------------------------------------------------------------
/src/utils/goRepeat.js:
--------------------------------------------------------------------------------
1 | // 去重
2 | export function goRepeat(data, name) {
3 |
4 | let newData = [],newObj = {}
5 | if (data.length) {
6 | data.forEach(item => {
7 | if (!newObj[item[name]]) {
8 | newData.push(item)
9 | newObj[item[name]] = true
10 | }
11 | })
12 | }
13 | console.log('newData',newData)
14 | return newData
15 | }
--------------------------------------------------------------------------------
/src/utils/isArrToObj.js:
--------------------------------------------------------------------------------
1 | // 数组转为对象 ==> [xx,qq,aa]:{xx:'',qq:'',aa:''}
2 | function isArrToObj(arr) {
3 | let obj = {}
4 |
5 | for (let i = 0; i < arr.length; i++) {
6 |
7 | let arr_i = arr[i]
8 | obj[arr_i] = ''
9 | }
10 | return obj
11 |
12 | }
13 |
14 | export default isArrToObj
--------------------------------------------------------------------------------
/src/utils/verification.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 非空判断
3 | * @param {isTrimAction} str
4 | */
5 | export function isTrimAction(str) {
6 | return (str+'').trim().length ? true: false
7 | }
--------------------------------------------------------------------------------
/src/views/Charts/Bar/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 柱图系列
3 |
8 |
9 |
29 |
--------------------------------------------------------------------------------
/src/views/Charts/Line/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 饼图系列
3 |
8 |
9 |
29 |
--------------------------------------------------------------------------------
/src/views/Docs/Drag/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 可拖拽div
3 |
12 |
13 |
85 |
--------------------------------------------------------------------------------
/src/views/Docs/Xlsx/components/handleHeads.js:
--------------------------------------------------------------------------------
1 |
2 | function Heads(data) {
3 | let heads = []
4 | data.forEach(item=>{
5 | for (const k in item) {
6 | if (heads.indexOf(k)=== -1) {
7 | heads.push(k)
8 | }
9 | }
10 | })
11 | return heads
12 | }
13 | export default Heads
14 |
15 |
--------------------------------------------------------------------------------
/src/views/Docs/Xlsx/components/handleTbody.js:
--------------------------------------------------------------------------------
1 | import isArrToObj from '../../../../utils/isArrToObj'
2 |
3 | function handleTbody(data, headArr) {
4 |
5 | let newData = []
6 | let headObj = isArrToObj(headArr)
7 | data.forEach(item => {
8 |
9 | let newObj = {...headObj}
10 | for (const k in item) {
11 |
12 | if (headArr.indexOf(k) !== -1) {
13 | newObj[k] = item[k]
14 | }
15 | }
16 | newData.push(newObj)
17 |
18 | })
19 | return newData
20 | }
21 |
22 | export default handleTbody
--------------------------------------------------------------------------------
/src/views/Docs/Xlsx/components/handleXlsx.js:
--------------------------------------------------------------------------------
1 | import XLSX from 'xlsx'
2 |
3 | function handleXlsx(file) {
4 | let workbook = XLSX.read(file.target.result, { type: 'array' })
5 | var sheetNames = workbook.SheetNames;
6 | var worksheet = workbook.Sheets[sheetNames[0]];
7 | let json = XLSX.utils.sheet_to_json(worksheet);
8 | let csv = XLSX.utils.sheet_to_csv(worksheet)
9 | return {json,csv}
10 | }
11 | export default handleXlsx
--------------------------------------------------------------------------------
/src/views/Docs/Xlsx/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
前端解析xlsx 、删除、下载
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | {{item.fileName}}
12 | 删除
13 | 文件下载
14 |
15 |
16 |
17 |
18 | {{thItem}}
19 | |
20 |
21 | 操作
22 | |
23 |
24 |
25 |
26 |
27 |
28 | {{_w}}
29 | |
30 |
31 |
32 | 删除
33 | |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
90 |
--------------------------------------------------------------------------------
/src/views/Found/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
404
4 | 回到首页
5 |
6 |
7 |
13 |
--------------------------------------------------------------------------------
/src/views/Game/GreedySnake/components/food.js:
--------------------------------------------------------------------------------
1 | import getColor from '../../../../utils/color'
2 | let foods = []
3 | class Food {
4 | constructor({x,y,width,height}) {
5 | this.x = x || 0
6 | this.y = y || 0
7 | this.width = width || 20
8 | this.height = height || 20
9 | }
10 | //初始化
11 | init(el) {
12 | this.bgc = getColor()
13 | this.delNode()
14 | this.foodNode(el)
15 | }
16 | // 创建食物节点
17 | foodNode(el) {
18 | // 创建食物div
19 | let Div = document.createElement('div')
20 | // 设置div样式
21 | Div.style.position = 'absolute'
22 | Div.style.width = this.width + 'px'
23 | Div.style.height = this.height + 'px'
24 | Div.style.backgroundColor = this.bgc
25 | // 计算 x, y轴坐标
26 | this.x = parseInt(Math.random()*el.offsetWidth/this.width)*this.width
27 | this.y = parseInt(Math.random()*el.offsetHeight/this.height)*this.height
28 |
29 | Div.style.left = this.x + 'px'
30 | Div.style.top = this.y + 'px'
31 |
32 | //将div 添加到地图中
33 | el.appendChild(Div)
34 | //将div添加到数组中
35 | foods.push(Div)
36 | }
37 | //删除食物🍜 和数组中的节点
38 | delNode() {
39 | foods.forEach((ele,i)=>{
40 | //找到父节点,通过父节点删除当前节点
41 | ele.parentNode.removeChild(ele)
42 | // 删除数组中的数据, 防止多次实力化时创建多个div(食物🍜)
43 | foods.splice(i,1)
44 | })
45 | }
46 | }
47 |
48 | export default Food
--------------------------------------------------------------------------------
/src/views/Game/GreedySnake/components/index.js:
--------------------------------------------------------------------------------
1 |
2 | //食物
3 | import Food from './food'
4 | import Snake from './snake'
5 |
6 | let flag = true
7 | // 贪吃🐍 入口
8 | class Game {
9 | constructor(el) {
10 | this.el = el
11 | this.food = new Food({})
12 | this.snake = new Snake({})
13 | this.timer = null
14 | }
15 | init() {
16 | if(!flag) return
17 | //食物
18 | this.food.init(this.el)
19 | // 🐍
20 | this.snake.init(this.el)
21 | //🐍移动
22 | this.runSnake(this.food, this.el)
23 | //键盘按下
24 | this.bindKey()
25 | }
26 | //移动
27 | runSnake(food, el) {
28 | this.timer = setInterval(() => {
29 | flag = false
30 | this.snake.move(food, el)
31 | this.snake.init(el)
32 | this.boundary()
33 | }, 130)
34 |
35 | }
36 | //移动边界
37 | boundary() {
38 | const { el, snake, timer } = this
39 | //地图 ,max X,Y
40 | const maxX = el.offsetWidth / snake.width
41 | const maxY = el.offsetHeight / snake.height
42 |
43 | //🐍头 X,Y
44 | const headX = snake.body[0].x
45 | const headY = snake.body[0].y
46 | // 移动x轴边界
47 | if (headX < 0 || headX >= maxX) {
48 | clearInterval(timer)
49 | flag = true
50 | alert('X轴撞墙了,最终得分:'+snake.fraction)
51 | }
52 | if (headY < 0 || headY >= maxY) {
53 | clearInterval(timer)
54 | flag = true
55 | alert('Y轴撞墙了,最终得分:'+snake.fraction)
56 | }
57 | }
58 | //按键,改变蛇头方向
59 | bindKey() {
60 | document.addEventListener('keydown', (e) => {
61 | switch (e.keyCode) {
62 | case 37:
63 | this.snake.direction = 'left'
64 | break;
65 | case 38:
66 | this.snake.direction = 'top'
67 | break;
68 | case 39:
69 | this.snake.direction = 'right'
70 | break;
71 | case 40:
72 | this.snake.direction = 'bottom'
73 | break;
74 | }
75 | })
76 | }
77 | //移除键盘事件
78 | removeKeyCode() {
79 | document.removeEventListener('keydown')
80 | }
81 | }
82 |
83 | export default Game
--------------------------------------------------------------------------------
/src/views/Game/GreedySnake/components/snake.js:
--------------------------------------------------------------------------------
1 | import getColor from '../../../../utils/color'
2 | let snakes = []
3 |
4 | class Snake {
5 |
6 | constructor({ width, height, direction }) {
7 | this.width = width || 20
8 | this.height = height || 20
9 | this.direction = direction || 'right'
10 | this.fraction = 0 // 得分
11 | this.body = [
12 | {
13 | x: 2, y: 2, bgc: 'red'
14 | }, {
15 | x: 1, y: 2, bgc: getColor()
16 | }, {
17 | x: 0, y: 2, bgc: getColor()
18 | }
19 | ]
20 | }
21 | //初始化
22 | init(el) {
23 | this.delSnake()
24 | this.snakeNodes(el)
25 | }
26 | // 创建🐍节点
27 | snakeNodes(el) {
28 | for (let i = 0; i < this.body.length; i++) {
29 | const ele = this.body[i]
30 | // 创建div, 设置属性
31 | let Div = document.createElement('div')
32 | Div.style.position = 'absolute'
33 | Div.style.width = this.width + 'px'
34 | Div.style.height = this.height + 'px'
35 | Div.style.left = ele.x * this.width + 'px'
36 | Div.style.top = ele.y * this.height + 'px'
37 | Div.style.backgroundColor = ele.bgc
38 | if(i === 0){
39 | Div.style.textAlign="center"
40 | Div.style.lineHeight = this.height + 'px'
41 | Div.style.zIndex = '1'
42 | Div.innerText = '🐍'
43 | }
44 | // 添加到数组中
45 | snakes.push(Div)
46 | //添加到地图节点中
47 | el.appendChild(Div)
48 | }
49 | }
50 | //删除节点,防止被多次实例化调用
51 | delSnake() {
52 |
53 | for (let i = snakes.length - 1; i >= 0; i--) {
54 | const ele = snakes[i]
55 | //删除当前元素
56 | ele.parentNode.removeChild(ele)
57 | //删除数组中当前元素
58 | snakes.splice(i, 1)
59 | }
60 | }
61 | //移动🐍
62 | move(food, el) {
63 | const { x, y } = food
64 |
65 | //移动身体
66 | for (let i = this.body.length - 1; i > 0; i--) {
67 | this.body[i].x = this.body[i - 1].x
68 | this.body[i].y = this.body[i - 1].y
69 | }
70 | //判断蛇头方向
71 | switch (this.direction) {
72 | case 'right':
73 | this.body[0].x += 1
74 | break;
75 | case 'left':
76 | this.body[0].x -= 1
77 | break;
78 | case 'top':
79 | this.body[0].y -= 1
80 | break;
81 | case 'bottom':
82 | this.body[0].y += 1
83 | break;
84 | }
85 | // 判断🐍吃食物
86 | //🐍头位置
87 | const headX = this.body[0].x * this.width
88 | const headY = this.body[0].y * this.height
89 | if (x === headX && y === headY) {
90 | // 🐍尾巴添加 div
91 | let { x, y } = this.body[this.body.length - 1]
92 | this.body.push({
93 | x, y, bgc:food.bgc
94 | })
95 | //得分
96 | // this.fraction++
97 | this.fraction += 2
98 | //初始化食物
99 | food.init(el)
100 | }
101 | }
102 | }
103 |
104 | export default Snake
--------------------------------------------------------------------------------
/src/views/Game/GreedySnake/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 益智小游戏 -- 贪吃 🐍
3 |
8 |
9 |
38 |
--------------------------------------------------------------------------------
/src/views/Home/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 首页展示点啥
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
38 |
--------------------------------------------------------------------------------
/src/views/Icon/index.vue:
--------------------------------------------------------------------------------
1 |
2 | 鼠标移上去有惊喜
3 |
4 |
5 |
6 | {{item.name}}
7 |
8 |
9 |
10 |
25 |
--------------------------------------------------------------------------------
/src/views/Layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/src/views/Login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
用户登录
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
59 |
--------------------------------------------------------------------------------
/src/views/Personal/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
VUEX 用户信息
4 |
5 |
6 | 用户名:
7 | {{user.userName}}
8 |
9 |
10 | 用户名:
11 | {{user.pwd}}
12 |
13 |
14 | 登陆日期:
15 | {{user.time}}
16 |
17 |
18 |
19 |
20 |
44 |
--------------------------------------------------------------------------------