Bladeren bron

feature:升级到vue3和element-plus

lin_xin 5 jaren geleden
bovenliggende
commit
96be359eab
50 gewijzigde bestanden met toevoegingen van 2507 en 2903 verwijderingen
  1. 0 3
      .browserslistrc
  2. 4 3
      .gitignore
  3. 0 6
      .prettierrc
  4. 25 83
      README.md
  5. 24 85
      README_EN.md
  6. 1 1
      babel.config.js
  7. 54 27
      package.json
  8. 0 5
      postcss.config.js
  9. 20 16
      public/index.html
  10. BIN
      screenshots/wms2.png
  11. 9 7
      src/App.vue
  12. 4 4
      src/assets/css/icon.css
  13. 0 29
      src/assets/css/theme-green/color-green.css
  14. BIN
      src/assets/css/theme-green/fonts/element-icons.ttf
  15. BIN
      src/assets/css/theme-green/fonts/element-icons.woff
  16. 0 0
      src/assets/css/theme-green/index.css
  17. BIN
      src/assets/logo.png
  18. 18 49
      src/components/Header.vue
  19. 184 0
      src/components/Sidebar.vue
  20. 179 0
      src/components/Tags.vue
  21. 0 51
      src/components/common/Home.vue
  22. 0 189
      src/components/common/Sidebar.vue
  23. 0 186
      src/components/common/Tags.vue
  24. 0 6
      src/components/common/bus.js
  25. 0 80
      src/components/common/directives.js
  26. 0 36
      src/components/page/DragDialog.vue
  27. 0 174
      src/components/page/DragList.vue
  28. 0 67
      src/components/page/Markdown.vue
  29. 0 141
      src/components/page/Upload.vue
  30. 0 53
      src/components/page/VueEditor.vue
  31. 12 48
      src/main.js
  32. 29 0
      src/plugins/element.js
  33. 154 117
      src/router/index.js
  34. 56 0
      src/store/index.js
  35. 4 10
      src/utils/i18n.js
  36. 56 56
      src/views/403.vue
  37. 56 56
      src/views/404.vue
  38. 5 0
      src/views/About.vue
  39. 148 148
      src/views/BaseCharts.vue
  40. 150 151
      src/views/BaseForm.vue
  41. 264 219
      src/views/BaseTable.vue
  42. 421 376
      src/views/Dashboard.vue
  43. 0 0
      src/views/Donate.vue
  44. 36 0
      src/views/Home.vue
  45. 1 14
      src/views/I18n.vue
  46. 224 224
      src/views/Icon.vue
  47. 27 17
      src/views/Login.vue
  48. 37 37
      src/views/Permission.vue
  49. 129 129
      src/views/Tabs.vue
  50. 176 0
      src/views/Upload.vue

+ 0 - 3
.browserslistrc

@@ -1,3 +0,0 @@
-> 1%
-last 2 versions
-not ie <= 8

+ 4 - 3
.gitignore

@@ -1,8 +1,8 @@
 .DS_Store
 node_modules
 /dist
-example.html
-favicon.ico
+
+
 # local env files
 .env.local
 .env.*.local
@@ -11,6 +11,7 @@ favicon.ico
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
+pnpm-debug.log*
 
 # Editor directories and files
 .idea
@@ -19,4 +20,4 @@ yarn-error.log*
 *.ntvs*
 *.njsproj
 *.sln
-*.sw*
+*.sw?

+ 0 - 6
.prettierrc

@@ -1,6 +0,0 @@
-{
-	"tabWidth": 4,
-	"singleQuote": true,
-	"trailingComma": "none",
-	"printWidth": 140
-}

+ 25 - 83
README.md

@@ -16,7 +16,8 @@
     <img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
   </a>
 
