浏览代码

Merge branch 'dev' of https://github.com/wenjianzhang/go-admin-ui into dev

bing127 5 年之前
父节点
当前提交
9fec65f156
共有 100 个文件被更改,包括 2624 次插入274 次删除
  1. 4 0
      .npmrc
  2. 5 2
      package.json
  3. 54 0
      src/api/file.js
  4. 45 0
      src/api/syscategory.js
  5. 46 0
      src/api/syscontent.js
  6. 3 2
      src/api/sysjob.js
  7. 20 0
      src/api/table.js
  8. 14 0
      src/api/tools/gen.js
  9. 9 0
      src/api/ws.js
  10. 二进制
      src/assets/icons/12-01.png
  11. 二进制
      src/assets/icons/AU-01.png
  12. 二进制
      src/assets/icons/Access.png
  13. 二进制
      src/assets/icons/AndroidStudio.png
  14. 二进制
      src/assets/icons/Awesome.png
  15. 二进制
      src/assets/icons/AwesomeVue.png
  16. 二进制
      src/assets/icons/Clion-01-01.png
  17. 二进制
      src/assets/icons/Dm-01-01.png
  18. 二进制
      src/assets/icons/Edge-01.png
  19. 二进制
      src/assets/icons/Excel.png
  20. 二进制
      src/assets/icons/Ic-01.png
  21. 二进制
      src/assets/icons/Idea.png
  22. 二进制
      src/assets/icons/Link.png
  23. 二进制
      src/assets/icons/OneDrive.png
  24. 二进制
      src/assets/icons/OneNote.png
  25. 二进制
      src/assets/icons/PDFbeifen.png
  26. 二进制
      src/assets/icons/Phpstorm-01.png
  27. 二进制
      src/assets/icons/PictureUnknow.png
  28. 二进制
      src/assets/icons/Pictureloadingfailed.png
  29. 二进制
      src/assets/icons/Pl-01.png
  30. 二进制
      src/assets/icons/Pn-01.png
  31. 二进制
      src/assets/icons/PowerPoint.png
  32. 二进制
      src/assets/icons/PowerShell.png
  33. 二进制
      src/assets/icons/Pycharm.png
  34. 二进制
      src/assets/icons/Typora.png
  35. 二进制
      src/assets/icons/UTools.png
  36. 二进制
      src/assets/icons/Unknow.png
  37. 二进制
      src/assets/icons/Visio.png
  38. 二进制
      src/assets/icons/VisualStudio.png
  39. 二进制
      src/assets/icons/Web.png
  40. 二进制
      src/assets/icons/Webstorm.png
  41. 二进制
      src/assets/icons/Windows.png
  42. 二进制
      src/assets/icons/WindowsTerminal_PRE-01.png
  43. 二进制
      src/assets/icons/Word.png
  44. 二进制
      src/assets/icons/Wordbeifen.png
  45. 二进制
      src/assets/icons/Zip.png
  46. 二进制
      src/assets/icons/adobe-01-01-01.png
  47. 二进制
      src/assets/icons/bianxingjingang.png
  48. 二进制
      src/assets/icons/bianxingjingang1.png
  49. 二进制
      src/assets/icons/chayue2.png
  50. 二进制
      src/assets/icons/daiyue.png
  51. 二进制
      src/assets/icons/excelbeifen.png
  52. 二进制
      src/assets/icons/fl-01-01.png
  53. 二进制
      src/assets/icons/nasa.png
  54. 二进制
      src/assets/icons/pf-01.png
  55. 二进制
      src/assets/icons/picture.png
  56. 二进制
      src/assets/icons/pptbeifen.png
  57. 二进制
      src/assets/icons/rar.png
  58. 二进制
      src/assets/icons/tubiaozhizuomo3-01.png
  59. 二进制
      src/assets/icons/tubiaozhizuomoban-01.png
  60. 二进制
      src/assets/icons/tubiaozhizuomoban10-01.png
  61. 二进制
      src/assets/icons/tubiaozhizuomoban11.png
  62. 二进制
      src/assets/icons/tubiaozhizuomoban2-01-01.png
  63. 二进制
      src/assets/icons/tubiaozhizuomoban4-01.png
  64. 二进制
      src/assets/icons/tubiaozhizuomoban5-01.png
  65. 二进制
      src/assets/icons/tubiaozhizuomoban6-01.png
  66. 二进制
      src/assets/icons/tubiaozhizuomoban7-01-01.png
  67. 二进制
      src/assets/icons/tubiaozhizuomoban8-01.png
  68. 二进制
      src/assets/icons/tubiaozhizuomoban9-01.png
  69. 二进制
      src/assets/icons/txtbeifen.png
  70. 二进制
      src/assets/icons/video.png
  71. 二进制
      src/assets/icons/video2.png
  72. 二进制
      src/assets/icons/voice.png
  73. 二进制
      src/assets/icons/wendang.png
  74. 二进制
      src/assets/icons/wenjianjia.png
  75. 2 2
      src/components/Breadcrumb/index.vue
  76. 137 0
      src/components/DragColumn/index.vue
  77. 362 0
      src/components/FileManage/Left.vue
  78. 665 0
      src/components/FileManage/Right.vue
  79. 0 2
      src/components/SvgIcon/index.vue
  80. 116 0
      src/components/UploadDialog/form.vue
  81. 53 0
      src/components/UploadDialog/index.vue
  82. 11 11
      src/layout/components/AppMain.vue
  83. 7 4
      src/layout/components/Settings/index.vue
  84. 6 0
      src/layout/components/Sidebar/index.vue
  85. 56 19
      src/layout/components/TagsView/index.vue
  86. 10 1
      src/main.js
  87. 11 0
      src/utils/costum.js
  88. 2 0
      src/utils/eventbus.js
  89. 1 0
      src/utils/index.js
  90. 5 5
      src/views/dashboard/admin/index.vue
  91. 45 0
      src/views/fileManage/index.vue
  92. 0 166
      src/views/monitor/server/index.vue
  93. 353 0
      src/views/syscategory/index.vue
  94. 401 0
      src/views/syscontent/index.vue
  95. 52 45
      src/views/sysjob/index.vue
  96. 24 6
      src/views/sysjob/log.vue
  97. 3 3
      src/views/system/monitor.vue
  98. 1 1
      src/views/system/settings.vue
  99. 98 3
      src/views/tools/gen/editTable.vue
  100. 3 2
      src/views/tools/gen/genInfoForm.vue

+ 4 - 0
.npmrc

@@ -0,0 +1,4 @@
+sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
+phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
+electron_mirror=https://npm.taobao.org/mirrors/electron/
+registry=https://registry.npm.taobao.org

+ 5 - 2
package.json

@@ -44,6 +44,7 @@
   },
   },
   "dependencies": {
   "dependencies": {
     "@riophae/vue-treeselect": "0.4.0",
     "@riophae/vue-treeselect": "0.4.0",
+    "awe-dnd": "^0.3.4",
     "axios": "0.19.2",
     "axios": "0.19.2",
     "clipboard": "2.0.6",
     "clipboard": "2.0.6",
     "codemirror": "5.56.0",
     "codemirror": "5.56.0",
@@ -62,12 +63,14 @@
     "normalize.css": "8.0.1",
     "normalize.css": "8.0.1",
     "nprogress": "0.2.0",
     "nprogress": "0.2.0",
     "path-to-regexp": "6.1.0",
     "path-to-regexp": "6.1.0",
+    "remixicon": "^2.5.0",
     "sass-resources-loader": "^2.0.3",
     "sass-resources-loader": "^2.0.3",
     "screenfull": "5.0.2",
     "screenfull": "5.0.2",
     "showdown": "^1.9.1",
     "showdown": "^1.9.1",
     "solarlunar": "^2.0.7",
     "solarlunar": "^2.0.7",
-    "sortablejs": "1.10.2",
+    "sortablejs": "^1.10.2",
     "tui-editor": "1.4.10",
     "tui-editor": "1.4.10",
+    "uuid": "^8.3.0",
     "viser-vue": "^2.4.8",
     "viser-vue": "^2.4.8",
     "vue": "2.6.11",
     "vue": "2.6.11",
     "vue-count-to": "1.0.13",
     "vue-count-to": "1.0.13",
@@ -112,7 +115,7 @@
     "script-ext-html-webpack-plugin": "2.1.4",
     "script-ext-html-webpack-plugin": "2.1.4",
     "script-loader": "0.7.2",
     "script-loader": "0.7.2",
     "serve-static": "^1.14.1",
     "serve-static": "^1.14.1",
-    "svg-sprite-loader": "5.0.0",
+    "svg-sprite-loader": "^5.0.0",
     "svgo": "1.3.2",
     "svgo": "1.3.2",
     "vue-template-compiler": "2.6.11"
     "vue-template-compiler": "2.6.11"
   },
   },

+ 54 - 0
src/api/file.js

@@ -0,0 +1,54 @@
+import request from '@/utils/request'
+import { data } from 'autoprefixer'
+
+export const sysfiledirList = data => request({
+  url: '/api/v1/sysfiledirList',
+  method: 'GET',
+  data
+})
+
+export const sysfiledirAcionAdd = data => request({
+  url: '/api/v1/sysfiledir',
+  method: 'POST',
+  data
+})
+
+export const sysfiledirAcionEdit = data => request({
+  url: '/api/v1/sysfiledir',
+  method: 'PUT',
+  data
+})
+
+export const sysfiledirAcionDel = data => request({
+  url: '/api/v1/sysfiledir/' + data,
+  method: 'DELETE'
+})
+
+export const sysfileinfoList = data => request({
+  url: `/api/v1/sysfileinfoList?pId=${data.pId}&pageSize=${data.pageSize}&pageIndex=${data.pageIndex}`,
+  method: 'GET',
+  data
+})
+
+export const sysfileinfo = id => request({
+  url: '/api/v1/sysfileinfo/' + id,
+  method: 'GET'
+})
+
+export const sysfileinfoAdd = data => request({
+  url: '/api/v1/sysfileinfo',
+  method: 'POST',
+  data
+})
+
+export const sysfileinfoEdit = data => request({
+  url: '/api/v1/sysfileinfo',
+  method: 'put',
+  data
+})
+
+export const sysfileinfoDelete = id => request({
+  url: '/api/v1/sysfileinfo/' + id,
+  method: 'DELETE',
+  data
+})

+ 45 - 0
src/api/syscategory.js