-基于 Vue + Element UI 的后台管理系统解决方案。[线上地址](https://lin-xin.gitee.io/example/work/)
+基于 Vue3 + Element Plus 的后台管理系统解决方案。[线上地址](https://lin-xin.gitee.io/example/work/)
+Vue2 版本请看 [tag-V4.2.0](https://github.com/lin-xin/vue-manage-system/tree/V4.2.0)
 
 > React + Ant Design 的版本正在开发中,仓库地址:[react-manage-system](https://github.com/lin-xin/react-manage-system)
 
@@ -28,47 +29,39 @@
 
 ![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms3.png)
 
-### 默认皮肤
+### 首页
 
 ![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms1.png)
 
-### 浅绿色皮肤
-
-![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms2.png)
-
 ## 赞赏
 
 请作者喝杯咖啡吧!(微信号:linxin_20)
 
 ![微信扫一扫](https://lin-xin.gitee.io/images/weixin.jpg)
 
-## 特别鸣谢
-
-- [实验楼](https://www.shiyanlou.com?source=vue-manage-system)
-
 ## 前言
 
-该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(Web Management System)开发。基于 vue.js,使用 vue-cli3 脚手架,引用 Element UI 组件库,方便开发快速简洁好看的组件。分离颜色样式,支持手动切换主题色,而且很方便使用自定义主题色。
+该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(Web Management System)开发。基于 Vue3,使用 vue-cli3 脚手架,引用 Element Plus 组件库,方便开发快速简洁好看的组件。分离颜色样式,支持手动切换主题色,而且很方便使用自定义主题色。
 
 ## 功能
 
--   [x] Element UI
+-   [x] Element Plus
 -   [x] 登录/注销
 -   [x] Dashboard
 -   [x] 表格
 -   [x] Tab 选项卡
 -   [x] 表单
 -   [x] 图表 :bar_chart:
--   [x] 富文本编辑器
--   [x] markdown 编辑器
+-   [ ] 富文本编辑器
+-   [ ] markdown 编辑器
 -   [x] 图片拖拽/裁剪上传
--   [x] 支持切换主题色 :sparkles:
--   [x] 列表拖拽排序
+-   [ ] 支持切换主题色 :sparkles:
+-   [ ] 列表拖拽排序
 -   [x] 权限测试
 -   [x] 404 / 403
 -   [x] 三级菜单
 -   [x] 自定义图标
--   [x] 可拖拽弹窗
+-   [ ] 可拖拽弹窗
 -   [x] 国际化
 
 ## 安装步骤
@@ -101,36 +94,36 @@ vue.js 封装 sChart.js 的图表组件。访问地址:[vue-schart](https://gi
 </template>
 
 <script>
-    import Schart from 'vue-schart'; // 导入Schart组件
+    import Schart from "vue-schart"; // 导入Schart组件
     export default {
         data() {
             return {
                 options: {
-                    type: 'bar',
+                    type: "bar",
                     title: {
-                        text: '最近一周各品类销售图'
+                        text: "最近一周各品类销售图",
                     },
-                    labels: ['周一', '周二', '周三', '周四', '周五'],
+                    labels: ["周一", "周二", "周三", "周四", "周五"],
                     datasets: [
                         {
-                            label: '家电',
-                            data: [234, 278, 270, 190, 230]
+                            label: "家电",
+                            data: [234, 278, 270, 190, 230],
                         },
                         {
-                            label: '百货',
-                            data: [164, 178, 190, 135, 160]
+                            label: "百货",
+                            data: [164, 178, 190, 135, 160],
                         },
                         {
-                            label: '食品',
-                            data: [144, 198, 150, 235, 120]
-                        }
-                    ]
-                }
+                            label: "食品",
+                            data: [144, 198, 150, 235, 120],
+                        },
+                    ],
+                },
             };
         },
         components: {
-            Schart
-        }
+            Schart,
+        },
     };
 </script>
 <style>
@@ -141,57 +134,6 @@ vue.js 封装 sChart.js 的图表组件。访问地址:[vue-schart](https://gi
 </style>
 ```
 
-## 其他注意事项
-
-### 一、如果我不想用到上面的某些组件呢,那我怎么在模板中删除掉不影响到其他功能呢?
-
-举个栗子,我不想用 Vue-Quill-Editor 这个组件,那我需要分四步走。
-
-第一步:删除该组件的路由,在目录 src/router/index.js 中,找到引入改组件的路由,删除下面这段代码。
-
-```JavaScript
-{
-    // 富文本编辑器组件
-    path: '/editor',
-    component: resolve => require(['../components/page/VueEditor.vue'], resolve)
-},
-```
-
-第二步:删除引入该组件的文件。在目录 src/components/page/ 删除 VueEditor.vue 文件。
-
-第三步:删除该页面的入口。在目录 src/components/common/Sidebar.vue 中,找到该入口,删除下面这段代码。
-
-```js
-{
-	index: 'editor',
-	title: '富文本编辑器'
-},
-```
-
-第四步:卸载该组件。执行以下命令:
-npm un vue-quill-editor -S
-
-完成。
-
-### 二、如何切换主题色呢?
-
-第一步:打开 src/main.js 文件,找到引入 element 样式的地方,换成浅绿色主题。
-
-```javascript
-import 'element-ui/lib/theme-default/index.css'; // 默认主题
-// import './assets/css/theme-green/index.css';       // 浅绿色主题
-```
-
-第二步:打开 src/App.vue 文件,找到 style 标签引入样式的地方,切换成浅绿色主题。
-
-```javascript
-@import "./assets/css/main.css";
-@import "./assets/css/color-dark.css";     /*深色主题*/
-/*@import "./assets/css/theme-green/color-green.css";   !*浅绿色主题*!*/
-```
-
-第三步:打开 src/components/common/Sidebar.vue 文件,找到 el-menu 标签,把 background-color/text-color/active-text-color 属性去掉即可。
-
 ## License
 
 [MIT](https://github.com/lin-xin/vue-manage-system/blob/master/LICENSE)

+ 24 - 85
README_EN.md

@@ -16,7 +16,8 @@
     <img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
   </a>
 
-The web management system solution based on Vue2 and Element-UI。[live demo](https://lin-xin.gitee.io/example/work/)
+The web management system solution based on Vue3 and ElementPlus。[live demo](https://lin-xin.gitee.io/example/work/)
+Please check the version of vue2 in [tag V4.2.0](https://github.com/lin-xin/vue-manage-system/tree/V4.2.0)
 
 ## Donation
 
@@ -24,7 +25,7 @@ The web management system solution based on Vue2 and Element-UI。[live demo](ht
 
 ## Preface
 
-The scheme as a set of multi-function background frame templates, suitable for most of the WEB management system development. Convenient development fast simple good components based on Vue2 and Element-UI. Color separation of color style, support manual switch themes, and it is convenient to use a custom theme color.
+The scheme as a set of multi-function background frame templates, suitable for most of the WEB management system development. Convenient development fast simple good components based on Vue3 and ElementPlus. Color separation of color style, support manual switch themes, and it is convenient to use a custom theme color.
 
 ## Function
 
@@ -35,11 +36,11 @@ The scheme as a set of multi-function background frame templates, suitable for m
 -   [x] Tabs
 -   [x] From
 -   [x] Chart :bar_chart:
--   [x] Editor
--   [x] Markdown
+-   [ ] Editor
+-   [ ] Markdown
 -   [x] Upload pictures by clipping or dragging
--   [x] Support manual switch themes :sparkles:
--   [x] List drag sort
+-   [ ] Support manual switch themes :sparkles:
+-   [ ] List drag sort
 -   [x] Permission
 -   [x] 404 / 403
 -   [x] Three level menu
@@ -75,36 +76,36 @@ Vue.js wrapper for sChart.js. Github : [vue-schart](https://github.com/linxin/vu
 </template>
 
 <script>
-    import Schart from 'vue-schart'; // 导入Schart组件
+    import Schart from "vue-schart"; // 导入Schart组件
     export default {
         data() {
             return {
                 options: {
-                    type: 'bar',
+                    type: "bar",
                     title: {
-                        text: '最近一周各品类销售图'
+                        text: "最近一周各品类销售图",
                     },
-                    labels: ['周一', '周二', '周三', '周四', '周五'],
+                    labels: ["周一", "周二", "周三", "周四", "周五"],
                     datasets: [
                         {
-                            label: '家电',
-                            data: [234, 278, 270, 190, 230]
+                            label: "家电",
+                            data: [234, 278, 270, 190, 230],
                         },
                         {
-                            label: '百货',
-                            data: [164, 178, 190, 135, 160]
+                            label: "百货",
+                            data: [164, 178, 190, 135, 160],
                         },
                         {
-                            label: '食品',
-                            data: [144, 198, 150, 235, 120]
-                        }
-                    ]
-                }
+                            label: "食品",
+                            data: [144, 198, 150, 235, 120],
+                        },
+                    ],
+                },
             };
         },
         components: {
-            Schart
-        }
+            Schart,
+        },
     };
 </script>
 <style>
@@ -119,77 +120,15 @@ Vue.js wrapper for sChart.js. Github : [vue-schart](https://github.com/linxin/vu
 
 A desktop component library based on vue.js2.0 . Github : [element](http://element.eleme.io/#/zh-CN/component/layout)
 
-### Vue-Quill-Editor
-
-Quill editor component for Vue2. Github : [vue-quill-editor](https://github.com/surmon-china/vue-quill-editor)
-
-### mavonEditor
-
-A markdown editor based on Vue that supports a variety of personalized features. Github: [mavonEditor](https://github.com/hinesboy/mavonEditor)
-
-### vue-cropperjs
-
-A Vue wrapper component for cropperjs. Github: [vue-cropperjs](https://github.com/Agontuk/vue-cropperjs)
-
-## Notice
-
-### 一、If I don't want to use some components, how can I delete it?
-
-For example, I don't want to use the Vue-Quill-Editor component, I need to take four steps.
-
-The first step to remove the component of the routing. Enter 'src/router/index.js' and delete the code below.
-
-```JavaScript
-{
-    path: '/editor',
-    component: resolve => require(['../components/page/VueEditor.vue'], resolve)
-},
-```
-
-Second,delete the component files. Enter 'src/components/page/' and delete 'VueEditor.vue' file.
-
-The third step is to delete the entry. Enter 'src/components/common/Sidebar.vue' and delete the code below.
-
-```js
-{
-	index: 'editor',
-	title: '富文本编辑器'
-},
-```
-
-Finally, uninstall this component.
-npm un vue-quill-editor -S
-
-Complete!
-
-### 二、How to switch themes?
-
-The first step to enter 'src/main.js' and change into green theme.
-
-```javascript
-import 'element-ui/lib/theme-default/index.css'; // default theme
-// import '../static/css/theme-green/index.css';       // green theme
-```
-
-The second step to enter 'src/App.vue' and change into green theme.
-
-```javascript
-@import "../static/css/main.css";
-@import "../static/css/color-dark.css";     /*深色主题*/
-/*@import "../static/css/theme-green/color-green.css";   !*浅绿色主题*!*/
-```
-
-Finally,enter 'src/components/common/Sidebar.vue' and find el-menu Tags,delete 'background-color/text-color/active-text-color'。
-
 ## Screenshot
 
 ### Default theme
 
 ![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms1.png)
 
-### Green theme
+### Login
 
-![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms2.png)
+![Image text](https://github.com/lin-xin/manage-system/raw/master/screenshots/wms3.png)
 
 ## License
 

+ 1 - 1
babel.config.js

@@ -1,5 +1,5 @@
 module.exports = {
   presets: [
-    '@vue/app'
+    '@vue/cli-plugin-babel/preset'
   ]
 }

+ 54 - 27
package.json

@@ -1,28 +1,55 @@
 {
-  "name": "vue-manage-system",
-  "version": "4.2.0",
-  "private": true,
-  "scripts": {
-    "dev": "npm run serve",
-    "serve": "vue-cli-service serve",
-    "build": "vue-cli-service build"
-  },
-  "dependencies": {
-    "axios": "^0.18.0",
-    "babel-polyfill": "^6.26.0",
-    "element-ui": "^2.11.0",
-    "mavon-editor": "^2.6.17",
-    "vue": "^2.6.10",
-    "vue-cropperjs": "^3.0.0",
-    "vue-i18n": "^8.10.0",
-    "vue-quill-editor": "^3.0.6",
-    "vue-router": "^3.0.3",
-    "vue-schart": "^2.0.0",
-    "vuedraggable": "^2.17.0"
-  },
-  "devDependencies": {
-    "@vue/cli-plugin-babel": "^3.9.0",
-    "@vue/cli-service": "^3.9.0",
-    "vue-template-compiler": "^2.6.10"
-  }
-}
+    "name": "vue-manage-system",
+    "version": "5.0.0",
+    "private": true,
+    "scripts": {
+        "serve": "vue-cli-service serve",
+        "build": "vue-cli-service build",
+        "lint": "vue-cli-service lint"
+    },
+    "dependencies": {
+        "axios": "^0.21.1",
+        "core-js": "~3.9.1",
+        "element-plus": "~1.0.2-beta.33",
+        "vue": "~3.0.7",
+        "vue-cropperjs": "^5.0.0",
+        "vue-i18n": "^9.0.0",
+        "vue-loader-v16": "^16.0.0-beta.5.4",
+        "vue-router": "~4.0.4",
+        "vue-schart": "^2.0.0",
+        "vuex": "~4.0.0"
+    },
+    "devDependencies": {
+        "@vue/cli-plugin-babel": "~4.5.11",
+        "@vue/cli-plugin-eslint": "~4.5.11",
+        "@vue/cli-plugin-router": "~4.5.11",
+        "@vue/cli-plugin-vuex": "~4.5.11",
+        "@vue/cli-service": "~4.5.11",
+        "@vue/compiler-sfc": "~3.0.7",
+        "babel-eslint": "~10.1.0",
+        "eslint": "~6.8.0",
+        "eslint-plugin-vue": "~7.7.0",
+        "sass": "~1.32.8",
+        "sass-loader": "~8.0.2",
+        "vue-cli-plugin-element-plus": "0.0.13"
+    },
+    "eslintConfig": {
+        "root": true,
+        "env": {
+            "node": true
+        },
+        "extends": [
+            "plugin:vue/vue3-essential",
+            "eslint:recommended"
+        ],
+        "parserOptions": {
+            "parser": "babel-eslint"
+        },
+        "rules": {}
+    },
+    "browserslist": [
+        "> 1%",
+        "last 2 versions",
+        "not dead"
+    ]
+}

+ 0 - 5
postcss.config.js

@@ -1,5 +0,0 @@
-module.exports = {
-  plugins: {
-    autoprefixer: {}
-  }
-}

+ 20 - 16
public/index.html

@@ -1,17 +1,21 @@
 <!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
-    <link rel="stylesheet" href="//at.alicdn.com/t/font_830376_qzecyukz0s.css">
-    <title>vue-manage-system</title>
-  </head>
-  <body>
-    <noscript>
-      <strong>We're sorry but vms doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
-    </noscript>
-    <div id="app"></div>
-    <!-- built files will be auto injected -->
-  </body>
-</html>
+<html lang="">
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width,initial-scale=1.0">
+  <title>vue-manage-system</title>
+  <link rel="stylesheet" href="https://at.alicdn.com/t/font_830376_qzecyukz0s.css">
+</head>
+
+<body>
+  <noscript>
+    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
+      Please enable it to continue.</strong>
+  </noscript>
+  <div id="app"></div>
+  <!-- built files will be auto injected -->
+</body>
+
+</html>

BIN
screenshots/wms2.png


+ 9 - 7
src/App.vue

@@ -1,10 +1,12 @@
 <template>
-    <div id="app">
-        <router-view></router-view>
-    </div>
+    <router-view />
 </template>
+
+<script>
+export default {};
+</script>
+
 <style>
-    @import "./assets/css/main.css";
-    @import "./assets/css/color-dark.css";     /*深色主题*/
-    /*@import "./assets/css/theme-green/color-green.css";   浅绿色主题*/
-</style>
+@import "./assets/css/main.css";
+@import "./assets/css/color-dark.css";
+</style>

+ 4 - 4
src/assets/css/icon.css

@@ -1,4 +1,4 @@
-
-    [class*=" el-icon-lx"], [class^=el-icon-lx] {
-        font-family: lx-iconfont!important;
-    }
+[class*=" el-icon-lx"],
+[class^=el-icon-lx] {
+    font-family: lx-iconfont !important;
+}

+ 0 - 29
src/assets/css/theme-green/color-green.css

@@ -1,29 +0,0 @@
-.header{
-    background-color: #07c4a8;
-}
-.login-wrap{
-    background: rgba(56, 157, 170, 0.82);;
-}
-.plugins-tips{
-    background: #f2f2f2;
-}
-.plugins-tips a{
-    color: #00d1b2;
-}
-.el-upload--text em {
-    color: #00d1b2;
-}
-.pure-button{
-    background: #00d1b2;
-}
-.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus {
-    background-color: #00d1b2 !important;
-    border-color: #00d1b2 !important;
-}
-.tags-li.active {
-    border: 1px solid #00d1b2;
-    background-color: #00d1b2;
-}
-.collapse-btn:hover{
-    background: #00d1b2;
-}

BIN
src/assets/css/theme-green/fonts/element-icons.ttf


BIN
src/assets/css/theme-green/fonts/element-icons.woff


File diff suppressed because it is too large
+ 0 - 0
src/assets/css/theme-green/index.css


BIN
src/assets/logo.png


+ 18 - 49
src/components/common/Header.vue → src/components/Header.vue

@@ -8,12 +8,6 @@
         <div class="logo">后台管理系统</div>
         <div class="header-right">
             <div class="header-user-con">
-                <!-- 全屏显示 -->
-                <div class="btn-fullscreen" @click="handleFullScreen">
-                    <el-tooltip effect="dark" :content="fullscreen?`取消全屏`:`全屏`" placement="bottom">
-                        <i class="el-icon-rank"></i>
-                    </el-tooltip>
-                </div>
                 <!-- 消息中心 -->
                 <div class="btn-bell">
                     <el-tooltip
@@ -29,7 +23,7 @@
                 </div>
                 <!-- 用户头像 -->
                 <div class="user-avator">
-                    <img src="../../assets/img/img.jpg" />
+                    <img src="../assets/img/img.jpg" />
                 </div>
                 <!-- 用户名下拉菜单 -->
                 <el-dropdown class="user-name" trigger="click" @command="handleCommand">
@@ -37,73 +31,48 @@
                         {{username}}
                         <i class="el-icon-caret-bottom"></i>
                     </span>
-                    <el-dropdown-menu slot="dropdown">
-                        <a href="https://github.com/lin-xin/vue-manage-system" target="_blank">
-                            <el-dropdown-item>项目仓库</el-dropdown-item>
-                        </a>
-                        <el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
-                    </el-dropdown-menu>
+                    <template #dropdown>
+                        <el-dropdown-menu>
+                            <a href="https://github.com/lin-xin/vue-manage-system" target="_blank">
+                                <el-dropdown-item>项目仓库</el-dropdown-item>
+                            </a>
+                            <el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
+                        </el-dropdown-menu>
+                    </template>
                 </el-dropdown>
             </div>
         </div>
     </div>
 </template>
 <script>
-import bus from '../common/bus';
 export default {
     data() {
         return {
-            collapse: false,
             fullscreen: false,
-            name: 'linxin',
+            name: "linxin",
             message: 2
         };
     },
     computed: {
         username() {
-            let username = localStorage.getItem('ms_username');
+            let username = localStorage.getItem("ms_username");
             return username ? username : this.name;
+        },
+        collapse() {
+            return this.$store.state.collapse;
         }
     },
     methods: {
         // 用户名下拉菜单选择事件
         handleCommand(command) {
-            if (command == 'loginout') {
-                localStorage.removeItem('ms_username');
-                this.$router.push('/login');
+            if (command == "loginout") {
+                localStorage.removeItem("ms_username");
+                this.$router.push("/login");
             }
         },
         // 侧边栏折叠
         collapseChage() {
-            this.collapse = !this.collapse;
-            bus.$emit('collapse', this.collapse);
-        },
-        // 全屏事件
-        handleFullScreen() {
-            let element = document.documentElement;
-            if (this.fullscreen) {
-                if (document.exitFullscreen) {
-                    document.exitFullscreen();
-                } else if (document.webkitCancelFullScreen) {
-                    document.webkitCancelFullScreen();
-                } else if (document.mozCancelFullScreen) {
-                    document.mozCancelFullScreen();
-                } else if (document.msExitFullscreen) {
-                    document.msExitFullscreen();
-                }
-            } else {
-                if (element.requestFullscreen) {
-                    element.requestFullscreen();
-                } else if (element.webkitRequestFullScreen) {
-                    element.webkitRequestFullScreen();
-                } else if (element.mozRequestFullScreen) {
-                    element.mozRequestFullScreen();
-                } else if (element.msRequestFullscreen) {
-                    // IE11
-                    element.msRequestFullscreen();
-                }
-            }
-            this.fullscreen = !this.fullscreen;
+            this.$store.commit("hadndleCollapse", !this.collapse);
         }
     },
     mounted() {

+ 184 - 0
src/components/Sidebar.vue

@@ -0,0 +1,184 @@
+<template>
+    <div class="sidebar">
+        <el-menu
+            class="sidebar-el-menu"
+            :default-active="onRoutes"
+            :collapse="collapse"
+            background-color="#324157"
+            text-color="#bfcbd9"
+            active-text-color="#20a0ff"
+            unique-opened
+            router
+        >
+            <template v-for="item in items">
+                <template v-if="item.subs">
+                    <el-submenu :index="item.index" :key="item.index">
+                        <template #title>
+                            <i :class="item.icon"></i>
+                            <span>{{ item.title }}</span>
+                        </template>
+                        <template v-for="subItem in item.subs">
+                            <el-submenu
+                                v-if="subItem.subs"
+                                :index="subItem.index"
+                                :key="subItem.index"
+                            >
+                                <template #title>{{ subItem.title }}</template>
+                                <el-menu-item
+                                    v-for="(threeItem, i) in subItem.subs"
+                                    :key="i"
+                                    :index="threeItem.index"
+                                >{{ threeItem.title }}</el-menu-item>
+                            </el-submenu>
+                            <el-menu-item
+                                v-else
+                                :index="subItem.index"
+                                :key="subItem.index"
+                            >{{ subItem.title }}</el-menu-item>
+                        </template>
+                    </el-submenu>
+                </template>
+                <template v-else>
+                    <el-menu-item :index="item.index" :key="item.index">
+                        <i :class="item.icon"></i>
+                        <template #title>{{ item.title }}</template>
+                    </el-menu-item>
+                </template>
+            </template>
+        </el-menu>
+    </div>
+</template>
+
+<script>
+// import bus from "../common/bus";
+export default {
+    data() {
+        return {
+            items: [
+                {
+                    icon: "el-icon-lx-home",
+                    index: "dashboard",
+                    title: "系统首页"
+                },
+                {
+                    icon: "el-icon-lx-cascades",
+                    index: "table",
+                    title: "基础表格"
+                },
+                {
+                    icon: "el-icon-lx-copy",
+                    index: "tabs",
+                    title: "tab选项卡"
+                },
+                {
+                    icon: "el-icon-lx-calendar",
+                    index: "3",
+                    title: "表单相关",
+                    subs: [
+                        {
+                            index: "form",
+                            title: "基本表单"
+                        },
+                        //         {
+                        //             index: "3-2",
+                        //             title: "三级菜单",
+                        //             subs: [
+                        //                 {
+                        //                     index: "editor",
+                        //                     title: "富文本编辑器"
+                        //                 },
+                        //                 {
+                        //                     index: "markdown",
+                        //                     title: "markdown编辑器"
+                        //                 }
+                        //             ]
+                        //         },
+                        {
+                            index: "upload",
+                            title: "文件上传"
+                        }
+                    ]
+                },
+                {
+                    icon: "el-icon-lx-emoji",
+                    index: "icon",
+                    title: "自定义图标"
+                },
+                {
+                    icon: "el-icon-pie-chart",
+                    index: "charts",
+                    title: "schart图表"
+                },
+                // {
+                //     icon: "el-icon-rank",
+                //     index: "6",
+                //     title: "拖拽组件",
+                //     subs: [
+                //         {
+                //             index: "drag",
+                //             title: "拖拽列表"
+                //         },
+                //         {
+                //             index: "dialog",
+                //             title: "拖拽弹框"
+                //         }
+                //     ]
+                // },
+                {
+                    icon: "el-icon-lx-global",
+                    index: "i18n",
+                    title: "国际化功能"
+                },
+                {
+                    icon: "el-icon-lx-warn",
+                    index: "7",
+                    title: "错误处理",
+                    subs: [
+                        {
+                            index: "permission",
+                            title: "权限测试"
+                        },
+                        {
+                            index: "404",
+                            title: "404页面"
+                        }
+                    ]
+                },
+                {
+                    icon: "el-icon-lx-redpacket_fill",
+                    index: "/donate",
+                    title: "支持作者"
+                }
+            ]
+        };
+    },
+    computed: {
+        onRoutes() {
+            return this.$route.path.replace("/", "");
+        },
+        collapse(){
+            return this.$store.state.collapse
+        }
+    }
+};
+</script>
+
+<style scoped>
+.sidebar {
+    display: block;
+    position: absolute;
+    left: 0;
+    top: 70px;
+    bottom: 0;
+    overflow-y: scroll;
+}
+.sidebar::-webkit-scrollbar {
+    width: 0;
+}
+.sidebar-el-menu:not(.el-menu--collapse) {
+    width: 250px;
+}
+.sidebar > ul {
+    height: 100%;
+}
+</style>

+ 179 - 0
src/components/Tags.vue

@@ -0,0 +1,179 @@
+<template>
+    <div class="tags" v-if="showTags">
+        <ul>
+            <li
+                class="tags-li"
+                v-for="(item,index) in tagsList"
+                :class="{'active': isActive(item.path)}"
+                :key="index"
+            >
+                <router-link :to="item.path" class="tags-li-title">{{item.title}}</router-link>
+                <span class="tags-li-icon" @click="closeTags(index)">
+                    <i class="el-icon-close"></i>
+                </span>
+            </li>
+        </ul>
+        <div class="tags-close-box">
+            <el-dropdown @command="handleTags">
+                <el-button size="mini" type="primary">
+                    标签选项
+                    <i class="el-icon-arrow-down el-icon--right"></i>
+                </el-button>
+                <template #dropdown>
+                    <el-dropdown-menu size="small">
+                        <el-dropdown-item command="other">关闭其他</el-dropdown-item>
+                        <el-dropdown-item command="all">关闭所有</el-dropdown-item>
+                    </el-dropdown-menu>
+                </template>
+            </el-dropdown>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    computed: {
+        tagsList() {
+            return this.$store.state.tagsList;
+        },
+        showTags() {
+            return this.tagsList.length > 0;
+        }
+    },
+    methods: {
+        isActive(path) {
+            return path === this.$route.fullPath;
+        },
+        // 关闭单个标签
+        closeTags(index) {
+            const delItem = this.tagsList[index];
+            this.$store.commit("delTagsItem", { index });
+            const item = this.tagsList[index]
+                ? this.tagsList[index]
+                : this.tagsList[index - 1];
+            if (item) {
+                delItem.path === this.$route.fullPath &&
+                    this.$router.push(item.path);
+            } else {
+                this.$router.push("/");
+            }
+        },
+        // 关闭全部标签
+        closeAll() {
+            this.$store.commit("clearTags");
+            this.$router.push("/");
+        },
+        // 关闭其他标签
+        closeOther() {
+            const curItem = this.tagsList.filter(item => {
+                return item.path === this.$route.fullPath;
+            });
+            this.$store.commit("closeTagsOther", curItem);
+        },
+        // 设置标签
+        setTags(route) {
+            const isExist = this.tagsList.some(item => {
+                return item.path === route.fullPath;
+            });
+            if (!isExist) {
+                if (this.tagsList.length >= 8) {
+                    this.$store.commit("delTagsItem", { index: 0 });
+                }
+                this.$store.commit("setTagsItem", {
+                    title: route.meta.title,
+                    path: route.fullPath
+                });
+            }
+        },
+        handleTags(command) {
+            command === "other" ? this.closeOther() : this.closeAll();
+        }
+    },
+    watch: {
+        $route(newValue) {
+            this.setTags(newValue);
+        }
+    },
+    created() {
+        this.setTags(this.$route);
+        // 关闭当前页面的标签页
+        // this.$store.commit("closeCurrentTag", {
+        //     $router: this.$router,
+        //     $route: this.$route
+        // });
+    }
+};
+</script>
+
+
+<style>
+.tags {
+    position: relative;
+    height: 30px;
+    overflow: hidden;
+    background: #fff;
+    padding-right: 120px;
+    box-shadow: 0 5px 10px #ddd;
+}
+
+.tags ul {
+    box-sizing: border-box;
+    width: 100%;
+    height: 100%;
+}
+
+.tags-li {
+    float: left;
+    margin: 3px 5px 2px 3px;
+    border-radius: 3px;
+    font-size: 12px;
+    overflow: hidden;
+    cursor: pointer;
+    height: 23px;
+    line-height: 23px;
+    border: 1px solid #e9eaec;
+    background: #fff;
+    padding: 0 5px 0 12px;
+    vertical-align: middle;
+    color: #666;
+    -webkit-transition: all 0.3s ease-in;
+    -moz-transition: all 0.3s ease-in;
+    transition: all 0.3s ease-in;
+}
+
+.tags-li:not(.active):hover {
+    background: #f8f8f8;
+}
+
+.tags-li.active {
+    color: #fff;
+}
+
+.tags-li-title {
+    float: left;
+    max-width: 80px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    margin-right: 5px;
+    color: #666;
+}
+
+.tags-li.active .tags-li-title {
+    color: #fff;
+}
+
+.tags-close-box {
+    position: absolute;
+    right: 0;
+    top: 0;
+    box-sizing: border-box;
+    padding-top: 1px;
+    text-align: center;
+    width: 110px;
+    height: 30px;
+    background: #fff;
+    box-shadow: -3px 0 15px 3px rgba(0, 0, 0, 0.1);
+    z-index: 10;
+}
+</style>

+ 0 - 51
src/components/common/Home.vue

@@ -1,51 +0,0 @@
-<template>
-    <div class="wrapper">
-        <v-head></v-head>
-        <v-sidebar></v-sidebar>
-        <div class="content-box" :class="{'content-collapse':collapse}">
-            <v-tags></v-tags>
-            <div class="content">
-                <transition name="move" mode="out-in">
-                    <keep-alive :include="tagsList">
-                        <router-view></router-view>
-                    </keep-alive>
-                </transition>
-                <el-backtop target=".content"></el-backtop>
-            </div>
-        </div>
-    </div>
-</template>
-
-<script>
-import vHead from './Header.vue';
-import vSidebar from './Sidebar.vue';
-import vTags from './Tags.vue';
-import bus from './bus';
-export default {
-    data() {
-        return {
-            tagsList: [],
-            collapse: false
-        };
-    },
-    components: {
-        vHead,
-        vSidebar,
-        vTags
-    },
-    created() {
-        bus.$on('collapse-content', msg => {
-            this.collapse = msg;
-        });
-
-        // 只有在标签页列表里的页面才使用keep-alive,即关闭标签之后就不保存到内存中了。
-        bus.$on('tags', msg => {
-            let arr = [];
-            for (let i = 0, len = msg.length; i < len; i++) {
-                msg[i].name && arr.push(msg[i].name);
-            }
-            this.tagsList = arr;
-        });
-    }
-};
-</script>

+ 0 - 189
src/components/common/Sidebar.vue

@@ -1,189 +0,0 @@
-<template>
-    <div class="sidebar">
-        <el-menu
-            class="sidebar-el-menu"
-            :default-active="onRoutes"
-            :collapse="collapse"
-            background-color="#324157"
-            text-color="#bfcbd9"
-            active-text-color="#20a0ff"
-            unique-opened
-            router
-        >
-            <template v-for="item in items">
-                <template v-if="item.subs">
-                    <el-submenu :index="item.index" :key="item.index">
-                        <template slot="title">
-                            <i :class="item.icon"></i>
-                            <span slot="title">{{ item.title }}</span>
-                        </template>
-                        <template v-for="subItem in item.subs">
-                            <el-submenu
-                                v-if="subItem.subs"
-                                :index="subItem.index"
-                                :key="subItem.index"
-                            >
-                                <template slot="title">{{ subItem.title }}</template>
-                                <el-menu-item
-                                    v-for="(threeItem,i) in subItem.subs"
-                                    :key="i"
-                                    :index="threeItem.index"
-                                >{{ threeItem.title }}</el-menu-item>
-                            </el-submenu>
-                            <el-menu-item
-                                v-else
-                                :index="subItem.index"
-                                :key="subItem.index"
-                            >{{ subItem.title }}</el-menu-item>
-                        </template>
-                    </el-submenu>
-                </template>
-                <template v-else>
-                    <el-menu-item :index="item.index" :key="item.index">
-                        <i :class="item.icon"></i>
-                        <span slot="title">{{ item.title }}</span>
-                    </el-menu-item>
-                </template>
-            </template>
-        </el-menu>
-    </div>
-</template>
-
-<script>
-import bus from '../common/bus';
-export default {
-    data() {
-        return {
-            collapse: false,
-            items: [
-                {
-                    icon: 'el-icon-lx-home',
-                    index: 'dashboard',
-                    title: '系统首页'
-                },
-                {
-                    icon: 'el-icon-lx-cascades',
-                    index: 'table',
-                    title: '基础表格'
-                },
-                {
-                    icon: 'el-icon-lx-copy',
-                    index: 'tabs',
-                    title: 'tab选项卡'
-                },
-                {
-                    icon: 'el-icon-lx-calendar',
-                    index: '3',
-                    title: '表单相关',
-                    subs: [
-                        {
-                            index: 'form',
-                            title: '基本表单'
-                        },
-                        {
-                            index: '3-2',
-                            title: '三级菜单',
-                            subs: [
-                                {
-                                    index: 'editor',
-                                    title: '富文本编辑器'
-                                },
-                                {
-                                    index: 'markdown',
-                                    title: 'markdown编辑器'
-                                }
-                            ]
-                        },
-                        {
-                            index: 'upload',
-                            title: '文件上传'
-                        }
-                    ]
-                },
-                {
-                    icon: 'el-icon-lx-emoji',
-                    index: 'icon',
-                    title: '自定义图标'
-                },
-                {
-                    icon: 'el-icon-pie-chart',
-                    index: 'charts',
-                    title: 'schart图表'
-                },
-                {
-                    icon: 'el-icon-rank',
-                    index: '6',
-                    title: '拖拽组件',
-                    subs: [
-                        {
-                            index: 'drag',
-                            title: '拖拽列表'
-                        },
-                        {
-                            index: 'dialog',
-                            title: '拖拽弹框'
-                        }
-                    ]
-                },
-                {
-                    icon: 'el-icon-lx-global',
-                    index: 'i18n',
-                    title: '国际化功能'
-                },
-                {
-                    icon: 'el-icon-lx-warn',
-                    index: '7',
-                    title: '错误处理',
-                    subs: [
-                        {
-                            index: 'permission',
-                            title: '权限测试'
-                        },
-                        {
-                            index: '404',
-                            title: '404页面'
-                        }
-                    ]
-                },
-                {
-                    icon: 'el-icon-lx-redpacket_fill',
-                    index: '/donate',
-                    title: '支持作者'
-                }
-            ]
-        };
-    },
-    computed: {
-        onRoutes() {
-            return this.$route.path.replace('/', '');
-        }
-    },
-    created() {
-        // 通过 Event Bus 进行组件间通信,来折叠侧边栏
-        bus.$on('collapse', msg => {
-            this.collapse = msg;
-            bus.$emit('collapse-content', msg);
-        });
-    }
-};
-</script>
-
-<style scoped>
-.sidebar {
-    display: block;
-    position: absolute;
-    left: 0;
-    top: 70px;
-    bottom: 0;
-    overflow-y: scroll;
-}
-.sidebar::-webkit-scrollbar {
-    width: 0;
-}
-.sidebar-el-menu:not(.el-menu--collapse) {
-    width: 250px;
-}
-.sidebar > ul {
-    height: 100%;
-}
-</style>

+ 0 - 186
src/components/common/Tags.vue

@@ -1,186 +0,0 @@
-<template>
-    <div class="tags" v-if="showTags">
-        <ul>
-            <li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index">
-                <router-link :to="item.path" class="tags-li-title">
-                    {{item.title}}
-                </router-link>
-                <span class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span>
-            </li>
-        </ul>
-        <div class="tags-close-box">
-            <el-dropdown @command="handleTags">
-                <el-button size="mini" type="primary">
-                    标签选项<i class="el-icon-arrow-down el-icon--right"></i>
-                </el-button>
-                <el-dropdown-menu size="small" slot="dropdown">
-                    <el-dropdown-item command="other">关闭其他</el-dropdown-item>
-                    <el-dropdown-item command="all">关闭所有</el-dropdown-item>
-                </el-dropdown-menu>
-            </el-dropdown>
-        </div>
-    </div>
-</template>
-
-<script>
-    import bus from './bus';
-    export default {
-        data() {
-            return {
-                tagsList: []
-            }
-        },
-        methods: {
-            isActive(path) {
-                return path === this.$route.fullPath;
-            },
-            // 关闭单个标签
-            closeTags(index) {
-                const delItem = this.tagsList.splice(index, 1)[0];
-                const item = this.tagsList[index] ? this.tagsList[index] : this.tagsList[index - 1];
-                if (item) {
-                    delItem.path === this.$route.fullPath && this.$router.push(item.path);
-                }else{
-                    this.$router.push('/');
-                }
-            },
-            // 关闭全部标签
-            closeAll(){
-                this.tagsList = [];
-                this.$router.push('/');
-            },
-            // 关闭其他标签
-            closeOther(){
-                const curItem = this.tagsList.filter(item => {
-                    return item.path === this.$route.fullPath;
-                })
-                this.tagsList = curItem;
-            },
-            // 设置标签
-            setTags(route){
-                const isExist = this.tagsList.some(item => {
-                    return item.path === route.fullPath;
-                })
-                if(!isExist){
-                    if(this.tagsList.length >= 8){
-                        this.tagsList.shift();
-                    }
-                    this.tagsList.push({
-                        title: route.meta.title,
-                        path: route.fullPath,
-                        name: route.matched[1].components.default.name
-                    })
-                }
-                bus.$emit('tags', this.tagsList);
-            },
-            handleTags(command){
-                command === 'other' ? this.closeOther() : this.closeAll();
-            }
-        },
-        computed: {
-            showTags() {
-                return this.tagsList.length > 0;
-            }
-        },
-        watch:{
-            $route(newValue, oldValue){
-                this.setTags(newValue);
-            }
-        },
-        created(){
-            this.setTags(this.$route);
-            // 监听关闭当前页面的标签页
-            bus.$on('close_current_tags', () => {
-                for (let i = 0, len = this.tagsList.length; i < len; i++) {
-                    const item = this.tagsList[i];
-                    if(item.path === this.$route.fullPath){
-                        if(i < len - 1){
-                            this.$router.push(this.tagsList[i+1].path);
-                        }else if(i > 0){
-                            this.$router.push(this.tagsList[i-1].path);
-                        }else{
-                            this.$router.push('/');
-                        }
-                        this.tagsList.splice(i, 1);
-                        break;
-                    }
-                }
-            })
-        }
-    }
-
-</script>
-
-
-<style>
-    .tags {
-        position: relative;
-        height: 30px;
-        overflow: hidden;
-        background: #fff;
-        padding-right: 120px;
-        box-shadow: 0 5px 10px #ddd;
-    }
-
-    .tags ul {
-        box-sizing: border-box;
-        width: 100%;
-        height: 100%;
-    }
-
-    .tags-li {
-        float: left;
-        margin: 3px 5px 2px 3px;
-        border-radius: 3px;
-        font-size: 12px;
-        overflow: hidden;
-        cursor: pointer;
-        height: 23px;
-        line-height: 23px;
-        border: 1px solid #e9eaec;
-        background: #fff;
-        padding: 0 5px 0 12px;
-        vertical-align: middle;
-        color: #666;
-        -webkit-transition: all .3s ease-in;
-        -moz-transition: all .3s ease-in;
-        transition: all .3s ease-in;
-    }
-
-    .tags-li:not(.active):hover {
-        background: #f8f8f8;
-    }
-
-    .tags-li.active {
-        color: #fff;
-    }
-
-    .tags-li-title {
-        float: left;
-        max-width: 80px;
-        overflow: hidden;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-        margin-right: 5px;
-        color: #666;
-    }
-
-    .tags-li.active .tags-li-title {
-        color: #fff;
-    }
-
-    .tags-close-box {
-        position: absolute;
-        right: 0;
-        top: 0;
-        box-sizing: border-box;
-        padding-top: 1px;
-        text-align: center;
-        width: 110px;
-        height: 30px;
-        background: #fff;
-        box-shadow: -3px 0 15px 3px rgba(0, 0, 0, .1);
-        z-index: 10;
-    }
-
-</style>

+ 0 - 6
src/components/common/bus.js

@@ -1,6 +0,0 @@
-import Vue from 'vue';
-
-// 使用 Event Bus
-const bus = new Vue();
-
-export default bus;

+ 0 - 80
src/components/common/directives.js

@@ -1,80 +0,0 @@
-import Vue from 'vue';
-
-// v-dialogDrag: 弹窗拖拽属性
-Vue.directive('dialogDrag', {
-    bind(el, binding, vnode, oldVnode) {
-        const dialogHeaderEl = el.querySelector('.el-dialog__header');
-        const dragDom = el.querySelector('.el-dialog');
-
-        dialogHeaderEl.style.cssText += ';cursor:move;'
-        dragDom.style.cssText += ';top:0px;'
-
-        // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
-        const sty = (() => {
-            if (window.document.currentStyle) {
-                return (dom, attr) => dom.currentStyle[attr];
-            } else {
-                return (dom, attr) => getComputedStyle(dom, false)[attr];
-            }
-        })()
-
-        dialogHeaderEl.onmousedown = (e) => {
-            // 鼠标按下,计算当前元素距离可视区的距离
-            const disX = e.clientX - dialogHeaderEl.offsetLeft;
-            const disY = e.clientY - dialogHeaderEl.offsetTop;
-
-            const screenWidth = document.body.clientWidth; // body当前宽度
-            const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) 
-
-            const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
-            const dragDomheight = dragDom.offsetHeight; // 对话框高度
-
-            const minDragDomLeft = dragDom.offsetLeft;
-            const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
-
-            const minDragDomTop = dragDom.offsetTop;
-            const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
-
-
-            // 获取到的值带px 正则匹配替换
-            let styL = sty(dragDom, 'left');
-            let styT = sty(dragDom, 'top');
-
-            // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
-            if (styL.includes('%')) {
-                styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
-                styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
-            } else {
-                styL = +styL.replace(/\px/g, '');
-                styT = +styT.replace(/\px/g, '');
-            };
-
-            document.onmousemove = function (e) {
-                // 通过事件委托,计算移动的距离 
-                let left = e.clientX - disX;
-                let top = e.clientY - disY;
-
-                // 边界处理
-                if (-(left) > minDragDomLeft) {
-                    left = -(minDragDomLeft);
-                } else if (left > maxDragDomLeft) {
-                    left = maxDragDomLeft;
-                }
-
-                if (-(top) > minDragDomTop) {
-                    top = -(minDragDomTop);
-                } else if (top > maxDragDomTop) {
-                    top = maxDragDomTop;
-                }
-
-                // 移动当前元素  
-                dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
-            };
-
-            document.onmouseup = function (e) {
-                document.onmousemove = null;
-                document.onmouseup = null;
-            };
-        }
-    }
-})

+ 0 - 36
src/components/page/DragDialog.vue

@@ -1,36 +0,0 @@
-<template>
-    <section class="main">
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-rank"></i> 拖拽组件</el-breadcrumb-item>
-                <el-breadcrumb-item>拖拽弹框</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <p>通过指令 v-dialogDrag 使 Dialog 对话框具有可拖拽的功能。</p>
-            <br>
-            <el-button type="primary" @click="visible = true;">点我弹框</el-button>
-        </div>
-        <el-dialog v-dialogDrag title="拖拽弹框" center :visible.sync="visible" width="30%">
-            我是一个可以拖拽的对话框!
-            <span slot="footer" class="dialog-footer">
-                <el-button @click="visible = false">取 消</el-button>
-                <el-button type="primary" @click="visible = false">确 定</el-button>
-            </span>
-        </el-dialog>
-    </section>
-</template>
-
-<script>
-export default {
-    data(){
-        return {
-            visible: false
-        }
-    }
-}
-</script>
-
-<style>
-
-</style>

+ 0 - 174
src/components/page/DragList.vue

@@ -1,174 +0,0 @@
-<template>
-    <section class="main">
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-rank"></i> 拖拽组件</el-breadcrumb-item>
-                <el-breadcrumb-item>拖拽排序</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="plugins-tips">
-                Vue.Draggable:基于 Sortable.js 的 Vue 拖拽组件。
-                访问地址:<a href="https://github.com/SortableJS/Vue.Draggable" target="_blank">Vue.Draggable</a>
-            </div>
-            <div class="drag-box">
-                <div class="drag-box-item">
-                    <div class="item-title">todo</div>
-                    <draggable v-model="todo" @remove="removeHandle" :options="dragOptions">
-                        <transition-group tag="div" id="todo" class="item-ul">
-                            <div v-for="item in todo" class="drag-list" :key="item.id">
-                                {{item.content}}
-                            </div>
-                        </transition-group>
-                    </draggable>
-                </div>
-                <div class="drag-box-item">
-                    <div class="item-title">doing</div>
-                    <draggable v-model="doing" @remove="removeHandle" :options="dragOptions">
-                        <transition-group tag="div" id="doing" class="item-ul">
-                            <div v-for="item in doing" class="drag-list" :key="item.id">
-                                {{item.content}}
-                            </div>
-                        </transition-group>
-                    </draggable>
-                </div>
-                <div class="drag-box-item">
-                    <div class="item-title">done</div>
-                    <draggable v-model="done" @remove="removeHandle" :options="dragOptions">
-                        <transition-group tag="div" id="done" class="item-ul">
-                            <div v-for="item in done" class="drag-list" :key="item.id">
-                                {{item.content}}
-                            </div>
-                        </transition-group>
-                    </draggable>
-                </div>
-            </div>
-        </div>
-    </section>
-</template>
-
-<script>
-    import draggable from 'vuedraggable'
-    export default {
-        name: 'draglist',
-        data() {
-            return {
-                dragOptions:{
-                    animation: 120,
-                    scroll: true,
-                    group: 'sortlist',
-                    ghostClass: 'ghost-style'
-                },
-                todo: [
-                    {
-                        id: 1,
-                        content: '开发图表组件'
-                    },
-                    {
-                        id: 2,
-                        content: '开发拖拽组件'
-                    },
-                    {
-                        id: 3,
-                        content: '开发权限测试组件'
-                    }
-                ],
-                doing: [
-                    {
-                        id: 1,
-                        content: '开发登录注册页面'
-                    },
-                    {
-                        id: 2,
-                        content: '开发头部组件'
-                    },
-                    {
-                        id: 3,
-                        content: '开发表格相关组件'
-                    },
-                    {
-                        id: 4,
-                        content: '开发表单相关组件'
-                    }
-                ],
-                done:[
-                    {
-                        id: 1,
-                        content: '初始化项目,生成工程目录,完成相关配置'
-                    },
-                    {
-                        id: 2,
-                        content: '开发项目整体框架'
-                    }
-                ]
-            }
-        },
-        components:{
-            draggable
-        },
-        methods: {
-            removeHandle(event){
-                console.log(event);
-                this.$message.success(`从 ${event.from.id} 移动到 ${event.to.id} `);
-            }
-        }
-    }
-
-</script>
-
-<style scoped>
-    .drag-box{
-        display: flex;
-        user-select: none;
-    }
-    .drag-box-item {
-        flex: 1;
-        max-width: 330px;
-        min-width: 300px;
-        background-color: #eff1f5;
-        margin-right: 16px;
-        border-radius: 6px;
-        border: 1px #e1e4e8 solid;
-    }
-    .item-title{
-        padding: 8px 8px 8px 12px;
-        font-size: 14px;
-        line-height: 1.5;
-        color: #24292e;
-        font-weight: 600;
-    }
-    .item-ul{
-        padding: 0 8px 8px;
-        height: 500px;
-        overflow-y: scroll;
-    }
-    .item-ul::-webkit-scrollbar{
-        width: 0;
-    }
-    .drag-list {
-        border: 1px #e1e4e8 solid;
-        padding: 10px;
-        margin: 5px 0 10px;
-        list-style: none;
-        background-color: #fff;
-        border-radius: 6px;
-        cursor: pointer;
-        -webkit-transition: border .3s ease-in;
-        transition: border .3s ease-in;
-    }
-    .drag-list:hover {
-        border: 1px solid #20a0ff;
-    }
-    .drag-title {
-        font-weight: 400;
-        line-height: 25px;
-        margin: 10px 0;
-        font-size: 22px;
-        color: #1f2f3d;
-    }
-    .ghost-style{
-        display: block;
-        color: transparent;
-        border-style: dashed
-    }
-</style>

+ 0 - 67
src/components/page/Markdown.vue

@@ -1,67 +0,0 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-lx-calendar"></i> 表单</el-breadcrumb-item>
-                <el-breadcrumb-item>markdown编辑器</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="plugins-tips">
-                mavonEditor:基于Vue的markdown编辑器。
-                访问地址:<a href="https://github.com/hinesboy/mavonEditor" target="_blank">mavonEditor</a>
-            </div>
-            <mavon-editor v-model="content" ref="md" @imgAdd="$imgAdd" @change="change" style="min-height: 600px"/>
-            <el-button class="editor-btn" type="primary" @click="submit">提交</el-button>
-        </div>
-    </div>
-</template>
-
-<script>
-    import { mavonEditor } from 'mavon-editor'
-    import 'mavon-editor/dist/css/index.css'
-    export default {
-        name: 'markdown',
-        data: function(){
-            return {
-                content:'',
-                html:'',
-                configs: {
-                }
-            }
-        },
-        components: {
-            mavonEditor
-        },
-        methods: {
-            // 将图片上传到服务器,返回地址替换到md中
-            $imgAdd(pos, $file){
-                var formdata = new FormData();
-                formdata.append('file', $file);
-                // 这里没有服务器供大家尝试,可将下面上传接口替换为你自己的服务器接口
-                this.$axios({
-                    url: '/common/upload',
-                    method: 'post',
-                    data: formdata,
-                    headers: { 'Content-Type': 'multipart/form-data' },
-                }).then((url) => {
-                    this.$refs.md.$img2Url(pos, url);
-                })
-            },
-            change(value, render){
-                // render 为 markdown 解析后的结果
-                this.html = render;
-            },
-            submit(){
-                console.log(this.content);
-                console.log(this.html);
-                this.$message.success('提交成功!');
-            }
-        }
-    }
-</script>
-<style scoped>
-    .editor-btn{
-        margin-top: 20px;
-    }
-</style>

+ 0 - 141
src/components/page/Upload.vue

@@ -1,141 +0,0 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-lx-calendar"></i> 表单</el-breadcrumb-item>
-                <el-breadcrumb-item>图片上传</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="content-title">支持拖拽</div>
-            <div class="plugins-tips">
-                Element UI自带上传组件。
-                访问地址:<a href="http://element.eleme.io/#/zh-CN/component/upload" target="_blank">Element UI Upload</a>
-            </div>
-            <el-upload
-                class="upload-demo"
-                drag
-                action="http://jsonplaceholder.typicode.com/api/posts/"
-                multiple>
-                <i class="el-icon-upload"></i>
-                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
-                <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
-            </el-upload>
-            <div class="content-title">支持裁剪</div>
-            <div class="plugins-tips">
-                vue-cropperjs:一个封装了 cropperjs 的 Vue 组件。
-                访问地址:<a href="https://github.com/Agontuk/vue-cropperjs" target="_blank">vue-cropperjs</a>
-            </div>
-            <div class="crop-demo">
-                <img :src="cropImg" class="pre-img">
-                <div class="crop-demo-btn">选择图片
-                    <input class="crop-input" type="file" name="image" accept="image/*" @change="setImage"/>
-                </div>
-            </div>
-        
-            <el-dialog title="裁剪图片" :visible.sync="dialogVisible" width="30%">
-                <vue-cropper ref='cropper' :src="imgSrc" :ready="cropImage" :zoom="cropImage" :cropmove="cropImage" style="width:100%;height:300px;"></vue-cropper>
-                <span slot="footer" class="dialog-footer">
-                    <el-button @click="cancelCrop">取 消</el-button>
-                    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
-                </span>
-            </el-dialog>
-        </div>
-    </div>
-</template>
-
-<script>
-    import VueCropper  from 'vue-cropperjs';
-    export default {
-        name: 'upload',
-        data: function(){
-            return {
-                defaultSrc: require('../../assets/img/img.jpg'),
-                fileList: [],
-                imgSrc: '',
-                cropImg: '',
-                dialogVisible: false,
-            }
-        },
-        components: {
-            VueCropper
-        },
-        methods:{
-            setImage(e){
-                const file = e.target.files[0];
-                if (!file.type.includes('image/')) {
-                    return;
-                }
-                const reader = new FileReader();
-                reader.onload = (event) => {
-                    this.dialogVisible = true;
-                    this.imgSrc = event.target.result;
-                    this.$refs.cropper && this.$refs.cropper.replace(event.target.result);
-                };
-                reader.readAsDataURL(file);
-            },
-            cropImage () {
-                this.cropImg = this.$refs.cropper.getCroppedCanvas().toDataURL();
-            },
-            cancelCrop(){
-                this.dialogVisible = false;
-                this.cropImg = this.defaultSrc;
-            },
-            imageuploaded(res) {
-                console.log(res)
-            },
-            handleError(){
-                this.$notify.error({
-                    title: '上传失败',
-                    message: '图片上传接口上传失败,可更改为自己的服务器接口'
-                });
-            }
-        },
-        created(){
-            this.cropImg = this.defaultSrc;
-        }
-    }
-</script>
-
-<style scoped>
-    .content-title{
-        font-weight: 400;
-        line-height: 50px;
-        margin: 10px 0;
-        font-size: 22px;
-        color: #1f2f3d;
-    }
-    .pre-img{   
-        width: 100px;
-        height: 100px;
-        background: #f8f8f8;
-        border: 1px solid #eee;
-        border-radius: 5px;
-    }
-    .crop-demo{
-        display: flex;
-        align-items: flex-end;
-    }
-    .crop-demo-btn{
-        position: relative;
-        width: 100px;
-        height: 40px;
-        line-height: 40px;
-        padding: 0 20px;
-        margin-left: 30px;
-        background-color: #409eff;
-        color: #fff;
-        font-size: 14px;
-        border-radius: 4px;
-        box-sizing: border-box;
-    }
-    .crop-input{
-        position: absolute;
-        width: 100px;
-        height: 40px;
-        left: 0;
-        top: 0;
-        opacity: 0;
-        cursor: pointer;
-    }
-</style>

+ 0 - 53
src/components/page/VueEditor.vue

@@ -1,53 +0,0 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-lx-calendar"></i> 表单</el-breadcrumb-item>
-                <el-breadcrumb-item>编辑器</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="plugins-tips">
-                Vue-Quill-Editor:基于Quill、适用于Vue2的富文本编辑器。
-                访问地址:<a href="https://github.com/surmon-china/vue-quill-editor" target="_blank">vue-quill-editor</a>
-            </div>
-            <quill-editor ref="myTextEditor" v-model="content" :options="editorOption"></quill-editor>
-            <el-button class="editor-btn" type="primary" @click="submit">提交</el-button>
-        </div>
-    </div>
-</template>
-
-<script>
-    import 'quill/dist/quill.core.css';
-    import 'quill/dist/quill.snow.css';
-    import 'quill/dist/quill.bubble.css';
-    import { quillEditor } from 'vue-quill-editor';
-    export default {
-        name: 'editor',
-        data: function(){
-            return {
-                content: '',
-                editorOption: {
-                    placeholder: 'Hello World'
-                }
-            }
-        },
-        components: {
-            quillEditor
-        },
-        methods: {
-            onEditorChange({ editor, html, text }) {
-                this.content = html;
-            },
-            submit(){
-                console.log(this.content);
-                this.$message.success('提交成功!');
-            }
-        }
-    }
-</script>
-<style scoped>
-    .editor-btn{
-        margin-top: 20px;
-    }
-</style>

+ 12 - 48
src/main.js

@@ -1,48 +1,12 @@
-import Vue from 'vue';
-import App from './App.vue';
-import router from './router';
-import ElementUI from 'element-ui';
-import VueI18n from 'vue-i18n';
-import { messages } from './components/common/i18n';
-import 'element-ui/lib/theme-chalk/index.css'; // 默认主题
-// import './assets/css/theme-green/index.css'; // 浅绿色主题
-import './assets/css/icon.css';
-import './components/common/directives';
-import 'babel-polyfill';
-
-Vue.config.productionTip = false;
-Vue.use(VueI18n);
-Vue.use(ElementUI, {
-    size: 'small'
-});
-const i18n = new VueI18n({
-    locale: 'zh',
-    messages
-});
-
-//使用钩子函数对路由进行权限跳转
-router.beforeEach((to, from, next) => {
-    document.title = `${to.meta.title} | vue-manage-system`;
-    const role = localStorage.getItem('ms_username');
-    if (!role && to.path !== '/login') {
-        next('/login');
-    } else if (to.meta.permission) {
-        // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
-        role === 'admin' ? next() : next('/403');
-    } else {
-        // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
-        if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') {
-            Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', {
-                confirmButtonText: '确定'
-            });
-        } else {
-            next();
-        }
-    }
-});
-
-new Vue({
-    router,
-    i18n,
-    render: h => h(App)
-}).$mount('#app');
+import {createApp} from 'vue'
+import App from './App.vue'
+import router from './router'
+import store from './store'
+import installElementPlus from './plugins/element'
+import './assets/css/icon.css'
+const app = createApp(App)
+installElementPlus(app)
+app
+    .use(store)
+    .use(router)
+    .mount('#app')

+ 29 - 0
src/plugins/element.js

@@ -0,0 +1,29 @@
+import ElementPlus from 'element-plus'
+import { createI18n } from 'vue-i18n'
+import 'element-plus/lib/theme-chalk/index.css'
+import localeZH from 'element-plus/lib/locale/lang/zh-cn'
+import localeEN from 'element-plus/lib/locale/lang/en'
+import messages from '../utils/i18n'
+// console.log(msg)
+
+// const messages = {
+//   [localeEN.name]: {
+//     el: localeEN.el,
+//     i18n: msg.en.i18n,
+//   },
+//   [localeZH.name]: {
+//     el: localeZH.el,
+//     i18n: msg.zh.i18n,
+//   },
+// }
+
+const i18n = createI18n({
+  locale: localeZH.name,
+  fallbackLocale: localeEN.name,
+  messages,
+})
+
+export default (app) => {
+  app.use(ElementPlus, { locale:localeZH })
+  app.use(i18n)
+}

+ 154 - 117
src/router/index.js

@@ -1,117 +1,154 @@
-import Vue from 'vue';
-import Router from 'vue-router';
-
-Vue.use(Router);
-
-export default new Router({
-    routes: [
-        {
-            path: '/',
-            redirect: '/dashboard'
-        },
-        {
-            path: '/',
-            component: () => import(/* webpackChunkName: "home" */ '../components/common/Home.vue'),
-            meta: { title: '自述文件' },
-            children: [
-                {
-                    path: '/dashboard',
-                    component: () => import(/* webpackChunkName: "dashboard" */ '../components/page/Dashboard.vue'),
-                    meta: { title: '系统首页' }
-                },
-                {
-                    path: '/icon',
-                    component: () => import(/* webpackChunkName: "icon" */ '../components/page/Icon.vue'),
-                    meta: { title: '自定义图标' }
-                },
-                {
-                    path: '/table',
-                    component: () => import(/* webpackChunkName: "table" */ '../components/page/BaseTable.vue'),
-                    meta: { title: '基础表格' }
-                },
-                {
-                    path: '/tabs',
-                    component: () => import(/* webpackChunkName: "tabs" */ '../components/page/Tabs.vue'),
-                    meta: { title: 'tab选项卡' }
-                },
-                {
-                    path: '/form',
-                    component: () => import(/* webpackChunkName: "form" */ '../components/page/BaseForm.vue'),
-                    meta: { title: '基本表单' }
-                },
-                {
-                    // 富文本编辑器组件
-                    path: '/editor',
-                    component: () => import(/* webpackChunkName: "editor" */ '../components/page/VueEditor.vue'),
-                    meta: { title: '富文本编辑器' }
-                },
-                {
-                    // markdown组件
-                    path: '/markdown',
-                    component: () => import(/* webpackChunkName: "markdown" */ '../components/page/Markdown.vue'),
-                    meta: { title: 'markdown编辑器' }
-                },
-                {
-                    // 图片上传组件
-                    path: '/upload',
-                    component: () => import(/* webpackChunkName: "upload" */ '../components/page/Upload.vue'),
-                    meta: { title: '文件上传' }
-                },
-                {
-                    // vue-schart组件
-                    path: '/charts',
-                    component: () => import(/* webpackChunkName: "chart" */ '../components/page/BaseCharts.vue'),
-                    meta: { title: 'schart图表' }
-                },
-                {
-                    // 拖拽列表组件
-                    path: '/drag',
-                    component: () => import(/* webpackChunkName: "drag" */ '../components/page/DragList.vue'),
-                    meta: { title: '拖拽列表' }
-                },
-                {
-                    // 拖拽Dialog组件
-                    path: '/dialog',
-                    component: () => import(/* webpackChunkName: "dragdialog" */ '../components/page/DragDialog.vue'),
-                    meta: { title: '拖拽弹框' }
-                },
-                {
-                    // 国际化组件
-                    path: '/i18n',
-                    component: () => import(/* webpackChunkName: "i18n" */ '../components/page/I18n.vue'),
-                    meta: { title: '国际化' }
-                },
-                {
-                    // 权限页面
-                    path: '/permission',
-                    component: () => import(/* webpackChunkName: "permission" */ '../components/page/Permission.vue'),
-                    meta: { title: '权限测试', permission: true }
-                },
-                {
-                    path: '/404',
-                    component: () => import(/* webpackChunkName: "404" */ '../components/page/404.vue'),
-                    meta: { title: '404' }
-                },
-                {
-                    path: '/403',
-                    component: () => import(/* webpackChunkName: "403" */ '../components/page/403.vue'),
-                    meta: { title: '403' }
-                },
-                {
-                    path: '/donate',
-                    component: () => import(/* webpackChunkName: "donate" */ '../components/page/Donate.vue'),
-                    meta: { title: '支持作者' }
-                }
-            ]
-        },
-        {
-            path: '/login',
-            component: () => import(/* webpackChunkName: "login" */ '../components/page/Login.vue'),
-            meta: { title: '登录' }
-        },
-        {
-            path: '*',
-            redirect: '/404'
-        }
-    ]
-});
+import {createRouter, createWebHistory} from "vue-router";
+import Home from "../views/Home.vue";
+
+const routes = [
+    {
+        path: '/',
+        redirect: '/dashboard'
+    }, {
+        path: "/",
+        name: "Home",
+        component: Home,
+        children: [
+            {
+                path: "/dashboard",
+                name: "Dashboard",
+                meta: {
+                    title: '系统首页'
+                },
+                component: () => import (
+                /* webpackChunkName: "dashboard" */
+                "../views/Dashboard.vue")
+            }, {
+                path: "/table",
+                name: "BaseTable",
+                meta: {
+                    title: '表格'
+                },
+                component: () => import (
+                /* webpackChunkName: "table" */
+                "../views/BaseTable.vue")
+            }, {
+                path: "/charts",
+                name: "BaseCharts",
+                meta: {
+                    title: '图表'
+                },
+                component: () => import (
+                /* webpackChunkName: "charts" */
+                "../views/BaseCharts.vue")
+            }, {
+                path: "/form",
+                name: "BaseForm",
+                meta: {
+                    title: '表单'
+                },
+                component: () => import (
+                /* webpackChunkName: "form" */
+                "../views/BaseForm.vue")
+            }, {
+                path: "/tabs",
+                name: "Tabs",
+                meta: {
+                    title: 'tab标签'
+                },
+                component: () => import (
+                /* webpackChunkName: "tabs" */
+                "../views/Tabs.vue")
+            }, {
+                path: "/donate",
+                name: "Donate",
+                meta: {
+                    title: '鼓励作者'
+                },
+                component: () => import (
+                /* webpackChunkName: "donate" */
+                "../views/Donate.vue")
+            }, {
+                path: "/permission",
+                name: "Permission",
+                meta: {
+                    title: '权限管理',
+                    permission: true
+                },
+                component: () => import (
+                /* webpackChunkName: "permission" */
+                "../views/Permission.vue")
+            }, {
+                path: "/i18n",
+                name: "I18n",
+                meta: {
+                    title: '国际化语言'
+                },
+                component: () => import (
+                /* webpackChunkName: "i18n" */
+                "../views/I18n.vue")
+            }, {
+                path: "/upload",
+                name: "Upload",
+                meta: {
+                    title: '上传插件'
+                },
+                component: () => import (
+                /* webpackChunkName: "upload" */
+                "../views/Upload.vue")
+            }, {
+                path: "/icon",
+                name: "Icon",
+                meta: {
+                    title: '自定义图标'
+                },
+                component: () => import (
+                /* webpackChunkName: "icon" */
+                "../views/Icon.vue")
+            }, {
+                path: '/404',
+                name: '404',
+                meta: {
+                    title: '找不到页面'
+                },
+                component: () => import (/* webpackChunkName: "404" */
+                '../views/404.vue')
+            }, {
+                path: '/403',
+                name: '403',
+                meta: {
+                    title: '没有权限'
+                },
+                component: () => import (/* webpackChunkName: "403" */
+                '../views/403.vue')
+            }
+        ]
+    }, {
+        path: "/login",
+        name: "Login",
+        meta: {
+            title: '登录'
+        },
+        component: () => import (
+        /* webpackChunkName: "login" */
+        "../views/Login.vue")
+    }
+];
+
+const router = createRouter({
+    history: createWebHistory(process.env.BASE_URL),
+    routes
+});
+
+router.beforeEach((to, from, next) => {
+    document.title = `${to.meta.title} | vue-manage-system`;
+    const role = localStorage.getItem('ms_username');
+    if (!role && to.path !== '/login') {
+        next('/login');
+    } else if (to.meta.permission) {
+        // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
+        role === 'admin'
+            ? next()
+            : next('/403');
+    } else {
+        next();
+    }
+});
+
+export default router;

+ 56 - 0
src/store/index.js

@@ -0,0 +1,56 @@
+import {createStore} from 'vuex'
+
+export default createStore({
+    state: {
+        tagsList: [],
+        collapse: false
+    },
+    mutations: {
+        delTagsItem(state, data) {
+            state
+                .tagsList
+                .splice(data.index, 1);
+        },
+        setTagsItem(state, data) {
+            state
+                .tagsList
+                .push(data)
+        },
+        clearTags(state) {
+            state.tagsList = []
+        },
+        closeTagsOther(state, data) {
+            state.tagsList = data;
+        },
+        closeCurrentTag(state, data) {
+            for (let i = 0, len = state.tagsList.length; i < len; i++) {
+                const item = state.tagsList[i];
+                if (item.path === data.$route.fullPath) {
+                    if (i < len - 1) {
+                        data
+                            .$router
+                            .push(state.tagsList[i + 1].path);
+                    } else if (i > 0) {
+                        data
+                            .$router
+                            .push(state.tagsList[i - 1].path);
+                    } else {
+                        data
+                            .$router
+                            .push("/");
+                    }
+                    state
+                        .tagsList
+                        .splice(i, 1);
+                    break;
+                }
+            }
+        },
+        // 侧边栏折叠
+        hadndleCollapse(state, data) {
+            state.collapse = data;
+        }
+    },
+    actions: {},
+    modules: {}
+})

+ 4 - 10
src/components/common/i18n.js → src/utils/i18n.js

@@ -1,5 +1,5 @@
-export const messages = {
-    'zh': {
+export default {
+    'zh-cn': {
         i18n: {
             breadcrumb: '国际化产品',
             tips: '通过切换语言按钮,来改变当前内容的语言。',
@@ -7,10 +7,7 @@ export const messages = {
             title1: '常用用法',
             p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。',
             p2: '没有什么比信念更能支撑我们度过艰难的时光了。',
-            p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。',
-            title2: '组件插值',
-            info: 'Element组件需要国际化,请参考 {action}。',
-            value: '文档'
+            p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。'
         }
     },
     'en': {
@@ -21,10 +18,7 @@ export const messages = {
             title1: 'Common usage',
             p1: "If you reveal your secrets to the wind you should not blame the wind for  revealing them to the trees.",
             p2: "Nothing can help us endure dark times better than our faith. ",
-            p3: "If you can do what you do best and be happy, you're further along in life  than most people.",
-            title2: 'Component interpolation',
-            info: 'The default language of Element is Chinese. If you wish to use another language, please refer to the {action}.',
-            value: 'documentation'
+            p3: "If you can do what you do best and be happy, you're further along in life  than most people."
         }
     }
 }

+ 56 - 56
src/components/page/403.vue → src/views/403.vue

@@ -1,56 +1,56 @@
-<template>
-  <div class="error-page">
-      <div class="error-code">4<span>0</span>3</div>
-      <div class="error-desc">啊哦~ 你没有权限访问该页面哦</div>
-      <div class="error-handle">
-          <router-link to="/">
-            <el-button type="primary" size="large">返回首页</el-button>
-          </router-link>
-          <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
-      </div>
-  </div>
-</template>
-
-<script>
-export default {
-  methods: {
-      goBack(){
-          this.$router.go(-1);
-      }
-  }
-}
-</script>
-
-
-<style scoped>
-    .error-page{
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        flex-direction: column;
-        width: 100%;
-        height: 100%;
-        background: #f3f3f3;
-        box-sizing: border-box;
-    }
-    .error-code{
-        line-height: 1;
-        font-size: 250px;
-        font-weight: bolder;
-        color: #f02d2d;
-    }
-    .error-code span{
-        color: #00a854;
-    }
-    .error-desc{
-        font-size: 30px;
-        color: #777;
-    }
-    .error-handle{
-        margin-top: 30px;
-        padding-bottom: 200px;
-    }
-    .error-btn{
-        margin-left: 100px;
-    }
-</style>
+<template>
+  <div class="error-page">
+      <div class="error-code">4<span>0</span>3</div>
+      <div class="error-desc">啊哦~ 你没有权限访问该页面哦</div>
+      <div class="error-handle">
+          <router-link to="/">
+            <el-button type="primary" size="large">返回首页</el-button>
+          </router-link>
+          <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
+      </div>
+  </div>
+</template>
+
+<script>
+export default {
+  methods: {
+      goBack(){
+          this.$router.go(-1);
+      }
+  }
+}
+</script>
+
+
+<style scoped>
+    .error-page{
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-direction: column;
+        width: 100%;
+        height: 100%;
+        background: #f3f3f3;
+        box-sizing: border-box;
+    }
+    .error-code{
+        line-height: 1;
+        font-size: 250px;
+        font-weight: bolder;
+        color: #f02d2d;
+    }
+    .error-code span{
+        color: #00a854;
+    }
+    .error-desc{
+        font-size: 30px;
+        color: #777;
+    }
+    .error-handle{
+        margin-top: 30px;
+        padding-bottom: 200px;
+    }
+    .error-btn{
+        margin-left: 100px;
+    }
+</style>

+ 56 - 56
src/components/page/404.vue → src/views/404.vue

@@ -1,56 +1,56 @@
-<template>
-  <div class="error-page">
-      <div class="error-code">4<span>0</span>4</div>
-      <div class="error-desc">啊哦~ 你所访问的页面不存在</div>
-      <div class="error-handle">
-          <router-link to="/">
-            <el-button type="primary" size="large">返回首页</el-button>
-          </router-link>
-          <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
-      </div>
-  </div>
-</template>
-
-<script>
-export default {
-  methods: {
-      goBack(){
-          this.$router.go(-1);
-      }
-  }
-}
-</script>
-
-
-<style scoped>
-    .error-page{
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        flex-direction: column;
-        width: 100%;
-        height: 100%;
-        background: #f3f3f3;
-        box-sizing: border-box;
-    }
-    .error-code{
-        line-height: 1;
-        font-size: 250px;
-        font-weight: bolder;
-        color: #2d8cf0;
-    }
-    .error-code span{
-        color: #00a854;
-    }
-    .error-desc{
-        font-size: 30px;
-        color: #777;
-    }
-    .error-handle{
-        margin-top: 30px;
-        padding-bottom: 200px;
-    }
-    .error-btn{
-        margin-left: 100px;
-    }
-</style>
+<template>
+  <div class="error-page">
+      <div class="error-code">4<span>0</span>4</div>
+      <div class="error-desc">啊哦~ 你所访问的页面不存在</div>
+      <div class="error-handle">
+          <router-link to="/">
+            <el-button type="primary" size="large">返回首页</el-button>
+          </router-link>
+          <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button>
+      </div>
+  </div>
+</template>
+
+<script>
+export default {
+  methods: {
+      goBack(){
+          this.$router.go(-1);
+      }
+  }
+}
+</script>
+
+
+<style scoped>
+    .error-page{
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-direction: column;
+        width: 100%;
+        height: 100%;
+        background: #f3f3f3;
+        box-sizing: border-box;
+    }
+    .error-code{
+        line-height: 1;
+        font-size: 250px;
+        font-weight: bolder;
+        color: #2d8cf0;
+    }
+    .error-code span{
+        color: #00a854;
+    }
+    .error-desc{
+        font-size: 30px;
+        color: #777;
+    }
+    .error-handle{
+        margin-top: 30px;
+        padding-bottom: 200px;
+    }
+    .error-btn{
+        margin-left: 100px;
+    }
+</style>

+ 5 - 0
src/views/About.vue

@@ -0,0 +1,5 @@
+<template>
+  <div class="about">
+    <h1>This is an about page</h1>
+  </div>
+</template>

+ 148 - 148
src/components/page/BaseCharts.vue → src/views/BaseCharts.vue

@@ -1,149 +1,149 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item>
-                    <i class="el-icon-pie-chart"></i> schart图表
-                </el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="plugins-tips">
-                vue-schart:vue.js封装sChart.js的图表组件。
-                访问地址:
-                <a
-                    href="https://github.com/lin-xin/vue-schart"
-                    target="_blank"
-                >vue-schart</a>
-            </div>
-            <div class="schart-box">
-                <div class="content-title">柱状图</div>
-                <schart class="schart" canvasId="bar" :options="options1"></schart>
-            </div>
-            <div class="schart-box">
-                <div class="content-title">折线图</div>
-                <schart class="schart" canvasId="line" :options="options2"></schart>
-            </div>
-            <div class="schart-box">
-                <div class="content-title">饼状图</div>
-                <schart class="schart" canvasId="pie" :options="options3"></schart>
-            </div>
-            <div class="schart-box">
-                <div class="content-title">环形图</div>
-                <schart class="schart" canvasId="ring" :options="options4"></schart>
-            </div>
-        </div>
-    </div>
-</template>
-
-<script>
-import Schart from 'vue-schart';
-export default {
-    name: 'basecharts',
-    components: {
-        Schart
-    },
-    data() {
-        return {
-            options1: {
-                type: 'bar',
-                title: {
-                    text: '最近一周各品类销售图'
-                },
-                bgColor: '#fbfbfb',
-                labels: ['周一', '周二', '周三', '周四', '周五'],
-                datasets: [
-                    {
-                        label: '家电',
-                        fillColor: 'rgba(241, 49, 74, 0.5)',
-                        data: [234, 278, 270, 190, 230]
-                    },
-                    {
-                        label: '百货',
-                        data: [164, 178, 190, 135, 160]
-                    },
-                    {
-                        label: '食品',
-                        data: [144, 198, 150, 235, 120]
-                    }
-                ]
-            },
-            options2: {
-                type: 'line',
-                title: {
-                    text: '最近几个月各品类销售趋势图'
-                },
-                bgColor: '#fbfbfb',
-                labels: ['6月', '7月', '8月', '9月', '10月'],
-                datasets: [
-                    {
-                        label: '家电',
-                        data: [234, 278, 270, 190, 230]
-                    },
-                    {
-                        label: '百货',
-                        data: [164, 178, 150, 135, 160]
-                    },
-                    {
-                        label: '食品',
-                        data: [114, 138, 200, 235, 190]
-                    }
-                ]
-            },
-            options3: {
-                type: 'pie',
-                title: {
-                    text: '服装品类销售饼状图'
-                },
-                legend: {
-                    position: 'left'
-                },
-                bgColor: '#fbfbfb',
-                labels: ['T恤', '牛仔裤', '连衣裙', '毛衣', '七分裤', '短裙', '羽绒服'],
-                datasets: [
-                    {
-                        data: [334, 278, 190, 235, 260, 200, 141]
-                    }
-                ]
-            },
-            options4: {
-                type: 'ring',
-                title: {
-                    text: '环形三等分'
-                },
-                showValue: false,
-                legend: {
-                    position: 'bottom',
-                    bottom: 40
-                },
-                bgColor: '#fbfbfb',
-                labels: ['vue', 'react', 'angular'],
-                datasets: [
-                    {
-                        data: [500, 500, 500]
-                    }
-                ]
-            }
-        };
-    }
-};
-</script>
-
-<style scoped>
-.schart-box {
-    display: inline-block;
-    margin: 20px;
-}
-.schart {
-    width: 600px;
-    height: 400px;
-}
-.content-title {
-    clear: both;
-    font-weight: 400;
-    line-height: 50px;
-    margin: 10px 0;
-    font-size: 22px;
-    color: #1f2f3d;
-}
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-pie-chart"></i> schart图表
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="plugins-tips">
+                vue-schart:vue.js封装sChart.js的图表组件。
+                访问地址:
+                <a
+                    href="https://github.com/lin-xin/vue-schart"
+                    target="_blank"
+                >vue-schart</a>
+            </div>
+            <div class="schart-box">
+                <div class="content-title">柱状图</div>
+                <schart class="schart" canvasId="bar" :options="options1"></schart>
+            </div>
+            <div class="schart-box">
+                <div class="content-title">折线图</div>
+                <schart class="schart" canvasId="line" :options="options2"></schart>
+            </div>
+            <div class="schart-box">
+                <div class="content-title">饼状图</div>
+                <schart class="schart" canvasId="pie" :options="options3"></schart>
+            </div>
+            <div class="schart-box">
+                <div class="content-title">环形图</div>
+                <schart class="schart" canvasId="ring" :options="options4"></schart>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import Schart from 'vue-schart';
+export default {
+    name: 'basecharts',
+    components: {
+        Schart
+    },
+    data() {
+        return {
+            options1: {
+                type: 'bar',
+                title: {
+                    text: '最近一周各品类销售图'
+                },
+                bgColor: '#fbfbfb',
+                labels: ['周一', '周二', '周三', '周四', '周五'],
+                datasets: [
+                    {
+                        label: '家电',
+                        fillColor: 'rgba(241, 49, 74, 0.5)',
+                        data: [234, 278, 270, 190, 230]
+                    },
+                    {
+                        label: '百货',
+                        data: [164, 178, 190, 135, 160]
+                    },
+                    {
+                        label: '食品',
+                        data: [144, 198, 150, 235, 120]
+                    }
+                ]
+            },
+            options2: {
+                type: 'line',
+                title: {
+                    text: '最近几个月各品类销售趋势图'
+                },
+                bgColor: '#fbfbfb',
+                labels: ['6月', '7月', '8月', '9月', '10月'],
+                datasets: [
+                    {
+                        label: '家电',
+                        data: [234, 278, 270, 190, 230]
+                    },
+                    {
+                        label: '百货',
+                        data: [164, 178, 150, 135, 160]
+                    },
+                    {
+                        label: '食品',
+                        data: [114, 138, 200, 235, 190]
+                    }
+                ]
+            },
+            options3: {
+                type: 'pie',
+                title: {
+                    text: '服装品类销售饼状图'
+                },
+                legend: {
+                    position: 'left'
+                },
+                bgColor: '#fbfbfb',
+                labels: ['T恤', '牛仔裤', '连衣裙', '毛衣', '七分裤', '短裙', '羽绒服'],
+                datasets: [
+                    {
+                        data: [334, 278, 190, 235, 260, 200, 141]
+                    }
+                ]
+            },
+            options4: {
+                type: 'ring',
+                title: {
+                    text: '环形三等分'
+                },
+                showValue: false,
+                legend: {
+                    position: 'bottom',
+                    bottom: 40
+                },
+                bgColor: '#fbfbfb',
+                labels: ['vue', 'react', 'angular'],
+                datasets: [
+                    {
+                        data: [500, 500, 500]
+                    }
+                ]
+            }
+        };
+    }
+};
+</script>
+
+<style scoped>
+.schart-box {
+    display: inline-block;
+    margin: 20px;
+}
+.schart {
+    width: 600px;
+    height: 400px;
+}
+.content-title {
+    clear: both;
+    font-weight: 400;
+    line-height: 50px;
+    margin: 10px 0;
+    font-size: 22px;
+    color: #1f2f3d;
+}
 </style>

+ 150 - 151
src/components/page/BaseForm.vue → src/views/BaseForm.vue

@@ -1,152 +1,151 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item>
-                    <i class="el-icon-lx-calendar"></i> 表单
-                </el-breadcrumb-item>
-                <el-breadcrumb-item>基本表单</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="form-box">
-                <el-form ref="form" :model="form" label-width="80px">
-                    <el-form-item label="表单名称">
-                        <el-input v-model="form.name"></el-input>
-                    </el-form-item>
-                    <el-form-item label="选择器">
-                        <el-select v-model="form.region" placeholder="请选择">
-                            <el-option key="bbk" label="步步高" value="bbk"></el-option>
-                            <el-option key="xtc" label="小天才" value="xtc"></el-option>
-                            <el-option key="imoo" label="imoo" value="imoo"></el-option>
-                        </el-select>
-                    </el-form-item>
-                    <el-form-item label="日期时间">
-                        <el-col :span="11">
-                            <el-date-picker
-                                type="date"
-                                placeholder="选择日期"
-                                v-model="form.date1"
-                                value-format="yyyy-MM-dd"
-                                style="width: 100%;"
-                            ></el-date-picker>
-                        </el-col>
-                        <el-col class="line" :span="2">-</el-col>
-                        <el-col :span="11">
-                            <el-time-picker
-                                placeholder="选择时间"
-                                v-model="form.date2"
-                                style="width: 100%;"
-                            ></el-time-picker>
-                        </el-col>
-                    </el-form-item>
-                    <el-form-item label="城市级联">
-                        <el-cascader :options="options" v-model="form.options"></el-cascader>
-                    </el-form-item>
-                    <el-form-item label="选择开关">
-                        <el-switch v-model="form.delivery"></el-switch>
-                    </el-form-item>
-                    <el-form-item label="多选框">
-                        <el-checkbox-group v-model="form.type">
-                            <el-checkbox label="步步高" name="type"></el-checkbox>
-                            <el-checkbox label="小天才" name="type"></el-checkbox>
-                            <el-checkbox label="imoo" name="type"></el-checkbox>
-                        </el-checkbox-group>
-                    </el-form-item>
-                    <el-form-item label="单选框">
-                        <el-radio-group v-model="form.resource">
-                            <el-radio label="步步高"></el-radio>
-                            <el-radio label="小天才"></el-radio>
-                            <el-radio label="imoo"></el-radio>
-                        </el-radio-group>
-                    </el-form-item>
-                    <el-form-item label="文本框">
-                        <el-input type="textarea" rows="5" v-model="form.desc"></el-input>
-                    </el-form-item>
-                    <el-form-item>
-                        <el-button type="primary" @click="onSubmit">表单提交</el-button>
-                        <el-button>取消</el-button>
-                    </el-form-item>
-                </el-form>
-            </div>
-        </div>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'baseform',
-    data() {
-        return {
-            options: [
-                {
-                    value: 'guangdong',
-                    label: '广东省',
-                    children: [
-                        {
-                            value: 'guangzhou',
-                            label: '广州市',
-                            children: [
-                                {
-                                    value: 'tianhe',
-                                    label: '天河区'
-                                },
-                                {
-                                    value: 'haizhu',
-                                    label: '海珠区'
-                                }
-                            ]
-                        },
-                        {
-                            value: 'dongguan',
-                            label: '东莞市',
-                            children: [
-                                {
-                                    value: 'changan',
-                                    label: '长安镇'
-                                },
-                                {
-                                    value: 'humen',
-                                    label: '虎门镇'
-                                }
-                            ]
-                        }
-                    ]
-                },
-                {
-                    value: 'hunan',
-                    label: '湖南省',
-                    children: [
-                        {
-                            value: 'changsha',
-                            label: '长沙市',
-                            children: [
-                                {
-                                    value: 'yuelu',
-                                    label: '岳麓区'
-                                }
-                            ]
-                        }
-                    ]
-                }
-            ],
-            form: {
-                name: '',
-                region: '',
-                date1: '',
-                date2: '',
-                delivery: true,
-                type: ['步步高'],
-                resource: '小天才',
-                desc: '',
-                options: []
-            }
-        };
-    },
-    methods: {
-        onSubmit() {
-            this.$message.success('提交成功!');
-        }
-    }
-};
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-calendar"></i> 表单
+                </el-breadcrumb-item>
+                <el-breadcrumb-item>基本表单</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="form-box">
+                <el-form ref="form" :model="form" label-width="80px">
+                    <el-form-item label="表单名称">
+                        <el-input v-model="form.name"></el-input>
+                    </el-form-item>
+                    <el-form-item label="选择器">
+                        <el-select v-model="form.region" placeholder="请选择">
+                            <el-option key="bbk" label="步步高" value="bbk"></el-option>
+                            <el-option key="xtc" label="小天才" value="xtc"></el-option>
+                            <el-option key="imoo" label="imoo" value="imoo"></el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item label="日期时间">
+                        <el-col :span="11">
+                            <el-date-picker
+                                type="date"
+                                placeholder="选择日期"
+                                v-model="form.date1"
+                                style="width: 100%;"
+                            ></el-date-picker>
+                        </el-col>
+                        <el-col class="line" :span="2">-</el-col>
+                        <el-col :span="11">
+                            <el-time-picker
+                                placeholder="选择时间"
+                                v-model="form.date2"
+                                style="width: 100%;"
+                            ></el-time-picker>
+                        </el-col>
+                    </el-form-item>
+                    <el-form-item label="城市级联">
+                        <el-cascader :options="options" v-model="form.options"></el-cascader>
+                    </el-form-item>
+                    <el-form-item label="选择开关">
+                        <el-switch v-model="form.delivery"></el-switch>
+                    </el-form-item>
+                    <el-form-item label="多选框">
+                        <el-checkbox-group v-model="form.type">
+                            <el-checkbox label="步步高" name="type"></el-checkbox>
+                            <el-checkbox label="小天才" name="type"></el-checkbox>
+                            <el-checkbox label="imoo" name="type"></el-checkbox>
+                        </el-checkbox-group>
+                    </el-form-item>
+                    <el-form-item label="单选框">
+                        <el-radio-group v-model="form.resource">
+                            <el-radio label="步步高"></el-radio>
+                            <el-radio label="小天才"></el-radio>
+                            <el-radio label="imoo"></el-radio>
+                        </el-radio-group>
+                    </el-form-item>
+                    <el-form-item label="文本框">
+                        <el-input type="textarea" rows="5" v-model="form.desc"></el-input>
+                    </el-form-item>
+                    <el-form-item>
+                        <el-button type="primary" @click="onSubmit">表单提交</el-button>
+                        <el-button>取消</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'baseform',
+    data() {
+        return {
+            options: [
+                {
+                    value: 'guangdong',
+                    label: '广东省',
+                    children: [
+                        {
+                            value: 'guangzhou',
+                            label: '广州市',
+                            children: [
+                                {
+                                    value: 'tianhe',
+                                    label: '天河区'
+                                },
+                                {
+                                    value: 'haizhu',
+                                    label: '海珠区'
+                                }
+                            ]
+                        },
+                        {
+                            value: 'dongguan',
+                            label: '东莞市',
+                            children: [
+                                {
+                                    value: 'changan',
+                                    label: '长安镇'
+                                },
+                                {
+                                    value: 'humen',
+                                    label: '虎门镇'
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    value: 'hunan',
+                    label: '湖南省',
+                    children: [
+                        {
+                            value: 'changsha',
+                            label: '长沙市',
+                            children: [
+                                {
+                                    value: 'yuelu',
+                                    label: '岳麓区'
+                                }
+                            ]
+                        }
+                    ]
+                }
+            ],
+            form: {
+                name: '',
+                region: '',
+                date1: '',
+                date2: '',
+                delivery: true,
+                type: ['步步高'],
+                resource: '小天才',
+                desc: '',
+                options: []
+            }
+        };
+    },
+    methods: {
+        onSubmit() {
+            this.$message.success('提交成功!');
+        }
+    }
+};
 </script>

+ 264 - 219
src/components/page/BaseTable.vue → src/views/BaseTable.vue

@@ -1,219 +1,264 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item>
-                    <i class="el-icon-lx-cascades"></i> 基础表格
-                </el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <div class="handle-box">
-                <el-button
-                    type="primary"
-                    icon="el-icon-delete"
-                    class="handle-del mr10"
-                    @click="delAllSelection"
-                >批量删除</el-button>
-                <el-select v-model="query.address" placeholder="地址" class="handle-select mr10">
-                    <el-option key="1" label="广东省" value="广东省"></el-option>
-                    <el-option key="2" label="湖南省" value="湖南省"></el-option>
-                </el-select>
-                <el-input v-model="query.name" placeholder="用户名" class="handle-input mr10"></el-input>
-                <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
-            </div>
-            <el-table
-                :data="tableData"
-                border
-                class="table"
-                ref="multipleTable"
-                header-cell-class-name="table-header"
-                @selection-change="handleSelectionChange"
-            >
-                <el-table-column type="selection" width="55" align="center"></el-table-column>
-                <el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
-                <el-table-column prop="name" label="用户名"></el-table-column>
-                <el-table-column label="账户余额">
-                    <template slot-scope="scope">¥{{scope.row.money}}</template>
-                </el-table-column>
-                <el-table-column label="头像(查看大图)" align="center">
-                    <template slot-scope="scope">
-                        <el-image
-                            class="table-td-thumb"
-                            :src="scope.row.thumb"
-                            :preview-src-list="[scope.row.thumb]"
-                        ></el-image>
-                    </template>
-                </el-table-column>
-                <el-table-column prop="address" label="地址"></el-table-column>
-                <el-table-column label="状态" align="center">
-                    <template slot-scope="scope">
-                        <el-tag
-                            :type="scope.row.state==='成功'?'success':(scope.row.state==='失败'?'danger':'')"
-                        >{{scope.row.state}}</el-tag>
-                    </template>
-                </el-table-column>
-
-                <el-table-column prop="date" label="注册时间"></el-table-column>
-                <el-table-column label="操作" width="180" align="center">
-                    <template slot-scope="scope">
-                        <el-button
-                            type="text"
-                            icon="el-icon-edit"
-                            @click="handleEdit(scope.$index, scope.row)"
-                        >编辑</el-button>
-                        <el-button
-                            type="text"
-                            icon="el-icon-delete"
-                            class="red"
-                            @click="handleDelete(scope.$index, scope.row)"
-                        >删除</el-button>
-                    </template>
-                </el-table-column>
-            </el-table>
-            <div class="pagination">
-                <el-pagination
-                    background
-                    layout="total, prev, pager, next"
-                    :current-page="query.pageIndex"
-                    :page-size="query.pageSize"
-                    :total="pageTotal"
-                    @current-change="handlePageChange"
-                ></el-pagination>
-            </div>
-        </div>
-
-        <!-- 编辑弹出框 -->
-        <el-dialog title="编辑" :visible.sync="editVisible" width="30%">
-            <el-form ref="form" :model="form" label-width="70px">
-                <el-form-item label="用户名">
-                    <el-input v-model="form.name"></el-input>
-                </el-form-item>
-                <el-form-item label="地址">
-                    <el-input v-model="form.address"></el-input>
-                </el-form-item>
-            </el-form>
-            <span slot="footer" class="dialog-footer">
-                <el-button @click="editVisible = false">取 消</el-button>
-                <el-button type="primary" @click="saveEdit">确 定</el-button>
-            </span>
-        </el-dialog>
-    </div>
-</template>
-
-<script>
-import { fetchData } from '../../api/index';
-export default {
-    name: 'basetable',
-    data() {
-        return {
-            query: {
-                address: '',
-                name: '',
-                pageIndex: 1,
-                pageSize: 10
-            },
-            tableData: [],
-            multipleSelection: [],
-            delList: [],
-            editVisible: false,
-            pageTotal: 0,
-            form: {},
-            idx: -1,
-            id: -1
-        };
-    },
-    created() {
-        this.getData();
-    },
-    methods: {
-        // 获取 easy-mock 的模拟数据
-        getData() {
-            fetchData(this.query).then(res => {
-                console.log(res);
-                this.tableData = res.list;
-                this.pageTotal = res.pageTotal || 50;
-            });
-        },
-        // 触发搜索按钮
-        handleSearch() {
-            this.$set(this.query, 'pageIndex', 1);
-            this.getData();
-        },
-        // 删除操作
-        handleDelete(index, row) {
-            // 二次确认删除
-            this.$confirm('确定要删除吗?', '提示', {
-                type: 'warning'
-            })
-                .then(() => {
-                    this.$message.success('删除成功');
-                    this.tableData.splice(index, 1);
-                })
-                .catch(() => {});
-        },
-        // 多选操作
-        handleSelectionChange(val) {
-            this.multipleSelection = val;
-        },
-        delAllSelection() {
-            const length = this.multipleSelection.length;
-            let str = '';
-            this.delList = this.delList.concat(this.multipleSelection);
-            for (let i = 0; i < length; i++) {
-                str += this.multipleSelection[i].name + ' ';
-            }
-            this.$message.error(`删除了${str}`);
-            this.multipleSelection = [];
-        },
-        // 编辑操作
-        handleEdit(index, row) {
-            this.idx = index;
-            this.form = row;
-            this.editVisible = true;
-        },
-        // 保存编辑
-        saveEdit() {
-            this.editVisible = false;
-            this.$message.success(`修改第 ${this.idx + 1} 行成功`);
-            this.$set(this.tableData, this.idx, this.form);
-        },
-        // 分页导航
-        handlePageChange(val) {
-            this.$set(this.query, 'pageIndex', val);
-            this.getData();
-        }
-    }
-};
-</script>
-
-<style scoped>
-.handle-box {
-    margin-bottom: 20px;
-}
-
-.handle-select {
-    width: 120px;
-}
-
-.handle-input {
-    width: 300px;
-    display: inline-block;
-}
-.table {
-    width: 100%;
-    font-size: 14px;
-}
-.red {
-    color: #ff0000;
-}
-.mr10 {
-    margin-right: 10px;
-}
-.table-td-thumb {
-    display: block;
-    margin: auto;
-    width: 40px;
-    height: 40px;
-}
-</style>
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-cascades"></i> 基础表格
+                </el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="handle-box">
+                <el-button
+                    type="primary"
+                    icon="el-icon-delete"
+                    class="handle-del mr10"
+                    @click="delAllSelection"
+                    >批量删除</el-button
+                >
+                <el-select
+                    v-model="query.address"
+                    placeholder="地址"
+                    class="handle-select mr10"
+                >
+                    <el-option
+                        key="1"
+                        label="广东省"
+                        value="广东省"
+                    ></el-option>
+                    <el-option
+                        key="2"
+                        label="湖南省"
+                        value="湖南省"
+                    ></el-option>
+                </el-select>
+                <el-input
+                    v-model="query.name"
+                    placeholder="用户名"
+                    class="handle-input mr10"
+                ></el-input>
+                <el-button
+                    type="primary"
+                    icon="el-icon-search"
+                    @click="handleSearch"
+                    >搜索</el-button
+                >
+            </div>
+            <el-table
+                :data="tableData"
+                border
+                class="table"
+                ref="multipleTable"
+                header-cell-class-name="table-header"
+                @selection-change="handleSelectionChange"
+            >
+                <el-table-column
+                    type="selection"
+                    width="55"
+                    align="center"
+                ></el-table-column>
+                <el-table-column
+                    prop="id"
+                    label="ID"
+                    width="55"
+                    align="center"
+                ></el-table-column>
+                <el-table-column prop="name" label="用户名"></el-table-column>
+                <el-table-column label="账户余额">
+                    <template #default="scope"
+                        >¥{{ scope.row.money }}</template
+                    >
+                </el-table-column>
+                <el-table-column label="头像(查看大图)" align="center">
+                    <template #default="scope">
+                        <el-image
+                            class="table-td-thumb"
+                            :src="scope.row.thumb"
+                            :preview-src-list="[scope.row.thumb]"
+                        ></el-image>
+                    </template>
+                </el-table-column>
+                <el-table-column prop="address" label="地址"></el-table-column>
+                <el-table-column label="状态" align="center">
+                    <template #default="scope">
+                        <el-tag
+                            :type="
+                                scope.row.state === '成功'
+                                    ? 'success'
+                                    : scope.row.state === '失败'
+                                    ? 'danger'
+                                    : ''
+                            "
+                            >{{ scope.row.state }}</el-tag
+                        >
+                    </template>
+                </el-table-column>
+
+                <el-table-column prop="date" label="注册时间"></el-table-column>
+                <el-table-column label="操作" width="180" align="center">
+                    <template #default="scope">
+                        <el-button
+                            type="text"
+                            icon="el-icon-edit"
+                            @click="handleEdit(scope.$index, scope.row)"
+                            >编辑</el-button
+                        >
+                        <el-button
+                            type="text"
+                            icon="el-icon-delete"
+                            class="red"
+                            @click="handleDelete(scope.$index, scope.row)"
+                            >删除</el-button
+                        >
+                    </template>
+                </el-table-column>
+            </el-table>
+            <div class="pagination">
+                <el-pagination
+                    background
+                    layout="total, prev, pager, next"
+                    :current-page="query.pageIndex"
+                    :page-size="query.pageSize"
+                    :total="pageTotal"
+                    @current-change="handlePageChange"
+                ></el-pagination>
+            </div>
+        </div>
+
+        <!-- 编辑弹出框 -->
+        <el-dialog title="编辑" v-model="editVisible" width="30%">
+            <el-form ref="form" :model="form" label-width="70px">
+                <el-form-item label="用户名">
+                    <el-input v-model="form.name"></el-input>
+                </el-form-item>
+                <el-form-item label="地址">
+                    <el-input v-model="form.address"></el-input>
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="editVisible = false">取 消</el-button>
+                    <el-button type="primary" @click="saveEdit"
+                        >确 定</el-button
+                    >
+                </span>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script>
+import { fetchData } from "../api/index";
+export default {
+    data() {
+        return {
+            query: {
+                address: "",
+                name: "",
+                pageIndex: 1,
+                pageSize: 10,
+            },
+            tableData: [],
+            multipleSelection: [],
+            delList: [],
+            editVisible: false,
+            pageTotal: 0,
+            form: {},
+            idx: -1,
+            id: -1,
+        };
+    },
+    created() {
+        this.getData();
+    },
+    methods: {
+        // 获取 easy-mock 的模拟数据
+        getData() {
+            fetchData(this.query).then((res) => {
+                console.log(res);
+                this.tableData = res.list;
+                this.pageTotal = res.pageTotal || 50;
+            });
+        },
+        // 触发搜索按钮
+        handleSearch() {
+            this.$set(this.query, "pageIndex", 1);
+            this.getData();
+        },
+        // 删除操作
+        handleDelete(index) {
+            // 二次确认删除
+            this.$confirm("确定要删除吗?", "提示", {
+                type: "warning",
+            })
+                .then(() => {
+                    this.$message.success("删除成功");
+                    this.tableData.splice(index, 1);
+                })
+                .catch(() => {});
+        },
+        // 多选操作
+        handleSelectionChange(val) {
+            this.multipleSelection = val;
+        },
+        delAllSelection() {
+            const length = this.multipleSelection.length;
+            let str = "";
+            this.delList = this.delList.concat(this.multipleSelection);
+            for (let i = 0; i < length; i++) {
+                str += this.multipleSelection[i].name + " ";
+            }
+            this.$message.error(`删除了${str}`);
+            this.multipleSelection = [];
+        },
+        // 编辑操作
+        handleEdit(index, row) {
+            this.idx = index;
+            this.form = row;
+            this.editVisible = true;
+        },
+        // 保存编辑
+        saveEdit() {
+            this.editVisible = false;
+            this.$message.success(`修改第 ${this.idx + 1} 行成功`);
+            this.$set(this.tableData, this.idx, this.form);
+        },
+        // 分页导航
+        handlePageChange(val) {
+            this.$set(this.query, "pageIndex", val);
+            this.getData();
+        },
+    },
+};
+</script>
+
+<style scoped>
+.handle-box {
+    margin-bottom: 20px;
+}
+
+.handle-select {
+    width: 120px;
+}
+
+.handle-input {
+    width: 300px;
+    display: inline-block;
+}
+.table {
+    width: 100%;
+    font-size: 14px;
+}
+.red {
+    color: #ff0000;
+}
+.mr10 {
+    margin-right: 10px;
+}
+.table-td-thumb {
+    display: block;
+    margin: auto;
+    width: 40px;
+    height: 40px;
+}
+</style>

+ 421 - 376
src/components/page/Dashboard.vue → src/views/Dashboard.vue

@@ -1,376 +1,421 @@
-<template>
-    <div>
-        <el-row :gutter="20">
-            <el-col :span="8">
-                <el-card shadow="hover" class="mgb20" style="height:252px;">
-                    <div class="user-info">
-                        <img src="../../assets/img/img.jpg" class="user-avator" alt />
-                        <div class="user-info-cont">
-                            <div class="user-info-name">{{name}}</div>
-                            <div>{{role}}</div>
-                        </div>
-                    </div>
-                    <div class="user-info-list">
-                        上次登录时间:
-                        <span>2019-11-01</span>
-                    </div>
-                    <div class="user-info-list">
-                        上次登录地点:
-                        <span>东莞</span>
-                    </div>
-                </el-card>
-                <el-card shadow="hover" style="height:252px;">
-                    <div slot="header" class="clearfix">
-                        <span>语言详情</span>
-                    </div>Vue
-                    <el-progress :percentage="71.3" color="#42b983"></el-progress>JavaScript
-                    <el-progress :percentage="24.1" color="#f1e05a"></el-progress>CSS
-                    <el-progress :percentage="13.7"></el-progress>HTML
-                    <el-progress :percentage="5.9" color="#f56c6c"></el-progress>
-                </el-card>
-            </el-col>
-            <el-col :span="16">
-                <el-row :gutter="20" class="mgb20">
-                    <el-col :span="8">
-                        <el-card shadow="hover" :body-style="{padding: '0px'}">
-                            <div class="grid-content grid-con-1">
-                                <i class="el-icon-lx-people grid-con-icon"></i>
-                                <div class="grid-cont-right">
-                                    <div class="grid-num">1234</div>
-                                    <div>用户访问量</div>
-                                </div>
-                            </div>
-                        </el-card>
-                    </el-col>
-                    <el-col :span="8">
-                        <el-card shadow="hover" :body-style="{padding: '0px'}">
-                            <div class="grid-content grid-con-2">
-                                <i class="el-icon-lx-notice grid-con-icon"></i>
-                                <div class="grid-cont-right">
-                                    <div class="grid-num">321</div>
-                                    <div>系统消息</div>
-                                </div>
-                            </div>
-                        </el-card>
-                    </el-col>
-                    <el-col :span="8">
-                        <el-card shadow="hover" :body-style="{padding: '0px'}">
-                            <div class="grid-content grid-con-3">
-                                <i class="el-icon-lx-goods grid-con-icon"></i>
-                                <div class="grid-cont-right">
-                                    <div class="grid-num">5000</div>
-                                    <div>数量</div>
-                                </div>
-                            </div>
-                        </el-card>
-                    </el-col>
-                </el-row>
-                <el-card shadow="hover" style="height:403px;">
-                    <div slot="header" class="clearfix">
-                        <span>待办事项</span>
-                        <el-button style="float: right; padding: 3px 0" type="text">添加</el-button>
-                    </div>
-                    <el-table :show-header="false" :data="todoList" style="width:100%;">
-                        <el-table-column width="40">
-                            <template slot-scope="scope">
-                                <el-checkbox v-model="scope.row.status"></el-checkbox>
-                            </template>
-                        </el-table-column>
-                        <el-table-column>
-                            <template slot-scope="scope">
-                                <div
-                                    class="todo-item"
-                                    :class="{'todo-item-del': scope.row.status}"
-                                >{{scope.row.title}}</div>
-                            </template>
-                        </el-table-column>
-                        <el-table-column width="60">
-                            <template>
-                                <i class="el-icon-edit"></i>
-                                <i class="el-icon-delete"></i>
-                            </template>
-                        </el-table-column>
-                    </el-table>
-                </el-card>
-            </el-col>
-        </el-row>
-        <el-row :gutter="20">
-            <el-col :span="12">
-                <el-card shadow="hover">
-                    <schart ref="bar" class="schart" canvasId="bar" :options="options"></schart>
-                </el-card>
-            </el-col>
-            <el-col :span="12">
-                <el-card shadow="hover">
-                    <schart ref="line" class="schart" canvasId="line" :options="options2"></schart>
-                </el-card>
-            </el-col>
-        </el-row>
-    </div>
-</template>
-
-<script>
-import Schart from 'vue-schart';
-import bus from '../common/bus';
-export default {
-    name: 'dashboard',
-    data() {
-        return {
-            name: localStorage.getItem('ms_username'),
-            todoList: [
-                {
-                    title: '今天要修复100个bug',
-                    status: false
-                },
-                {
-                    title: '今天要修复100个bug',
-                    status: false
-                },
-                {
-                    title: '今天要写100行代码加几个bug吧',
-                    status: false
-                },
-                {
-                    title: '今天要修复100个bug',
-                    status: false
-                },
-                {
-                    title: '今天要修复100个bug',
-                    status: true
-                },
-                {
-                    title: '今天要写100行代码加几个bug吧',
-                    status: true
-                }
-            ],
-            data: [
-                {
-                    name: '2018/09/04',
-                    value: 1083
-                },
-                {
-                    name: '2018/09/05',
-                    value: 941
-                },
-                {
-                    name: '2018/09/06',
-                    value: 1139
-                },
-                {
-                    name: '2018/09/07',
-                    value: 816
-                },
-                {
-                    name: '2018/09/08',
-                    value: 327
-                },
-                {
-                    name: '2018/09/09',
-                    value: 228
-                },
-                {
-                    name: '2018/09/10',
-                    value: 1065
-                }
-            ],
-            options: {
-                type: 'bar',
-                title: {
-                    text: '最近一周各品类销售图'
-                },
-                xRorate: 25,
-                labels: ['周一', '周二', '周三', '周四', '周五'],
-                datasets: [
-                    {
-                        label: '家电',
-                        data: [234, 278, 270, 190, 230]
-                    },
-                    {
-                        label: '百货',
-                        data: [164, 178, 190, 135, 160]
-                    },
-                    {
-                        label: '食品',
-                        data: [144, 198, 150, 235, 120]
-                    }
-                ]
-            },
-            options2: {
-                type: 'line',
-                title: {
-                    text: '最近几个月各品类销售趋势图'
-                },
-                labels: ['6月', '7月', '8月', '9月', '10月'],
-                datasets: [
-                    {
-                        label: '家电',
-                        data: [234, 278, 270, 190, 230]
-                    },
-                    {
-                        label: '百货',
-                        data: [164, 178, 150, 135, 160]
-                    },
-                    {
-                        label: '食品',
-                        data: [74, 118, 200, 235, 90]
-                    }
-                ]
-            }
-        };
-    },
-    components: {
-        Schart
-    },
-    computed: {
-        role() {
-            return this.name === 'admin' ? '超级管理员' : '普通用户';
-        }
-    },
-    // created() {
-    //     this.handleListener();
-    //     this.changeDate();
-    // },
-    // activated() {
-    //     this.handleListener();
-    // },
-    // deactivated() {
-    //     window.removeEventListener('resize', this.renderChart);
-    //     bus.$off('collapse', this.handleBus);
-    // },
-    methods: {
-        changeDate() {
-            const now = new Date().getTime();
-            this.data.forEach((item, index) => {
-                const date = new Date(now - (6 - index) * 86400000);
-                item.name = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
-            });
-        }
-        // handleListener() {
-        //     bus.$on('collapse', this.handleBus);
-        //     // 调用renderChart方法对图表进行重新渲染
-        //     window.addEventListener('resize', this.renderChart);
-        // },
-        // handleBus(msg) {
-        //     setTimeout(() => {
-        //         this.renderChart();
-        //     }, 200);
-        // },
-        // renderChart() {
-        //     this.$refs.bar.renderChart();
-        //     this.$refs.line.renderChart();
-        // }
-    }
-};
-</script>
-
-
-<style scoped>
-.el-row {
-    margin-bottom: 20px;
-}
-
-.grid-content {
-    display: flex;
-    align-items: center;
-    height: 100px;
-}
-
-.grid-cont-right {
-    flex: 1;
-    text-align: center;
-    font-size: 14px;
-    color: #999;
-}
-
-.grid-num {
-    font-size: 30px;
-    font-weight: bold;
-}
-
-.grid-con-icon {
-    font-size: 50px;
-    width: 100px;
-    height: 100px;
-    text-align: center;
-    line-height: 100px;
-    color: #fff;
-}
-
-.grid-con-1 .grid-con-icon {
-    background: rgb(45, 140, 240);
-}
-
-.grid-con-1 .grid-num {
-    color: rgb(45, 140, 240);
-}
-
-.grid-con-2 .grid-con-icon {
-    background: rgb(100, 213, 114);
-}
-
-.grid-con-2 .grid-num {
-    color: rgb(45, 140, 240);
-}
-
-.grid-con-3 .grid-con-icon {
-    background: rgb(242, 94, 67);
-}
-
-.grid-con-3 .grid-num {
-    color: rgb(242, 94, 67);
-}
-
-.user-info {
-    display: flex;
-    align-items: center;
-    padding-bottom: 20px;
-    border-bottom: 2px solid #ccc;
-    margin-bottom: 20px;
-}
-
-.user-avator {
-    width: 120px;
-    height: 120px;
-    border-radius: 50%;
-}
-
-.user-info-cont {
-    padding-left: 50px;
-    flex: 1;
-    font-size: 14px;
-    color: #999;
-}
-
-.user-info-cont div:first-child {
-    font-size: 30px;
-    color: #222;
-}
-
-.user-info-list {
-    font-size: 14px;
-    color: #999;
-    line-height: 25px;
-}
-
-.user-info-list span {
-    margin-left: 70px;
-}
-
-.mgb20 {
-    margin-bottom: 20px;
-}
-
-.todo-item {
-    font-size: 14px;
-}
-
-.todo-item-del {
-    text-decoration: line-through;
-    color: #999;
-}
-
-.schart {
-    width: 100%;
-    height: 300px;
-}
-</style>
+<template>
+    <div>
+        <el-row :gutter="20">
+            <el-col :span="8">
+                <el-card shadow="hover" class="mgb20" style="height:252px;">
+                    <div class="user-info">
+                        <img
+                            src="../assets/img/img.jpg"
+                            class="user-avator"
+                            alt
+                        />
+                        <div class="user-info-cont">
+                            <div class="user-info-name">{{ name }}</div>
+                            <div>{{ role }}</div>
+                        </div>
+                    </div>
+                    <div class="user-info-list">
+                        上次登录时间:
+                        <span>2019-11-01</span>
+                    </div>
+                    <div class="user-info-list">
+                        上次登录地点:
+                        <span>东莞</span>
+                    </div>
+                </el-card>
+                <el-card shadow="hover" style="height:252px;">
+                    <template #header>
+                        <div class="clearfix">
+                            <span>语言详情</span>
+                        </div>
+                    </template>
+                    Vue
+                    <el-progress
+                        :percentage="71.3"
+                        color="#42b983"
+                    ></el-progress
+                    >JavaScript
+                    <el-progress
+                        :percentage="24.1"
+                        color="#f1e05a"
+                    ></el-progress
+                    >CSS <el-progress :percentage="13.7"></el-progress>HTML
+                    <el-progress
+                        :percentage="5.9"
+                        color="#f56c6c"
+                    ></el-progress>
+                </el-card>
+            </el-col>
+            <el-col :span="16">
+                <el-row :gutter="20" class="mgb20">
+                    <el-col :span="8">
+                        <el-card
+                            shadow="hover"
+                            :body-style="{ padding: '0px' }"
+                        >
+                            <div class="grid-content grid-con-1">
+                                <i class="el-icon-user-solid grid-con-icon"></i>
+                                <div class="grid-cont-right">
+                                    <div class="grid-num">1234</div>
+                                    <div>用户访问量</div>
+                                </div>
+                            </div>
+                        </el-card>
+                    </el-col>
+                    <el-col :span="8">
+                        <el-card
+                            shadow="hover"
+                            :body-style="{ padding: '0px' }"
+                        >
+                            <div class="grid-content grid-con-2">
+                                <i
+                                    class="el-icon-message-solid grid-con-icon"
+                                ></i>
+                                <div class="grid-cont-right">
+                                    <div class="grid-num">321</div>
+                                    <div>系统消息</div>
+                                </div>
+                            </div>
+                        </el-card>
+                    </el-col>
+                    <el-col :span="8">
+                        <el-card
+                            shadow="hover"
+                            :body-style="{ padding: '0px' }"
+                        >
+                            <div class="grid-content grid-con-3">
+                                <i class="el-icon-s-goods grid-con-icon"></i>
+                                <div class="grid-cont-right">
+                                    <div class="grid-num">5000</div>
+                                    <div>数量</div>
+                                </div>
+                            </div>
+                        </el-card>
+                    </el-col>
+                </el-row>
+                <el-card shadow="hover" style="height:403px;">
+                    <template #header>
+                        <div class="clearfix">
+                            <span>待办事项</span>
+                            <el-button
+                                style="float: right; padding: 3px 0"
+                                type="text"
+                                >添加</el-button
+                            >
+                        </div>
+                    </template>
+
+                    <el-table
+                        :show-header="false"
+                        :data="todoList"
+                        style="width:100%;"
+                    >
+                        <el-table-column width="40">
+                            <template #default="scope">
+                                <el-checkbox
+                                    v-model="scope.row.status"
+                                ></el-checkbox>
+                            </template>
+                        </el-table-column>
+                        <el-table-column>
+                            <template #default="scope">
+                                <div
+                                    class="todo-item"
+                                    :class="{
+                                        'todo-item-del': scope.row.status,
+                                    }"
+                                >
+                                    {{ scope.row.title }}
+                                </div>
+                            </template>
+                        </el-table-column>
+                        <el-table-column width="60">
+                            <template>
+                                <i class="el-icon-edit"></i>
+                                <i class="el-icon-delete"></i>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </el-card>
+            </el-col>
+        </el-row>
+        <el-row :gutter="20">
+            <el-col :span="12">
+                <el-card shadow="hover">
+                    <schart
+                        ref="bar"
+                        class="schart"
+                        canvasId="bar"
+                        :options="options"
+                    ></schart>
+                </el-card>
+            </el-col>
+            <el-col :span="12">
+                <el-card shadow="hover">
+                    <schart
+                        ref="line"
+                        class="schart"
+                        canvasId="line"
+                        :options="options2"
+                    ></schart>
+                </el-card>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<script>
+import Schart from "vue-schart";
+// import bus from '../common/bus';
+export default {
+    name: "dashboard",
+    data() {
+        return {
+            name: localStorage.getItem("ms_username"),
+            todoList: [
+                {
+                    title: "今天要修复100个bug",
+                    status: false,
+                },
+                {
+                    title: "今天要修复100个bug",
+                    status: false,
+                },
+                {
+                    title: "今天要写100行代码加几个bug吧",
+                    status: false,
+                },
+                {
+                    title: "今天要修复100个bug",
+                    status: false,
+                },
+                {
+                    title: "今天要修复100个bug",
+                    status: true,
+                },
+                {
+                    title: "今天要写100行代码加几个bug吧",
+                    status: true,
+                },
+            ],
+            data: [
+                {
+                    name: "2018/09/04",
+                    value: 1083,
+                },
+                {
+                    name: "2018/09/05",
+                    value: 941,
+                },
+                {
+                    name: "2018/09/06",
+                    value: 1139,
+                },
+                {
+                    name: "2018/09/07",
+                    value: 816,
+                },
+                {
+                    name: "2018/09/08",
+                    value: 327,
+                },
+                {
+                    name: "2018/09/09",
+                    value: 228,
+                },
+                {
+                    name: "2018/09/10",
+                    value: 1065,
+                },
+            ],
+            options: {
+                type: "bar",
+                title: {
+                    text: "最近一周各品类销售图",
+                },
+                xRorate: 25,
+                labels: ["周一", "周二", "周三", "周四", "周五"],
+                datasets: [
+                    {
+                        label: "家电",
+                        data: [234, 278, 270, 190, 230],
+                    },
+                    {
+                        label: "百货",
+                        data: [164, 178, 190, 135, 160],
+                    },
+                    {
+                        label: "食品",
+                        data: [144, 198, 150, 235, 120],
+                    },
+                ],
+            },
+            options2: {
+                type: "line",
+                title: {
+                    text: "最近几个月各品类销售趋势图",
+                },
+                labels: ["6月", "7月", "8月", "9月", "10月"],
+                datasets: [
+                    {
+                        label: "家电",
+                        data: [234, 278, 270, 190, 230],
+                    },
+                    {
+                        label: "百货",
+                        data: [164, 178, 150, 135, 160],
+                    },
+                    {
+                        label: "食品",
+                        data: [74, 118, 200, 235, 90],
+                    },
+                ],
+            },
+        };
+    },
+    components: {
+        Schart,
+    },
+    computed: {
+        role() {
+            return this.name === "admin" ? "超级管理员" : "普通用户";
+        },
+    },
+
+    methods: {
+        changeDate() {
+            const now = new Date().getTime();
+            this.data.forEach((item, index) => {
+                const date = new Date(now - (6 - index) * 86400000);
+                item.name = `${date.getFullYear()}/${date.getMonth() +
+                    1}/${date.getDate()}`;
+            });
+        },
+        // handleListener() {
+        //     bus.$on('collapse', this.handleBus);
+        //     // 调用renderChart方法对图表进行重新渲染
+        //     window.addEventListener('resize', this.renderChart);
+        // },
+        // handleBus(msg) {
+        //     setTimeout(() => {
+        //         this.renderChart();
+        //     }, 200);
+        // },
+        // renderChart() {
+        //     this.$refs.bar.renderChart();
+        //     this.$refs.line.renderChart();
+        // }
+    },
+};
+</script>
+
+<style scoped>
+.el-row {
+    margin-bottom: 20px;
+}
+
+.grid-content {
+    display: flex;
+    align-items: center;
+    height: 100px;
+}
+
+.grid-cont-right {
+    flex: 1;
+    text-align: center;
+    font-size: 14px;
+    color: #999;
+}
+
+.grid-num {
+    font-size: 30px;
+    font-weight: bold;
+}
+
+.grid-con-icon {
+    font-size: 50px;
+    width: 100px;
+    height: 100px;
+    text-align: center;
+    line-height: 100px;
+    color: #fff;
+}
+
+.grid-con-1 .grid-con-icon {
+    background: rgb(45, 140, 240);
+}
+
+.grid-con-1 .grid-num {
+    color: rgb(45, 140, 240);
+}
+
+.grid-con-2 .grid-con-icon {
+    background: rgb(100, 213, 114);
+}
+
+.grid-con-2 .grid-num {
+    color: rgb(45, 140, 240);
+}
+
+.grid-con-3 .grid-con-icon {
+    background: rgb(242, 94, 67);
+}
+
+.grid-con-3 .grid-num {
+    color: rgb(242, 94, 67);
+}
+
+.user-info {
+    display: flex;
+    align-items: center;
+    padding-bottom: 20px;
+    border-bottom: 2px solid #ccc;
+    margin-bottom: 20px;
+}
+
+.user-avator {
+    width: 120px;
+    height: 120px;
+    border-radius: 50%;
+}
+
+.user-info-cont {
+    padding-left: 50px;
+    flex: 1;
+    font-size: 14px;
+    color: #999;
+}
+
+.user-info-cont div:first-child {
+    font-size: 30px;
+    color: #222;
+}
+
+.user-info-list {
+    font-size: 14px;
+    color: #999;
+    line-height: 25px;
+}
+
+.user-info-list span {
+    margin-left: 70px;
+}
+
+.mgb20 {
+    margin-bottom: 20px;
+}
+
+.todo-item {
+    font-size: 14px;
+}
+
+.todo-item-del {
+    text-decoration: line-through;
+    color: #999;
+}
+
+.schart {
+    width: 100%;
+    height: 300px;
+}
+</style>

+ 0 - 0
src/components/page/Donate.vue → src/views/Donate.vue


+ 36 - 0
src/views/Home.vue

@@ -0,0 +1,36 @@
+<template>
+    <div class="about">
+        <v-header />
+        <v-sidebar />
+        <div class="content-box" :class="{'content-collapse':collapse}">
+            <v-tags></v-tags>
+            <div class="content">
+                    <!-- <keep-alive :include="tagsList"> -->
+                    <router-view v-slot="{ Component }">
+                <transition name="move" mode="out-in">
+<component :is="Component" />
+                </transition>
+                    </router-view>
+                    <!-- </keep-alive> -->
+                <!-- <el-backtop target=".content"></el-backtop> -->
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import vHeader from "../components/Header";
+import vSidebar from "../components/Sidebar";
+import vTags from "../components/Tags.vue";
+export default {
+    components: {
+        vHeader,
+        vSidebar,
+        vTags
+    },
+    computed:{
+        collapse(){
+            return this.$store.state.collapse
+        }
+    }
+};
+</script>

+ 1 - 14
src/components/page/I18n.vue → src/views/I18n.vue

@@ -7,29 +7,19 @@
         </div>
         <div class="container">
             <span>{{$t('i18n.tips')}}</span>
-            <el-button type="primary" @click="$i18n.locale = $i18n.locale === 'zh'?'en':'zh';">{{$t('i18n.btn')}}</el-button>
+            <el-button type="primary" @click="$i18n.locale = $i18n.locale === 'zh-cn'?'en':'zh-cn';">{{$t('i18n.btn')}}</el-button>
             <div class="list">
             <h2>{{$t('i18n.title1')}}</h2>
                 <p>{{$t('i18n.p1')}}</p>
                 <p>{{$t('i18n.p2')}}</p>
                 <p>{{$t('i18n.p3')}}</p>
             </div>
-            <h2>{{$t('i18n.title2')}}</h2>
-            <div>
-                <i18n path="i18n.info" tag="p">
-                    <a place="action" href="https://element.eleme.cn/2.0/#/zh-CN/component/i18n">{{ $t('i18n.value') }}</a>
-                </i18n>
-            </div>
         </div>
     </section>
 </template>
 
 <script>
 export default {
-    data(){
-        return {
-        }
-    }
 }
 </script>
 
@@ -40,7 +30,4 @@ export default {
 .list p{
     margin-bottom: 20px;
 }
-a{
-    color: #409eff;
-}
 </style>

+ 224 - 224
src/components/page/Icon.vue → src/views/Icon.vue

@@ -1,225 +1,225 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-lx-emoji"></i> 自定义图标</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <h2>使用方法</h2>
-            <p style="line-height: 50px;">
-                直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{iconList.length}}个图标)
-            </p>
-            <p class="example-p">
-                <i class="el-icon-lx-redpacket_fill" style="font-size: 30px;color: #ff5900"></i>
-                <span>&lt;i class=&quot;el-icon-lx-redpacket_fill&quot;&gt;&lt;/i&gt;</span>
-            </p>
-            <p class="example-p">
-                <i class="el-icon-lx-weibo" style="font-size: 30px;color:#fd5656"></i>
-                <span>&lt;i class=&quot;el-icon-lx-weibo&quot;&gt;&lt;/i&gt;</span>
-            </p>
-            <p class="example-p">
-                <i class="el-icon-lx-emojifill" style="font-size: 30px;color: #ffc300"></i>
-                <span>&lt;i class=&quot;el-icon-lx-emojifill&quot;&gt;&lt;/i&gt;</span>
-            </p>
-            <br>
-            <h2>图标</h2>
-            <div class="search-box">
-                <el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
-            </div>
-            <ul>
-                <li class="icon-li" v-for="(item,index) in list" :key="index">
-                    <div class="icon-li-content">
-                        <i :class="`el-icon-lx-${item}`"></i>
-                        <span>{{item}}</span>
-                    </div>
-                </li>
-            </ul>
-        </div>
-
-    </div>
-</template>
-
-<script>
-    export default {
-        data: function(){
-            return {
-                keyword: '',
-                iconList: [
-                    'attentionforbid',
-                    'attentionforbidfill',
-                    'attention',
-                    'attentionfill',
-                    'tag',
-                    'tagfill',
-                    'people',
-                    'peoplefill',
-                    'notice',
-                    'noticefill',
-                    'mobile',
-                    'mobilefill',
-                    'voice',
-                    'voicefill',
-                    'unlock',
-                    'lock',
-                    'home',
-                    'homefill',
-                    'delete',
-                    'deletefill',
-                    'notification',
-                    'notificationfill',
-                    'notificationforbidfill',
-                    'like',
-                    'likefill',
-                    'comment',
-                    'commentfill',
-                    'camera',
-                    'camerafill',
-                    'warn',
-                    'warnfill',
-                    'time',
-                    'timefill',
-                    'location',
-                    'locationfill',
-                    'favor',
-                    'favorfill',
-                    'skin',
-                    'skinfill',
-                    'news',
-                    'newsfill',
-                    'record',
-                    'recordfill',
-                    'emoji',
-                    'emojifill',
-                    'message',
-                    'messagefill',
-                    'goods',
-                    'goodsfill',
-                    'crown',
-                    'crownfill',
-                    'move',
-                    'add',
-                    'hot',
-                    'hotfill',
-                    'service',
-                    'servicefill',
-                    'present',
-                    'presentfill',
-                    'pic',
-                    'picfill',
-                    'rank',
-                    'rankfill',
-                    'male',
-                    'female',
-                    'down',
-                    'top',
-                    'recharge',
-                    'rechargefill',
-                    'forward',
-                    'forwardfill',
-                    'info',
-                    'infofill',
-                    'redpacket',
-                    'redpacket_fill',
-                    'roundadd',
-                    'roundaddfill',
-                    'friendadd',
-                    'friendaddfill',
-                    'cart',
-                    'cartfill',
-                    'more',
-                    'moreandroid',
-                    'back',
-                    'right',
-                    'shop',
-                    'shopfill',
-                    'question',
-                    'questionfill',
-                    'roundclose',
-                    'roundclosefill',
-                    'roundcheck',
-                    'roundcheckfill',
-                    'global',
-                    'mail',
-                    'punch',
-                    'exit',
-                    'upload',
-                    'read',
-                    'file',
-                    'link',
-                    'full',
-                    'group',
-                    'friend',
-                    'profile',
-                    'addressbook',
-                    'calendar',
-                    'text',
-                    'copy',
-                    'share',
-                    'wifi',
-                    'vipcard',
-                    'weibo',
-                    'remind',
-                    'refresh',
-                    'filter',
-                    'settings',
-                    'scan',
-                    'qrcode',
-                    'cascades',
-                    'apps',
-                    'sort',
-                    'searchlist',
-                    'search',
-                    'edit'
-                ]
-            }
-        },
-        computed: {
-            list(){
-                return this.iconList.filter((item) => {
-                    return item.indexOf(this.keyword) !== -1;
-                })
-            }
-        }
-    }
-</script>
-
-<style scoped>
-.example-p{
-    height: 45px;
-    display: flex;
-    align-items: center;
-}
-.search-box{
-    text-align: center;
-    margin-top: 10px;
-}
-.search{
-    width: 300px;
-}
-ul,li{
-    list-style: none;
-}
-.icon-li{
-    display: inline-block;
-    padding: 10px;
-    width: 120px;
-    height: 120px;
-}
-.icon-li-content{
-    display: flex;
-    height: 100%;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    cursor: pointer;
-}
-.icon-li-content i{
-    font-size: 36px;
-    color: #606266;
-}
-.icon-li-content span{
-    margin-top: 10px;
-    color: #787878;
-}
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item><i class="el-icon-lx-emoji"></i> 自定义图标</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <h2>使用方法</h2>
+            <p style="line-height: 50px;">
+                直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{iconList.length}}个图标)
+            </p>
+            <p class="example-p">
+                <i class="el-icon-lx-redpacket_fill" style="font-size: 30px;color: #ff5900"></i>
+                <span>&lt;i class=&quot;el-icon-lx-redpacket_fill&quot;&gt;&lt;/i&gt;</span>
+            </p>
+            <p class="example-p">
+                <i class="el-icon-lx-weibo" style="font-size: 30px;color:#fd5656"></i>
+                <span>&lt;i class=&quot;el-icon-lx-weibo&quot;&gt;&lt;/i&gt;</span>
+            </p>
+            <p class="example-p">
+                <i class="el-icon-lx-emojifill" style="font-size: 30px;color: #ffc300"></i>
+                <span>&lt;i class=&quot;el-icon-lx-emojifill&quot;&gt;&lt;/i&gt;</span>
+            </p>
+            <br>
+            <h2>图标</h2>
+            <div class="search-box">
+                <el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
+            </div>
+            <ul>
+                <li class="icon-li" v-for="(item,index) in list" :key="index">
+                    <div class="icon-li-content">
+                        <i :class="`el-icon-lx-${item}`"></i>
+                        <span>{{item}}</span>
+                    </div>
+                </li>
+            </ul>
+        </div>
+
+    </div>
+</template>
+
+<script>
+    export default {
+        data: function(){
+            return {
+                keyword: '',
+                iconList: [
+                    'attentionforbid',
+                    'attentionforbidfill',
+                    'attention',
+                    'attentionfill',
+                    'tag',
+                    'tagfill',
+                    'people',
+                    'peoplefill',
+                    'notice',
+                    'noticefill',
+                    'mobile',
+                    'mobilefill',
+                    'voice',
+                    'voicefill',
+                    'unlock',
+                    'lock',
+                    'home',
+                    'homefill',
+                    'delete',
+                    'deletefill',
+                    'notification',
+                    'notificationfill',
+                    'notificationforbidfill',
+                    'like',
+                    'likefill',
+                    'comment',
+                    'commentfill',
+                    'camera',
+                    'camerafill',
+                    'warn',
+                    'warnfill',
+                    'time',
+                    'timefill',
+                    'location',
+                    'locationfill',
+                    'favor',
+                    'favorfill',
+                    'skin',
+                    'skinfill',
+                    'news',
+                    'newsfill',
+                    'record',
+                    'recordfill',
+                    'emoji',
+                    'emojifill',
+                    'message',
+                    'messagefill',
+                    'goods',
+                    'goodsfill',
+                    'crown',
+                    'crownfill',
+                    'move',
+                    'add',
+                    'hot',
+                    'hotfill',
+                    'service',
+                    'servicefill',
+                    'present',
+                    'presentfill',
+                    'pic',
+                    'picfill',
+                    'rank',
+                    'rankfill',
+                    'male',
+                    'female',
+                    'down',
+                    'top',
+                    'recharge',
+                    'rechargefill',
+                    'forward',
+                    'forwardfill',
+                    'info',
+                    'infofill',
+                    'redpacket',
+                    'redpacket_fill',
+                    'roundadd',
+                    'roundaddfill',
+                    'friendadd',
+                    'friendaddfill',
+                    'cart',
+                    'cartfill',
+                    'more',
+                    'moreandroid',
+                    'back',
+                    'right',
+                    'shop',
+                    'shopfill',
+                    'question',
+                    'questionfill',
+                    'roundclose',
+                    'roundclosefill',
+                    'roundcheck',
+                    'roundcheckfill',
+                    'global',
+                    'mail',
+                    'punch',
+                    'exit',
+                    'upload',
+                    'read',
+                    'file',
+                    'link',
+                    'full',
+                    'group',
+                    'friend',
+                    'profile',
+                    'addressbook',
+                    'calendar',
+                    'text',
+                    'copy',
+                    'share',
+                    'wifi',
+                    'vipcard',
+                    'weibo',
+                    'remind',
+                    'refresh',
+                    'filter',
+                    'settings',
+                    'scan',
+                    'qrcode',
+                    'cascades',
+                    'apps',
+                    'sort',
+                    'searchlist',
+                    'search',
+                    'edit'
+                ]
+            }
+        },
+        computed: {
+            list(){
+                return this.iconList.filter((item) => {
+                    return item.indexOf(this.keyword) !== -1;
+                })
+            }
+        }
+    }
+</script>
+
+<style scoped>
+.example-p{
+    height: 45px;
+    display: flex;
+    align-items: center;
+}
+.search-box{
+    text-align: center;
+    margin-top: 10px;
+}
+.search{
+    width: 300px;
+}
+ul,li{
+    list-style: none;
+}
+.icon-li{
+    display: inline-block;
+    padding: 10px;
+    width: 120px;
+    height: 120px;
+}
+.icon-li-content{
+    display: flex;
+    height: 100%;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+}
+.icon-li-content i{
+    font-size: 36px;
+    color: #606266;
+}
+.icon-li-content span{
+    margin-top: 10px;
+    color: #787878;
+}
 </style>

+ 27 - 17
src/components/page/Login.vue → src/views/Login.vue

@@ -5,7 +5,9 @@
             <el-form :model="param" :rules="rules" ref="login" label-width="0px" class="ms-content">
                 <el-form-item prop="username">
                     <el-input v-model="param.username" placeholder="username">
-                        <el-button slot="prepend" icon="el-icon-lx-people"></el-button>
+                        <template #prepend>
+                            <el-button icon="el-icon-user"></el-button>
+                        </template>
                     </el-input>
                 </el-form-item>
                 <el-form-item prop="password">
@@ -13,9 +15,11 @@
                         type="password"
                         placeholder="password"
                         v-model="param.password"
-                        @keyup.enter.native="submitForm()"
+                        @keyup.enter="submitForm()"
                     >
-                        <el-button slot="prepend" icon="el-icon-lx-lock"></el-button>
+                        <template #prepend>
+                            <el-button icon="el-icon-lock"></el-button>
+                        </template>
                     </el-input>
                 </el-form-item>
                 <div class="login-btn">
@@ -29,33 +33,39 @@
 
 <script>
 export default {
-    data: function() {
+    data() {
         return {
             param: {
-                username: 'admin',
-                password: '123123',
+                username: "admin",
+                password: "123123"
             },
             rules: {
-                username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
-                password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
-            },
+                username: [
+                    { required: true, message: "请输入用户名", trigger: "blur" }
+                ],
+                password: [
+                    { required: true, message: "请输入密码", trigger: "blur" }
+                ]
+            }
         };
     },
+    created() {
+        this.$store.commit("clearTags");
+    },
     methods: {
         submitForm() {
             this.$refs.login.validate(valid => {
                 if (valid) {
-                    this.$message.success('登录成功');
-                    localStorage.setItem('ms_username', this.param.username);
-                    this.$router.push('/');
+                    this.$message.success("登录成功");
+                    localStorage.setItem("ms_username", this.param.username);
+                    this.$router.push("/");
                 } else {
-                    this.$message.error('请输入账号和密码');
-                    console.log('error submit!!');
+                    this.$message.error("请输入账号和密码");
                     return false;
                 }
             });
-        },
-    },
+        }
+    }
 };
 </script>
 
@@ -64,7 +74,7 @@ export default {
     position: relative;
     width: 100%;
     height: 100%;
-    background-image: url(../../assets/img/login-bg.jpg);
+    background-image: url(../assets/img/login-bg.jpg);
     background-size: 100%;
 }
 .ms-title {

+ 37 - 37
src/components/page/Permission.vue → src/views/Permission.vue

@@ -1,38 +1,38 @@
-<template>
-    <div>
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-lx-warn"></i> 权限测试</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <h1>管理员权限页面</h1>
-            <p>只有用 admin 账号登录的才拥有管理员权限,才能进到这个页面,其他账号想进来都会跳到403页面,重新用管理员账号登录才有权限。</p>
-            <p>想尝试一下,请<router-link to="/login" class="logout">退出登录</router-link>,随便输入个账号名,再进来试试看。</p>
-        </div>
-
-    </div>
-</template>
-
-<script>
-    export default {
-        data: function(){
-            return {}
-        }
-    }
-</script>
-
-<style scoped>
-h1{
-    text-align: center;
-    margin: 30px 0;
-}
-p{
-    line-height: 30px;
-    margin-bottom: 10px;
-    text-indent: 2em;
-}
-.logout{
-    color: #409EFF;
-}
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item><i class="el-icon-lx-warn"></i> 权限测试</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <h1>管理员权限页面</h1>
+            <p>只有用 admin 账号登录的才拥有管理员权限,才能进到这个页面,其他账号想进来都会跳到403页面,重新用管理员账号登录才有权限。</p>
+            <p>想尝试一下,请<router-link to="/login" class="logout">退出登录</router-link>,随便输入个账号名,再进来试试看。</p>
+        </div>
+
+    </div>
+</template>
+
+<script>
+    export default {
+        data: function(){
+            return {}
+        }
+    }
+</script>
+
+<style scoped>
+h1{
+    text-align: center;
+    margin: 30px 0;
+}
+p{
+    line-height: 30px;
+    margin-bottom: 10px;
+    text-indent: 2em;
+}
+.logout{
+    color: #409EFF;
+}
 </style>

+ 129 - 129
src/components/page/Tabs.vue → src/views/Tabs.vue

@@ -1,129 +1,129 @@
-<template>
-    <div class="">
-        <div class="crumbs">
-            <el-breadcrumb separator="/">
-                <el-breadcrumb-item><i class="el-icon-lx-copy"></i> tab选项卡</el-breadcrumb-item>
-            </el-breadcrumb>
-        </div>
-        <div class="container">
-            <el-tabs v-model="message">
-                <el-tab-pane :label="`未读消息(${unread.length})`" name="first">
-                    <el-table :data="unread" :show-header="false" style="width: 100%">
-                        <el-table-column>
-                            <template slot-scope="scope">
-                                <span class="message-title">{{scope.row.title}}</span>
-                            </template>
-                        </el-table-column>
-                        <el-table-column prop="date" width="180"></el-table-column>
-                        <el-table-column width="120">
-                            <template slot-scope="scope">
-                                <el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
-                            </template>
-                        </el-table-column>
-                    </el-table>
-                    <div class="handle-row">
-                        <el-button type="primary">全部标为已读</el-button>
-                    </div>
-                </el-tab-pane>
-                <el-tab-pane :label="`已读消息(${read.length})`" name="second">
-                    <template v-if="message === 'second'">
-                        <el-table :data="read" :show-header="false" style="width: 100%">
-                            <el-table-column>
-                                <template slot-scope="scope">
-                                    <span class="message-title">{{scope.row.title}}</span>
-                                </template>
-                            </el-table-column>
-                            <el-table-column prop="date" width="150"></el-table-column>
-                            <el-table-column width="120">
-                                <template slot-scope="scope">
-                                    <el-button type="danger" @click="handleDel(scope.$index)">删除</el-button>
-                                </template>
-                            </el-table-column>
-                        </el-table>
-                        <div class="handle-row">
-                            <el-button type="danger">删除全部</el-button>
-                        </div>
-                    </template>
-                </el-tab-pane>
-                <el-tab-pane :label="`回收站(${recycle.length})`" name="third">
-                    <template v-if="message === 'third'">
-                        <el-table :data="recycle" :show-header="false" style="width: 100%">
-                            <el-table-column>
-                                <template slot-scope="scope">
-                                    <span class="message-title">{{scope.row.title}}</span>
-                                </template>
-                            </el-table-column>
-                            <el-table-column prop="date" width="150"></el-table-column>
-                            <el-table-column width="120">
-                                <template slot-scope="scope">
-                                    <el-button @click="handleRestore(scope.$index)">还原</el-button>
-                                </template>
-                            </el-table-column>
-                        </el-table>
-                        <div class="handle-row">
-                            <el-button type="danger">清空回收站</el-button>
-                        </div>
-                    </template>
-                </el-tab-pane>
-            </el-tabs>
-        </div>
-    </div>
-</template>
-
-<script>
-    export default {
-        name: 'tabs',
-        data() {
-            return {
-                message: 'first',
-                showHeader: false,
-                unread: [{
-                    date: '2018-04-19 20:00:00',
-                    title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护',
-                },{
-                    date: '2018-04-19 21:00:00',
-                    title: '今晚12点整发大红包,先到先得',
-                }],
-                read: [{
-                    date: '2018-04-19 20:00:00',
-                    title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
-                }],
-                recycle: [{
-                    date: '2018-04-19 20:00:00',
-                    title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
-                }]
-            }
-        },
-        methods: {
-            handleRead(index) {
-                const item = this.unread.splice(index, 1);
-                console.log(item);
-                this.read = item.concat(this.read);
-            },
-            handleDel(index) {
-                const item = this.read.splice(index, 1);
-                this.recycle = item.concat(this.recycle);
-            },
-            handleRestore(index) {
-                const item = this.recycle.splice(index, 1);
-                this.read = item.concat(this.read);
-            }
-        },
-        computed: {
-            unreadNum(){
-                return this.unread.length;
-            }
-        }
-    }
-
-</script>
-
-<style>
-.message-title{
-    cursor: pointer;
-}
-.handle-row{
-    margin-top: 30px;
-}
-</style>
-
+<template>
+    <div class="">
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item><i class="el-icon-lx-copy"></i> tab选项卡</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <el-tabs v-model="message">
+                <el-tab-pane :label="`未读消息(${unread.length})`" name="first">
+                    <el-table :data="unread" :show-header="false" style="width: 100%">
+                        <el-table-column>
+                            <template #default="scope">
+                                <span class="message-title">{{scope.row.title}}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="date" width="180"></el-table-column>
+                        <el-table-column width="120">
+                            <template #default="scope">
+                                <el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                    <div class="handle-row">
+                        <el-button type="primary">全部标为已读</el-button>
+                    </div>
+                </el-tab-pane>
+                <el-tab-pane :label="`已读消息(${read.length})`" name="second">
+                    <template v-if="message === 'second'">
+                        <el-table :data="read" :show-header="false" style="width: 100%">
+                            <el-table-column>
+                                <template #default="scope">
+                                    <span class="message-title">{{scope.row.title}}</span>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="date" width="150"></el-table-column>
+                            <el-table-column width="120">
+                                <template #default="scope">
+                                    <el-button type="danger" @click="handleDel(scope.$index)">删除</el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                        <div class="handle-row">
+                            <el-button type="danger">删除全部</el-button>
+                        </div>
+                    </template>
+                </el-tab-pane>
+                <el-tab-pane :label="`回收站(${recycle.length})`" name="third">
+                    <template v-if="message === 'third'">
+                        <el-table :data="recycle" :show-header="false" style="width: 100%">
+                            <el-table-column>
+                                <template #default="scope">
+                                    <span class="message-title">{{scope.row.title}}</span>
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="date" width="150"></el-table-column>
+                            <el-table-column width="120">
+                                <template #default="scope">
+                                    <el-button @click="handleRestore(scope.$index)">还原</el-button>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                        <div class="handle-row">
+                            <el-button type="danger">清空回收站</el-button>
+                        </div>
+                    </template>
+                </el-tab-pane>
+            </el-tabs>
+        </div>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'tabs',
+        data() {
+            return {
+                message: 'first',
+                showHeader: false,
+                unread: [{
+                    date: '2018-04-19 20:00:00',
+                    title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护',
+                },{
+                    date: '2018-04-19 21:00:00',
+                    title: '今晚12点整发大红包,先到先得',
+                }],
+                read: [{
+                    date: '2018-04-19 20:00:00',
+                    title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
+                }],
+                recycle: [{
+                    date: '2018-04-19 20:00:00',
+                    title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
+                }]
+            }
+        },
+        methods: {
+            handleRead(index) {
+                const item = this.unread.splice(index, 1);
+                console.log(item);
+                this.read = item.concat(this.read);
+            },
+            handleDel(index) {
+                const item = this.read.splice(index, 1);
+                this.recycle = item.concat(this.recycle);
+            },
+            handleRestore(index) {
+                const item = this.recycle.splice(index, 1);
+                this.read = item.concat(this.read);
+            }
+        },
+        computed: {
+            unreadNum(){
+                return this.unread.length;
+            }
+        }
+    }
+
+</script>
+
+<style>
+.message-title{
+    cursor: pointer;
+}
+.handle-row{
+    margin-top: 30px;
+}
+</style>
+

+ 176 - 0
src/views/Upload.vue

@@ -0,0 +1,176 @@
+<template>
+    <div>
+        <div class="crumbs">
+            <el-breadcrumb separator="/">
+                <el-breadcrumb-item>
+                    <i class="el-icon-lx-calendar"></i> 表单
+                </el-breadcrumb-item>
+                <el-breadcrumb-item>图片上传</el-breadcrumb-item>
+            </el-breadcrumb>
+        </div>
+        <div class="container">
+            <div class="content-title">支持拖拽</div>
+            <div class="plugins-tips">
+                Element UI自带上传组件。
+                访问地址:
+                <a
+                    href="http://element.eleme.io/#/zh-CN/component/upload"
+                    target="_blank"
+                >Element UI Upload</a>
+            </div>
+            <el-upload
+                class="upload-demo"
+                drag
+                action="http://jsonplaceholder.typicode.com/api/posts/"
+                multiple
+            >
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">
+                    将文件拖到此处,或
+                    <em>点击上传</em>
+                </div>
+                <template #tip>
+                    <div class="el-upload__tip">只能上传 jpg/png 文件,且不超过 500kb</div>
+                </template>
+            </el-upload>
+
+            <div class="content-title">支持裁剪</div>
+            <div class="plugins-tips">
+                vue-cropperjs:一个封装了 cropperjs 的 Vue 组件。
+                访问地址:
+                <a
+                    href="https://github.com/Agontuk/vue-cropperjs"
+                    target="_blank"
+                >vue-cropperjs</a>
+            </div>
+            <div class="crop-demo">
+                <img :src="cropImg" class="pre-img" />
+                <div class="crop-demo-btn">
+                    选择图片
+                    <input
+                        class="crop-input"
+                        type="file"
+                        name="image"
+                        accept="image/*"
+                        @change="setImage"
+                    />
+                </div>
+            </div>
+
+            <el-dialog title="裁剪图片" v-model="dialogVisible" width="600px">
+                <vue-cropper
+                    ref="cropper"
+                    :src="imgSrc"
+                    :ready="cropImage"
+                    :zoom="cropImage"
+                    :cropmove="cropImage"
+                    style="width:100%;height:300px;"
+                ></vue-cropper>
+                <template #footer>
+                    <span class="dialog-footer">
+                        <el-button @click="cancelCrop">取 消</el-button>
+                        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
+                    </span>
+                </template>
+            </el-dialog>
+        </div>
+    </div>
+</template>
+
+<script>
+import VueCropper from "vue-cropperjs";
+import "cropperjs/dist/cropper.css";
+export default {
+    data() {
+        return {
+            defaultSrc: require("../assets/img/img.jpg"),
+            fileList: [],
+            imgSrc: "",
+            cropImg: "",
+            dialogVisible: false
+        };
+    },
+    components: {
+        VueCropper
+    },
+    methods: {
+        setImage(e) {
+            const file = e.target.files[0];
+            if (!file.type.includes("image/")) {
+                return;
+            }
+            const reader = new FileReader();
+            reader.onload = event => {
+                this.dialogVisible = true;
+                this.imgSrc = event.target.result;
+                this.$refs.cropper &&
+                    this.$refs.cropper.replace(event.target.result);
+            };
+            reader.readAsDataURL(file);
+        },
+        cropImage() {
+            this.cropImg = this.$refs.cropper.getCroppedCanvas().toDataURL();
+        },
+        cancelCrop() {
+            this.dialogVisible = false;
+            this.cropImg = this.defaultSrc;
+        },
+        imageuploaded(res) {
+            console.log(res);
+        },
+        handleError() {
+            this.$notify.error({
+                title: "上传失败",
+                message: "图片上传接口上传失败,可更改为自己的服务器接口"
+            });
+        }
+    },
+    created() {
+        this.cropImg = this.defaultSrc;
+    }
+};
+</script>
+
+<style scoped>
+.content-title {
+    font-weight: 400;
+    line-height: 50px;
+    margin: 10px 0;
+    font-size: 22px;
+    color: #1f2f3d;
+}
+
+.pre-img {
+    width: 100px;
+    height: 100px;
+    background: #f8f8f8;
+    border: 1px solid #eee;
+    border-radius: 5px;
+}
+.crop-demo {
+    display: flex;
+    align-items: flex-end;
+}
+.crop-demo-btn {
+    position: relative;
+    width: 100px;
+    height: 40px;
+    line-height: 40px;
+    padding: 0 20px;
+    margin-left: 30px;
+    background-color: #409eff;
+    color: #fff;
+    font-size: 14px;
+    border-radius: 4px;
+    box-sizing: border-box;
+}
+.crop-input {
+    position: absolute;
+    width: 100px;
+    height: 40px;
+    left: 0;
+    top: 0;
+    opacity: 0;
+    cursor: pointer;
+}
+</style>

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