@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+
+// 查询SysCategory列表
+export function listSysCategory(query) {
+  return request({
+    url: '/api/v1/syscategoryList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询SysCategory详细
+export function getSysCategory(id) {
+  return request({
+    url: '/api/v1/syscategory/' + id,
+    method: 'get'
+  })
+}
+
+// 新增SysCategory
+export function addSysCategory(data) {
+  return request({
+    url: '/api/v1/syscategory',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改SysCategory
+export function updateSysCategory(data) {
+  return request({
+    url: '/api/v1/syscategory',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除SysCategory
+export function delSysCategory(id) {
+  return request({
+    url: '/api/v1/syscategory/' + id,
+    method: 'delete'
+  })
+}
+

+ 46 - 0
src/api/syscontent.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+
+// 查询SysContent列表
+export function listSysContent(query) {
+return request({
+url: '/api/v1/syscontentList',
+method: 'get',
+params: query
+})
+}
+
+// 查询SysContent详细
+export function getSysContent (id) {
+return request({
+url: '/api/v1/syscontent/' + id,
+method: 'get'
+})
+}
+
+
+// 新增SysContent
+export function addSysContent(data) {
+return request({
+url: '/api/v1/syscontent',
+method: 'post',
+data: data
+})
+}
+
+// 修改SysContent
+export function updateSysContent(data) {
+return request({
+url: '/api/v1/syscontent',
+method: 'put',
+data: data
+})
+}
+
+// 删除SysContent
+export function delSysContent(id) {
+return request({
+url: '/api/v1/syscontent/' + id,
+method: 'delete'
+})
+}
+

+ 3 - 2
src/api/sysjob.js

@@ -36,10 +36,11 @@ export function updateSysJob(data) {
 }
 }
 
 
 // 删除SysJob
 // 删除SysJob
-export function delSysJob(jobId) {
+export function delSysJob(jobId, data) {
   return request({
   return request({
     url: '/api/v1/sysjob/' + jobId,
     url: '/api/v1/sysjob/' + jobId,
-    method: 'delete'
+    method: 'delete',
+    data: data
   })
   })
 }
 }
 
 

+ 20 - 0
src/api/table.js

@@ -0,0 +1,20 @@
+// 查询列表
+export function getItems(f, query) {
+  query = query || { pageSize: 10000 }
+  return f(query)
+}
+
+export function setItems(response, k, v) {
+  const data = []
+  k = k || 'id'
+  v = v || 'name'
+  if (response.data && response.data.list && response.data.list.length > 0) {
+    response.data.list.forEach(e => {
+      data.push({
+        key: e[k].toString(),
+        value: e[v].toString()
+      })
+    })
+    return data
+  }
+}

+ 14 - 0
src/api/tools/gen.js

@@ -25,6 +25,13 @@ export function getGenTable(tableId) {
   })
   })
 }
 }
 
 
+export function getGenTableInfo(tablename) {
+  return request({
+    url: '/api/v1/sys/tables?tableName=' + tablename,
+    method: 'get'
+  })
+}
+
 // 修改代码生成信息
 // 修改代码生成信息
 export function updateGenTable(data) {
 export function updateGenTable(data) {
   return request({
   return request({
@@ -79,3 +86,10 @@ export function toDBTable(tableId) {
     method: 'get'
     method: 'get'
   })
   })
 }
 }
+
+export function getTableTree() {
+  return request({
+    url: '/api/v1/gen/tabletree',
+    method: 'get'
+  })
+}

+ 9 - 0
src/api/ws.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 查询SysJob列表
+export function unWsLogout(id, group) {
+  return request({
+    url: '/wslogout/' + id + '/' + group,
+    method: 'get'
+  })
+}

二进制
src/assets/icons/12-01.png


二进制
src/assets/icons/AU-01.png


二进制
src/assets/icons/Access.png


二进制
src/assets/icons/AndroidStudio.png


二进制
src/assets/icons/Awesome.png


二进制
src/assets/icons/AwesomeVue.png


二进制
src/assets/icons/Clion-01-01.png


二进制
src/assets/icons/Dm-01-01.png


二进制
src/assets/icons/Edge-01.png


二进制
src/assets/icons/Excel.png


二进制
src/assets/icons/Ic-01.png


二进制
src/assets/icons/Idea.png


二进制
src/assets/icons/Link.png


二进制
src/assets/icons/OneDrive.png


二进制
src/assets/icons/OneNote.png


二进制
src/assets/icons/PDFbeifen.png


二进制
src/assets/icons/Phpstorm-01.png


二进制
src/assets/icons/PictureUnknow.png


二进制
src/assets/icons/Pictureloadingfailed.png


二进制
src/assets/icons/Pl-01.png


二进制
src/assets/icons/Pn-01.png


二进制
src/assets/icons/PowerPoint.png


二进制
src/assets/icons/PowerShell.png


二进制
src/assets/icons/Pycharm.png


二进制
src/assets/icons/Typora.png


二进制
src/assets/icons/UTools.png


二进制
src/assets/icons/Unknow.png


二进制
src/assets/icons/Visio.png


二进制
src/assets/icons/VisualStudio.png


二进制
src/assets/icons/Web.png


二进制
src/assets/icons/Webstorm.png


二进制
src/assets/icons/Windows.png


二进制
src/assets/icons/WindowsTerminal_PRE-01.png


二进制
src/assets/icons/Word.png


二进制
src/assets/icons/Wordbeifen.png


二进制
src/assets/icons/Zip.png


二进制
src/assets/icons/adobe-01-01-01.png


二进制
src/assets/icons/bianxingjingang.png


二进制
src/assets/icons/bianxingjingang1.png


二进制
src/assets/icons/chayue2.png


二进制
src/assets/icons/daiyue.png


二进制
src/assets/icons/excelbeifen.png


二进制
src/assets/icons/fl-01-01.png


二进制
src/assets/icons/nasa.png


二进制
src/assets/icons/pf-01.png


二进制
src/assets/icons/picture.png


二进制
src/assets/icons/pptbeifen.png


二进制
src/assets/icons/rar.png


二进制
src/assets/icons/tubiaozhizuomo3-01.png


二进制
src/assets/icons/tubiaozhizuomoban-01.png


二进制
src/assets/icons/tubiaozhizuomoban10-01.png


二进制
src/assets/icons/tubiaozhizuomoban11.png


二进制
src/assets/icons/tubiaozhizuomoban2-01-01.png


二进制
src/assets/icons/tubiaozhizuomoban4-01.png


二进制
src/assets/icons/tubiaozhizuomoban5-01.png


二进制
src/assets/icons/tubiaozhizuomoban6-01.png


二进制
src/assets/icons/tubiaozhizuomoban7-01-01.png


二进制
src/assets/icons/tubiaozhizuomoban8-01.png


二进制
src/assets/icons/tubiaozhizuomoban9-01.png


二进制
src/assets/icons/txtbeifen.png


二进制
src/assets/icons/video.png


二进制
src/assets/icons/video2.png


二进制
src/assets/icons/voice.png


二进制
src/assets/icons/wendang.png


二进制
src/assets/icons/wenjianjia.png


+ 2 - 2
src/components/Breadcrumb/index.vue

@@ -10,7 +10,7 @@
 </template>
 </template>
 
 
 <script>
 <script>
-import pathToRegexp from 'path-to-regexp'
+import { compile } from 'path-to-regexp'
 
 
 export default {
 export default {
   data() {
   data() {
@@ -52,7 +52,7 @@ export default {
     pathCompile(path) {
     pathCompile(path) {
       // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
       // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
       const { params } = this.$route
       const { params } = this.$route
-      var toPath = pathToRegexp.compile(path)
+      var toPath = compile(path)
       return toPath(params)
       return toPath(params)
     },
     },
     handleLink(item) {
     handleLink(item) {

+ 137 - 0
src/components/DragColumn/index.vue

@@ -0,0 +1,137 @@
+<template>
+  <div>
+    <div class="layout">
+      <div class="layout-left" :style="{ width: leftWidth }">
+        <slot name="left" />
+      </div>
+      <div ref="drag" class="layout-drag" :style="{ left: leftWidth }" @mousedown="handleDown">
+        <span class="line" />
+        <span class="line" />
+        <span class="line" />
+        <span class="line" />
+        <span class="line" />
+        <span class="line" />
+      </div>
+      <div class="layout-right" :style="{ width: rightWidth }">
+        <slot name="right" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'DragColumn',
+  data() {
+    return {
+      disX: 0,
+      layoutWidth: 0,
+      dragWidth: 0,
+      leftWidth: 0,
+      rightWidth: 0
+    }
+  },
+  mounted() {
+    this.layoutWidth = document.querySelector('.layout').clientWidth
+    this.dragWidth = document.querySelector('.layout-drag').clientWidth
+    this.leftWidth = (0.165 * this.layoutWidth) + 'px'
+    this.rightWidth = (0.825 * this.layoutWidth) + 'px'
+    window.onresize = () => {
+      this.layoutWidth = document.querySelector('.layout').clientWidth
+      this.dragWidth = document.querySelector('.layout-drag').clientWidth
+      this.leftWidth = (0.165 * this.layoutWidth) + 'px'
+      this.rightWidth = (0.825 * this.layoutWidth) + 'px'
+    }
+  },
+  methods: {
+    handleDown(e) {
+      const ev = e || event
+      const pos = this.getPos(ev)
+      const drag = this.$refs.drag
+      this.disX = pos.x - drag.offsetLeft
+      document.onmousemove = moveEvent => {
+        const oEvent = moveEvent || event
+        const movePos = this.getPos(oEvent)
+        const t = movePos.x - this.disX
+        const surplusWidth = this.layoutWidth - this.dragWidth - t
+        const leftWidth = this.layoutWidth - this.dragWidth - surplusWidth
+        if (leftWidth < 260) {
+          return false
+        } else if (surplusWidth < 260) {
+          return false
+        }
+        this.leftWidth = leftWidth + 'px'
+        this.rightWidth = surplusWidth + 'px'
+      }
+      document.onmouseup = () => {
+        document.onmousemove = null
+        document.onmouseup = null
+      }
+      return false
+    },
+    getPos(ev) {
+      const scrollTop = document.documentElement.scrollTop || document.body.scrollTop
+      const scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
+      return { x: ev.clientX + scrollLeft, y: ev.clientY + scrollTop }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.layout {
+  height: calc(100vh - 113px);
+  position: relative;
+  .layout-left {
+    width: 25.5%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+  }
+  .layout-drag {
+    width: 1%;
+    position: absolute;
+    height: 100%;
+    top: 0;
+    bottom: 0;
+    left: 25.5%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    cursor: col-resize;
+    &:active{
+      .line{
+        transition: all 0.3s ease-in-out;
+        background: #0f82ff;
+        width: 3.5px;
+        height: 3.5px;
+        border-radius: 50%;
+      }
+    }
+    .line {
+      display: inline-block;
+      width: 2px;
+      height: 2px;
+      background: #898989;
+      margin-bottom: 5px;
+      border-radius: 50%;
+    }
+  }
+  .layout-right {
+    width: 73.5%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+  }
+}
+.focus{
+  .line{
+    color: red;
+  }
+}
+</style>

+ 362 - 0
src/components/FileManage/Left.vue

@@ -0,0 +1,362 @@
+<template>
+  <div class="left">
+    <el-card>
+      <el-scrollbar>
+        <el-tree
+          ref="tree"
+          :data="data"
+          :props="defaultProps"
+          node-key="id"
+          :draggable="drag"
+          default-expand-all
+          :expand-on-click-node="false"
+          :indent="22"
+          @node-contextmenu="rightKeyClick"
+          @node-click="handleNodeClick"
+        >
+          <span slot-scope="{ node, data }" class="custom-tree-node">
+            <span>
+              <i
+                v-show="node.childNodes.length > 0"
+                class="icon"
+                :class="
+                  node.expanded ? 'el-icon-folder-opened' : 'el-icon-folder'
+                "
+              />
+              <span v-if="rename.status && rename.node.id === data.id">
+                <input
+                  ref="nodeInput"
+                  v-focus="rename.status"
+                  :value="node.label"
+                  placeholder="请输入目录名称"
+                  type="text"
+                  @blur.stop="handleBlur(node, data)"
+                  @keyup.enter="handleBlur(node, data)"
+                >
+              </span>
+              <span v-else class="file-name">
+                {{ node.label }}
+              </span>
+            </span>
+          </span>
+        </el-tree>
+      </el-scrollbar>
+    </el-card>
+    <div
+      v-show="visible"
+      id="perTreeMenu"
+      :style="{ ...rightMenu }"
+      class="contextmenu"
+    >
+      <div
+        class="contextMenu-item left-contextMenu-item"
+        @click="handleAction(1)"
+        @mouseover="handleTagsOver(0)"
+        @mouseleave="handleTagsLeave(0)"
+      >
+        <i class="el-icon-folder-add" />
+        <span> 创建目录</span>
+      </div>
+      <el-divider />
+      <div
+        class="contextMenu-item left-contextMenu-item"
+        @click="handleAction(2)"
+        @mouseover="handleTagsOver(1)"
+        @mouseleave="handleTagsLeave(1)"
+      >
+        <i class="el-icon-upload2" />
+        <span> 上传</span>
+      </div>
+      <el-divider />
+      <div
+        class="contextMenu-item left-contextMenu-item"
+        @click="handleAction(3)"
+        @mouseover="handleTagsOver(2)"
+        @mouseleave="handleTagsLeave(2)"
+      >
+        <i class="el-icon-edit" />
+        <span> 重命名</span>
+      </div>
+      <el-divider />
+      <div
+        class="contextMenu-item left-contextMenu-item"
+        @click="handleAction(4)"
+        @mouseover="handleTagsOver(3)"
+        @mouseleave="handleTagsLeave(3)"
+      >
+        <i class="el-icon-folder-delete" />
+        <span> 删除</span>
+      </div>
+    </div>
+    <upload-dialog
+      :show="uploadShow"
+      @confirm="handleUploadConfirm"
+      @cancel="handleUploadCancel"
+    />
+  </div>
+</template>
+
+<script>
+// eslint-disable-next-line no-unused-vars
+import { v1 as uuidv1 } from 'uuid'
+import UploadDialog from '@/components/UploadDialog/index'
+import {
+  sysfiledirList,
+  sysfiledirAcionAdd,
+  sysfiledirAcionEdit,
+  sysfiledirAcionDel
+} from '@/api/file'
+import eventBus from '@/utils/eventbus'
+export default {
+  name: 'Left',
+  components: {
+    UploadDialog
+  },
+  directives: {
+    focus: {
+      inserted: function(el, { value }) {
+        if (value) {
+          el.focus()
+          el.select()
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      rename: {
+        status: false,
+        node: ''
+      },
+      uploadShow: false,
+      drag: false,
+      data: [],
+      defaultProps: {
+        children: 'children',
+        label: 'label'
+      },
+      rightMenu: {},
+      visible: false
+    }
+  },
+  mounted() {
+    this.getDirList()
+  },
+  methods: {
+    handleNodeClick(e) {
+      const result = this.treeFindPath(this.data, node => node.id === e.id)
+      eventBus.$emit('treeNodeClick', {
+        treeNodePath: result,
+        currentNode: e
+      })
+    },
+    treeFindPath(tree, func, path = []) {
+      if (!tree) return []
+      for (const data of tree) {
+        path.push(data)
+        if (func(data)) return path
+        if (data.children) {
+          const findChildren = this.treeFindPath(data.children, func, path)
+          if (findChildren.length) return findChildren
+        }
+        path.pop()
+      }
+      return []
+    },
+    getDirList() {
+      sysfiledirList().then(ret => {
+        if (ret.code === 200) {
+          this.data = ret.data
+          eventBus.$emit('treeNodeClick', {
+            treeNodePath: ret.data,
+            currentNode: ret.data[0]
+          })
+        }
+      })
+    },
+    handleUploadConfirm() {
+      this.uploadShow = false
+    },
+    handleUploadCancel() {
+      this.uploadShow = false
+    },
+    handleTagsOver(index) {
+      const tags = document.querySelectorAll('.left-contextMenu-item')
+      const item = tags[index]
+      item.style.cssText = `color:${
+        this.$store.state.settings.theme
+      };background:${this.$store.state.settings.theme.colorRgb()}`
+    },
+    handleTagsLeave(index) {
+      const tags = document.querySelectorAll('.left-contextMenu-item')
+      const item = tags[index]
+      item.style.cssText = `color:#606266`
+    },
+    handleBlur(n, d) {
+      this.rename = {
+        status: false,
+        node: ''
+      }
+      d.label = this.$refs.nodeInput.value
+      console.log(d)
+      sysfiledirAcionEdit({
+        id: d.id,
+        label: d.label,
+        pId: d.pId
+      }).then(ret => {
+        if (ret.code === 200) {
+          this.$refs.tree.updateKeyChildren(n.id, d)
+        }
+      })
+    },
+    rightKeyClick(e, a, c) {
+      this.rightMenu = { top: e.pageY + 'px', left: e.pageX + 'px' }
+      this.visible = true
+      this.rightData = {
+        currentNode: c,
+        currentData: a
+      }
+      document.onclick = ev => {
+        if (ev.target !== document.getElementById('perTreeMenu')) {
+          this.visible = false
+        }
+      }
+    },
+    handleAction(e) {
+      switch (e) {
+        case 1:
+          sysfiledirAcionAdd({
+            label: '新建文件夹',
+            pId: this.rightData.currentData.id
+          }).then(ret => {
+            if (ret.code === 200) {
+              this.$refs.tree.append(ret.data, this.rightData.currentData.id)
+            }
+          })
+          break
+        case 2:
+          this.uploadShow = true
+          break
+        case 3:
+          this.rename = {
+            status: true,
+            node: this.rightData.currentData
+          }
+          console.log(this.rename)
+          break
+        case 4:
+          sysfiledirAcionDel(this.rightData.currentData.id).then(ret => {
+            if (ret.code === 200) {
+              this.$refs.tree.remove(this.rightData.currentNode)
+            }
+          })
+          break
+      }
+    }
+  }
+}
+
+// eslint-disable-next-line no-extend-native
+String.prototype.colorRgb = function() {
+  let sColor = this.toLowerCase()
+  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
+  if (sColor && reg.test(sColor)) {
+    if (sColor.length === 4) {
+      let sColorNew = '#'
+      for (let i = 1; i < 4; i += 1) {
+        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
+      }
+      sColor = sColorNew
+    }
+    const sColorChange = []
+    for (let i = 1; i < 7; i += 2) {
+      sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
+    }
+    return 'rgba(' + sColorChange.join(',') + ',0.2)'
+  } else {
+    return sColor
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.left /deep/ {
+  height: 100%;
+  .el-card {
+    height: 100%;
+    overflow: hidden;
+  }
+    .el-tree-node:focus>.el-tree-node__content{
+          background-color: rgba(24, 144, 255,0.9);
+        .icon{
+          color: #fff!important;
+        }
+        .file-name{
+          color: #fff!important;
+        }
+    }
+  .el-card__body {
+    padding: 10px !important;
+  }
+  .el-scrollbar {
+    height: calc(100vh - 133px);
+  }
+  .file-name {
+    color: rgb(71, 84, 102);
+    font-size: 14px;
+  }
+  .el-tree-node__content {
+    height: 35px;
+  }
+  .custom-tree-node {
+    .icon {
+      font-size: 16px;
+      color: #709fbe;
+    }
+  }
+  .el-tree-node :nth-child(2) {
+    padding: 1px;
+    overflow: visible;
+  }
+  .el-scrollbar__wrap::-webkit-scrollbar {
+    display: none;
+  }
+  input {
+    padding: 3px 8px;
+    box-sizing: border-box;
+    &:focus {
+      outline: none;
+      border-color: rgb(24, 144, 255);
+      box-shadow: 0 0 10px rgb(24, 144, 255);
+    }
+  }
+}
+.contextmenu {
+  background: #fff;
+  z-index: 3000;
+  position: fixed;
+  list-style-type: none;
+  border-radius: 4px;
+  box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.1), 0 1px 7px 0 rgba(0, 0, 0, 0.1);
+  -moz-user-select: none;
+  -webkit-user-select: none;
+  user-select: none;
+  .el-divider--horizontal {
+    margin: 0;
+  }
+  .contextMenu-item {
+    height: 46px;
+    cursor: pointer;
+    line-height: 46px;
+    width: 180px;
+    padding: 0 0 0 20px;
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    span {
+      margin-left: 6px;
+      font-size: 14.3px;
+    }
+  }
+}
+</style>

+ 665 - 0
src/components/FileManage/Right.vue

@@ -0,0 +1,665 @@
+<template>
+  <div class="right">
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <el-row>
+          <el-col :span="18">
+            <el-breadcrumb separator-class="el-icon-arrow-right" class="dir">
+              <el-breadcrumb-item
+                v-for="item in treePath.treeNodePath"
+                :key="item.id"
+                >{{ item.label }}</el-breadcrumb-item
+              >
+            </el-breadcrumb>
+          </el-col>
+          <el-col :span="6">
+            <div class="file-action">
+              <!-- <el-input
+                v-model="searchFile"
+                placeholder="请输入内容"
+                class="input-with-select"
+              >
+                <el-button slot="append" type="primary">搜索</el-button>
+              </el-input> -->
+              <div class="file-btn">
+                <div
+                  v-for="(item, index) in rightBtn"
+                  :key="index"
+                  class="file-btn-item"
+                  :class="index === rightIndex ? 'file-btn-item-active' : ''"
+                  @click="handleRightBtn(index)"
+                >
+                  <i :class="item.icon" />
+                </div>
+              </div>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+      <div
+        class="file-container"
+        @contextmenu.prevent="rightClick('', '', $event, 1)"
+      >
+        <el-scrollbar v-if="rightIndex === 0">
+          <div class="file-container-inner">
+            <div
+              v-for="(item, index) in tableData"
+              :key="index"
+              v-dragging="{ item: item, list: tableData, group: 'item' }"
+              class="file-item-inner"
+            >
+              <div
+                class="file-item"
+                @contextmenu.prevent.stop="rightClick(item, '', $event, 2)"
+              >
+                <div class="file-item-icon">
+                  <img :src="item.fullUrl | formatFile" alt="" />
+                </div>
+                <div v-if="!item.open" class="file-item-title">
+                  {{ item.name }}
+                </div>
+                <div v-else class="file-item-title">
+                  <el-input
+                    v-model="item.name"
+                    placeholder="请输入内容"
+                    @blur="handleBlur($event, item)"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-scrollbar>
+        <el-scrollbar v-else>
+          <el-table
+            :data="tableData"
+            highlight-current-row
+            border
+            style="width: 100%"
+          >
+            <el-table-column prop="name" align="center" label="文件名">
+              <template slot-scope="scope">
+                <span v-if="!scope.row.open" v-text="scope.row.name" />
+                <el-input
+                  v-else
+                  @blur="handleBlur($event, scope.row)"
+                  v-model="scope.row.name"
+                  placeholder="请输入内容"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column prop="createdAt" align="center" label="上传日期">
+              <template slot-scope="scope">
+                <span
+                  v-if="!scope.row.open"
+                  v-text="parseTime(scope.row.createdAt)"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column prop="type" align="center" label="文件类型">
+              <template slot-scope="scope">
+                <div class="type">
+                  <img :src="scope.row.fullUrl | formatFile" alt="" />
+                  <span v-text="scope.row.type" />
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column prop="size" align="center" label="文件大小">
+              <template slot-scope="scope">
+                <span v-text="renderSize(scope.row.size)" />
+              </template>
+            </el-table-column>
+            <el-table-column prop="action" align="center" label="操作">
+              <template slot-scope="scope">
+                <el-dropdown trigger="click">
+                  <span class="el-dropdown-link">
+                    操作<i class="el-icon-arrow-down el-icon--right"></i>
+                  </span>
+                  <el-dropdown-menu slot="dropdown">
+                    <el-dropdown-item icon="el-icon-folder-add" @click.native.stop="handleTableAction(scope.row,1)">上传</el-dropdown-item>
+                    <el-dropdown-item icon="el-icon-edit" @click.native.stop="handleTableAction(scope.row,2)">重命名</el-dropdown-item>
+                    <el-dropdown-item icon="el-icon-folder-delete" @click.native.stop="handleTableAction(scope.row,3)">删除</el-dropdown-item>
+                    <el-dropdown-item icon="el-icon-download" @click.native.stop="handleTableAction(scope.row,4)">下载</el-dropdown-item>
+                  </el-dropdown-menu>
+                </el-dropdown>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-scrollbar>
+        <div class="page">
+          <el-pagination
+            layout="prev, pager, next, jumper, total"
+            prev-text="上一页"
+            next-text="下一页"
+            @current-change="handlePage"
+            :current-page="pageNo"
+            :page-size="pageSize"
+            :total="total"
+          >
+          </el-pagination>
+        </div>
+      </div>
+    </el-card>
+    <div
+      v-show="visible"
+      id="perTreeMenu"
+      :style="{ ...rightMenu }"
+      class="contextmenu"
+    >
+      <div
+        class="right-contextMenu-item contextMenu-item"
+        @click="handleAction(1)"
+        @mouseover="handleTagsOver(0)"
+        @mouseleave="handleTagsLeave(0)"
+      >
+        <i class="el-icon-folder-add" />
+        <span> 上传</span>
+      </div>
+      <el-divider />
+      <div
+        v-show="!isBlank"
+        class="right-contextMenu-item contextMenu-item"
+        @click="handleAction(2)"
+        @mouseover="handleTagsOver(1)"
+        @mouseleave="handleTagsLeave(1)"
+      >
+        <i class="el-icon-edit" />
+        <span> 重命名</span>
+      </div>
+      <el-divider />
+      <div
+        v-show="!isBlank"
+        class="right-contextMenu-item contextMenu-item"
+        @click="handleAction(3)"
+        @mouseover="handleTagsOver(2)"
+        @mouseleave="handleTagsLeave(2)"
+      >
+        <i class="el-icon-folder-delete" />
+        <span> 删除</span>
+      </div>
+      <el-divider />
+      <div
+        v-show="!isBlank"
+        class="right-contextMenu-item contextMenu-item"
+        @click="handleAction(4)"
+        @mouseover="handleTagsOver(3)"
+        @mouseleave="handleTagsLeave(3)"
+      >
+        <i class="el-icon-download" />
+        <span> 下载</span>
+      </div>
+    </div>
+    <upload-dialog
+      :show="uploadShow"
+      @confirm="handleUploadConfirm"
+      @cancel="handleUploadCancel"
+    />
+  </div>
+</template>
+
+<script>
+import Sortable from "sortablejs";
+import UploadDialog from "@/components/UploadDialog/index";
+import eventBus from "@/utils/eventbus";
+import { parseTime } from "@/utils";
+import {
+  sysfileinfo,
+  sysfileinfoList,
+  sysfileinfoAdd,
+  sysfileinfoEdit,
+  sysfileinfoDelete
+} from "@/api/file";
+export default {
+  name: "Right",
+  components: {
+    UploadDialog
+  },
+  data() {
+    return {
+      uploadShow: false,
+      pageNo: 1,
+      pageSize: 50,
+      total: 0,
+      rightBtn: [
+        {
+          icon: "el-icon-s-grid"
+        },
+        {
+          icon: "ri-table-fill"
+        }
+      ],
+      rightIndex: 0,
+      rightData: {},
+      tableData: [],
+      searchFile: "",
+      height: 0,
+      visible: false,
+      rightMenu: {},
+      treePath: {},
+      isBlank: false
+    };
+  },
+  filters: {
+    formatFile(pic) {
+      let type = pic.substring(pic.lastIndexOf(".") + 1, pic.length);
+      const FileIcons = [
+        {
+          icon: "",
+          matchList: ["bmp", "jpg", "png", "jpeg", "gif", "webp"]
+        },
+        {
+          icon: require("../../assets/icons/txtbeifen.png"),
+          matchList: ["text", "txt"]
+        },
+        {
+          icon: require("../../assets/icons/Zip.png"),
+          matchList: ["zip", "tar", "7z"]
+        },
+        {
+          icon: require("../../assets/icons/rar.png"),
+          matchList: ["rar"]
+        },
+        {
+          icon: require("../../assets/icons/Word.png"),
+          matchList: ["doc", "docx"]
+        },
+        {
+          icon: require("../../assets/icons/pptbeifen.png"),
+          matchList: ["ppt", "pptx"]
+        },
+        {
+          icon: require("../../assets/icons/Excel.png"),
+          matchList: ["xlsx", "xls"]
+        },
+        {
+          icon: require("../../assets/icons/PDFbeifen.png"),
+          matchList: ["pdf", "pdfx"]
+        },
+        {
+          icon: require("../../assets/icons/Idea.png"),
+          matchList: ["java", "class", "jar", "kt"]
+        },
+        {
+          icon: require("../../assets/icons/tubiaozhizuomoban-01.png"),
+          matchList: ["psd"]
+        },
+        {
+          icon: require("../../assets/icons/tubiaozhizuomoban2-01-01.png"),
+          matchList: ["ai"]
+        },
+        {
+          icon: require("../../assets/icons/Web.png"),
+          matchList: ["ts", "html", "css", "js"]
+        },
+        {
+          icon: require("../../assets/icons/video2.png"),
+          matchList: ["mp4"]
+        },
+        {
+          icon: require("../../assets/icons/voice.png"),
+          matchList: ["mp3"]
+        },
+        {
+          icon: require("../../assets/icons/AwesomeVue.png"),
+          matchList: ["vue"]
+        },
+        {
+          icon: require("../../assets/icons/Pycharm.png"),
+          matchList: ["py"]
+        },
+        {
+          icon: require("../../assets/icons/Phpstorm-01.png"),
+          matchList: ["php"]
+        }
+      ];
+      const UnknowIcon = require("../../assets/icons/Unknow.png");
+      if (FileIcons[0].matchList.includes(type)) {
+        return pic;
+      } else {
+        let file = FileIcons.filter(item => item.matchList.includes(type));
+        if (file.length > 0) {
+          return file[0].icon;
+        } else {
+          return UnknowIcon;
+        }
+      }
+    }
+  },
+  mounted() {
+    eventBus.$on("treeNodeClick", e => {
+      this.treePath = e;
+      this.getList();
+    });
+    this.rowDrop();
+    this.height = document.querySelector(".layout-right").clientHeight - 107;
+  },
+  destroyed() {
+    eventBus.$off("treeNodeClick");
+  },
+  methods: {
+    handlePage(e) {
+      this.pageNo = e;
+      this.getList();
+    },
+    getList() {
+      const pId = this.treePath.currentNode.id;
+      if (pId) {
+        sysfileinfoList({
+          pId,
+          pageIndex: this.pageNo,
+          pageSize: this.pageSize
+        }).then(ret => {
+          if (ret.code === 200) {
+            this.total = ret.data.count;
+            this.tableData = ret.data.list.map(item => {
+              return {
+                ...item,
+                open: false
+              };
+            });
+          }
+        });
+      }
+    },
+    handleUploadConfirm(e) {
+      this.uploadMultiple(e).then(ret => {
+        if (ret) {
+          this.getList();
+        }
+      });
+      this.uploadShow = false;
+    },
+    uploadMultiple(e) {
+      const path = e.map(item => {
+        return sysfileinfoAdd({
+          type: item.type,
+          name: item.name,
+          size: `${item.size}`,
+          url: item.path,
+          fullUrl: item.full_path,
+          pId: this.treePath.currentNode.id
+        });
+      });
+      return Promise.all(path);
+    },
+    handleUploadCancel() {
+      this.uploadShow = false;
+    },
+    handleTableAction(a,b) {
+      console.log(typeof b)
+      console.log(a)
+        this.rightData.currentData = a;
+        this.handleAction(b)
+    },
+    handleAction(e) {
+      switch (e) {
+        case 1:
+          this.uploadShow = true;
+          break;
+        case 2:
+          this.tableData.forEach((item, index) => {
+            if (item.id === this.rightData.currentData.id) {
+              this.tableData[index].open = true;
+            }
+          });
+          break;
+        case 3:
+          sysfileinfoDelete(this.rightData.currentData.id).then(ret => {
+            if (ret.code === 200) {
+              this.getList();
+            }
+          });
+          break;
+        case 4:
+          window.open(this.rightData.currentData.fullUrl);
+          break;
+      }
+    },
+    handleTagsOver(index) {
+      const tags = document.querySelectorAll(".right-contextMenu-item");
+      const item = tags[index];
+      item.style.cssText = `color:${
+        this.$store.state.settings.theme
+      };background:${this.$store.state.settings.theme.colorRgb()}`;
+    },
+    handleTagsLeave(index) {
+      const tags = document.querySelectorAll(".right-contextMenu-item");
+      const item = tags[index];
+      item.style.cssText = `color:#606266`;
+    },
+    rightClick(a, b, c, d) {
+      c.preventDefault();
+      this.rightMenu = { top: c.pageY + "px", left: c.pageX + "px" };
+      this.visible = true;
+      if (!a) {
+        this.isBlank = true;
+      } else {
+        this.isBlank = false;
+      }
+      this.rightData = {
+        currentNode: b,
+        currentData: a
+      };
+      document.onclick = ev => {
+        if (ev.target !== document.getElementById("perTreeMenu")) {
+          this.visible = false;
+        }
+      };
+    },
+    handleBlur(a, b) {
+      console.log(a, b);
+      if (this.tableData.length > 0) {
+        this.tableData.forEach(item => {
+          item.open = false;
+        });
+        sysfileinfoEdit({
+          ...b
+        });
+      }
+    },
+    rowDrop() {
+      const tbody = document.querySelector(".el-table__body-wrapper tbody");
+      if (tbody) {
+        const _this = this;
+        Sortable.create(tbody, {
+          onEnd({ newIndex, oldIndex }) {
+            const currRow = _this.tableData.splice(oldIndex, 1)[0];
+            _this.tableData.splice(newIndex, 0, currRow);
+          }
+        });
+      }
+    },
+    handleRightBtn(e) {
+      this.rightIndex = e;
+    },
+    renderSize(value) {
+      if (value === null || value === "") {
+        return "0 Bytes";
+      }
+      const unitArr = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
+      let index = 0;
+      const srcsize = parseFloat(value);
+      index = Math.floor(Math.log(srcsize) / Math.log(1024));
+      let size = srcsize / Math.pow(1024, index);
+      size = size.toFixed(2);
+      return size + unitArr[index];
+    }
+  }
+};
+
+// eslint-disable-next-line no-extend-native
+String.prototype.colorRgb = function() {
+  let sColor = this.toLowerCase();
+  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
+  if (sColor && reg.test(sColor)) {
+    if (sColor.length === 4) {
+      let sColorNew = "#";
+      for (let i = 1; i < 4; i += 1) {
+        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
+      }
+      sColor = sColorNew;
+    }
+    const sColorChange = [];
+    for (let i = 1; i < 7; i += 2) {
+      sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2)));
+    }
+    return "rgba(" + sColorChange.join(",") + ",0.2)";
+  } else {
+    return sColor;
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.file-btn {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  margin-left: 8px;
+  .file-btn-item {
+    width: 35px;
+    height: 35px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: pointer;
+    border-radius: 3px;
+    i {
+      font-size: 20px;
+      border-color: #ccc;
+      color: #8a8a8a;
+    }
+  }
+}
+.file-btn-item-active {
+  background-color: #e6e6e6;
+}
+.file-action {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+}
+.dir {
+  height: 36px;
+  line-height: 36px;
+}
+.file-container /deep/ {
+  .el-scrollbar__wrap::-webkit-scrollbar {
+    display: none;
+  }
+  .el-table .cell {
+    line-height: 35px;
+  }
+  .el-table thead {
+    tr {
+      background-color: #d8e5f0 !important;
+    }
+  }
+  .el-table .el-table__header-wrapper th {
+    background-color: transparent;
+  }
+  .file-item-inner {
+    width: 12%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    cursor: move;
+  }
+  .file-container-inner {
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    flex-wrap: wrap;
+  }
+  .file-item {
+    width: 130px;
+    height: 130px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    .file-item-icon {
+      margin-bottom: 5px;
+      img {
+        width: 50px;
+        height: 50px;
+      }
+    }
+    .file-item-title {
+      word-break: break-all;
+      font-size: 14px;
+      line-height: 20px;
+      text-align: center;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      width: 60%;
+    }
+    &:active {
+      background-color: #f0f1f5;
+    }
+  }
+  .el-scrollbar {
+    height: calc(100vh - 280px);
+  }
+  .page {
+    height: 60rpx;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+}
+.right {
+  height: 100%;
+  .el-card {
+    height: 100%;
+  }
+}
+.file {
+  position: relative;
+}
+
+.contextmenu {
+  background: #fff;
+  z-index: 3000;
+  position: fixed;
+  list-style-type: none;
+  border-radius: 4px;
+  box-shadow: 0 3px 10px 0 rgba(0, 0, 0, 0.1), 0 1px 7px 0 rgba(0, 0, 0, 0.1);
+  -moz-user-select: none;
+  -webkit-user-select: none;
+  user-select: none;
+  .el-divider--horizontal {
+    margin: 0;
+  }
+  .contextMenu-item {
+    height: 46px;
+    cursor: pointer;
+    line-height: 46px;
+    width: 180px;
+    padding: 0 0 0 20px;
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    color: #333;
+    span {
+      margin-left: 6px;
+      font-size: 14.3px;
+    }
+    //&:hover {
+    //  color: currentColor;
+    //  background: currentColor;
+    //}
+  }
+}
+
+.type {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  img {
+    width: 20px;
+    height: 20px;
+    margin-right: 5px;
+  }
+}
+</style>

+ 0 - 2
src/components/SvgIcon/index.vue

@@ -8,7 +8,6 @@
 <script>
 <script>
 // doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
 // doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
 import { isExternal } from '@/utils/validate'
 import { isExternal } from '@/utils/validate'
-
 export default {
 export default {
   name: 'SvgIcon',
   name: 'SvgIcon',
   props: {
   props: {
@@ -53,7 +52,6 @@ export default {
   fill: currentColor;
   fill: currentColor;
   overflow: hidden;
   overflow: hidden;
 }
 }
-
 .svg-external-icon {
 .svg-external-icon {
   background-color: currentColor;
   background-color: currentColor;
   mask-size: cover!important;
   mask-size: cover!important;

+ 116 - 0
src/components/UploadDialog/form.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="form">
+    <el-form ref="form" :model="form" label-width="100px" label-position="left">
+      <el-form-item label="上传数据源">
+        <el-radio-group v-model="form.dataSource">
+          <el-radio-button label="1">本地</el-radio-button>
+          <el-radio-button label="2">阿里云OSS</el-radio-button>
+          <el-radio-button label="3">七牛云</el-radio-button>
+          <el-radio-button label="4">腾讯云COS</el-radio-button>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <el-tabs v-model="activeTab">
+      <el-tab-pane label="文件" name="1">
+        <el-upload
+          ref="upload"
+          class="upload-demo"
+          drag
+          :action="url"
+          :auto-upload="false"
+          :limit="limit"
+          :on-exceed="handleLimit"
+          :http-request="uploadFile"
+          multiple
+        >
+          <i class="el-icon-upload" />
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+        </el-upload>
+      </el-tab-pane>
+      <el-tab-pane label="Base64文件" name="2">
+        <el-input
+          v-model="form.base64"
+          type="textarea"
+          :autosize="{ minRows: 7, maxRows: 8 }"
+        />
+      </el-tab-pane>
+    </el-tabs>
+    <div class="dialog-footer">
+      <el-button @click="cancel">关 闭</el-button>
+      <el-button type="primary" @click="confirm">提 交</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import request from '@/utils/request'
+export default {
+  name: 'UploadForm',
+  data() {
+    return {
+      url: process.env.VUE_APP_BASE_API + '/api/v1/public/uploadFile',
+      activeTab: '1',
+      form: {
+        dataSource: '1',
+        base64: ''
+      },
+      formData: '',
+      limit:10
+    }
+  },
+  mounted() {},
+  methods: {
+    handleLimit(e) {
+      if(e.length > this.limit) {
+         this.$message({
+          message: `最大单次只可上传${this.limit}条`,
+          type: 'warning'
+        });
+      }
+    },
+    uploadFile(file) {
+      this.formData.append('file', file.file)
+    },
+    confirm() {
+      if (this.activeTab === '2') {
+        this.formData = new FormData()
+        this.formData.append('file', this.form.base64)
+        this.formData.append('type', '3')
+      } else {
+        this.formData = new FormData()
+        this.$refs.upload.submit()
+        this.formData.append('type', '2')
+      }
+      request.post(this.url, this.formData, {
+        'Content-Type': 'multipart/form-data'
+      }).then(ret => {
+        if (ret.code === 200) {
+          this.form.base64 = ''
+          this.$refs.upload.clearFiles()
+          this.$emit('confirm', Array.isArray(ret.data) ? ret.data : [ret.data])
+        }
+      })
+    },
+    cancel() {
+      this.$emit('cancel')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.form /deep/ {
+  .el-upload {
+    width: 100%;
+  }
+  .el-upload-dragger {
+    width: 100%;
+  }
+}
+.dialog-footer {
+  padding: 30px 0;
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+}
+</style>

+ 53 - 0
src/components/UploadDialog/index.vue

@@ -0,0 +1,53 @@
+<template>
+  <div class="upload-dialog">
+    <el-dialog
+      v-dialogDrag
+      title="上传文件"
+      :visible.sync="show"
+      width="30%"
+      @close="cancel"
+    >
+      <upload-form @confirm="confirm" @cancel="cancel"/>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import UploadForm from './form'
+export default {
+  name: 'UploadDialog',
+  components: {
+    UploadForm
+  },
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+
+    }
+  },
+  mounted() {
+
+  },
+  methods: {
+    confirm(e) {
+      this.$emit('confirm', e)
+    },
+    cancel() {
+      this.$emit('cancel')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .upload-dialog /deep/ {
+    .el-dialog__body{
+      padding: 30px 20px 0 20px;
+    }
+  }
+</style>

+ 11 - 11
src/layout/components/AppMain.vue

@@ -25,26 +25,26 @@ export default {
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .app-main {
 .app-main {
   /* 50= navbar  50  */
   /* 50= navbar  50  */
-  min-height: calc(100vh - 50px);
+  min-height: calc(100vh - 93px);
   width: 100%;
   width: 100%;
   position: relative;
   position: relative;
   overflow: hidden;
   overflow: hidden;
 }
 }
 
 
 .fixed-header+.app-main {
 .fixed-header+.app-main {
-  padding-top: 50px;
+  padding-top: 93px;
 }
 }
 
 
-.hasTagsView {
-  .app-main {
-    /* 84 = navbar + tags-view = 50 + 34 */
-    min-height: calc(100vh - 93px);
-  }
+// .hasTagsView {
+//   .app-main {
+//     /* 84 = navbar + tags-view = 50 + 34 */
+//     min-height: calc(100vh - 93px);
+//   }
 
 
-  .fixed-header+.app-main {
-    padding-top: 93px;
-  }
-}
+//   .fixed-header+.app-main {
+//     padding-top: 93px;
+//   }
+// }
 </style>
 </style>
 
 
 <style lang="scss">
 <style lang="scss">

+ 7 - 4
src/layout/components/Settings/index.vue

@@ -43,17 +43,17 @@
         </div>
         </div>
         <div class="drawer-item">
         <div class="drawer-item">
           <span>开启任务栏</span>
           <span>开启任务栏</span>
-          <el-switch v-model="tagsView" class="drawer-switch" />
+          <el-switch v-model="tagsView" :active-color="activeColor" class="drawer-switch" />
         </div>
         </div>
 
 
         <div class="drawer-item">
         <div class="drawer-item">
           <span>Header 固定</span>
           <span>Header 固定</span>
-          <el-switch v-model="fixedHeader" class="drawer-switch" />
+          <el-switch :active-color="activeColor" v-model="fixedHeader" class="drawer-switch" />
         </div>
         </div>
 
 
         <div class="drawer-item">
         <div class="drawer-item">
           <span>侧边栏Logo</span>
           <span>侧边栏Logo</span>
-          <el-switch v-model="sidebarLogo" class="drawer-switch" />
+          <el-switch :active-color="activeColor" v-model="sidebarLogo" class="drawer-switch" />
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>
@@ -66,7 +66,9 @@ import ThemePicker from '@/components/ThemePicker'
 export default {
 export default {
   components: { ThemePicker },
   components: { ThemePicker },
   data() {
   data() {
-    return {}
+    return {
+      activeColor: this.$store.state.settings.theme
+    }
   },
   },
   computed: {
   computed: {
     theme() {
     theme() {
@@ -111,6 +113,7 @@ export default {
   },
   },
   methods: {
   methods: {
     themeChange(val) {
     themeChange(val) {
+      this.activeColor = val
       this.$store.dispatch('settings/changeSetting', {
       this.$store.dispatch('settings/changeSetting', {
         key: 'theme',
         key: 'theme',
         value: val
         value: val

+ 6 - 0
src/layout/components/Sidebar/index.vue

@@ -49,6 +49,12 @@ export default {
     isCollapse() {
     isCollapse() {
       return !this.sidebar.opened
       return !this.sidebar.opened
     }
     }
+  },
+  mounted() {
+
+  },
+  methods: {
+
   }
   }
 }
 }
 </script>
 </script>

+ 56 - 19
src/layout/components/TagsView/index.vue

@@ -11,25 +11,24 @@
         :closable="item.fullPath === '/dashboard' ? false : true"
         :closable="item.fullPath === '/dashboard' ? false : true"
         :name="item.fullPath"
         :name="item.fullPath"
       >
       >
-        <template #label>
-          <router-link
-            ref="tag"
-            tag="span"
-            class="tags-view-item"
-            :style="{ color: item.fullPath === $route.fullPath ? theme : '' }"
-            :to="{ path: item.path, query: item.query, fullPath: item.fullPath }"
-            @contextmenu.prevent.native="openMenu(item,$event)"
-          >
-            {{ item.title }}
-          </router-link>
-        </template>
+        <router-link
+          ref="tag"
+          slot="label"
+          tag="span"
+          class="tags-view-item"
+          :style="{ color: item.fullPath === $route.fullPath ? theme : '' }"
+          :to="{ path: item.path, query: item.query, fullPath: item.fullPath }"
+          @contextmenu.prevent.native="openMenu(item,$event)"
+        >
+          {{ item.title }}
+        </router-link>
       </el-tab-pane>
       </el-tab-pane>
     </el-tabs>
     </el-tabs>
     <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
     <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
-      <li @click="refreshSelectedTag(selectedTag)">刷新当前标签页</li>
-      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前标签页</li>
-      <li @click="closeOthersTags">关闭其他标签页</li>
-      <li @click="closeAllTags(selectedTag)">关闭全部标签页</li>
+      <li class="tags-item" @click="refreshSelectedTag(selectedTag)" @mouseover="handleTagsOver(1)" @mouseleave="handleTagsLeave(1)">刷新当前标签页</li>
+      <li v-if="!isAffix(selectedTag)" class="tags-item" @click="closeSelectedTag(selectedTag)" @mouseover="handleTagsOver(2)" @mouseleave="handleTagsLeave(2)">关闭当前标签页</li>
+      <li class="tags-item" @click="closeOthersTags" @mouseover="handleTagsOver(3)" @mouseleave="handleTagsLeave(3)">关闭其他标签页</li>
+      <li class="tags-item" @click="closeAllTags(selectedTag)" @mouseover="handleTagsOver(4)" @mouseleave="handleTagsLeave(4)">关闭全部标签页</li>
     </ul>
     </ul>
   </div>
   </div>
 </template>
 </template>
@@ -77,6 +76,18 @@ export default {
     this.isActive()
     this.isActive()
   },
   },
   methods: {
   methods: {
+    handleTagsOver(index) {
+      const tags = document.querySelectorAll('.tags-item')
+      const item = tags[index - 1]
+      item.style.cssText = `color:${this.$store.state.settings.theme};background:${
+        this.$store.state.settings.theme.colorRgb()
+      }`
+    },
+    handleTagsLeave(index) {
+      const tags = document.querySelectorAll('.tags-item')
+      const item = tags[index - 1]
+      item.style.cssText = `color:#606266`
+    },
     isActive() {
     isActive() {
       const index = this.visitedViews.findIndex(item => item.fullPath === this.$route.fullPath)
       const index = this.visitedViews.findIndex(item => item.fullPath === this.$route.fullPath)
       const pathIndex = index > -1 ? index : 0
       const pathIndex = index > -1 ? index : 0
@@ -211,10 +222,30 @@ export default {
     }
     }
   }
   }
 }
 }
+
+String.prototype.colorRgb = function() {
+  let sColor = this.toLowerCase()
+  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
+  if (sColor && reg.test(sColor)) {
+    if (sColor.length === 4) {
+      let sColorNew = '#'
+      for (let i = 1; i < 4; i += 1) {
+        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
+      }
+      sColor = sColorNew
+    }
+    const sColorChange = []
+    for (let i = 1; i < 7; i += 2) {
+      sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
+    }
+    return 'rgba(' + sColorChange.join(',') + ',0.2)'
+  } else {
+    return sColor
+  }
+}
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
-
 .tags-view-container /deep/{
 .tags-view-container /deep/{
   height: 43px;
   height: 43px;
   width: 100%;
   width: 100%;
@@ -280,13 +311,19 @@ export default {
     font-size: 12px;
     font-size: 12px;
     font-weight: 400;
     font-weight: 400;
     color: #333;
     color: #333;
-    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+    box-shadow: 1px 2px 10px #ccc;
     -moz-user-select:none;
     -moz-user-select:none;
     -webkit-user-select:none;
     -webkit-user-select:none;
     user-select:none;
     user-select:none;
     li {
     li {
+      list-style: none;
+      line-height: 36px;
+      padding: 2px 20px;
       margin: 0;
       margin: 0;
-      padding: 10px 22px;
+      font-size: 14px;
+      color: #606266;
+      cursor: pointer;
+      outline: 0;
       cursor: pointer;
       cursor: pointer;
       &:hover {
       &:hover {
         background: #eee;
         background: #eee;

+ 10 - 1
src/main.js

@@ -16,8 +16,9 @@ import router from './router'
 import permission from './directive/permission'
 import permission from './directive/permission'
 
 
 import { getDicts } from '@/api/system/dict/data'
 import { getDicts } from '@/api/system/dict/data'
+import { getItems, setItems } from '@/api/table'
 import { getConfigKey } from '@/api/system/config'
 import { getConfigKey } from '@/api/system/config'
-import { parseTime, resetForm, addDateRange, selectDictLabel, download } from '@/utils/costum'
+import { parseTime, resetForm, addDateRange, selectDictLabel, download, selectItemsLabel } from '@/utils/costum'
 
 
 import './icons' // icon
 import './icons' // icon
 import './permission' // permission control
 import './permission' // permission control
@@ -38,11 +39,14 @@ import '@/utils/dialog'
 
 
 // 全局方法挂载
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts
 Vue.prototype.getDicts = getDicts
+Vue.prototype.getItems = getItems
+Vue.prototype.setItems = setItems
 Vue.prototype.getConfigKey = getConfigKey
 Vue.prototype.getConfigKey = getConfigKey
 Vue.prototype.parseTime = parseTime
 Vue.prototype.parseTime = parseTime
 Vue.prototype.resetForm = resetForm
 Vue.prototype.resetForm = resetForm
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.selectDictLabel = selectDictLabel
 Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectItemsLabel = selectItemsLabel
 Vue.prototype.download = download
 Vue.prototype.download = download
 
 
 // 全局组件挂载
 // 全局组件挂载
@@ -67,6 +71,11 @@ Vue.use(Element, {
   size: Cookies.get('size') || 'medium' // set element-ui default size
   size: Cookies.get('size') || 'medium' // set element-ui default size
 })
 })
 
 
+import VueDND from 'awe-dnd'
+Vue.use(VueDND)
+
+import 'remixicon/fonts/remixicon.css'
+
 // register global utility filters
 // register global utility filters
 Object.keys(filters).forEach(key => {
 Object.keys(filters).forEach(key => {
   Vue.filter(key, filters[key])
   Vue.filter(key, filters[key])

+ 11 - 0
src/utils/costum.js

@@ -69,6 +69,17 @@ export function selectDictLabel(datas, value) {
   return actions.join('')
   return actions.join('')
 }
 }
 
 
+export function selectItemsLabel(datas, value) {
+  var actions = []
+  Object.keys(datas).map((key) => {
+    if (datas[key].key === ('' + value)) {
+      actions.push(datas[key].value)
+      return false
+    }
+  })
+  return actions.join('')
+}
+
 // 字符串格式化(%s )
 // 字符串格式化(%s )
 export function sprintf(str) {
 export function sprintf(str) {
   var args = arguments; var flag = true; var i = 1
   var args = arguments; var flag = true; var i = 1

+ 2 - 0
src/utils/eventbus.js

@@ -0,0 +1,2 @@
+import Vue from 'vue'
+export default new Vue()

+ 1 - 0
src/utils/index.js

@@ -360,3 +360,4 @@ export function formatJson(filterVal, jsonData) {
     }
     }
   }))
   }))
 }
 }
+

+ 5 - 5
src/views/dashboard/admin/index.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div class="dashboard-editor-container">
   <div class="dashboard-editor-container">
     <el-row :gutter="12">
     <el-row :gutter="12">
-      <el-col :sm="24" :xs="6" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
+      <el-col :sm="24" :xs="24" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
         <chart-card title="总销售额" total="¥126,560">
         <chart-card title="总销售额" total="¥126,560">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
             <i class="el-icon-warning-outline" />
             <i class="el-icon-warning-outline" />
@@ -17,7 +17,7 @@
           <template slot="footer">日均销售额<span>¥ 234.56</span></template>
           <template slot="footer">日均销售额<span>¥ 234.56</span></template>
         </chart-card>
         </chart-card>
       </el-col>
       </el-col>
-      <el-col :sm="24" :xs="6" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
+      <el-col :sm="24" :xs="24" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
         <chart-card title="访问量" :total="8846">
         <chart-card title="访问量" :total="8846">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
             <i class="el-icon-warning-outline" />
             <i class="el-icon-warning-outline" />
@@ -28,7 +28,7 @@
           <template slot="footer">日访问量<span> {{ '1234' }}</span></template>
           <template slot="footer">日访问量<span> {{ '1234' }}</span></template>
         </chart-card>
         </chart-card>
       </el-col>
       </el-col>
-      <el-col :sm="24" :xs="6" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
+      <el-col :sm="24" :xs="24" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
         <chart-card title="支付笔数" :total="6560">
         <chart-card title="支付笔数" :total="6560">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
             <i class="el-icon-warning-outline" />
             <i class="el-icon-warning-outline" />
@@ -39,7 +39,7 @@
           <template slot="footer">转化率 <span>60%</span></template>
           <template slot="footer">转化率 <span>60%</span></template>
         </chart-card>
         </chart-card>
       </el-col>
       </el-col>
-      <el-col :sm="24" :xs="6" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
+      <el-col :sm="24" :xs="24" :md="6" :xl="6" :lg="6" :style="{ marginBottom: '12px' }">
         <chart-card title="运营活动效果" total="78%">
         <chart-card title="运营活动效果" total="78%">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
           <el-tooltip slot="action" class="item" effect="dark" content="指标说明" placement="top-start">
             <i class="el-icon-warning-outline" />
             <i class="el-icon-warning-outline" />
@@ -61,7 +61,7 @@
 
 
     <el-card :bordered="false" :body-style="{padding: '0'}">
     <el-card :bordered="false" :body-style="{padding: '0'}">
       <div class="salesCard">
       <div class="salesCard">
-        <el-tabs>
+        <el-tabs >
           <el-tab-pane label="销售额">
           <el-tab-pane label="销售额">
             <el-row>
             <el-row>
               <el-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
               <el-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">

+ 45 - 0
src/views/fileManage/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="file">
+    <BasicLayout>
+      <template #wrapper>
+        <DragColumn>
+          <div slot="left" class="left">
+            <Left />
+          </div>
+          <div slot="right" class="right">
+            <Right />
+          </div>
+        </DragColumn>
+      </template>
+    </BasicLayout>
+  </div>
+</template>
+
+<script>
+
+import DragColumn from '@/components/DragColumn/index'
+import Left from '@/components/FileManage/Left'
+import Right from '@/components/FileManage/Right'
+export default {
+  name: 'FileManage',
+  components: {
+    DragColumn,
+    Left,
+    Right
+  },
+  data() {
+    return {
+
+    }
+  },
+  mounted() {
+  },
+  methods: {
+
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 0 - 166
src/views/monitor/server/index.vue

@@ -1,166 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-row>
-
-      <el-col :span="12" class="card-box">
-        <el-card>
-          <div slot="header">
-            <span>服务器信息</span>
-          </div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <table cellspacing="0" style="width: 100%;">
-              <thead>
-                <tr>
-                  <th class="is-leaf"><div class="cell">属性</div></th>
-                  <th class="is-leaf"><div class="cell">值</div></th>
-                </tr>
-              </thead>
-              <tbody>
-                <tr>
-                  <td><div class="cell">服务器架构</div></td>
-                  <td><div v-if="server.os" class="cell">{{ server.os.arch }}</div></td>
-                </tr>
-                <tr>
-                  <td><div class="cell">操作系统</div></td>
-                  <td><div v-if="server.os" class="cell">{{ server.os.goOs }}</div></td>
-                </tr>
-                <tr>
-                  <td><div class="cell">核心数</div></td>
-                  <td><div v-if="server.cpu" class="cell">{{ server.cpu.cpuNum }}</div></td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="12" class="card-box">
-        <el-card>
-          <div slot="header"><span>内存</span></div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <table cellspacing="0" style="width: 100%;">
-              <thead>
-                <tr>
-                  <th class="is-leaf"><div class="cell">属性</div></th>
-                  <th class="is-leaf"><div class="cell">值</div></th>
-                </tr>
-              </thead>
-              <tbody>
-                <tr>
-                  <td><div class="cell">总内存</div></td>
-                  <td><div v-if="server.mem" class="cell">{{ server.mem.total }}G</div></td>
-
-                </tr>
-                <tr>
-                  <td><div class="cell">已用内存</div></td>
-                  <td><div v-if="server.mem" class="cell">{{ server.mem.used }}G</div></td>
-
-                </tr>
-                <tr>
-                  <td><div class="cell">使用率</div></td>
-                  <td><div v-if="server.mem" class="cell" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
-
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="12" class="card-box">
-        <el-card>
-          <div slot="header">
-            <span>go运行环境</span>
-          </div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <table cellspacing="0" style="width: 100%;">
-              <thead>
-                <tr>
-                  <th class="is-leaf"><div class="cell">属性</div></th>
-                  <th class="is-leaf"><div class="cell">值</div></th>
-                </tr>
-              </thead>
-              <tbody>
-                <tr>
-                  <td><div class="cell">go version</div></td>
-                  <td><div v-if="server.os" class="cell">{{ server.os.version }}</div></td>
-                </tr>
-                <tr>
-                  <td><div class="cell">Goroutine</div></td>
-                  <td><div v-if="server.os" class="cell">{{ server.os.numGoroutine }}</div></td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        </el-card>
-      </el-col>
-
-      <el-col :span="12" class="card-box">
-        <el-card>
-          <div slot="header">
-            <span>磁盘状态</span>
-          </div>
-          <div class="el-table el-table--enable-row-hover el-table--medium">
-            <table cellspacing="0" style="width: 100%;">
-              <thead>
-                <tr>
-                  <th class="is-leaf"><div class="cell">属性</div></th>
-                  <th class="is-leaf"><div class="cell">值</div></th>
-                </tr>
-              </thead>
-              <tbody v-if="server.disk">
-
-                <tr>
-                  <td><div class="cell">总共</div></td>
-                  <td><div class="cell">{{ server.disk.total }}</div></td>
-                </tr>
-                <tr>
-                  <td><div class="cell">可用</div></td>
-                  <td><div class="cell">{{ server.disk.free }}</div></td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script>
-import { getServer } from '@/api/monitor/server'
-
-export default {
-  name: 'Server',
-  data() {
-    return {
-      // 加载层信息
-      loading: [],
-      // 服务器信息
-      server: []
-    }
-  },
-  created() {
-    this.getList()
-    this.openLoading()
-  },
-  methods: {
-    /** 查询服务器信息 */
-    getList() {
-      getServer().then(response => {
-        this.server = response
-        this.loading.close()
-      })
-    },
-    // 打开加载层
-    openLoading() {
-      this.loading = this.$loading({
-        lock: true,
-        text: '拼命读取中',
-        spinner: 'el-icon-loading',
-        background: 'rgba(0, 0, 0, 0.7)'
-      })
-    }
-  }
-}
-</script>

+ 353 - 0
src/views/syscategory/index.vue

@@ -0,0 +1,353 @@
+
+<template>
+  <BasicLayout>
+    <template #wrapper>
+      <el-card class="box-card">
+        <el-form ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
+          <el-form-item label="名称" prop="name">
+            <el-input
+              v-model="queryParams.name"
+              placeholder="请输入名称"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="状态" prop="status">
+            <el-select
+              v-model="queryParams.status"
+              placeholder="分类状态"
+              clearable
+              size="small"
+            >
+              <el-option
+                v-for="dict in statusOptions"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+              v-permisaction="['syscategory:syscategory:add']"
+              type="primary"
+              icon="el-icon-plus"
+              size="mini"
+              @click="handleAdd"
+            >新增
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              v-permisaction="['syscategory:syscategory:edit']"
+              type="success"
+              icon="el-icon-edit"
+              size="mini"
+              :disabled="single"
+              @click="handleUpdate"
+            >修改
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              v-permisaction="['syscategory:syscategory:remove']"
+              type="danger"
+              icon="el-icon-delete"
+              size="mini"
+              :disabled="multiple"
+              @click="handleDelete"
+            >删除
+            </el-button>
+          </el-col>
+        </el-row>
+
+        <el-table v-loading="loading" :data="syscategoryList" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" align="center" /><el-table-column
+            label="名称"
+            align="center"
+            prop="name"
+            :show-overflow-tooltip="true"
+          /><el-table-column
+            label="排序"
+            align="center"
+            prop="sort"
+            :show-overflow-tooltip="true"
+          /><el-table-column
+            label="状态"
+            align="center"
+            prop="status"
+            :formatter="statusFormat"
+            width="100"
+          >
+            <template slot-scope="scope">
+              {{ statusFormat(scope.row) }}
+            </template>
+          </el-table-column><el-table-column
+            label="创建时间"
+            align="center"
+            prop="createdAt"
+            :show-overflow-tooltip="true"
+          />
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button
+                v-permisaction="['syscategory:syscategory:edit']"
+                size="mini"
+                type="text"
+                icon="el-icon-edit"
+                @click="handleUpdate(scope.row)"
+              >修改
+              </el-button>
+              <el-button
+                v-permisaction="['syscategory:syscategory:remove']"
+                size="mini"
+                type="text"
+                icon="el-icon-delete"
+                @click="handleDelete(scope.row)"
+              >删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination
+          v-show="total>0"
+          :total="total"
+          :page.sync="queryParams.pageIndex"
+          :limit.sync="queryParams.pageSize"
+          @pagination="getList"
+        />
+
+        <!-- 添加或修改对话框 -->
+        <el-dialog :title="title" :visible.sync="open" width="500px">
+          <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+
+            <el-form-item label="名称" prop="name">
+              <el-input
+                v-model="form.name"
+                placeholder="名称"
+              />
+            </el-form-item>
+            <el-form-item label="图片" prop="img">
+              <el-input
+                v-model="form.img"
+                placeholder="图片"
+              />
+            </el-form-item>
+            <el-form-item label="排序" prop="sort">
+              <el-input
+                v-model="form.sort"
+                placeholder="排序"
+              />
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select
+                v-model="form.status"
+                placeholder="请选择"
+              >
+                <el-option
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="备注" prop="remark">
+              <el-input
+                v-model="form.remark"
+                placeholder="备注"
+              />
+            </el-form-item>
+          </el-form>
+          <div slot="footer" class="dialog-footer">
+            <el-button type="primary" @click="submitForm">确 定</el-button>
+            <el-button @click="cancel">取 消</el-button>
+          </div>
+        </el-dialog>
+      </el-card>
+    </template>
+  </BasicLayout>
+</template>
+
+<script>
+import { addSysCategory, delSysCategory, getSysCategory, listSysCategory, updateSysCategory } from '@/api/syscategory'
+
+export default {
+  name: 'Config',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 总条数
+      total: 0,
+      // 弹出层标题
+      title: '',
+      // 是否显示弹出层
+      open: false,
+      isEdit: false,
+      // 类型数据字典
+      typeOptions: [],
+      syscategoryList: [],
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageIndex: 1,
+        pageSize: 10,
+        name:
+            undefined,
+        status:
+            undefined
+
+      },
+      // 表单参数
+      form: {
+      },
+      // 表单校验
+      rules: { name:
+                [
+                  { required: true, message: '名称不能为空', trigger: 'blur' }
+                ],
+      status:
+                [
+                  { required: true, message: '状态不能为空', trigger: 'blur' }
+                ]
+      }
+    }
+  },
+  created() {
+    this.getList()
+    this.getDicts('sys_category').then(response => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询参数列表 */
+    getList() {
+      this.loading = true
+      listSysCategory(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.syscategoryList = response.data.list
+        this.total = response.data.count
+        this.loading = false
+      }
+      )
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+
+        id: undefined,
+        name: undefined,
+        img: undefined,
+        sort: undefined,
+        status: undefined,
+        remark: undefined
+      }
+      this.resetForm('form')
+    },
+    statusFormat(row) {
+      return this.selectDictLabel(this.statusOptions, row.status)
+    },
+
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageIndex = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = []
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '添加分类'
+      this.isEdit = false
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset()
+      const id =
+                row.id || this.ids
+      getSysCategory(id).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改分类'
+        this.isEdit = true
+      })
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          if (this.form.id !== undefined) {
+            updateSysCategory(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess('修改成功')
+                this.open = false
+                this.getList()
+              } else {
+                this.msgError(response.msg)
+              }
+            })
+          } else {
+            addSysCategory(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess('新增成功')
+                this.open = false
+                this.getList()
+              } else {
+                this.msgError(response.msg)
+              }
+            })
+          }
+        }
+      })
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const Ids = row.id || this.ids
+      this.$confirm('是否确认删除编号为"' + Ids + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delSysCategory(Ids)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(function() {
+      })
+    }
+  }
+}
+</script>

+ 401 - 0
src/views/syscontent/index.vue

@@ -0,0 +1,401 @@
+<template>
+  <BasicLayout>
+    <template #wrapper>
+      <el-card class="box-card">
+        <el-form ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
+          <el-form-item label="分类id" prop="cateId"><el-select
+            v-model="form.cateId"
+            placeholder="请选择"
+          >
+            <el-option
+              v-for="dict in cateIdOptions"
+              :key="dict.key"
+              :label="dict.value"
+              :value="dict.key"
+            />
+          </el-select>
+          </el-form-item>
+          <el-form-item label="名称" prop="name"><el-input
+            v-model="queryParams.name"
+            placeholder="请输入名称"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+          />
+          </el-form-item>
+          <el-form-item label="状态" prop="status"><el-select
+            v-model="queryParams.status"
+            placeholder="内容管理状态"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+          </el-form-item>
+
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+              v-permisaction="['syscontent:syscontent:add']"
+              type="primary"
+              icon="el-icon-plus"
+              size="mini"
+              @click="handleAdd"
+            >新增
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              v-permisaction="['syscontent:syscontent:edit']"
+              type="success"
+              icon="el-icon-edit"
+              size="mini"
+              :disabled="single"
+              @click="handleUpdate"
+            >修改
+            </el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button
+              v-permisaction="['syscontent:syscontent:remove']"
+              type="danger"
+              icon="el-icon-delete"
+              size="mini"
+              :disabled="multiple"
+              @click="handleDelete"
+            >删除
+            </el-button>
+          </el-col>
+        </el-row>
+
+        <el-table v-loading="loading" :data="syscontentList" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" align="center" /><el-table-column label="分类id" align="center" prop="cateId" :formatter="cateIdFormat" width="100">
+            <template slot-scope="scope">
+              {{ cateIdFormat(scope.row) }}
+            </template>
+          </el-table-column><el-table-column
+            label="名称"
+            align="center"
+            prop="name"
+            :show-overflow-tooltip="true"
+          /><el-table-column
+            label="状态"
+            align="center"
+            prop="status"
+            :formatter="statusFormat"
+            width="100"
+          >
+            <template slot-scope="scope">
+              {{ statusFormat(scope.row) }}
+            </template>
+          </el-table-column><el-table-column
+            label="创建时间"
+            align="center"
+            prop="createdAt"
+            :show-overflow-tooltip="true"
+          />
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button
+                v-permisaction="['syscontent:syscontent:edit']"
+                size="mini"
+                type="text"
+                icon="el-icon-edit"
+                @click="handleUpdate(scope.row)"
+              >修改
+              </el-button>
+              <el-button
+                v-permisaction="['syscontent:syscontent:remove']"
+                size="mini"
+                type="text"
+                icon="el-icon-delete"
+                @click="handleDelete(scope.row)"
+              >删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination
+          v-show="total>0"
+          :total="total"
+          :page.sync="queryParams.pageIndex"
+          :limit.sync="queryParams.pageSize"
+          @pagination="getList"
+        />
+
+        <!-- 添加或修改对话框 -->
+        <el-dialog :title="title" :visible.sync="open" width="500px">
+          <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+
+            <el-form-item label="分类id" prop="cateId">
+              <el-select
+                v-model="form.cateId"
+                placeholder="请选择"
+              >
+                <el-option
+                  v-for="dict in cateIdOptions"
+                  :key="dict.key"
+                  :label="dict.value"
+                  :value="dict.key"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="名称" prop="name">
+              <el-input
+                v-model="form.name"
+                placeholder="名称"
+              />
+            </el-form-item>
+            <el-form-item label="状态" prop="status">
+              <el-select
+                v-model="form.status"
+                placeholder="请选择"
+              >
+                <el-option
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="图片" prop="img">
+              <el-input
+                v-model="form.img"
+                placeholder="图片"
+              />
+            </el-form-item>
+            <el-form-item label="内容" prop="content">
+              <el-input
+                v-model="form.content"
+                type="textarea"
+                :rows="2"
+                placeholder="请输入内容"
+              />
+            </el-form-item>
+            <el-form-item label="备注" prop="remark">
+              <el-input
+                v-model="form.remark"
+                placeholder="备注"
+              />
+            </el-form-item>
+            <el-form-item label="排序" prop="sort">
+              <el-input
+                v-model="form.sort"
+                placeholder="排序"
+              />
+            </el-form-item>
+          </el-form>
+          <div slot="footer" class="dialog-footer">
+            <el-button type="primary" @click="submitForm">确 定</el-button>
+            <el-button @click="cancel">取 消</el-button>
+          </div>
+        </el-dialog>
+      </el-card>
+    </template>
+  </BasicLayout>
+</template>
+
+<script>
+import { addSysContent, delSysContent, getSysContent, listSysContent, updateSysContent } from '@/api/syscontent'
+import { listSysCategory } from '@/api/syscategory'
+
+export default {
+  name: 'Config',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 总条数
+      total: 0,
+      // 弹出层标题
+      title: '',
+      // 是否显示弹出层
+      open: false,
+      isEdit: false,
+      // 类型数据字典
+      typeOptions: [],
+      syscontentList: [],
+      statusOptions: [],
+      // 关系表类型
+      cateIdOptions: [],
+
+      // 查询参数
+      queryParams: {
+        pageIndex: 1,
+        pageSize: 10,
+        cateId: undefined,
+        name: undefined,
+        status: undefined
+
+      },
+      // 表单参数
+      form: {
+      },
+      // 表单校验
+      rules: { cateId:
+                [
+                  { required: true, message: '分类id不能为空', trigger: 'blur' }
+                ],
+      name:
+                [
+                  { required: true, message: '名称不能为空', trigger: 'blur' }
+                ],
+      status:
+                [
+                  { required: true, message: '状态不能为空', trigger: 'blur' }
+                ]
+      }
+    }
+  },
+  created() {
+    this.getList()
+    this.getSysCategoryItems()
+
+    this.getDicts('sys_content_status').then(response => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询参数列表 */
+    getList() {
+      this.loading = true
+      listSysContent(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.syscontentList = response.data.list
+        this.total = response.data.count
+        this.loading = false
+      }
+      )
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+
+        id: undefined,
+        cateId: undefined,
+        name: undefined,
+        status: undefined,
+        img: undefined,
+        content: undefined,
+        remark: undefined,
+        sort: undefined
+      }
+      this.resetForm('form')
+    },
+    cateIdFormat(row) {
+      return this.selectItemsLabel(this.cateIdOptions, row.cateId)
+    },
+    statusFormat(row) {
+      return this.selectDictLabel(this.statusOptions, row.status)
+    },
+    // 关系
+    getSysCategoryItems() {
+      this.getItems(listSysCategory, undefined).then(res => {
+        this.cateIdOptions = this.setItems(res, 'id', 'name')
+      })
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageIndex = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = []
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '添加内容管理'
+      this.isEdit = false
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset()
+      const id =
+                row.id || this.ids
+      getSysContent(id).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改内容管理'
+        this.isEdit = true
+      })
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          if (this.form.id !== undefined) {
+            updateSysContent(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess('修改成功')
+                this.open = false
+                this.getList()
+              } else {
+                this.msgError(response.msg)
+              }
+            })
+          } else {
+            addSysContent(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess('新增成功')
+                this.open = false
+                this.getList()
+              } else {
+                this.msgError(response.msg)
+              }
+            })
+          }
+        }
+      })
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const Ids = row.id || this.ids
+      this.$confirm('是否确认删除编号为"' + Ids + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delSysContent(Ids)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(function() {
+      })
+    }
+  }
+}
+</script>

+ 52 - 45
src/views/sysjob/index.vue

@@ -98,17 +98,20 @@
           </el-row>
           </el-row>
 
 
           <el-table v-loading="loading" :data="sysjobList" @selection-change="handleSelectionChange">
           <el-table v-loading="loading" :data="sysjobList" @selection-change="handleSelectionChange">
-            <el-table-column type="selection" width="55" align="center" /><el-table-column
+            <el-table-column type="selection" width="55" align="center" />
+            <el-table-column
               label="编码"
               label="编码"
               align="center"
               align="center"
               prop="jobId"
               prop="jobId"
               :show-overflow-tooltip="true"
               :show-overflow-tooltip="true"
-            /><el-table-column
+            />
+            <el-table-column
               label="名称"
               label="名称"
               align="center"
               align="center"
               prop="jobName"
               prop="jobName"
               :show-overflow-tooltip="true"
               :show-overflow-tooltip="true"
-            /><el-table-column
+            />
+            <el-table-column
               label="任务分组"
               label="任务分组"
               align="center"
               align="center"
               prop="jobGroup"
               prop="jobGroup"
@@ -118,17 +121,20 @@
               <template slot-scope="scope">
               <template slot-scope="scope">
                 {{ jobGroupFormat(scope.row) }}
                 {{ jobGroupFormat(scope.row) }}
               </template>
               </template>
-            </el-table-column><el-table-column
+            </el-table-column>
+            <el-table-column
               label="cron表达式"
               label="cron表达式"
               align="center"
               align="center"
               prop="cronExpression"
               prop="cronExpression"
               :show-overflow-tooltip="true"
               :show-overflow-tooltip="true"
-            /><el-table-column
+            />
+            <el-table-column
               label="调用目标"
               label="调用目标"
               align="center"
               align="center"
               prop="invokeTarget"
               prop="invokeTarget"
               :show-overflow-tooltip="true"
               :show-overflow-tooltip="true"
-            /><el-table-column
+            />
+            <el-table-column
               label="状态"
               label="状态"
               align="center"
               align="center"
               prop="status"
               prop="status"
@@ -232,6 +238,24 @@
                     />
                     />
                   </el-form-item>
                   </el-form-item>
                 </el-col>
                 </el-col>
+                <el-col :span="24">
+                  <el-form-item label="目标参数" prop="args">
+                    <span slot="label">
+                      目标参数
+                      <el-tooltip placement="top">
+                        <div slot="content">
+                          参数示例:有参:请以string格式填写;无参:为空;
+                          <br>参数说明:目前仅支持函数调用
+                        </div>
+                        <i class="el-icon-question" />
+                      </el-tooltip>
+                    </span>
+                    <el-input
+                      v-model="form.args"
+                      placeholder="目标参数"
+                    />
+                  </el-form-item>
+                </el-col>
                 <el-col :span="12">
                 <el-col :span="12">
                   <el-form-item label="cron表达式" prop="cronExpression">
                   <el-form-item label="cron表达式" prop="cronExpression">
                     <el-input
                     <el-input
@@ -251,14 +275,14 @@
                 <el-col :span="24">
                 <el-col :span="24">
                   <el-form-item label="调用类型" prop="jobType">
                   <el-form-item label="调用类型" prop="jobType">
                     <el-radio-group v-model="form.jobType" size="small">
                     <el-radio-group v-model="form.jobType" size="small">
-                      <el-radio-button label="1">接口方式</el-radio-button>
-                      <el-radio-button label="2">函数【无参】</el-radio-button>
+                      <el-radio-button label="1">接口</el-radio-button>
+                      <el-radio-button label="2">函数</el-radio-button>
                     </el-radio-group>
                     </el-radio-group>
                   </el-form-item>
                   </el-form-item>
                 </el-col>
                 </el-col>
 
 
                 <el-col :span="24">
                 <el-col :span="24">
-                  <el-form-item label="错误策略" prop="misfirePolicy">
+                  <el-form-item label="执行策略" prop="misfirePolicy">
                     <el-radio-group v-model="form.misfirePolicy" size="small">
                     <el-radio-group v-model="form.misfirePolicy" size="small">
                       <el-radio-button label="1">立即执行</el-radio-button>
                       <el-radio-button label="1">立即执行</el-radio-button>
                       <el-radio-button label="2">执行一次</el-radio-button>
                       <el-radio-button label="2">执行一次</el-radio-button>
@@ -307,6 +331,7 @@ export default {
     return {
     return {
       // 遮罩层
       // 遮罩层
       loading: true,
       loading: true,
+      id: 0,
       // 选中数组
       // 选中数组
       ids: [],
       ids: [],
       // 非单个禁用
       // 非单个禁用
@@ -329,42 +354,22 @@ export default {
       queryParams: {
       queryParams: {
         pageIndex: 1,
         pageIndex: 1,
         pageSize: 10,
         pageSize: 10,
-        jobName:
-            undefined,
-        jobGroup:
-            undefined,
-        status:
-            undefined
+        jobName: undefined,
+        jobGroup: undefined,
+        status: undefined
 
 
       },
       },
       // 表单参数
       // 表单参数
       form: {
       form: {
       },
       },
       // 表单校验
       // 表单校验
-      rules: { jobId:
-                [
-                  { required: true, message: '编码不能为空', trigger: 'blur' }
-                ],
-      jobName:
-                [
-                  { required: true, message: '名称不能为空', trigger: 'blur' }
-                ],
-      jobGroup:
-                [
-                  { required: true, message: '任务分组不能为空', trigger: 'blur' }
-                ],
-      cronExpression:
-                [
-                  { required: true, message: 'cron表达式不能为空', trigger: 'blur' }
-                ],
-      invokeTarget:
-                [
-                  { required: true, message: '调用目标不能为空', trigger: 'blur' }
-                ],
-      status:
-                [
-                  { required: true, message: '状态不能为空', trigger: 'blur' }
-                ]
+      rules: {
+        jobId: [{ required: true, message: '编码不能为空', trigger: 'blur' }],
+        jobName: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
+        jobGroup: [{ required: true, message: '任务分组不能为空', trigger: 'blur' }],
+        cronExpression: [{ required: true, message: 'cron表达式不能为空', trigger: 'blur' }],
+        invokeTarget: [{ required: true, message: '调用目标不能为空', trigger: 'blur' }],
+        status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
       }
       }
     }
     }
   },
   },
@@ -386,8 +391,7 @@ export default {
         this.sysjobList = response.data.list
         this.sysjobList = response.data.list
         this.total = response.data.count
         this.total = response.data.count
         this.loading = false
         this.loading = false
-      }
-      )
+      })
     },
     },
     // 取消按钮
     // 取消按钮
     cancel() {
     cancel() {
@@ -402,6 +406,7 @@ export default {
         jobGroup: undefined,
         jobGroup: undefined,
         cronExpression: undefined,
         cronExpression: undefined,
         invokeTarget: undefined,
         invokeTarget: undefined,
+        args: undefined,
         misfirePolicy: 1,
         misfirePolicy: 1,
         concurrent: 1,
         concurrent: 1,
         jobType: 1,
         jobType: 1,
@@ -415,7 +420,6 @@ export default {
     statusFormat(row) {
     statusFormat(row) {
       return this.selectDictLabel(this.statusOptions, row.status)
       return this.selectDictLabel(this.statusOptions, row.status)
     },
     },
-
     /** 搜索按钮操作 */
     /** 搜索按钮操作 */
     handleQuery() {
     handleQuery() {
       this.queryParams.pageIndex = 1
       this.queryParams.pageIndex = 1
@@ -443,8 +447,7 @@ export default {
     /** 修改按钮操作 */
     /** 修改按钮操作 */
     handleUpdate(row) {
     handleUpdate(row) {
       this.reset()
       this.reset()
-      const jobId =
-                row.jobId || this.ids
+      const jobId = row.jobId || this.ids
       getSysJob(jobId).then(response => {
       getSysJob(jobId).then(response => {
         this.form = response.data
         this.form = response.data
         this.form.status = String(this.form.status)
         this.form.status = String(this.form.status)
@@ -501,7 +504,11 @@ export default {
         cancelButtonText: '取消',
         cancelButtonText: '取消',
         type: 'warning'
         type: 'warning'
       }).then(function() {
       }).then(function() {
-        return delSysJob(Ids)
+        if (Ids.length > 1) {
+          return delSysJob(Ids.shift(), { 'ids': Ids })
+        } else {
+          return delSysJob(Ids, { 'ids': [] })
+        }
       }).then(() => {
       }).then(() => {
         this.getList()
         this.getList()
         this.msgSuccess('删除成功')
         this.msgSuccess('删除成功')

+ 24 - 6
src/views/sysjob/log.vue

@@ -28,28 +28,36 @@
 </template>
 </template>
 
 
 <script>
 <script>
+
+import { unWsLogout } from '@/api/ws'
 export default {
 export default {
   name: 'Test',
   name: 'Test',
   data() {
   data() {
     return {
     return {
       websock: null,
       websock: null,
-      arrs: []
+      arrs: [],
+      id: undefined,
+      group: undefined
     }
     }
   },
   },
   created() {
   created() {
+    this.id = this.guid()
+    this.group = 'log'
     this.initWebSocket()
     this.initWebSocket()
   },
   },
   destroyed() {
   destroyed() {
+    console.log('断开websocket连接')
     this.websock.close() // 离开路由之后断开websocket连接
     this.websock.close() // 离开路由之后断开websocket连接
+    unWsLogout(this.id, this.group).then(response => {
+      console.log(response.data)
+    }
+    )
   },
   },
   methods: {
   methods: {
     initWebSocket() { // 初始化weosocket
     initWebSocket() { // 初始化weosocket
       console.log(this.$store.state.user.token)
       console.log(this.$store.state.user.token)
-      const wsuri = 'ws://127.0.0.1:8000/ws?token=oooooooo'
-      this.websock = new WebSocket(wsuri, ['aaaaaaaaaaaaaaaaaaaaaaa'])
-      //   this.websock.on('headers', headers => {
-      //     headers.push('Authorization:Bearer sssss')
-      //   })
+      const wsuri = 'ws://127.0.0.1:8000/ws/' + this.id + '/' + this.group + '?token=' + this.$store.state.user.token
+      this.websock = new WebSocket(wsuri)
       this.websock.onmessage = this.websocketonmessage
       this.websock.onmessage = this.websocketonmessage
       this.websock.onopen = this.websocketonopen
       this.websock.onopen = this.websocketonopen
       this.websock.onerror = this.websocketonerror
       this.websock.onerror = this.websocketonerror
@@ -75,7 +83,17 @@ export default {
     //   this.websock.send(Data)
     //   this.websock.send(Data)
     },
     },
     websocketclose(e) { // 关闭
     websocketclose(e) { // 关闭
+      unWsLogout(this.id, this.group).then(response => {
+        console.log(response.data)
+      }
+      )
       console.log('断开连接', e)
       console.log('断开连接', e)
+    },
+    guid() {
+      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+        var r = Math.random() * 16 | 0; var v = c === 'x' ? r : (r & 0x3 | 0x8)
+        return v.toString(16)
+      })
     }
     }
   }
   }
 }
 }

+ 3 - 3
src/views/system/monitor.vue

@@ -10,7 +10,7 @@
               </div>
               </div>
               <div class="monitor">
               <div class="monitor">
                 <div class="monitor-header">
                 <div class="monitor-header">
-                  <el-progress type="circle" :percentage="info.cpu.Percent" />
+                  <el-progress :color="$store.state.settings.theme" type="circle" :percentage="info.cpu.Percent" />
                 </div>
                 </div>
                 <div class="monitor-footer">
                 <div class="monitor-footer">
                   <Cell label="CPU主频" :value="info.cpu.cpuInfo[0].modelName.split('@ ')[1]" border />
                   <Cell label="CPU主频" :value="info.cpu.cpuInfo[0].modelName.split('@ ')[1]" border />
@@ -26,7 +26,7 @@
               </div>
               </div>
               <div class="monitor">
               <div class="monitor">
                 <div class="monitor-header">
                 <div class="monitor-header">
-                  <el-progress type="circle" :percentage="info.mem.usage" />
+                  <el-progress :color="$store.state.settings.theme" type="circle" :percentage="info.mem.usage" />
                 </div>
                 </div>
                 <div class="monitor-footer">
                 <div class="monitor-footer">
                   <Cell label="总内存" :value="info.mem.total+'G'" border />
                   <Cell label="总内存" :value="info.mem.total+'G'" border />
@@ -42,7 +42,7 @@
               </div>
               </div>
               <div class="monitor">
               <div class="monitor">
                 <div class="monitor-header">
                 <div class="monitor-header">
-                  <el-progress type="circle" :percentage=" `${((info.disk.free / info.disk.total) * 100).toFixed(2)}` " />
+                  <el-progress :color="$store.state.settings.theme" type="circle" :percentage=" `${((info.disk.free / info.disk.total) * 100).toFixed(2)}` " />
                 </div>
                 </div>
                 <div class="monitor-footer">
                 <div class="monitor-footer">
                   <Cell label="总内存" :value="info.disk.total+'G'" border />
                   <Cell label="总内存" :value="info.disk.total+'G'" border />

+ 1 - 1
src/views/system/settings.vue

@@ -72,7 +72,7 @@ export default {
       })
       })
     },
     },
     handleAvatarSuccess(e) {
     handleAvatarSuccess(e) {
-      this.ruleForm.logo = e.data
+      this.ruleForm.logo = e.data.full_path
     },
     },
     beforeAvatarUpload(e) {
     beforeAvatarUpload(e) {
 
 

+ 98 - 3
src/views/tools/gen/editTable.vue

@@ -92,8 +92,9 @@
                 <el-option label="下拉框" value="select" />
                 <el-option label="下拉框" value="select" />
                 <el-option label="单选框" value="radio" />
                 <el-option label="单选框" value="radio" />
                 <!-- <el-option label="复选框" value="checkbox" />
                 <!-- <el-option label="复选框" value="checkbox" />
+                <el-option label="日期控件" value="datetime" />-->
                 <el-option label="文本域" value="textarea" />
                 <el-option label="文本域" value="textarea" />
-                <el-option label="日期控件" value="datetime" /> -->
+
               </el-select>
               </el-select>
             </template>
             </template>
           </el-table-column>
           </el-table-column>
@@ -112,6 +113,51 @@
               </el-select>
               </el-select>
             </template>
             </template>
           </el-table-column>
           </el-table-column>
+          <el-table-column label="关系表" width="160">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.fkTableName" clearable filterable placeholder="请选择" @change="handleChangeConfig(scope.row,scope.$index)">
+                <el-option
+                  v-for="table in tableTree"
+                  :key="table.tableName"
+                  :label="table.tableName"
+                  :value="table.tableName"
+                >
+                  <span style="float: left">{{ table.tableName }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ table.tableComment }}</span>
+                </el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="关系表key" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.fkLabelId" clearable filterable placeholder="请选择">
+                <el-option
+                  v-for="column in scope.row.fkCol"
+                  :key="column.columnName"
+                  :label="column.columnName"
+                  :value="column.columnName"
+                >
+                  <span style="float: left">{{ column.columnName }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ column.columnComment }}</span>
+                </el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="关系表value" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.fkLabelName" clearable filterable placeholder="请选择">
+                <el-option
+                  v-for="column in scope.row.fkCol"
+                  :key="column.columnName"
+                  :label="column.columnName"
+                  :value="column.columnName"
+                >
+                  <span style="float: left">{{ column.columnName }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ column.columnComment }}</span>
+                </el-option>
+              </el-select>
+            </template>
+          </el-table-column>
         </el-table>
         </el-table>
       </el-tab-pane>
       </el-tab-pane>
       <el-tab-pane label="生成信息" name="genInfo">
       <el-tab-pane label="生成信息" name="genInfo">
@@ -127,7 +173,8 @@
   </el-card>
   </el-card>
 </template>
 </template>
 <script>
 <script>
-import { getGenTable, updateGenTable } from '@/api/tools/gen'
+import { getGenTable, updateGenTable, getTableTree } from '@/api/tools/gen'
+// import { listTable } from '@/api/tools/gen'
 import { optionselect as getDictOptionselect } from '@/api/system/dict/type'
 import { optionselect as getDictOptionselect } from '@/api/system/dict/type'
 import basicInfoForm from './basicInfoForm'
 import basicInfoForm from './basicInfoForm'
 import genInfoForm from './genInfoForm'
 import genInfoForm from './genInfoForm'
@@ -145,20 +192,36 @@ export default {
       tableHeight: document.documentElement.scrollHeight - 245 + 'px',
       tableHeight: document.documentElement.scrollHeight - 245 + 'px',
       // 表列信息
       // 表列信息
       columns: [],
       columns: [],
+      tableTree: [],
       // 字典信息
       // 字典信息
       dictOptions: [],
       dictOptions: [],
       // 表详细信息
       // 表详细信息
       info: {}
       info: {}
     }
     }
   },
   },
+
   beforeCreate() {
   beforeCreate() {
+    getTableTree().then(response => {
+      this.tableTree = response.data
+      this.tableTree.unshift({ tableId: 0, tableName: '请选择' })
+    })
     const { tableId } = this.$route.query
     const { tableId } = this.$route.query
     if (tableId) {
     if (tableId) {
       // 获取表详细信息
       // 获取表详细信息
       getGenTable(tableId).then(res => {
       getGenTable(tableId).then(res => {
-        this.columns = res.data.rows
+        this.columns = res.data.list
         this.info = res.data.info
         this.info = res.data.info
+
+        this.columns.forEach(item => {
+          this.tableTree.filter(function(e) {
+            if (e.tableId === item.fkTableName) {
+              item.fkCol = e.columns || [{ columnId: 0, columnName: '请选择' }]
+              // item.fkCol.unshift({ columnId: 0, columnName: '请选择' })
+            }
+          })
+        })
       })
       })
+
       /** 查询字典下拉列表 */
       /** 查询字典下拉列表 */
       getDictOptionselect().then(response => {
       getDictOptionselect().then(response => {
         this.dictOptions = response.data
         this.dictOptions = response.data
@@ -166,6 +229,16 @@ export default {
     }
     }
   },
   },
   methods: {
   methods: {
+    handleChangeConfig(row, index) {
+      console.log(row)
+      console.log(index)
+      this.tableTree.filter(function(item) {
+        if (item.tableName === row.fkTableName) {
+          row.fkCol = item.columns
+          // row.fkCol.unshift({ columnId: 0, columnName: '请选择' })
+        }
+      })
+    },
     /** 提交按钮 */
     /** 提交按钮 */
     submitForm() {
     submitForm() {
       const basicForm = this.$refs.basicInfo.$refs.basicInfoForm
       const basicForm = this.$refs.basicInfo.$refs.basicInfoForm
@@ -192,6 +265,28 @@ export default {
         }
         }
       })
       })
     },
     },
+    getTables() {
+      getTableTree().then(response => {
+        this.tableTree = response.data
+        this.tableTree.unshift({ tableId: 0, tableName: '请选择' })
+      })
+
+      console.log(this.tableList)
+    },
+    getTablesCol(tableName) {
+      return this.tableTree.filter(function(item) {
+        if (item.tableName === tableName) {
+          return item.columns
+        }
+      })
+    },
+    // getTableColList(tableId) {
+    //   this.getItems(getGenTable, { tableId: tableId }).then(res => {
+    //     this.dictOptions = this.setItems(res, 'columnName', 'columnComment')
+    //   })
+
+    //   console.log(this.tableList)
+    // },
     getFormPromise(form) {
     getFormPromise(form) {
       return new Promise(resolve => {
       return new Promise(resolve => {
         form.validate(res => {
         form.validate(res => {

+ 3 - 2
src/views/tools/gen/genInfoForm.vue

@@ -5,8 +5,9 @@
         <el-form-item prop="tplCategory">
         <el-form-item prop="tplCategory">
           <span slot="label">生成模板</span>
           <span slot="label">生成模板</span>
           <el-select v-model="info.tplCategory">
           <el-select v-model="info.tplCategory">
-            <el-option label="单表(增删改查)" value="crud" />
-            <!-- <el-option label="树表(增删改查)" value="tree" /> -->
+            <el-option label="关系表(增删改查)" value="crud" />
+            <!-- <el-option label="关系表(增删改查)" value="mcrud" />
+            <el-option label="树表(增删改查)" value="tree" /> -->
           </el-select>
           </el-select>
         </el-form-item>
         </el-form-item>
       </el-col>
       </el-col>