Browse Source

first add

Chale 4 years ago
parent
commit
891b9bad8c
100 changed files with 13039 additions and 0 deletions
  1. 39 0
      .editorconfig
  2. 21 0
      .gitignore
  3. 4 0
      Dockerfile
  4. 21 0
      LICENSE
  5. 5 0
      babel.config.js
  6. 43 0
      docker/dist.conf
  7. 2 0
      docker/startDocker.sh
  8. BIN
      favicon.ico
  9. 24 0
      idea.config.js
  10. 49 0
      package.json
  11. BIN
      public/avatar2.jpg
  12. 16 0
      public/index.html
  13. BIN
      public/logo.png
  14. 57 0
      src/App.vue
  15. 10 0
      src/api/index.js
  16. 77 0
      src/api/login.js
  17. 6 0
      src/api/public.js
  18. 69 0
      src/assets/background.svg
  19. BIN
      src/assets/logo.png
  20. 43 0
      src/assets/logo.svg
  21. 95 0
      src/components/ChartCard.vue
  22. 58 0
      src/components/HelloWorld.vue
  23. 304 0
      src/components/addOrEdit/addOrEdit.vue
  24. 57 0
      src/components/chart/Bar.vue
  25. 66 0
      src/components/chart/MiniArea.vue
  26. 68 0
      src/components/chart/Radar.vue
  27. 77 0
      src/components/chart/RankList.vue
  28. 64 0
      src/components/chart/TransferBar.vue
  29. 73 0
      src/components/layout/HeaderNotice.vue
  30. 22 0
      src/components/layout/LayoutBaseView.vue
  31. 0 0
      src/components/layout/LayoutFooter.vue
  32. 121 0
      src/components/layout/LayoutHeader.vue
  33. 331 0
      src/components/layout/LayoutMain.vue
  34. 22 0
      src/components/layout/LayoutView.vue
  35. 223 0
      src/components/layout/PageHeader.vue
  36. 93 0
      src/components/layout/PageLayout.vue
  37. 80 0
      src/components/layout/PageView.vue
  38. 16 0
      src/components/layout/RouteView.vue
  39. 74 0
      src/components/menu/SiderMenu.vue
  40. 159 0
      src/components/menu/index.js
  41. 82 0
      src/components/pagination/pagination.vue
  42. 95 0
      src/components/public.js
  43. 263 0
      src/components/queryCondition/queryCondition.vue
  44. 249 0
      src/components/table/README.md
  45. 253 0
      src/components/table/StandardTable.vue
  46. 263 0
      src/components/table/index.js
  47. 46 0
      src/components/tools/Breadcrumb.vue
  48. 147 0
      src/components/tools/DetailList.vue
  49. 32 0
      src/components/tools/FooterToolBar.vue
  50. 67 0
      src/components/tools/HeadInfo.vue
  51. 46 0
      src/main.js
  52. 65 0
      src/permission.js
  53. 1 0
      src/router/_import_development.js
  54. 1 0
      src/router/_import_production.js
  55. 100 0
      src/router/index.js
  56. 13 0
      src/store/getters.js
  57. 27 0
      src/store/index.js
  58. 48 0
      src/store/modules/app.js
  59. 192 0
      src/store/modules/permission.js
  60. 92 0
      src/store/modules/user.js
  61. 3 0
      src/store/mutation-types.js
  62. 19 0
      src/utils/auth.js
  63. 37 0
      src/utils/axios.js
  64. 23 0
      src/utils/device.js
  65. 105 0
      src/utils/request.js
  66. 78 0
      src/utils/storage.js
  67. 76 0
      src/utils/util.js
  68. 18 0
      src/views/Home.vue
  69. 341 0
      src/views/Login.vue
  70. 25 0
      src/views/account/center/Index.vue
  71. 154 0
      src/views/account/settings/BaseSetting.vue
  72. 25 0
      src/views/account/settings/Binding.vue
  73. 75 0
      src/views/account/settings/Custom.vue
  74. 153 0
      src/views/account/settings/Index.vue
  75. 206 0
      src/views/account/settings/IndexOld.vue
  76. 25 0
      src/views/account/settings/Notification.vue
  77. 41 0
      src/views/account/settings/Security.vue
  78. 15 0
      src/views/dashboard/Analysis.vue
  79. 15 0
      src/views/dashboard/Monitor.vue
  80. 15 0
      src/views/dashboard/worktop.vue
  81. 17 0
      src/views/exception/403.vue
  82. 15 0
      src/views/exception/404.vue
  83. 17 0
      src/views/exception/500.vue
  84. 75 0
      src/views/exception/ExceptionPage.vue
  85. 19 0
      src/views/exception/type.js
  86. 436 0
      src/views/platform/appManagement.vue
  87. 381 0
      src/views/platform/cityManagement.vue
  88. 383 0
      src/views/platform/countyManagement.vue
  89. 526 0
      src/views/platform/dictManagement.vue
  90. 341 0
      src/views/platform/fileManagement.vue
  91. 561 0
      src/views/platform/menuManagement.vue
  92. 231 0
      src/views/platform/operationLog.vue
  93. 730 0
      src/views/platform/operatorManagement.vue
  94. 470 0
      src/views/platform/operatorTypeManagement.vue
  95. 388 0
      src/views/platform/parameterManagement.vue
  96. 386 0
      src/views/platform/provinceManagement.vue
  97. 520 0
      src/views/platform/roleManagement.vue
  98. 546 0
      src/views/platform/scheduleTask.vue
  99. 458 0
      src/views/platform/sequenceManagement.vue
  100. 519 0
      src/views/platform/smsChannelManagement.vue

+ 39 - 0
.editorconfig

@@ -0,0 +1,39 @@
+[*]
+charset=utf-8
+end_of_line=crlf
+insert_final_newline=false
+indent_style=space
+indent_size=2
+
+[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
+indent_style=space
+indent_size=2
+
+[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
+indent_style=space
+indent_size=2
+
+[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
+indent_style=space
+indent_size=2
+
+[*.svg]
+indent_style=space
+indent_size=2
+
+[*.js.map]
+indent_style=space
+indent_size=2
+
+[*.less]
+indent_style=space
+indent_size=2
+
+[*.vue]
+indent_style=space
+indent_size=2
+
+[{.analysis_options,*.yml,*.yaml}]
+indent_style=space
+indent_size=2
+

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*

+ 4 - 0
Dockerfile

@@ -0,0 +1,4 @@
+FROM nginx:latest
+COPY docker/dist.conf /etc/nginx/conf.d/dist.conf
+RUN rm  /etc/nginx/conf.d/default.conf -rf
+COPY dist/  /usr/share/nginx/html/

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Anan Yang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 5 - 0
babel.config.js

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

+ 43 - 0
docker/dist.conf

@@ -0,0 +1,43 @@
+upstream upstream-sl-gateway-support {
+  server test_sl-gateway-support:22222 weight=1;
+}
+
+server {
+        listen  80;
+        server_name  _;
+       
+      root /usr/share/nginx/html/;
+      index index.html; 
+
+        location / {
+             try_files $uri $uri/ @router;
+             index index.html;
+         }
+
+        location @router {
+            rewrite ^.*$ /index.html last;
+        }        
+
+    location /gateway {
+            proxy_pass http://upstream-sl-gateway-support/gateway;
+            proxy_redirect off;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header Host $http_host;
+            proxy_connect_timeout 30;
+            proxy_send_timeout 180;
+            proxy_read_timeout 180;
+            proxy_buffering off;
+            client_max_body_size 100m;
+    }
+
+
+    error_page 404 /404.html;
+        location = /40x.html {
+    }
+
+    error_page 500 502 503 504 /50x.html;
+        location = /50x.html {
+    }
+
+}

+ 2 - 0
docker/startDocker.sh

@@ -0,0 +1,2 @@
+#docker build -t speedlight/web-support-platform .
+docker run --name test_web-support-platform -v /etc/localtime:/etc/localtime --link test_sl-gateway-support:sl-gateway-support -p 8081:80  --restart always -d speedlight/web-support-platform

BIN
favicon.ico


+ 24 - 0
idea.config.js

@@ -0,0 +1,24 @@
+'use strict'
+const path = require('path')
+
+function resolve(dir) {
+  return path.join(__dirname, '.', dir)
+}
+
+module.exports = {
+    context: path.resolve(__dirname, './'),
+    resolve: {
+        extensions: ['.js', '.vue', '.json'],
+        alias: {
+            'config': resolve('config'),
+            '@': resolve('src'),
+            '@views': resolve('src/views'),
+            '@comp': resolve('src/components'),
+            '@core': resolve('src/core'),
+            '@utils': resolve('src/utils'),
+            '@entry': resolve('src/entry'),
+            '@router': resolve('src/router'),
+            '@store': resolve('src/store')
+        }
+    },
+}

+ 49 - 0
package.json

@@ -0,0 +1,49 @@
+{
+  "name": "support",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "@antv/data-set": "^0.8.9",
+    "ant-design-vue": "^1.1.3",
+    "axios": "^0.18.0",
+    "cache-loader": "^1.2.5",
+    "dayjs": "^1.7.5",
+    "enquire.js": "^2.1.6",
+    "js-cookie": "^2.2.0",
+    "lodash.get": "^4.4.2",
+    "md5": "^2.2.1",
+    "nprogress": "^0.2.0",
+    "viser-vue": "^2.3.0",
+    "vue": "^2.5.17",
+    "vue-cropper": "^0.4.0",
+    "vue-loader": "^15.4.2",
+    "vue-ls": "^3.2.0",
+    "vue-router": "^3.0.1",
+    "vuex": "^3.0.1",
+    "node-sass": "^4.12.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "^3.0.1",
+    "@vue/cli-service": "^3.0.1",
+    "less": "^3.8.1",
+    "less-loader": "^4.1.0",
+    "node-sass": "^4.12.0",
+    "sass-loader": "^7.0.1",
+    "vue-template-compiler": "^2.5.17"
+  },
+  "postcss": {
+    "plugins": {
+      "autoprefixer": {}
+    }
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

BIN
public/avatar2.jpg


+ 16 - 0
public/index.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="zh-cmn-Hans">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>SL支撑平台</title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but support doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

BIN
public/logo.png


+ 57 - 0
src/App.vue

@@ -0,0 +1,57 @@
+<template>
+  <a-locale-provider :locale="locale">
+    <div id="app">
+      <router-view />
+    </div>
+  </a-locale-provider>
+</template>
+<script>
+import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
+import enquireScreen from "@/utils/device";
+
+export default {
+  provide() {
+    return {
+      reload: this.reload
+    };
+  },
+  data() {
+    return {
+      locale: zhCN,
+      isRouterAlive: true
+    };
+  },
+  // method: {
+  //   reload() {
+  //     this.isRouterAlive = false;
+  //     this.$nextTick(function(){
+  //       this.isRouterAlive = true;
+  //     })
+  //   }
+  // },
+  created() {
+    let that = this;
+    enquireScreen(deviceType => {
+      // tablet
+      if (deviceType === 0) {
+        that.$store.commit("TOGGLE_DEVICE", "tablet");
+        that.$store.commit("CLOSE_SIDEBAR", false);
+      }
+      // mobile
+      else if (deviceType === 1) {
+        that.$store.commit("TOGGLE_DEVICE", "mobile");
+        that.$store.commit("CLOSE_SIDEBAR", false);
+      } else {
+        that.$store.commit("TOGGLE_DEVICE", "desktop");
+        that.$store.commit("SET_SIDEBAR_TYPE", true);
+      }
+    });
+  }
+};
+</script>
+
+<style>
+#app {
+  height: 100%;
+}
+</style>

+ 10 - 0
src/api/index.js

@@ -0,0 +1,10 @@
+const api = {
+    Login: '/auth/login',
+    Logout: '/auth/logout',
+    ForgePassword: '/auth/forge-password',
+    Register: '/auth/register',
+    SendSms: '/account/sms',
+    // get my info
+    UserInfo: '/user/info'
+}
+export default api

+ 77 - 0
src/api/login.js

@@ -0,0 +1,77 @@
+import {
+  axios
+} from '@/utils/request'
+
+/**
+ * login func
+ * parameter: {
+ *     username: '',
+ *     password: '',
+ *     remember_me: true,
+ *     captcha: '12345'
+ * }
+ * @param parameter
+ * @returns {*}
+ */
+export function login(parameter) { //登陆
+  return axios({
+    url: '/api/token',
+    method: 'post',
+    data: parameter
+  })
+}
+
+export function getUserInfo() {
+  return axios({
+    url: '/basic/user/app/info',
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    }
+  })
+}
+
+
+export function getUserMenuPermissionsList() {
+  return axios({
+    url: '/basic/menu/list',
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    }
+  })
+}
+
+export function getUserMenuList() {
+  return axios({
+    url: '/basic/menu/nav',
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    }
+  })
+}
+
+export function CustomerTestData() { //客户检测数据
+  return axios({
+    url: '/customer/list',
+    method: 'post',
+    data: {
+      currentPage: 1,
+      pageSize: 10
+    },
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    }
+  })
+}
+
+export function logout() {
+  return axios({
+    url: '/api/auth/logout',
+    method: 'post',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8'
+    }
+  })
+}

+ 6 - 0
src/api/public.js

@@ -0,0 +1,6 @@
+// export const BASEURL = 'http://localhost:22222/gateway'
+export const BASEURL = '/gateway'
+export const METHOD_POST = 'POST'
+export const METHOD_GET = 'GET'
+export const METHOD_DELETE = 'DELETE'
+export const METHOD_PUT = 'PUT'

+ 69 - 0
src/assets/background.svg

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 21</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
+            <g id="Group-21" transform="translate(77.000000, 73.000000)">
+                <g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
+                    <ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
+                    <ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
+                    <path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
+                    <path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
+                    <path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
+                        <ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
+                        <path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
+                    </g>
+                </g>
+                <g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
+                    <ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
+                    <ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
+                    <path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
+                    <g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
+                        <ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
+                        <path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
+                    </g>
+                    <ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
+                    <path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
+                </g>
+                <g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
+                    <ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
+                    <g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
+                        <ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
+                        <path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
+                    </g>
+                    <path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                    <ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
+                    <ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
+                    <path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                </g>
+                <g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
+                    <g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
+                        <circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
+                        <path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
+                    </g>
+                    <circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
+                    <path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
+                    <path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
+                    <path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
+                    <circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
+                    <circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
+                    <circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
src/assets/logo.png


+ 43 - 0
src/assets/logo.svg

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="200px" height="200px" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 28 Copy 5</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+        <linearGradient x1="62.1023273%" y1="0%" x2="108.19718%" y2="37.8635764%" id="linearGradient-1">
+            <stop stop-color="#4285EB" offset="0%"></stop>
+            <stop stop-color="#2EC7FF" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="69.644116%" y1="0%" x2="54.0428975%" y2="108.456714%" id="linearGradient-2">
+            <stop stop-color="#29CDFF" offset="0%"></stop>
+            <stop stop-color="#148EFF" offset="37.8600687%"></stop>
+            <stop stop-color="#0A60FF" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="69.6908165%" y1="-12.9743587%" x2="16.7228981%" y2="117.391248%" id="linearGradient-3">
+            <stop stop-color="#FA816E" offset="0%"></stop>
+            <stop stop-color="#F74A5C" offset="41.472606%"></stop>
+            <stop stop-color="#F51D2C" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-4">
+            <stop stop-color="#FA8E7D" offset="0%"></stop>
+            <stop stop-color="#F74A5C" offset="51.2635191%"></stop>
+            <stop stop-color="#F51D2C" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="logo" transform="translate(-20.000000, -20.000000)">
+            <g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)">
+                <g id="Group-27-Copy-3">
+                    <g id="Group-25" fill-rule="nonzero">
+                        <g id="2">
+                            <path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-1)"></path>
+                            <path d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z" id="Shape" fill="url(#linearGradient-2)"></path>
+                        </g>
+                        <path d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z" id="Shape" fill="url(#linearGradient-3)"></path>
+                    </g>
+                    <ellipse id="Combined-Shape" fill="url(#linearGradient-4)" cx="100.519339" cy="100.436681" rx="23.6001926" ry="23.580786"></ellipse>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 95 - 0
src/components/ChartCard.vue

@@ -0,0 +1,95 @@
+<template>
+  <a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
+    <div class="chart-card-header">
+      <div class="meta">
+        <span class="chart-card-title">{{ title }}</span>
+        <span class="chart-card-action">
+          <slot name="action"></slot>
+        </span>
+      </div>
+      <div class="total"><span>{{ total }}</span></div>
+    </div>
+    <div class="chart-card-content">
+      <div class="content-fix">
+        <slot></slot>
+      </div>
+    </div>
+    <div class="chart-card-footer">
+      <slot name="footer"></slot>
+    </div>
+  </a-card>
+</template>
+
+<script>
+  export default {
+    name: "ChartCard",
+    props: {
+      title: {
+        type: String,
+        default: ''
+      },
+      total: {
+        type: String,
+        default: ''
+      },
+      loading: {
+        type: Boolean,
+        default: false
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+    .chart-card-header{
+        position: relative;
+        overflow: hidden;
+        width: 100%;
+
+        .meta{
+            position: relative;
+            overflow: hidden;
+            width: 100%;
+            color: rgba(0,0,0,.45);
+            font-size: 14px;
+            line-height: 22px;
+        }
+    }
+    .chart-card-action{
+        cursor: pointer;
+        position: absolute;
+        top: 0;
+        right: 0;
+    }
+    .chart-card-footer{
+        border-top: 1px solid #e8e8e8;
+        padding-top: 9px;
+        margin-top: 8px;
+    }
+    .chart-card-content{
+        margin-bottom: 12px;
+        position: relative;
+        height: 46px;
+        width: 100%;
+
+        .content-fix{
+            position: absolute;
+            left: 0;
+            bottom: 0;
+            width: 100%;
+        }
+    }
+
+    .total {
+        overflow: hidden;
+        text-overflow: ellipsis;
+        word-break: break-all;
+        white-space: nowrap;
+        color: #000;
+        margin-top: 4px;
+        margin-bottom: 0;
+        font-size: 30px;
+        line-height: 38px;
+        height: 38px;
+    }
+</style>

+ 58 - 0
src/components/HelloWorld.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="hello">
+    <h1>{{ msg }}</h1>
+    <p>
+      For guide and recipes on how to configure / customize this project,<br>
+      check out the
+      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
+    </p>
+    <h3>Installed CLI Plugins</h3>
+    <ul>
+      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
+      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
+    </ul>
+    <h3>Essential Links</h3>
+    <ul>
+      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
+      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
+      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
+      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
+      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
+    </ul>
+    <h3>Ecosystem</h3>
+    <ul>
+      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
+      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
+      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
+      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
+      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
+    </ul>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'HelloWorld',
+  props: {
+    msg: String
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="scss">
+h3 {
+  margin: 40px 0 0;
+}
+ul {
+  list-style-type: none;
+  padding: 0;
+}
+li {
+  display: inline-block;
+  margin: 0 10px;
+}
+a {
+  color: #42b983;
+}
+</style>

+ 304 - 0
src/components/addOrEdit/addOrEdit.vue

@@ -0,0 +1,304 @@
+<template>
+  <a-modal
+    width="800px"
+    :title="optionType == 'add' ? '新增' : '编辑'"
+    v-model="visible"
+    @ok="handleAddOrEdit"
+    @cancel="handleCancel"
+  >
+    <a-form layout="horizontal">
+      <a-row :gutter="24">
+        <a-col v-for="(item, key) in queryDataBefore" v-if="!(in_array(hiddenAllId, item.param))" :key="key" :md="12" :sm="24">
+          <a-form-item :label=item.name :required=item.required >
+            <a-select v-if="in_array(allSelectStatus, item.param)" v-model="selectedStatus" @change="changeStatus(key, selectedStatus)">
+              <a-select-option v-for="(option, index) in queryAddOrEditStatus" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(supportCustomSign, item.param)" v-model="selectedSupport" @change="changeSupport(key, selectedSupport)">
+              <a-select-option v-for="(option, index) in queryAddOrEditSupport" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(supportQueryBalance, item.param)" v-model="selectedQuerySupport" @change="changeQuerySupport(key, selectedQuerySupport)">
+              <a-select-option v-for="(option, index) in queryAddOrEditSupport" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(allSelectTaskStatus, item.param)" v-model="selectedSupport" @change="changeSupport(key, selectedSupport)">
+              <a-select-option v-for="(option, index) in taskStatus" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(allOperatorSex, item.param)" v-model="selectedGender" @change="changeGender(key, selectedGender)">
+              <a-select-option v-for="(option, index) in operatorSex" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(allOperatorLevel, item.param)" v-model="selectedOperatorLevel" @change="changeOperatorLevel(key, selectedOperatorLevel)">
+              <a-select-option v-for="(option, index) in operatorLevel" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(allDictLevel, item.param)" v-model="selectedDictLevel" @change="changeDictLevel(key, selectedDictLevel)">
+              <a-select-option v-for="(option, index) in dictLevel" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(allResetType, item.param)" v-model="selectedResetType" @change="changeResetType(key, selectedResetType)">
+              <a-select-option v-for="(option, index) in resetType" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="in_array(allRegionGroupCode, item.param)" v-model="selectedRegionGroupCode" @change="changeRegionGroupCode(key, selectedRegionGroupCode)">
+              <a-select-option v-for="(option, index) in regionGroupCode" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="item.param == 'appId' || item.param == 'appId'" v-model="selectId" @change="changeId(key, selectId)">
+              <a-select-option v-for="(option, index) in appList" :key="index" :value=option.id>
+                {{ option.appName }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="item.param == 'menuShowType'" v-model="selectedMenuShowType" @change="changeMenuShowType(key, selectedMenuShowType)">
+              <a-select-option v-for="(option, index) in menuShowType" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="item.param == 'menuStatus'" v-model="selectedMenuStatus" @change="changeMenuStatus(key, selectedMenuStatus)">
+              <a-select-option v-for="(option, index) in menuStatus" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="item.param == 'menuType'" v-model="selectedMenuType" @change="changeMenuType(key, selectedMenuType)">
+              <a-select-option v-for="(option, index) in menuType" :key="index" :value=option.selectValue>
+                {{ option.selectText }}
+              </a-select-option>
+            </a-select>
+            <a-select v-else-if="item.param == 'operatorType'" v-model="selectOperatorType" @change="changeOperatorType(key, selectOperatorType)">
+              <a-select-option v-for="(option, index) in operatorType" :value=option.typeCode :key="index">
+                {{ option.typeName}}
+              </a-select-option>
+            </a-select>
+            <a-input v-else v-model="item.value" :placeholder="'请输入' + item.name"/>
+          </a-form-item>
+        </a-col>
+      </a-row>
+    </a-form>
+  </a-modal>
+</template>
+
+<script>
+  import { BASEURL, METHOD_POST } from '@/api/public';
+  import { 
+    allSelectStatus, 
+    supportCustomSign, 
+    supportQueryBalance,
+    hiddenAllId, 
+    in_array, 
+    allSelectTaskStatus, 
+    taskStatus,
+    operatorSex,
+    allOperatorSex,
+    allOperatorLevel,
+    operatorLevel,
+    allDictLevel,
+    dictLevel,
+    resetType,
+    allResetType,
+    allRegionGroupCode,
+    regionGroupCode,
+    menuShowType,
+    menuStatus,
+    menuType
+  } from '@/components/public';
+  export default {
+    name: "AddOrEdit",
+    props: {
+      optionType: {
+        type: String,
+        required: true
+      },
+      showDlg: {
+        type: Boolean,
+        required: true
+      },
+      queryDataBefore: {
+        type: Array,
+        required: true
+      },
+      queryAddOrEditStatus: {
+        type: Array,
+        required: true
+      },
+      queryAddOrEditSupport: {
+        type: Array,
+        required: true
+      },
+      appList: {
+        type: Array,
+        required: true
+      }
+    },
+    data() {
+      return {
+        currentPage: 1,//当前的页数
+        pageSize: 10,//每页显示的条数
+        selectedStatus: 'enabled',
+        selectedSupport: 'support',
+        selectedQuerySupport: 'support',
+        selectId: 'c1384aa20d4711e8b3d2fc4dd44915e7',
+        selectedGender: 'male',
+        selectedOperatorLevel: 'belonging_admin',
+        selectedDictLevel: 'whole',
+        selectedResetType: 'default',
+        selectedRegionGroupCode: 'default',
+        allSelectStatus: allSelectStatus,
+        supportCustomSign: supportCustomSign,
+        supportQueryBalance: supportQueryBalance,
+        hiddenAllId: hiddenAllId,
+        in_array: in_array,
+        visible: false,
+        allSelectTaskStatus: allSelectTaskStatus,
+        taskStatus: taskStatus,
+        allOperatorSex: allOperatorSex,
+        operatorSex: operatorSex,
+        operatorLevel: operatorLevel,
+        allOperatorLevel: allOperatorLevel,
+        dictLevel: dictLevel,
+        allDictLevel: allDictLevel,
+        resetType: resetType,
+        allResetType: allResetType,
+        regionGroupCode: regionGroupCode,
+        allRegionGroupCode: allRegionGroupCode,
+        menuShowType: menuShowType,
+        menuStatus: menuStatus,
+        menuType: menuType,
+        selectedMenuShowType: 'display',
+        selectedMenuStatus: 'enabled',
+        selectedMenuType: 'menu',
+        operatorType: [],
+        selectOperatorType: 'supplier_supplier'
+      }
+    },
+    watch: {
+      'showDlg': function (showDlg) {
+        this.visible = showDlg
+      }
+    },
+    methods: {
+      // 状态选择
+      changeOperatorType(key, selectOperatorType) {
+        this.queryDataBefore[key].value = selectOperatorType
+      },
+      changeMenuType(key, selectedMenuType) {
+        this.queryDataBefore[key].value = selectedMenuType
+      },
+      changeMenuStatus(key, selectedMenuStatus) {
+        this.queryDataBefore[key].value = selectedMenuStatus
+      },
+      changeMenuShowType(key, selectedMenuShowType) {
+        this.queryDataBefore[key].value = selectedMenuShowType
+      },
+      changeQuerySupport(key, selectedQuerySupport) {
+        this.queryDataBefore[key].value = selectedQuerySupport
+      },
+      changeRegionGroupCode(key, selectedRegionGroupCode){
+        this.queryDataBefore[key].value = selectedRegionGroupCode
+      },
+      changeResetType(key, selectedResetType) {
+        this.queryDataBefore[key].value = selectedResetType
+      },
+      changeDictLevel(key, selectedDictLevel) {
+        this.queryDataBefore[key].value = selectedDictLevel
+      },
+      changeOperatorLevel(key, selectedOperatorLevel) {
+        this.queryDataBefore[key].value = selectedOperatorLevel
+      },
+      changeGender(key, selectedGender) {
+        this.queryDataBefore[key].value = selectedGender
+      },
+      changeStatus(key, selectedStatus) {
+        this.queryDataBefore[key].value = selectedStatus
+      },
+      changeSupport(key, selectedSupport) {
+        this.queryDataBefore[key].value = selectedSupport
+      },
+      changeId(key, selectId) {
+        this.queryDataBefore[key].value = selectId
+      },
+      valCheck(data){
+        let flag = true
+        let phoneReg = /^[1][3,4,5,7,8][0-9]{9}$/; // 手机号
+        let cardReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/; // 身份证验证
+        for(let i in data) {
+          if(data[i].param == 'userMobilePhone') {
+              if(!phoneReg.test(data[i].value)) {
+                this.$message.warning('请输入正确的手机号码!');
+                flag = false;
+              }
+            }
+          if(data[i].param == 'operatorPid') {
+            if(!cardReg.test(data[i].value)) {
+              this.$message.warning('请输入正确的身份证!');
+              flag = false;
+            }
+          }
+          if(data[i].param != 'id' && data[i].required && data[i].value == null) {
+            flag = false;
+            console.log(i)
+          }
+        }
+        return flag;
+      },
+      handleAddOrEdit() {
+        console.log(this.queryDataBefore)
+        let flag = this.valCheck(this.queryDataBefore)
+        console.log(flag)
+        if(!flag) {
+          this.$message.warning('请输入必填项!');
+          return;
+        } else {
+          for(let i in his.queryDataBeftore) {
+            
+          }
+          this.$emit('handleAddOrEdit', this.queryDataBefore )
+          console.log(111)
+          this.$emit('update:showDlg', this.showDlg)
+        }
+      },
+      handleCancel() {
+        this.$emit('handleCancel', this.queryDataBefore )
+        this.$emit('update:showDlg', this.showDlg)
+      },
+    },
+    mounted() {
+      let data = { currentPage:1, pageSize:10, where: {} }
+      for(let i in this.queryDataBefore) {
+        if(this.queryDataBefore[i].param === 'operatorType') {
+          this.queryDataBefore[i].value === this.selectOperatorType
+          this.axios({
+            url:  'basic/operatorType/pageList',
+            method: METHOD_POST,
+            data: data
+          }).then(res=>{
+            console.log(res)
+            if(res.code == 0) {
+              this.operatorType = res.page.list
+              console.log(this.operatorType)
+            } else {
+              this.$message.error(res.msg);
+            }
+          }).catch(() => {
+            this.loading = false;
+            this.$message.error('请求超时!');
+          })
+          }
+      } 
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 57 - 0
src/components/chart/Bar.vue

@@ -0,0 +1,57 @@
+<template>
+  <div :style="{ padding: '0 0 32px 32px' }">
+    <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
+    <v-chart
+      height="254"
+      :data="data"
+      :forceFit="true"
+      :padding="['auto', 'auto', '40', '50']">
+      <v-tooltip />
+      <v-axis />
+      <v-bar position="x*y"/>
+    </v-chart>
+  </div>
+</template>
+
+<script>
+  const data = []
+  for (let i = 0; i < 12; i += 1) {
+    data.push({
+      x: `${i + 1}月`,
+      y: Math.floor(Math.random() * 1000) + 200
+    })
+  }
+  const tooltip = [
+    'x*y',
+    (x, y) => ({
+      name: x,
+      value: y
+    })
+  ]
+  const scale = [{
+    dataKey: 'x',
+    min: 2
+  }, {
+    dataKey: 'y',
+    title: '时间',
+    min: 1,
+    max: 22
+  }]
+
+  export default {
+    name: "Bar",
+    props: {
+      title: {
+        type: String,
+        default: ''
+      }
+    },
+    data () {
+      return {
+        data,
+        scale,
+        tooltip
+      }
+    }
+  }
+</script>

+ 66 - 0
src/components/chart/MiniArea.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="antv-mini-chart">
+    <div class="chart-content" :style="{ height: 46 }">
+      <v-chart :force-fit="true" :height="height" :data="data" :padding="[36, 5, 18, 5]">
+        <v-tooltip />
+        <v-smooth-area position="x*y" />
+      </v-chart>
+    </div>
+  </div>
+</template>
+
+<script>
+  import moment from 'moment'
+  const data = []
+  const beginDay = new Date().getTime()
+  const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5]
+  for (let i = 0; i < fakeY.length; i += 1) {
+    data.push({
+      x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
+      y: fakeY[i]
+    })
+  }
+  const tooltip = [
+    'x*y',
+    (x, y) => ({
+      name: x,
+      value: y
+    })
+  ]
+  const scale = [{
+    dataKey: 'x',
+    min: 2
+  }, {
+    dataKey: 'y',
+    title: '时间',
+    min: 1,
+    max: 22
+  }]
+
+  export default {
+    name: "MiniArea",
+    data () {
+      return {
+        data,
+        scale,
+        tooltip,
+        height: 100
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+    .antv-mini-chart {
+        position: relative;
+        width: 100%;
+
+        .chart-content {
+            position: absolute;
+            bottom: -28px;
+            width: 100%;
+            margin: 0 -5px;
+            overflow: hidden;
+        }
+    }
+</style>

+ 68 - 0
src/components/chart/Radar.vue

@@ -0,0 +1,68 @@
+<template>
+  <v-chart :forceFit="true" height="400" :data="data" :padding="[20, 20, 95, 20]" :scale="scale">
+    <v-tooltip></v-tooltip>
+    <v-axis :dataKey="axis1Opts.dataKey" :line="axis1Opts.line" :tickLine="axis1Opts.tickLine" :grid="axis1Opts.grid" />
+    <v-axis :dataKey="axis2Opts.dataKey" :line="axis2Opts.line" :tickLine="axis2Opts.tickLine" :grid="axis2Opts.grid" />
+    <v-legend dataKey="user" marker="circle" :offset="30" />
+    <v-coord type="polar" radius="0.8" />
+    <v-line position="item*score" color="user" :size="2" />
+    <v-point position="item*score" color="user" :size="4" shape="circle" />
+  </v-chart>
+</template>
+
+<script>
+  const axis1Opts = {
+    dataKey: 'item',
+    line: null,
+    tickLine: null,
+    grid: {
+      lineStyle: {
+        lineDash: null
+      },
+      hideFirstLine: false
+    }
+  }
+  const axis2Opts = {
+    dataKey: 'score',
+    line: null,
+    tickLine: null,
+    grid: {
+      type: 'polygon',
+      lineStyle: {
+        lineDash: null
+      }
+    }
+  }
+
+  const scale = [
+    {
+      dataKey: 'score',
+      min: 0,
+      max: 80
+    }, {
+      dataKey: 'user',
+      alias: '类型'
+    }
+  ]
+
+  export default {
+    name: 'Radar',
+    props: {
+      data: {
+        type: Array,
+        default: null,
+      }
+    },
+    data () {
+      return {
+        axis1Opts,
+        axis2Opts,
+        scale
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 77 - 0
src/components/chart/RankList.vue

@@ -0,0 +1,77 @@
+<template>
+  <div class="rank">
+    <h4 class="title">{{ title }}</h4>
+    <ul class="list">
+      <li :key="index" v-for="(item, index) in list">
+        <span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
+        <span>{{ item.name }}</span>
+        <span>{{ item.total }}</span>
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "RankList",
+    // ['title', 'platfrom']
+    props: {
+      title: {
+        type: String,
+        default: ''
+      },
+      list: {
+        type: Array,
+        default: null
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+
+  .rank {
+    padding: 0 32px 32px 72px;
+
+    .list {
+      margin: 25px 0 0;
+      padding: 0;
+      list-style: none;
+
+      li {
+        margin-top: 16px;
+
+        span {
+          color: rgba(0, 0, 0, .65);
+          font-size: 14px;
+          line-height: 22px;
+
+          &:first-child {
+            background-color: #f5f5f5;
+            border-radius: 20px;
+            display: inline-block;
+            font-size: 12px;
+            font-weight: 600;
+            margin-right: 24px;
+            height: 20px;
+            line-height: 20px;
+            width: 20px;
+            text-align: center;
+          }
+          &.active {
+            background-color: #314659;
+            color: #fff;
+          }
+          &:last-child {
+            float: right;
+          }
+        }
+      }
+    }
+  }
+
+  .mobile .rank {
+    padding: 0 32px 32px 32px;
+  }
+
+</style>

+ 64 - 0
src/components/chart/TransferBar.vue

@@ -0,0 +1,64 @@
+<template>
+  <div :style="{ padding: '0 0 32px 32px' }">
+    <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
+    <v-chart
+      height="254"
+      :data="data"
+      :scale="scale"
+      :forceFit="true"
+      :padding="['auto', 'auto', '40', '50']">
+      <v-tooltip />
+      <v-axis />
+      <v-bar position="x*y"/>
+    </v-chart>
+  </div>
+</template>
+
+<script>
+  const tooltip = [
+    'x*y',
+    (x, y) => ({
+      name: x,
+      value: y
+    })
+  ]
+  const scale = [{
+    dataKey: 'x',
+    title: '日期(天)',
+    alias: '日期(天)',
+    min: 2
+  }, {
+    dataKey: 'y',
+    title: '流量(Gb)',
+    alias: '流量(Gb)',
+    min: 1
+  }]
+
+  export default {
+    name: "Bar",
+    props: {
+      title: {
+        type: String,
+        default: ''
+      }
+    },
+    data () {
+      return {
+        data: [],
+        scale,
+        tooltip
+      }
+    },
+    created () {
+      this.getMonthBar()
+    },
+    methods: {
+      getMonthBar() {
+        this.$http.get('/analysis/month-bar')
+          .then(res => {
+            this.data = res.result
+          })
+      }
+    }
+  }
+</script>

+ 73 - 0
src/components/layout/HeaderNotice.vue

@@ -0,0 +1,73 @@
+<template>
+  <a-popover trigger="click" placement="bottomRight">
+    <template slot="content">
+      <a-spin :spinning="loadding">
+        <a-tabs>
+          <a-tab-pane tab="通知" key="1">
+            <a-list>
+              <a-list-item>
+                <a-list-item-meta title="你收到了 14 份新周报" description="一年前">
+                  <a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"/>
+                </a-list-item-meta>
+              </a-list-item>
+              <a-list-item>
+                <a-list-item-meta title="你推荐的 曲妮妮 已通过第三轮面试" description="一年前">
+                  <a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png"/>
+                </a-list-item-meta>
+              </a-list-item>
+              <a-list-item>
+                <a-list-item-meta title="这种模板可以区分多种通知类型" description="一年前">
+                  <a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png"/>
+                </a-list-item-meta>
+              </a-list-item>
+            </a-list>
+          </a-tab-pane>
+          <a-tab-pane tab="消息" key="2">
+            123
+          </a-tab-pane>
+          <a-tab-pane tab="待办" key="3">
+            123
+          </a-tab-pane>
+        </a-tabs>
+      </a-spin>
+    </template>
+    <span @click="fetchNotice" class="header-notice">
+      <a-badge count="12">
+        <a-icon style="font-size: 16px; padding: 4px" type="bell" />
+      </a-badge>
+    </span>
+  </a-popover>
+</template>
+
+<script>
+  export default {
+    name: "HeaderNotice",
+    data () {
+      return {
+        loadding: false
+      }
+    },
+    methods: {
+      fetchNotice () {
+        if (this.loadding) {
+          this.loadding = false
+          return
+        }
+        this.loadding = true
+        setTimeout(() => {
+          this.loadding = false
+        }, 2000)
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .header-notice{
+    display: inline-block;
+    transition: all 0.3s;
+    span {
+      vertical-align: initial;
+    }
+  }
+</style>

+ 22 - 0
src/components/layout/LayoutBaseView.vue

@@ -0,0 +1,22 @@
+<template>
+  <layout-main>
+    <page-view />
+  </layout-main>
+</template>
+
+<script>
+  import LayoutMain from './LayoutMain'
+  import PageView from './PageView'
+
+  export default {
+    name: "GlobalView",
+    components: {
+      LayoutMain,
+      PageView
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 0 - 0
src/components/layout/LayoutFooter.vue


+ 121 - 0
src/components/layout/LayoutHeader.vue

@@ -0,0 +1,121 @@
+<template>
+  <a-layout-header style="padding: 0px;">
+    <div class="header">
+      <a-icon class="trigger" v-if="device==='mobile'" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click.native="toggle"></a-icon>
+      <a-icon class="trigger" v-else :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click.native="toggle" />
+
+      <div class="user-wrapper">
+        <!-- <span class="action">
+          <a-icon type="question-circle-o"></a-icon>
+        </span> -->
+        <!-- <header-notice class="action"/> -->
+        <a-dropdown>
+          <span class="action ant-dropdown-link user-dropdown-menu">
+            <a-avatar class="avatar" size="small" :src="avatar()" />
+            <span>{{ nickname() }}</span>
+          </span>
+          <a-menu slot="overlay" class="user-dropdown-menu-wrapper">
+            <a-menu-item key="0">
+              <router-link :to="{ name: 'profile' }">
+                <a-icon type="user" />
+                <span>个人中心</span>
+              </router-link>
+            </a-menu-item>
+            <!-- <a-menu-item key="1">
+              <router-link :to="{ name: 'orderDetail'}">
+                <a-icon type="setting" />
+                <span>订单详情</span>
+              </router-link>
+            </a-menu-item> -->
+            <!-- <a-menu-item key="2">
+              <a href="javascript:;" @click="handlepassword">
+                <a-icon  type="edit"/>
+                <span>修改密码</span>
+              </a>
+            </a-menu-item>-->
+            <a-menu-divider />
+            <a-menu-item key="3">
+              <a href="javascript:;" @click="handleLogout">
+                <a-icon type="logout" />
+                <span>退出登录</span>
+              </a>
+            </a-menu-item>
+          </a-menu>
+        </a-dropdown>
+
+      </div>
+    </div>
+  </a-layout-header>
+</template>
+
+<script>
+import HeaderNotice from "./HeaderNotice";
+import { mapActions, mapGetters } from "vuex";
+import md5 from "md5";
+export default {
+  name: "LayoutHeader",
+  components: {
+    HeaderNotice
+  },
+  props: {
+    collapsed: {
+      type: Boolean,
+      required: false,
+      default: false
+    },
+    device: {
+      type: String,
+      required: false,
+      default: "desktop"
+    }
+  },
+  data() {
+    return {};
+  },
+  created() {},
+  methods: {
+    ...mapActions(["Logout"]),
+    ...mapGetters(["nickname", "avatar"]),
+    handleLogout() {
+      const that = this;
+
+      this.$confirm({
+        title: "提示",
+        content: "真的要注销登录吗 ?",
+        onOk() {
+          return that
+            .Logout({})
+            .then(() => {
+              window.location.reload();
+            })
+            .catch(err => {
+              that.$message.error({
+                title: "错误",
+                description: err.message
+              });
+            });
+        },
+        onCancel() {}
+      });
+    },
+    onOk() {
+      return this.Logout({})
+        .then(() => {
+          window.location.reload();
+        })
+        .catch(err => {
+          that.$message.error({
+            title: "错误",
+            description: err.message
+          });
+        });
+    },
+    toggle() {
+      this.$emit("toggle");
+    }
+  }
+};
+</script>
+
+<style scoped>
+</style>

+ 331 - 0
src/components/layout/LayoutMain.vue

@@ -0,0 +1,331 @@
+<template>
+  <a-layout class="layout" :class="device">
+
+    <a-drawer 
+      v-if="device === 'mobile'"
+      :wrapClassName="'drawer-sider ' + theme"
+      placement="left"
+      @close="() => this.collapsed = false"
+      :closable="false"
+      :visible="collapsed"
+    >
+      <sider-menu
+        mode="inline"
+        :menus="menus"
+        @menuSelect="menuSelect"
+        :theme="theme"
+        :collapsed="false"
+        :collapsible="true"></sider-menu>
+    </a-drawer>
+    <sider-menu
+      v-else
+      :menus="menus"
+      :theme="theme"
+      :mode="menuMode"
+      :collapsed="collapsed"
+      :collapsible="true"></sider-menu>
+
+    <a-layout>
+      <!-- layout header -->
+      <layout-header :collapsed="collapsed" :device="device" @toggle="toggle"/>
+      <!-- layout content -->
+      <a-layout-content :style="{ margin: '24px 24px 0', height: '100%' }">
+        <!-- content -->
+        <slot/>
+      </a-layout-content>
+
+      <a-layout-footer style="padding: 0px">
+        <!--<layout-footer/>-->
+      </a-layout-footer>
+    </a-layout>
+  </a-layout>
+</template>
+
+<script>
+  import SiderMenu from '@/components/menu/SiderMenu'
+  import LayoutHeader from './LayoutHeader'
+  import LayoutFooter from './LayoutFooter'
+  import { mapState, mapActions } from 'vuex'
+
+  export default {
+    name: "LayoutView",
+    components: {
+      SiderMenu,
+      LayoutHeader,
+      LayoutFooter
+    },
+    data() {
+      return {
+        // light, dark
+        menuTheme: 'light',
+        // inline, horizontal
+        menuMode: 'inline',
+        collapsed: false,
+        menus: []
+      }
+    },
+    created() {
+      this.menus = this.mainMenu
+    },
+    computed: {
+      ...mapState({
+        mainMenu: state => state.permission.addRouters,
+        sidebarOpened: state => state.app.sidebar.opened,
+        theme: state => state.app.theme,
+        device: state => state.app.device,
+      })
+    },
+    mounted() {
+      this.collapsed = this.sidebarOpened
+    },
+    methods: {
+      ...mapActions(['setSidebar']),
+      toggle() {
+        this.collapsed = !this.collapsed;
+        this.setSidebar(this.collapsed)
+      },
+      menuSelect() {
+        if (this.device !== 'desktop') {
+          this.collapsed = false
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss">
+
+  body {
+    // 打开滚动条固定显示
+    overflow-y: scroll;
+  }
+
+  .layout {
+    min-height: 100vh;
+    overflow-x: hidden;
+
+    &.mobile {
+
+      .ant-layout-content {
+
+        .content {
+          margin: 24px 0 0;
+        }
+      }
+
+      .ant-table-wrapper {
+        .ant-table-body {
+          overflow-y: auto;
+        }
+      }
+    }
+
+    &.ant-layout-has-sider {
+      flex-direction: row;
+    }
+
+    .trigger {
+      font-size: 20px;
+      line-height: 64px;
+      padding: 0 24px;
+      cursor: pointer;
+      transition: color .3s;
+      &:hover {
+        color: #1890ff;
+        background: #e6f7ff;
+      }
+    }
+
+    .header {
+      height: 64px;
+      padding: 0 12px 0 0;
+      background: #fff;
+      box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
+      position: relative;
+
+      .user-wrapper {
+        float: right;
+        height: 100%;
+
+        .action {
+          cursor: pointer;
+          padding: 0 12px;
+          display: inline-block;
+          transition: all .3s;
+          height: 100%;
+
+          &:hover {
+            background: #e6f7ff;
+          }
+
+          .avatar {
+            margin: 20px 8px 20px 0;
+            color: #1890ff;
+            background: hsla(0, 0%, 100%, .85);
+            vertical-align: middle;
+          }
+
+          .icon {
+            font-size: 16px;
+            padding: 4px;
+          }
+        }
+      }
+    }
+
+    // 内容区
+    .layout-content {
+      margin: 24px 24px 0px;
+      height: 100%;
+    }
+
+  }
+
+  // drawer-sider 自定义
+  .ant-drawer.drawer-sider {
+    .sider {
+      box-shadow: none;
+    }
+
+    &.dark {
+      .ant-drawer-content {
+        background-color: rgb(0, 21, 41);
+      }
+    }
+    &.light {
+      box-shadow: none;
+      .ant-drawer-content {
+        background-color: #fff;
+      }
+    }
+
+    .ant-drawer-body {
+      padding: 0
+    }
+  }
+
+  // 菜单样式
+  .sider {
+    box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
+    position: relative;
+    z-index: 10;
+
+    .logo {
+      height: 64px;
+      position: relative;
+      line-height: 64px;
+      padding-left: 24px;
+      -webkit-transition: all .3s;
+      transition: all .3s;
+      background: #002140;
+      overflow: hidden;
+
+      img, h1 {
+        display: inline-block;
+        vertical-align: middle;
+      }
+
+      img {
+        height: 32px;
+      }
+
+      h1 {
+        color: #fff;
+        font-size: 20px;
+        margin: 0 0 0 12px;
+        font-family: "Myriad Pro", "Helvetica Neue", Arial, Helvetica, sans-serif;
+        font-weight: 600;
+      }
+    }
+
+    &.light {
+      background-color: #fff;
+      box-shadow: 2px 0px 8px 0px rgba(29, 35, 41, 0.05);
+
+      .logo {
+        background: #fff;
+        box-shadow: 1px 1px 0px 0px #e8e8e8;
+
+        h1 {
+          color: unset;
+        }
+      }
+
+      .ant-menu-light {
+        border-right-color: transparent;
+      }
+    }
+
+  }
+
+  // 外置的样式控制
+  .user-dropdown-menu-wrapper.ant-dropdown-menu {
+    padding: 4px 0;
+
+    .ant-dropdown-menu-item {
+      width: 160px;
+    }
+
+    .ant-dropdown-menu-item > .anticon:first-child,
+    .ant-dropdown-menu-item > a > .anticon:first-child,
+    .ant-dropdown-menu-submenu-title > .anticon:first-child
+    .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
+      min-width: 12px;
+      margin-right: 8px;
+    }
+
+  }
+
+  // 数据列表 样式
+  .table-alert {
+    margin-bottom: 16px;
+  }
+
+  .table-page-search-wrapper {
+
+    .ant-form-inline {
+
+      .ant-form-item {
+        display: flex;
+        margin-bottom: 24px;
+        margin-right: 0;
+
+        .ant-form-item-control-wrapper {
+          flex: 1 1;
+          display: inline-block;
+          vertical-align: middle;
+        }
+
+        >.ant-form-item-label {
+          line-height: 32px;
+          padding-right: 8px;
+          width: auto;
+        }
+        .ant-form-item-control {
+          height: 32px;
+          line-height: 32px;
+        }
+      }
+    }
+
+    .table-page-search-submitButtons {
+      display: block;
+      margin-bottom: 24px;
+      white-space: nowrap;
+    }
+
+  }
+
+  .content {
+
+
+
+    .table-operator {
+      margin-bottom: 18px;
+
+      button {
+        margin-right: 8px;
+      }
+    }
+  }
+</style>

+ 22 - 0
src/components/layout/LayoutView.vue

@@ -0,0 +1,22 @@
+<template>
+  <layout-main>
+    <route-view/>
+  </layout-main>
+</template>
+
+<script>
+  import LayoutMain from './LayoutMain'
+  import RouteView from './RouteView'
+
+  export default {
+    name: "GlobalView",
+    components: {
+      LayoutMain,
+      RouteView
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 223 - 0
src/components/layout/PageHeader.vue

@@ -0,0 +1,223 @@
+<template>
+  <div class="page-header">
+
+    <a-breadcrumb class="breadcrumb">
+      <a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
+        <router-link v-if="item.name != name" :to="{ path: item.path }">
+          {{ item.meta.title }}
+        </router-link>
+        <span v-else>{{ item.meta.title }}</span>
+      </a-breadcrumb-item>
+    </a-breadcrumb>
+
+    <div class="detail">
+      <div class="main" v-if="!$route.meta.hiddenPageHeader">
+        <div class="row">
+          <img v-if="logo" :src="logo" class="logo"/>
+          <!-- <h1 v-if="title" class="title">{{ title }}</h1> -->
+          <div class="action">
+            <slot name="action"></slot>
+          </div>
+        </div>
+        <div class="row">
+          <div v-if="avatar" class="avatar">
+            <a-avatar :src="avatar"/>
+          </div>
+          <div v-if="this.$slots.content" class="headerContent">
+            <slot name="content"></slot>
+          </div>
+          <div v-if="this.$slots.extra" class="extra">
+            <slot name="extra"></slot>
+          </div>
+        </div>
+      </div>
+
+    </div>
+  </div>
+</template>
+
+<script>
+  import Breadcrumb from '@/components/tools/Breadcrumb'
+
+  export default {
+    name: "PageHeader",
+    components: {
+      "s-breadcrumb": Breadcrumb
+    },
+    props: {
+      title: {
+        type: String,
+        default: '',
+        required: false
+      },
+      breadcrumb: {
+        type: Array,
+        default: null,
+        required: false
+      },
+      logo: {
+        type: String,
+        default: '',
+        required: false
+      },
+      avatar: {
+        type: String,
+        default: '',
+        required: false
+      }
+    },
+    data() {
+      return {
+        name: '',
+        breadList: [],
+      }
+    },
+    created() {
+      this.getBreadcrumb()
+    },
+    methods: {
+      getBreadcrumb() {
+
+        this.breadList = []
+        this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
+
+        this.name = this.$route.name
+        this.$route.matched.forEach((item) => {
+          // item.meta.name === 'dashboard' ? item.path = '/dashboard' : this.$route.path === item.path
+          this.breadList.push(item)
+        })
+      }
+    },
+    watch: {
+      $route() {
+        this.getBreadcrumb()
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .page-header {
+    background: #fff;
+    padding: 16px 32px 0;
+    border-bottom: 1px solid #e8e8e8;
+
+    .breadcrumb {
+      margin-bottom: 16px;
+    }
+
+    .detail {
+      display: flex;
+      /*margin-bottom: 16px;*/
+
+      .avatar {
+        flex: 0 1 72px;
+        margin: 0 24px 8px 0;
+
+        & > span {
+          border-radius: 72px;
+          display: block;
+          width: 72px;
+          height: 72px;
+        }
+      }
+
+      .main {
+        width: 100%;
+        flex: 0 1 auto;
+
+        .row {
+          display: flex;
+          width: 100%;
+
+          .avatar {
+            margin-bottom: 16px;
+          }
+        }
+
+        .title {
+          font-size: 20px;
+          font-weight: 500;
+
+          font-size: 20px;
+          line-height: 28px;
+          font-weight: 500;
+          color: rgba(0,0,0,.85);
+          margin-bottom: 16px;
+          flex: auto;
+
+        }
+        .logo {
+          width: 28px;
+          height: 28px;
+          border-radius: 4px;
+          margin-right: 16px;
+        }
+        .content, .headerContent {
+          flex: auto;
+          color: rgba(0,0,0,.45);
+          line-height: 22px;
+
+          .link {
+            margin-top: 16px;
+            line-height: 24px;
+
+            a {
+              font-size: 14px;
+              margin-right: 32px;
+            }
+          }
+        }
+        .extra {
+          flex: 0 1 auto;
+          margin-left: 88px;
+          min-width: 242px;
+          text-align: right;
+        }
+        .action {
+          margin-left: 56px;
+          min-width: 266px;
+          flex: 0 1 auto;
+          text-align: right;
+          &:empty {
+            display: none;
+          }
+        }
+      }
+    }
+  }
+
+  .mobile .page-header {
+
+    .main {
+
+      .row {
+        flex-wrap: wrap;
+
+        .avatar {
+          flex: 0 1 25%;
+          margin: 0 2% 8px 0;
+        }
+        .content, .headerContent {
+          flex: 0 1 70%;
+
+          .link {
+            margin-top: 16px;
+            line-height: 24px;
+
+            a {
+              font-size: 14px;
+              margin-right: 10px;
+            }
+          }
+        }
+        .extra {
+          flex: 1 1 auto;
+          margin-left: 0;
+          min-width: 0;
+          text-align: right;
+        }
+      }
+    }
+  }
+</style>

+ 93 - 0
src/components/layout/PageLayout.vue

@@ -0,0 +1,93 @@
+<template>
+  <div :style="!$route.meta.hideHeader ? 'margin: -24px -24px 0px;' : null">
+    <!-- pageHeader , route meta hideHeader:true on hide -->
+    <page-header v-if="!$route.meta.hideHeader" :title="title" :logo="logo" :avatar="avatar">
+      <slot slot="action" name="action"></slot>
+      <slot slot="content" name="headerContent"></slot>
+      <div slot="content" v-if="!this.$slots.headerContent && desc">
+        <p style="font-size: 14px;color: rgba(0,0,0,.65)">{{ desc }}</p>
+        <div class="link">
+          <template v-for="(link, index) in linkList">
+            <a :key="index" :href="link.href">
+              <a-icon :type="link.icon" /><span>{{ link.title }}</span>
+            </a>
+          </template>
+        </div>
+      </div>
+      <slot slot="extra" name="extra"></slot>
+    </page-header>
+    <div class="content">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+  import PageHeader from './PageHeader'
+
+  export default {
+    name: "LayoutContent",
+    components: {
+      PageHeader
+    },
+    // ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage']
+    props: {
+      desc: {
+        type: String,
+        default: null
+      },
+      logo: {
+        type: String,
+        default: null
+      },
+      title: {
+        type: String,
+        default: null
+      },
+      avatar: {
+        type: String,
+        default: null
+      },
+      linkList: {
+        type: Array,
+        default: null
+      },
+      extraImage: {
+        type: String,
+        default: null
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+    .content {
+        margin: 24px 24px 0;
+
+      .link {
+        margin-top: 16px;
+
+        &:not(:empty) {
+          margin-bottom: 16px;
+        }
+        a {
+          margin-right: 32px;
+          height: 24px;
+          line-height: 24px;
+          display: inline-block;
+
+          i {
+            font-size: 24px;
+            margin-right: 8px;
+            vertical-align: middle;
+          }
+          span {
+            height: 24px;
+            line-height: 24px;
+            display: inline-block;
+            vertical-align: middle;
+          }
+        }
+      }
+    }
+</style>

+ 80 - 0
src/components/layout/PageView.vue

@@ -0,0 +1,80 @@
+<template>
+  <page-layout :desc="description" :title="getTitle" :link-list="linkList">
+    <div slot="extra" class="extra-img">
+      <img :src="extraImage"/>
+    </div>
+    <!-- keep-alive  -->
+    <route-view ref="content"></route-view>
+  </page-layout>
+</template>
+
+<script>
+  import PageLayout from './PageLayout'
+  import RouteView from './RouteView'
+
+  export default {
+    name: "PageContent",
+    components: {
+      RouteView,
+      PageLayout
+    },
+    data () {
+      return {
+        title: '',
+        description: '',
+        linkList: [],
+        extraImage: ''
+      }
+    },
+    mounted () {
+      this.getPageHeaderInfo()
+    },
+    updated () {
+      this.getPageHeaderInfo()
+    },
+    computed: {
+
+      getTitle () {
+        return this.$route.meta.title
+      }
+
+    },
+    methods: {
+      getPageHeaderInfo () {
+        // eslint-disable-next-line
+        this.title = this.$route.meta.title
+        // 因为套用了一层 route-view 所以要取 ref 对象下的子节点的第一个对象
+        const content = this.$refs.content && this.$refs.content.$children[0]
+        if (content) {
+          this.description = content.description
+          this.linkList = content.linkList
+          this.extraImage = content.extraImage
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .extra-img {
+    margin-top: -60px;
+    text-align: center;
+    width: 195px;
+
+    img {
+      width: 100%;
+    }
+  }
+
+  .mobile {
+    .extra-img{
+      margin-top: 0;
+      text-align: center;
+      width: 96px;
+
+      img{
+        width: 100%;
+      }
+    }
+  }
+</style>

+ 16 - 0
src/components/layout/RouteView.vue

@@ -0,0 +1,16 @@
+<template>
+  <keep-alive v-if="$route.meta.keepAlive">
+    <router-view></router-view>
+  </keep-alive>
+  <router-view v-else></router-view>
+</template>
+
+<script>
+  export default {
+    name: "RouteView"
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 74 - 0
src/components/menu/SiderMenu.vue

@@ -0,0 +1,74 @@
+<template>
+  <a-layout-sider 
+    :class="['sider', isMobile ? null : 'shadow', theme ]" 
+    width="256px" 
+    :collapsible="collapsible"
+    v-model="collapsed" 
+    :trigger="null">
+    <div class="logo">
+      <img src="../../../public/logo.png" alt="">
+      <router-link :to="{name:'appManagement'}">
+        <h1>支撑平台</h1>
+      </router-link>
+    </div>
+    <s-menu
+      :collapsed="collapsed"
+      :menu="menus"
+      :theme="theme"
+      @select="onSelect"
+      :mode="mode"
+      style="padding: 16px 0px;"
+    >
+
+    </s-menu>
+  </a-layout-sider>
+</template>
+
+<script>
+  import ALayoutSider from "ant-design-vue/es/layout/Sider"
+  import SMenu from './index'
+
+  export default {
+    name: "SiderMenu",
+    components: { ALayoutSider, SMenu },
+    props: {
+      mode: {
+        type: String,
+        required: false,
+        default: 'inline'
+      },
+      theme: {
+        type: String,
+        required: false,
+        default: 'dark'
+      },
+      collapsible: {
+        type: Boolean,
+        required: false,
+        default: false
+      },
+      collapsed: {
+        type: Boolean,
+        required: false,
+        default: false
+      },
+      menus: {
+        type: Array,
+        required: true
+      }
+    },
+    created () {
+
+    },
+    computed: {
+      isMobile () {
+        return this.$store.state.app.device !== 'desktop'
+      }
+    },
+    methods: {
+      onSelect (obj) {
+        this.$emit('menuSelect', obj)
+      }
+    }
+  }
+</script>

+ 159 - 0
src/components/menu/index.js

@@ -0,0 +1,159 @@
+import Menu from 'ant-design-vue/es/menu'
+import Icon from 'ant-design-vue/es/icon'
+
+const { Item, SubMenu } = Menu
+
+export default {
+  name: 'SMenu',
+  props: {
+    menu: {
+      type: Array,
+      required: true
+    },
+    theme: {
+      type: String,
+      required: false,
+      default: 'dark'
+    },
+    mode: {
+      type: String,
+      required: false,
+      default: 'inline'
+    },
+    collapsed: {
+      type: Boolean,
+      required: false,
+      default: false
+    }
+  },
+  data () {
+    return {
+      openKeys: [],
+      selectedKeys: [],
+      cachedOpenKeys: []
+    }
+  },
+  computed: {
+    rootSubmenuKeys: (vm) => {
+      let keys = []
+      vm.menu.forEach(item => keys.push(item.path))
+      return keys
+    }
+  },
+  created () {
+    this.updateMenu()
+  },
+  watch: {
+    collapsed (val) {
+      if (val) {
+        this.cachedOpenKeys = this.openKeys
+        this.openKeys = []
+      } else {
+        this.openKeys = this.cachedOpenKeys
+      }
+    },
+    '$route': function () {
+      this.updateMenu()
+    }
+  },
+  methods: {
+    renderIcon: function (h, icon) {
+      return icon === 'none' || icon === undefined ? null
+        : h(Icon, { props: { type: icon !== undefined ? icon : '' } })
+    },
+    renderMenuItem: function (h, menu, pIndex, index) {
+      return h(Item, { key: menu.path ? menu.path : 'item_' + pIndex + '_' + index },
+        [
+          h(
+            'router-link',
+            { attrs: { to: { name: menu.name } } },
+            [
+              this.renderIcon(h, menu.meta.icon),
+              h('span', [ menu.meta.title ])
+            ]
+          )
+        ]
+      )
+    },
+    renderSubMenu: function (h, menu, pIndex, index) {
+      const this2_ = this;
+      let subItem = [ h('span',
+        { slot: 'title' },
+        [
+          this.renderIcon(h, menu.meta.icon),
+          h('span', [ menu.meta.title ])
+        ]
+      ) ]
+      let itemArr = []
+      let pIndex_ = pIndex + '_' + index
+      if (!menu.alwaysShow) {
+        menu.children.forEach(function (item, i) {
+          itemArr.push(this2_.renderItem(h, item, pIndex_, i))
+        })
+      }
+      return h(
+        SubMenu,
+        { key: menu.path ? menu.path : 'submenu_' + pIndex + '_' + index },
+        subItem.concat(itemArr)
+      )
+    },
+    renderItem: function (h, menu, pIndex, index) {
+      if (!menu.hidden) {
+        return menu.children && !menu.alwaysShow ? this.renderSubMenu(h, menu, pIndex, index) : this.renderMenuItem(h, menu, pIndex, index)
+      }
+    },
+    renderMenu: function (h, menuTree) {
+      const this2_ = this
+      let menuArr = []
+      menuTree.forEach(function (menu, i) {
+        if (!menu.hidden) {
+          menuArr.push(this2_.renderItem(h, menu, '0', i))
+        }
+      })
+      return menuArr
+    },
+    onOpenChange (openKeys) {
+      const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
+      if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
+        this.openKeys = openKeys
+      } else {
+        this.openKeys = latestOpenKey ? [ latestOpenKey ] : []
+      }
+    },
+    updateMenu () {
+      let routes = this.$route.matched.concat()
+      if (routes.length >= 3 && this.$route.meta.hidden) {
+        routes.pop()
+        this.selectedKeys = [ routes[1].path ]
+      } else {
+        this.selectedKeys = [ routes.pop().path ]
+      }
+      let openKeys = []
+      routes.forEach((item) => {
+        openKeys.push(item.path)
+      })
+      this.collapsed ? this.cachedOpenKeys = openKeys : this.openKeys = openKeys
+    }
+  },
+  render (h) {
+    return h(
+      Menu,
+      {
+        props: {
+          theme: this.$props.theme,
+          mode: this.$props.mode,
+          inlineCollapsed: false,
+          openKeys: this.openKeys,
+          selectedKeys: this.selectedKeys
+        },
+        on: {
+          openChange: this.onOpenChange,
+          select: (obj) => {
+            this.selectedKeys = obj.selectedKeys
+            this.$emit('select', obj)
+          }
+        }
+      }, this.renderMenu(h, this.menu)
+    )
+  }
+}

+ 82 - 0
src/components/pagination/pagination.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="pagination">
+    <a-pagination
+      showQuickJumper
+      hideOnSinglePage
+      showSizeChanger
+      v-model="currentPage"
+      :pageSizeOptions="pageSizeOptions"
+      :pageSize="pageSize"
+      :total="total"
+      @change="change"
+    >
+      <template slot='buildOptionText' >
+        <span>{{ pageSize }}条/页</span>
+      </template>
+    </a-pagination>
+    <span class="record">共{{ total }}条记录&nbsp;第{{ current }}/{{ totalPage }}页</span>
+  </div>
+</template>
+
+<script>
+    export default {
+      name: "Pagination",
+      // props: ['current', 'pageSizeOptions', 'pageSize', 'total', 'totalPage'],
+      props: {
+        current: {
+          type: Number,
+          required: true
+        },
+        pageSizeOptions: {
+          type: Array,
+          required: true
+        },
+        pageSize: {
+          type: Number,
+          required: true
+        },
+        total: {
+          type: Number,
+          required: true
+        },
+        totalPage: {
+          type: Number,
+          required: true
+        },
+      },
+      data() {
+        return {
+          currentPage: 1
+        }
+      },
+      watch: {
+        'current': function (current) {
+          this.currentPage = current
+        }
+      },
+      methods: {
+        change(currentPage, pageSize) {
+          // console.log(page,pageSize)
+          this.$emit("change", {
+            currentPage,
+            pageSize
+          })
+        }
+      }
+    }
+</script>
+
+<style scoped>
+  .pagination {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 32px;
+  }
+  .record {
+    color: #ccc;
+    position: absolute;
+    bottom: 30px;
+    left: 25px
+  }
+</style>

+ 95 - 0
src/components/public.js

@@ -0,0 +1,95 @@
+export const allSelectStatus = [
+  "upstreamChannelStatus", "configStatus", "dictStatus", "operatorStatus", 
+  "roleStatus", "appStatus", "regionStatus", "userStatus", "configStatus", 
+  "dictStatus", "configStatus", "taskStatus", "typeStatus"
+]
+export const allSelectMessageStatus = ["smsSendStatus"]
+export const allSelectTaskStatus = ["taskStatus"]
+export const supportCustomSign = ["supportCustomSign", ]
+export const supportQueryBalance = ["supportQueryBalance", ]
+export const allUserType = ["userType" ]
+export const allOperatorSex = ["operatorSex" ]
+export const allOperatorLevel = ["operatorLevel" ]
+export const allResetType = ["resetType" ]
+export const allDictLevel = ["dictLevel" ]
+export const allRegionGroupCode = ["regionGroupCode" ]
+
+export const hiddenAllId = ["id"]
+
+export const regionGroupCode = [
+  {selectText: '默认', selectValue: 'defalut' },
+  {selectText: '其他', selectValue: '' }
+];
+export const resetType = [
+  {selectText: '全局', selectValue: 'default' },
+  {selectText: '月重置', selectValue: 'month' },
+  {selectText: '日重置', selectValue: 'day' },
+  {selectText: '时重置', selectValue: 'hour' }
+];
+export const dictLevel = [
+  {selectText: '全局', selectValue: 'whole' },
+  {selectText: '应用', selectValue: 'app' }
+];
+export const operatorLevel = [
+  {selectText: '归属管理员', selectValue: 'belonging_admin' },
+  {selectText: '普通操作员', selectValue: 'ordinary_operator' }
+];
+export const operatorSex = [
+  {selectText: '男', selectValue: 'male' },
+  {selectText: '女', selectValue: 'female' }
+];
+export const userType = [
+  {selectText: '全部', selectValue: '' },
+  {selectText: '支撑平台操作人员', selectValue: 'operation_supplier' }
+];
+export const queryStatus = [
+  {selectText: '全部', selectValue: '' },
+  {selectText: '启用', selectValue: 'enabled' },
+  {selectText: '禁用', selectValue: 'disabled' }
+];
+export const smsSendStatus = [
+  {selectText: '全部', selectValue: '' },
+  {selectText: '成功', selectValue: 'success' },
+  {selectText: '失败', selectValue: 'fail' }
+];
+export const taskStatus = [
+  {selectText: '全部', selectValue: '' },
+  {selectText: '正常', selectValue: 'default' },
+  {selectText: '暂停', selectValue: 'paused' }
+];
+export const querySupport = [
+  {selectText: '全部', selectValue: '' },
+  {selectText: '支持', selectValue: 'support' },
+  {selectText: '不支持', selectValue: 'not_support' }
+];
+export const queryAddOrEditStatus = [
+  {selectText: '启用', selectValue: 'enabled' },
+  {selectText: '禁用', selectValue: 'disabled' }
+];
+export const queryAddOrEditSupport = [
+  {selectText: '支持', selectValue: 'support' },
+  {selectText: '不支持', selectValue: 'not_support' }
+];
+
+export const menuShowType = [
+  { selectText: '显示', selectValue: 'display' },
+  { selectText: '隐藏', selectValue: 'hide' }
+];
+export const menuStatus = [
+  { selectText: '启用', selectValue: 'enabled' },
+  { selectText: '禁用', selectValue: 'disabled' }
+];
+export const menuType = [
+  { selectText: '菜单', selectValue: 'menu' },
+  { selectText: '目录', selectValue: 'catalog' },
+  { selectText: '按钮', selectValue: 'button' }
+];
+
+export const in_array = (arr, element) => {
+  for (let i = 0; i < arr.length; i++) {
+    if (arr[i] == element) {
+      return true;
+    }
+  }
+  return false;
+}

+ 263 - 0
src/components/queryCondition/queryCondition.vue

@@ -0,0 +1,263 @@
+<template>
+  <div class="table-page-search-wrapper">
+    <a-form layout="inline">
+      <a-row :gutter="48">
+        <a-col v-if="appList.length > 0" :md="8" :sm="24">
+          <a-form-item label="应用归属">
+            <a-select placeholder="请选择" @change="changeAppID">
+              <a-select-option v-for="(option,key) in appList" :value=option.id :key="key">
+                {{ option.appName }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </a-col>
+        <template v-if="appList.length > 0">
+          <a-col v-for="(item, key) in queryValue" :key="key" :md="8" :sm="24">
+            <a-form-item :label=item.name v-if="key < num">
+              <a-select v-if="in_array(allSelectStatus, item.param)" v-model="selected" @change="changeStatus(key)">
+                <a-select-option v-for="(option,index) in queryStatus" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(allSelectMessageStatus, item.param)" v-model="selectMessageStatus" @change="changeMessageStatus(key)">
+                <a-select-option v-for="(option,index) in smsSendStatus" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(supportCustomSign, item.param)" v-model="selectedQuerySupport" @change="changeQuerySupport(key)">
+                <a-select-option v-for="(option,index) in querySupport" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(supportQueryBalance, item.param)" v-model="selectedSupport" @change="changeSupport(key)">
+                <a-select-option v-for="(option,index) in querySupport" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(allSelectTaskStatus, item.param)" v-model="selectTaskStatus" @change="changeTaskStatus(key)">
+                <a-select-option v-for="(option,index) in taskStatus" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(allUserType, item.param)" v-model="selectUserType" @change="changeUserType(key)">
+                <a-select-option v-for="(option,index) in userType" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="item.param == 'operatorType'" v-model="selectOperatorType" @change="changeOperatorType(key)">
+                <a-select-option v-for="(option,index) in operatorType" :value=option.id :key="index">
+                  {{ option.typeName}}
+                </a-select-option>
+              </a-select>
+              <a-input v-else v-model="item.value" :placeholder="'请输入' + item.name"/>
+            </a-form-item>
+          </a-col>
+        </template>
+        <template v-else>
+          <a-col v-for="(item, key) in queryValue" :key="key" :md="8" :sm="24">
+            <a-form-item :label=item.name v-if="key < twoNum">
+              <a-select v-if="in_array(allSelectStatus, item.param)" v-model="selected" @change="changeStatus(key)">
+                <a-select-option v-for="(option,index) in queryStatus" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(allSelectMessageStatus, item.param)" v-model="selectMessageStatus" @change="changeMessageStatus(key)">
+                <a-select-option v-for="(option,index) in smsSendStatus" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(supportCustomSign, item.param)" v-model="selectedQuerySupport" @change="changeQuerySupport(key)">
+                <a-select-option v-for="(option,index) in querySupport" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(supportQueryBalance, item.param)" v-model="selectedSupport" @change="changeSupport(key)">
+                <a-select-option v-for="(option,index) in querySupport" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(allSelectTaskStatus, item.param)" v-model="selectTaskStatus" @change="changeTaskStatus(key)">
+                <a-select-option v-for="(option,index) in taskStatus" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="in_array(allUserType, item.param)" v-model="selectUserType" @change="changeUserType(key)">
+                <a-select-option v-for="(option,index) in userType" :value=option.selectValue :key="index">
+                  {{ option.selectText }}
+                </a-select-option>
+              </a-select>
+              <a-select v-else-if="item.param == 'operatorType'" v-model="selectOperatorType" @change="changeOperatorType(key)">
+                <a-select-option v-for="(option,index) in operatorType" :value=option.id :key="index">
+                  {{ option.typeName}}
+                </a-select-option>
+              </a-select>
+              <a-input v-else v-model="item.value" :placeholder="'请输入' + item.name"/>
+            </a-form-item>
+          </a-col>
+        </template>
+        <a-col :md="!(advanced) && 8 || 24" :sm="24">
+          <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+            <a-button type="primary" @click="inquire">查询</a-button>
+            <a-button style="margin-left: 8px" @click="resetting">重置</a-button>
+            <a @click="toggleAdvanced" style="margin-left: 8px">
+              {{ advanced ? '收起' : '展开' }}
+              <a-icon :type="advanced ? 'up' : 'down'"/>
+            </a>
+          </span>
+        </a-col>
+      </a-row>
+    </a-form>
+  </div>
+</template>
+
+<script>
+  import { 
+    allSelectStatus, 
+    supportCustomSign,
+    supportQueryBalance, 
+    allSelectMessageStatus, 
+    in_array, 
+    smsSendStatus, 
+    allSelectTaskStatus, 
+    taskStatus,
+    querySupport,
+    allUserType,
+    userType
+  } from '@/components/public';
+  import { BASEURL, METHOD_POST } from '@/api/public';
+
+  export default {
+    name: "QueryCondition",
+    props: {
+      queryValue: {
+        type: Array,
+        required: true
+      },
+      queryStatus: {
+        type: Array,
+        required: true
+      },
+      appList: {
+        type: Array,
+        required: true
+      }
+    },
+    data() {
+      return {
+        num: 1,
+        twoNum: 2,
+        selected: '全部',
+        selectMessageStatus: '全部',
+        selectedSupport: '全部',
+        selectedQuerySupport: '全部',
+        selectTaskStatus: '全部',
+        selectUserType: '全部',
+        querySupport: querySupport,
+        advanced: false,
+        allSelectStatus: allSelectStatus,
+        allSelectMessageStatus: allSelectMessageStatus,
+        supportCustomSign: supportCustomSign,
+        supportQueryBalance: supportQueryBalance,
+        in_array: in_array,
+        smsSendStatus: smsSendStatus,
+        allSelectTaskStatus: allSelectTaskStatus,
+        taskStatus: taskStatus,
+        allUserType: allUserType,
+        userType: userType,
+        operatorType: [],
+        selectOperatorType: '全部'
+      }
+    },
+    methods: {
+      changeAppID(e) {
+        console.log(e)
+        this.appId = e
+        this.$emit("changeAppID", e)
+      },
+      // 状态选择
+      changeMessageStatus(key) {
+        this.queryValue[key].value = this.selectMessageStatus
+      },
+      changeQuerySupport(key) {
+        this.queryValue[key].value = this.selectedQuerySupport
+      },
+      changeSupport(key) {
+        this.queryValue[key].value = this.selectedSupport
+      },
+      changeTaskStatus(key) {
+        this.queryValue[key].value = this.selectTaskStatus
+      },
+      changeUserType(key) {
+        this.queryValue[key].value = this.selectUserType
+      },
+      changeStatus(key) {
+        this.queryValue[key].value = this.selected
+      },
+      changeOperatorType(key) {
+        this.queryValue[key].value = this.selectOperatorType
+      },
+
+      //收起&展开
+      toggleAdvanced(){
+        this.advanced = !this.advanced
+        if(this.appList.length > 0) {
+          if(this.num == 1) {
+            this.num = this.queryValue.length
+            } else {
+            this.num = 1
+          }
+        } else {
+          if(this.twoNum == 2) {
+            this.twoNum = this.queryValue.length
+            } else {
+            this.twoNum = 2
+          }
+        }
+      },
+
+      // 点击查询
+      inquire() {
+        this.$emit("inquire", this.queryValue)
+      },
+
+      // 重置
+      resetting() {
+        this.queryValue.forEach(item => {
+          item.value = null
+        });
+        this.selected = '全部',
+        this.selectMessageStatus = '全部',
+        this.selectedSupport = '全部',
+        this.selectedQuerySupport = '全部',
+        this.selectTaskStatus = '全部',
+        this.selectUserType = '全部'
+      }
+    },
+    mounted() {
+      let data = { currentPage:1, pageSize:10, where: this.queryCondition }
+      for(let i in this.queryValue) {
+        if(this.queryValue[i].param === 'operatorType') {
+          this.axios({
+            url:  'basic/operatorType/pageList',
+            method: METHOD_POST,
+            data: data
+          }).then(res=>{
+            if(res.code == 0) {
+              this.operatorType = res.page.list
+            } else {
+              this.$message.error(res.msg);
+            }
+          }).catch(() => {
+            this.loading = false;
+            this.$message.error('请求超时!');
+          })
+          }
+      } 
+    }
+
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 249 - 0
src/components/table/README.md

@@ -0,0 +1,249 @@
+#### Table 重封装组件说明
+
+
+说明:
+
+>  基础的使用方式与 API 与 [官方版(Table)](https://vuecomponent.github.io/ant-design-vue/components/table-cn/) 本一致,在其基础上,封装了加载数据的方法。
+>
+> 你无需在你是用表格的页面进行分页逻辑处理,仅需向 Table 组件传递绑定 `:data="Promise"` 对象即可
+
+
+
+例子1(基础使用):
+
+```vue
+<template>
+    <s-table
+      size="default"
+      :columns="columns"
+      :data="loadData"
+    >
+    </s-table>
+</template>
+
+<script>
+  	import STable from '@/components/table/'
+    export default {
+    	components: {
+    		STable
+    	},
+        data () {
+            return {
+                columns: [
+                  {
+                    title: '规则编号',
+                    dataIndex: 'no'
+                  },
+                  {
+                    title: '描述',
+                    dataIndex: 'description'
+                  },
+                  {
+                    title: '服务调用次数',
+                    dataIndex: 'callNo',
+                    sorter: true,
+                    needTotal: true,
+                    customRender: (text) => text + ' 次'
+                  },
+                  {
+                    title: '状态',
+                    dataIndex: 'status',
+                    needTotal: true
+                  },
+                  {
+                    title: '更新时间',
+                    dataIndex: 'updatedAt',
+                    sorter: true
+                  }
+                ],
+                // 查询条件参数
+                queryParam: {},
+                // 加载数据方法 必须为 Promise 对象
+                loadData: parameter => {
+                  return this.$http.get('/service', {
+                    params: Object.assign(parameter, this.queryParam)
+                  }).then(res => {
+                    return res.result
+                  })
+                },
+            }
+    }
+</script>
+
+```
+
+
+
+例子2(简单的表格,最后一列是各种操作。):
+
+```vue
+<template>
+    <s-table
+      size="default"
+      :columns="columns"
+      :data="loadData"
+    >
+        <span slot="action" slot-scope="text, record">
+          <a>编辑</a>
+          <a-divider type="vertical" />
+          <a-dropdown>
+            <a class="ant-dropdown-link">
+              更多 <a-icon type="down" />
+            </a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a href="javascript:;">1st menu item</a>
+              </a-menu-item>
+              <a-menu-item>
+                <a href="javascript:;">2nd menu item</a>
+              </a-menu-item>
+              <a-menu-item>
+                <a href="javascript:;">3rd menu item</a>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+    </s-table>
+</template>
+
+<script>
+  	import STable from '@/components/table/'
+    export default {
+    	components: {
+    		STable
+    	},
+        data () {
+            return {
+                columns: [
+                    {
+                        title: '规则编号',
+                        dataIndex: 'no'
+                    },
+                    {
+                        title: '描述',
+                        dataIndex: 'description'
+                    },
+                    {
+                        title: '服务调用次数',
+                        dataIndex: 'callNo',
+                    },
+                    {
+                        title: '状态',
+                        dataIndex: 'status',
+                    },
+                    {
+                        title: '更新时间',
+                        dataIndex: 'updatedAt',
+                    },
+                    {
+						table: '操作',
+                        dataIndex: 'action',
+                        scopedSlots: { customRender: 'action' },
+                    }
+                ],
+                // 查询条件参数
+                queryParam: {},
+                // 加载数据方法 必须为 Promise 对象
+                loadData: parameter => {
+                  return this.$http.get('/service', {
+                    params: Object.assign(parameter, this.queryParam)
+                  }).then(res => {
+                    return res.result
+                  })
+                },
+            }
+    }
+</script>
+```
+
+
+
+
+
+### 注意事项:
+
+你可能需要为了与后端提供的接口返回结果一致而去修改以下代码:
+(需要注意的是,这里的修改是全局性的,意味着整个项目所有使用该 table 组件都需要遵守这个返回结果定义的字段。)
+`@/components/table/index.js`  第 89 行起
+
+
+
+```javascript
+result.then(r => {
+  this.localPagination = Object.assign({}, this.localPagination, {
+      current: r.pageNo, // 返回结果中的当前分页数
+      total: r.totalCount, // 返回结果中的总记录数
+      showSizeChanger: this.showSizeChanger,
+      pageSize: (pagination && pagination.pageSize) ||
+      this.localPagination.pageSize
+  });
+  this.localDataSource = r.data; // 返回结果中的数组数据
+})
+```
+返回 JSON 例子:
+```json
+{
+  "message": "",
+  "result": {
+    "data": [{
+        id: 1,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
+        title: 'Alipay',
+        description: '那是一种内在的东西, 他们到达不了,也无法触及的',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 2,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
+        title: 'Angular',
+        description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 3,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
+        title: 'Ant Design',
+        description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 4,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
+        title: 'Ant Design Pro',
+        description: '那时候我只会想自己想要什么,从不想自己拥有什么',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 5,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
+        title: 'Bootstrap',
+        description: '凛冬将至',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 6,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png',
+        title: 'Vue',
+        description: '生命就像一盒巧克力,结果往往出人意料',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      }
+    ],
+    "pageSize": 10,
+    "pageNo": 0,
+    "totalPage": 6,
+    "totalCount": 57
+  },
+  "status": 200,
+  "timestamp": 1534955098193
+}
+```
+
+
+
+最后更新于: 2018-08-30 AM

+ 253 - 0
src/components/table/StandardTable.vue

@@ -0,0 +1,253 @@
+<template>
+  <div class="standard-table">
+    <div class="alert">
+      <a-alert type="info" :show-icon="true">
+        <div slot="message">
+          已选择&nbsp;<a style="font-weight: 600">{{ selectedRows.length }}</a>&nbsp;&nbsp;
+          <template v-for="(item, index) in needTotalList" v-if="item.needTotal">
+            {{ item.title }} 总计&nbsp;
+            <a :key="index" style="font-weight: 600">
+              {{ item.customRender ? item.customRender(item.total) : item.total }}
+            </a>&nbsp;&nbsp;
+          </template>
+          <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+        </div>
+      </a-alert>
+    </div>
+    <a-table
+      :size="size"
+      :bordered="bordered"
+      :loading="loading"
+      :columns="columns"
+      :dataSource="current"
+      :rowKey="rowKey"
+      :pagination="pagination"
+      :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: updateSelect }"
+    >
+    </a-table>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "StandardTable",
+    // props: ['bordered', 'loading', 'columns', 'data', 'rowKey', 'pagination', 'selectedRows'],
+    props: {
+
+      /**
+       * 数据加载函数,返回值必须是 Promise
+       * 默认情况下必须传递 data 参数;
+       *    如果使用本地数据渲染表格,业务代码中将获取本地数据包装为 Promise 即可。
+       *
+       * currentData 用于向外暴露表格当前渲染的数据,
+       * 业务开发中也可以直接修改 currentData,从而重新渲染表格(仅推荐用于客户端排序、数据过滤等场景)
+       */
+      data: {
+        type: Function,
+        required: true
+      },
+      dataSource: {
+        type: Array,
+        default () {
+          return []
+        }
+      },
+      columns: {
+        type: Array,
+        required: true
+      },
+/*      pagination: {
+        type: Object,
+        default () {
+          return {}
+        }
+      },*/
+      pageSize: {
+        type: Number,
+        default: 10
+      },
+      pageNum: {
+        type: Number,
+        default: 1
+      },
+      pageSizeOptions: {
+        type: Array,
+        default () {
+          return ['10', '20', '30', '40', '50']
+        }
+      },
+      responseParamsName: {
+        type: Object,
+        default () {
+          return {}
+        }
+      },
+      bordered: {
+        type: Boolean,
+        default: false
+      },
+      /**
+       * 表格大小风格,default, middle, small
+       */
+      size: {
+        type: String,
+        default: 'default'
+      },
+      rowKey: {
+        type: String,
+        default: ''
+      },
+      selectedRows: {
+        type: Array,
+        default: null
+      }
+    },
+    data () {
+      return {
+        needTotalList: [],
+        selectedRowKeys: [],
+
+        loading: true,
+
+        total: 0,
+        pageNumber: this.pageNum,
+        currentPageSize: this.pageSize,
+        defaultCurrent: 1,
+        sortParams: {},
+
+        current: [],
+        pagination: {},
+        paramsName: {},
+      }
+    },
+    created () {
+      //数据请求参数配置
+      this.paramsName = Object.assign(
+        {},
+        {
+          pageNumber: "pageNo",
+          pageSize: "pageSize",
+          total: "totalCount",
+          results: "data",
+          sortColumns: "sortColumns"
+        },
+        this.responseParamsName
+      );
+
+      console.log(this.columns)
+      this.needTotalList = this.initTotalList(this.columns)
+
+      // load data
+      this.loadData( { pageNum: this.pageNumber } )
+    },
+    methods: {
+      updateSelect (selectedRowKeys, selectedRows) {
+        this.selectedRowKeys = selectedRowKeys
+        let list = this.needTotalList
+        this.needTotalList = list.map(item => {
+          return {
+            ...item,
+            total: selectedRows.reduce((sum, val) => {
+              return sum + val[item.dataIndex]
+            }, 0)
+          }
+        })
+        this.$emit('change', selectedRowKeys, selectedRows)
+      },
+      initTotalList (columns) {
+        const totalList = []
+        columns.forEach(column => {
+          if (column.needTotal) {
+            totalList.push({ ...column, total: 0 })
+          }
+        })
+        return totalList
+      },
+
+      loadData (params) {
+        let that = this
+        that.loading = true
+        params = Object.assign({}, params)
+        const remoteParams = Object.assign({}, that.sortParams)
+        remoteParams[that.paramsName.pageNumber] = params.pageNum || that.pageNumber
+        remoteParams[that.paramsName.pageSize] = params.pageSize || that.currentPageSize
+
+        if (params.pageNum) {
+          that.pageNumber = params.pageNum
+        }
+        if (params.pageSize) {
+          that.currentPageSize = params.pageSize
+        }
+
+        let dataPromise = that.data(remoteParams)
+
+        dataPromise.then( response => {
+          if (!response) {
+            that.loading = false
+            return
+          }
+          let results = response[that.paramsName.results]
+          results = (results instanceof Array && results) || []
+
+          that.current = results
+
+          that.$emit("update:currentData", that.current.slice())
+          that.$emit("dataloaded", that.current.slice())
+
+          that.total = response[that.paramsName.total] * 1
+          that.pagination = that.pager()
+          that.loading = false
+        }, () => {
+          // error callback
+          that.loading = false
+        })
+      },
+      // eslint-disable-next-line
+      onPagerChange (page, pageSize) {
+        this.pageNumber = page
+        this.loadData({ pageNum: page })
+      },
+      onPagerSizeChange (current, size) {
+        this.currentPageSize = size
+        /*
+        if (current === this.pageNumber) this.loadData()
+        console.log('page-size-change', current, size)
+        */
+      },
+      onClearSelected () {
+        this.selectedRowKeys = []
+        this.updateSelect([], [])
+      },
+      pager () {
+        return {
+          total: this.total,
+          showTotal: total => `共有 ${total} 条`,
+          showSizeChanger: true,
+          pageSizeOptions: this.pageSizeOptions,
+          pageSize: this.pageSize,
+          defaultCurrent: this.defaultCurrent,
+          onChange: this.onPagerChange,
+          onShowSizeChange: this.onPagerSizeChange
+        }
+      }
+    },
+    watch: {
+      'selectedRows': function (selectedRows) {
+        this.needTotalList = this.needTotalList.map(item => {
+          return {
+            ...item,
+            total: selectedRows.reduce( (sum, val) => {
+              return sum + val[item.dataIndex]
+            }, 0)
+          }
+        })
+      }
+    }
+  }
+</script>
+
+<style scoped>
+    .alert {
+        margin-bottom: 16px;
+    }
+</style>

+ 263 - 0
src/components/table/index.js

@@ -0,0 +1,263 @@
+import T from "ant-design-vue/es/table/Table";
+import get from "lodash.get"
+export default {
+  data() {
+    return {
+      needTotalList: [],
+
+      selectedRows: [],
+      selectedRowKeys: [],
+
+      localLoading: false,
+      localDataSource: [],
+      localPagination: Object.assign({}, T.props.pagination)
+    };
+  },
+  props: Object.assign({}, T.props, {
+    rowKey: {
+      type: String,
+      default: 'id'
+    },
+    data: {
+      type: Function,
+      required: true
+    },
+    pageNum: {
+      type: Number,
+      default: 1
+    },
+    pageSize: {
+      type: Number,
+      default: 10
+    },
+    showSizeChanger: {
+      type: Boolean,
+      default: true
+    },
+    showAlertInfo: {
+      type: Boolean,
+      default: false
+    },
+    showPagination: {
+      default: 'auto'
+    }
+  }),
+  watch: {
+    'localPagination.current'(val) {
+      this.$router.push({
+        name: this.$route.name,
+        params: Object.assign({}, this.$route.params, {
+          pageNo: val
+        }),
+      });
+    },
+    pageNum(val) {
+      Object.assign(this.localPagination, {
+        current: val
+      });
+    },
+    pageSize(val) {
+      console.log('pageSize:', val)
+      Object.assign(this.localPagination, {
+        pageSize: val
+      });
+    },
+    showSizeChanger(val) {
+      console.log('showSizeChanger', val)
+      Object.assign(this.localPagination, {
+        showSizeChanger: val
+      });
+    }
+  },
+  created() {
+    this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, {
+      current: this.pageNum,
+      pageSize: this.pageSize,
+      showSizeChanger: this.showSizeChanger
+    });
+    this.needTotalList = this.initTotalList(this.columns)
+    this.loadData();
+  },
+  methods: {
+    refresh() {
+      this.loadData();
+    },
+    loadData(pagination, filters, sorter) {
+      this.localLoading = true
+      var result = this.data(
+        Object.assign({
+            pageNo: (pagination && pagination.current) ||
+              this.localPagination.current,
+            pageSize: (pagination && pagination.pageSize) ||
+              this.localPagination.pageSize
+          },
+          (sorter && sorter.field && {
+            sortField: sorter.field
+          }) || {},
+          (sorter && sorter.order && {
+            sortOrder: sorter.order
+          }) || {}, {
+            ...filters
+          }
+        )
+      );
+
+      if (result instanceof Promise) {
+        result.then(r => {
+          this.localPagination = Object.assign({}, this.localPagination, {
+            current: r.pageNo,  // 返回结果中的当前分页数
+            total: r.totalCount, // 返回结果中的总记录数
+            showSizeChanger: this.showSizeChanger,
+            pageSize: (pagination && pagination.pageSize) ||
+              this.localPagination.pageSize
+          });
+
+          !r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
+          this.localDataSource = r.data; // 返回结果中的数组数据
+          this.localLoading = false
+        });
+      }
+    },
+    initTotalList(columns) {
+      const totalList = []
+      columns && columns instanceof Array && columns.forEach(column => {
+        if (column.needTotal) {
+          totalList.push({ ...column,
+            total: 0
+          })
+        }
+      })
+      return totalList
+    },
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys
+      this.selectedRows = selectedRows
+      let list = this.needTotalList
+      this.needTotalList = list.map(item => {
+        return {
+          ...item,
+          total: selectedRows.reduce((sum, val) => {
+            let total = sum + get(val, item.dataIndex)
+            return isNaN(total) ? 0 : total
+          }, 0)
+        }
+      })
+      // this.$emit('change', selectedRowKeys, selectedRows)
+    },
+    updateEdit() {
+      this.selectedRows = []
+    },
+    onClearSelected() {
+      this.selectedRowKeys = []
+      this.updateSelect([], [])
+    },
+    renderMsg(h) {
+      const _vm = this
+      let d = []
+      // 构建 已选择
+      d.push(
+        h('span', {
+          style: {
+            marginRight: '12px'
+          }
+        }, ['已选择 ', h('a', {
+          style: {
+            fontWeight: 600
+          }
+        }, this.selectedRows.length)])
+      );
+
+      // 构建 列统计
+      this.needTotalList.map(item => {
+        d.push(h('span', {
+            style: {
+              marginRight: '12px'
+            }
+          },
+          [
+            `${ item.title }总计 `,
+            h('a', {
+              style: {
+                fontWeight: 600
+              }
+            }, `${ !item.customRender ? item.total : item.customRender(item.total) }`)
+          ]))
+      });
+
+      // 构建 清空选择
+      d.push(h('a', {
+        style: {
+          marginLeft: '24px'
+        },
+        on: {
+          click: _vm.onClearSelected
+        }
+      }, '清空'))
+      return d
+    },
+    renderAlert(h) {
+      return h('span', {
+        slot: 'message'
+      }, this.renderMsg(h))
+    },
+  },
+
+  render(h) {
+    const _vm = this
+
+    let props = {},
+      localKeys = Object.keys(this.$data);
+
+    Object.keys(T.props).forEach(k => {
+      let localKey = `local${k.substring(0,1).toUpperCase()}${k.substring(1)}`;
+      if (localKeys.includes(localKey)) {
+        return props[k] = _vm[localKey];
+      }
+      return props[k] = _vm[k];
+    })
+
+
+    // 显示信息提示
+    // if (this.showAlertInfo) {
+
+    //   props.rowSelection = {
+    //     selectedRowKeys: this.selectedRowKeys,
+    //     onChange: (selectedRowKeys, selectedRows) => {
+    //       _vm.updateSelect(selectedRowKeys, selectedRows)
+    //       _vm.$emit('onSelect', { selectedRowKeys: selectedRowKeys, selectedRows: selectedRows })
+    //     }
+    //   };
+
+    //   return h('div', {}, [
+    //     h("a-alert", {
+    //       style: {
+    //         marginBottom: '16px'
+    //       },
+    //       props: {
+    //         type: 'info',
+    //         showIcon: true
+    //       }
+    //     }, [_vm.renderAlert(h)]),
+    //     h("a-table", {
+    //       tag: "component",
+    //       attrs: props,
+    //       on: {
+    //         change: _vm.loadData
+    //       },
+    //       scopedSlots: this.$scopedSlots
+    //     }, this.$slots.default)
+    //   ]);
+
+    // }
+
+    return h("a-table", {
+      tag: "component",
+      attrs: props,
+      on: {
+        change: _vm.loadData
+      },
+      scopedSlots: this.$scopedSlots
+    }, this.$slots.default);
+
+  }
+};

+ 46 - 0
src/components/tools/Breadcrumb.vue

@@ -0,0 +1,46 @@
+<template>
+  <a-breadcrumb class="breadcrumb">
+    <a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
+      <router-link v-if="item.name != name" :to="{ path: item.path }">
+        {{ item.meta.title }}
+      </router-link>
+      <span v-else>{{ item.meta.title }}</span>
+    </a-breadcrumb-item>
+  </a-breadcrumb>
+</template>
+
+<script>
+export default {
+    data() {
+      return {
+        name: '',
+        breadList: [],
+      }
+    },
+  created () {
+    this.getBreadcrumb()
+  },
+  methods: {
+    getBreadcrumb() {
+
+      this.breadList = []
+      this.breadList.push({ name: 'index', path: '/dashboard/', meta: { title: '首页' } })
+
+      this.name = this.$route.name
+      this.$route.matched.forEach((item) => {
+        // item.meta.name === 'dashboard' ? item.path = '/dashboard' : this.$route.path === item.path
+          this.breadList.push(item)
+      })
+    }
+  },
+  watch: {
+    $route() {
+      this.getBreadcrumb()
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 147 - 0
src/components/tools/DetailList.vue

@@ -0,0 +1,147 @@
+<template>
+  <div :class="['detail-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
+    <div v-if="title" class="title">{{ title }}</div>
+    <a-row>
+      <slot></slot>
+    </a-row>
+  </div>
+</template>
+
+<script>
+  import { Col } from 'ant-design-vue/es/grid/'
+
+  const Item = {
+    name: 'DetailListItem',
+    props: {
+      term: {
+        type: String,
+        default: '',
+        required: false
+      },
+    },
+    inject: {
+      col: {
+        type: Number
+      }
+    },
+    render () {
+      return (
+        <Col {...{props: responsive[this.col]}}>
+          <div class="term">{this.$props.term}</div>
+          <div class="content">{this.$slots.default}</div>
+        </Col>
+      )
+    }
+  }
+
+  const responsive = {
+    1: { xs: 24 },
+    2: { xs: 24, sm: 12 },
+    3: { xs: 24, sm: 12, md: 8 },
+    4: { xs: 24, sm: 12, md: 6 }
+  }
+
+  export default {
+    name: "DetailList",
+    Item: Item,
+    components: {
+      Col
+    },
+    props: {
+      title: {
+        type: String,
+        default: '',
+        required: false
+      },
+      col: {
+        type: Number,
+        required: false,
+        default: 3
+      },
+      size: {
+        type: String,
+        required: false,
+        default: 'large'
+      },
+      layout: {
+        type: String,
+        required: false,
+        default: 'horizontal'
+      }
+    },
+    provide () {
+      return {
+        col: this.col > 4 ? 4 : this.col
+      }
+    }
+  }
+</script>
+
+<style lang="scss">
+
+  .detail-list {
+
+    .title {
+      color: rgba(0,0,0,.85);
+      font-size: 14px;
+      font-weight: 500;
+      margin-bottom: 16px;
+    }
+
+    .term {
+      color: rgba(0,0,0,.85);
+      display: table-cell;
+      line-height: 20px;
+      margin-right: 8px;
+      padding-bottom: 16px;
+      white-space: nowrap;
+
+      &:after {
+        content: ":";
+        margin: 0 8px 0 2px;
+        position: relative;
+        top: -.5px;
+      }
+    }
+
+    .content {
+      color: rgba(0,0,0,.65);
+      display: table-cell;
+      line-height: 22px;
+      padding-bottom: 16px;
+      width: 100%;
+    }
+
+    &.small {
+
+      .title {
+        font-size: 14px;
+        color: rgba(0, 0, 0, .65);
+        font-weight: normal;
+        margin-bottom: 12px;
+      }
+      .term, .content {
+        padding-bottom: 8px;
+      }
+    }
+
+    &.large {
+      .term, .content {
+        padding-bottom: 16px;
+      }
+
+      .title {
+        font-size: 16px;
+      }
+    }
+
+    &.vertical {
+      .term {
+        padding-bottom: 8px;
+      }
+      .term, .content {
+        display: block;
+      }
+    }
+  }
+</style>

+ 32 - 0
src/components/tools/FooterToolBar.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="toolbar">
+    <div style="float: left">
+      <slot name="extra"></slot>
+    </div>
+    <div style="float: right">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "FooterToolBar"
+  }
+</script>
+
+<style lang="scss" scoped>
+  .toolbar {
+    position: fixed;
+    width: 100%;
+    bottom: 0;
+    right: 0;
+    height: 56px;
+    line-height: 56px;
+    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
+    background: #ccc;
+    border-top: 1px solid #e8e8e8;
+    padding: 0 24px;
+    z-index: 9;
+  }
+</style>

+ 67 - 0
src/components/tools/HeadInfo.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="head-info" :class="center && 'center'">
+    <span>{{ title }}</span>
+    <p>{{ content }}</p>
+    <em v-if="bordered"/>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "HeadInfo",
+    props: {
+      title: {
+        type: String,
+        default: ''
+      },
+      content: {
+        type: String,
+        default: ''
+      },
+      bordered: {
+        type: Boolean,
+        default: false
+      },
+      center: {
+        type: Boolean,
+        default: true
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .head-info {
+    position: relative;
+    text-align: left;
+    padding: 0 32px 0 0;
+    min-width: 125px;
+
+    &.center {
+      text-align: center;
+      padding: 0 32px;
+    }
+
+    span {
+      color: rgba(0, 0, 0, .45);
+      display: inline-block;
+      font-size: 14px;
+      line-height: 22px;
+      margin-bottom: 4px;
+    }
+    p {
+      color: rgba(0, 0, 0, .85);
+      font-size: 24px;
+      line-height: 32px;
+      margin: 0;
+    }
+    em {
+      background-color: #e8e8e8;
+      position: absolute;
+      height: 56px;
+      width: 1px;
+      top: 0;
+      right: 0;
+    }
+  }
+</style>

+ 46 - 0
src/main.js

@@ -0,0 +1,46 @@
+import Vue from 'vue'
+import App from './App.vue'
+import Storage from 'vue-ls'
+import router from './router/'
+import store from './store/'
+
+import { VueAxios } from "@/utils/request"
+
+import Antd from 'ant-design-vue'
+import Viser from 'viser-vue'
+import 'ant-design-vue/dist/antd.less';  // or 'ant-design-vue/dist/antd.less'
+
+import * as dayjs from 'dayjs' // 日期时间支持库
+
+import '@/permission' // permission control
+
+import { ACCESS_TOKEN, DEFAULT_THEME, SIDEBAR_TYPE } from "@/store/mutation-types"
+
+Vue.filter('dayjs', function(dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
+  return dayjs(dataStr).format(pattern)
+})
+
+const options = {
+  namespace: 'ant__', // key prefix
+  name: 'ls', // name variable Vue.[ls] or this.[$ls],
+  storage: 'local', // storage name session, local, memory
+}
+
+Vue.config.productionTip = false
+
+Vue.use(Storage, options)
+Vue.use(Antd)
+Vue.use(VueAxios, router)
+Vue.use(Viser)
+
+new Vue({
+  router,
+  store,
+  mounted () {
+    store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, true))
+    store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, 'dark'))
+    store.commit('SET_ACCESSTOKEN', Vue.ls.get(ACCESS_TOKEN))
+
+  },
+  render: h => h(App)
+}).$mount('#app')

+ 65 - 0
src/permission.js

@@ -0,0 +1,65 @@
+import Vue from 'vue'
+import router from './router'
+import store from './store'
+
+import NProgress from 'nprogress' // progress bar
+import 'nprogress/nprogress.css' // progress bar style
+import {
+  ACCESS_TOKEN
+} from "@/store/mutation-types"
+
+NProgress.configure({
+  showSpinner: false
+}) // NProgress Configuration
+
+const whiteList = ['/login', '/exception/403', '/exception/404', '/exception/500'] // no redirect whitelist
+
+router.beforeEach((to, from, next) => {
+  NProgress.start()
+  if (Vue.ls.get(ACCESS_TOKEN)) {
+    /* has token */
+    if (to.path === '/login') {
+      next({
+        name: 'appManagement'
+      })
+      NProgress.done()
+    } else {
+      //先判断store中是否存在路由菜单列表
+      if (store.getters.addRouters.length === 0) {
+        store.dispatch('GetUserInfo').then(data => {
+          store.dispatch('GetUserMenuList').then(res => {
+            store.dispatch('GenerateMenuList', {
+              res
+            }).then(() => { // 根据roles权限生成可访问的路由表
+              router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
+              next({
+                ...to,
+                replace: true
+              }) // hack方法 确保addRoutes已完成
+            })
+          })
+        }).catch(() => {
+          store.dispatch('Logout').then(() => {
+            next({
+              path: '/login'
+            })
+          })
+        })
+      } else {
+        next()
+      }
+    }
+  } else {
+    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
+      next()
+    } else {
+      next('/login')
+      NProgress.done()
+    }
+  }
+
+})
+
+router.afterEach(() => {
+  NProgress.done()
+})

+ 1 - 0
src/router/_import_development.js

@@ -0,0 +1 @@
+module.exports = file => require('@/views/' + file + '.vue').default

+ 1 - 0
src/router/_import_production.js

@@ -0,0 +1 @@
+module.exports = file => () => import('@/views/' + file + '.vue')

+ 100 - 0
src/router/index.js

@@ -0,0 +1,100 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import Layout from '../components/layout/LayoutView'
+import LayoutBase from '../components/layout/LayoutBaseView'
+import RouteView from '../components/layout/RouteView'
+
+Vue.use(Router)
+/**
+ * 路由配置说明:
+ * 建议:sider menu 请不要超过三级菜单,若超过三级菜单,则应该设计为顶部主菜单 配合左侧次级菜单
+ *
+ * hidden: true                   if `hidden:true` will not show in the sidebar(default is false)
+ * alwaysShow: true               if set true, will always show the root menu, whatever its child routes length
+ *                                if not set alwaysShow, only more than one route under the children
+ *                                it will becomes nested mode, otherwise not show the root menu
+ * redirect: noredirect           if `redirect:noredirect` will no redirct in the breadcrumb
+ * name:'router-name'             the name is used by <keep-alive> (must set!!!)
+ * meta : {
+    title: 'title'               the name show in submenu and breadcrumb (recommend set)
+    icon: 'svg-name'             the icon show in the sidebar,
+    keepAlive: true              keep alive component
+    hiddenPageHeader: true       if `hiddenPageHeader: true` will not show page-header(details)
+  }
+ **/
+export const constantRouterMap = [
+  {
+    path: '/',
+    component: Layout,
+    redirect: '/login',
+    name: '首页',
+    hidden: true
+  },
+  {
+    path: '/login',
+    component: () => import('../views/Login')
+  },
+  {
+    path: '/exception',
+    name: 'exception',
+    component: RouteView,
+    redirect: '/exception/403',
+    meta: { title: '异常页', icon: 'warning', permission: ['exception'] },
+    children: [
+      {
+        path: '/exception/403',
+        name: 'Exception403',
+        component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/403'),
+        meta: { title: '403', permission: ['exception'] }
+      },
+      {
+        path: '/exception/404',
+        name: 'Exception404',
+        component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/404'),
+        meta: { title: '404', permission: ['exception'] }
+      },
+      {
+        path: '/exception/500',
+        name: 'Exception500',
+        component: () => import(/* webpackChunkName: "fail" */ '@/views/exception/500'),
+        meta: { title: '500', permission: ['exception'] }
+      }
+    ]
+  },
+  {
+    path: '/profile',
+    name: 'profile',
+    component: LayoutBase,
+    redirect: '/profile/profileInfo',
+    meta: { title: '个人中心', icon: 'global', permission: ['profile'] },
+    children: [{
+      path: '/profile/profileInfo',
+      name: 'profileInfo',
+      redirect: '/profile/profileBase',
+      meta: { title: '用户资料', icon: 'global', permission: ['profileInfo'] },
+      component: () => import(/* webpackChunkName: "fail" */ '../views/profile/profileInfo'),
+      children: [{
+        path: '/profile/profileBase',
+        name: 'profileBase',
+        component: () => import(/* webpackChunkName: "fail" */ '../views/profile/profileBase'),
+        meta: { title: '基本信息', icon: 'global', permission: ['profileInfo'] },
+      }, {
+        path: '/profile/modifyPassword',
+        name: 'modifyPassword',
+        component: () => import(/* webpackChunkName: "fail" */ '../views/profile/modifyPassword'),
+        meta: { title: '安全设置', icon: 'global', permission: ['profileInfo'] },
+      }]
+    }],
+  }
+]
+
+export default new Router({
+  mode: 'history',
+  base: process.env.BASE_URL,
+  scrollBehavior: () => ({
+    y: 0
+  }),
+  routes: constantRouterMap
+})
+
+export const asyncRouterMap = []

+ 13 - 0
src/store/getters.js

@@ -0,0 +1,13 @@
+const getters = {
+  device: state => state.app.device,
+  theme: state => state.app.theme,
+  token: state => state.user.token,
+  avatar: state => state.user.avatar,
+  nickname: state => state.user.name,
+  welcome: state => state.user.welcome,
+  roles: state => state.user.roles,
+  userInfo: state => state.user.info,
+  addRouters: state => state.permission.addRouters
+}
+
+export default getters

+ 27 - 0
src/store/index.js

@@ -0,0 +1,27 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+import app from './modules/app'
+import user from './modules/user'
+import permission from './modules/permission'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+  modules: {
+    app,
+    user,
+    permission
+  },
+  state: {
+
+  },
+  mutations: {
+
+  },
+  actions: {
+
+  },
+  getters
+})

+ 48 - 0
src/store/modules/app.js

@@ -0,0 +1,48 @@
+import Vue from 'vue'
+import { SIDEBAR_TYPE, DEFAULT_THEME } from "@/store/mutation-types"
+
+const app = {
+  state: {
+    sidebar: {
+      opened: true,
+      withoutAnimation: false
+    },
+    device: 'desktop',
+    theme: ''
+  },
+  mutations: {
+    SET_SIDEBAR_TYPE: (state, type) => {
+      state.sidebar.opened = type
+      Vue.ls.set(SIDEBAR_TYPE, type)
+    },
+    CLOSE_SIDEBAR: (state, withoutAnimation) => {
+      Vue.ls.set(SIDEBAR_TYPE, true)
+      state.sidebar.opened = false
+      state.sidebar.withoutAnimation = withoutAnimation
+    },
+    TOGGLE_DEVICE: (state, device) => {
+      state.device = device
+    },
+    TOGGLE_THEME: (state, theme) => {
+      // setStore('_DEFAULT_THEME', theme)
+      Vue.ls.set(DEFAULT_THEME, theme)
+      state.theme = theme
+    }
+  },
+  actions: {
+    setSidebar: ({ commit }, type) => {
+      commit('SET_SIDEBAR_TYPE', type)
+    },
+    CloseSidebar({ commit }, { withoutAnimation }) {
+      commit('CLOSE_SIDEBAR', withoutAnimation)
+    },
+    ToggleDevice({ commit }, device) {
+      commit('TOGGLE_DEVICE', device)
+    },
+    ToggleTheme({ commit }, theme) {
+      commit('TOGGLE_THEME', theme)
+    }
+  }
+}
+
+export default app

+ 192 - 0
src/store/modules/permission.js

@@ -0,0 +1,192 @@
+import {
+  constantRouterMap
+} from "@/router"
+// import importFile from '@/router/file'
+import Layout from '@/components/layout/LayoutView'
+import LayoutBase from '@/components/layout/LayoutBaseView'
+import RouteView from '@/components/layout/RouteView'
+const _import = require('@/router/_import_' + process.env.NODE_ENV) //获取组件的方法
+// console.log(importFile)
+
+function filterAsyncRouter(asyncRouterList) {
+  const asyncRouterMap = setAsyncRouters(asyncRouterList)
+  for (let i in asyncRouterMap) {
+    let children = asyncRouterMap[i].children
+    if (asyncRouterMap[i].component) {
+      if (asyncRouterMap[i].component === 'Layout') { //Layout组件特殊处理
+        asyncRouterMap[i].component = Layout
+      } else if (asyncRouterMap[i].component === 'LayoutBase') { //Layout组件特殊处理
+        asyncRouterMap[i].component = LayoutBase
+      } else if (asyncRouterMap[i].component === 'RouteView') { //Layout组件特殊处理
+        asyncRouterMap[i].component = RouteView
+      } else {
+        asyncRouterMap[i].component = _import(asyncRouterMap[i].component)
+      }
+    }
+    for (const j in children) {
+      if (children[j].component) {
+        if (children[j].component === 'Layout') { //Layout组件特殊处理
+          children[j].component = Layout
+        } else if (children[j].component === 'LayoutBase') { //Layout组件特殊处理
+          children[j].component = LayoutBase
+        } else if (children[j].component === 'RouteView') { //Layout组件特殊处理
+          children[j].component = RouteView
+        } else {
+          children[j].component = _import(children[j].component)
+        }
+      }
+    }
+  }
+
+  console.log(asyncRouterMap)
+  return asyncRouterMap
+}
+
+//构建菜单树
+function toTree(data) {
+  // 删除 所有 children,以防止多次调用
+  data.forEach(function (item) {
+    delete item.children;
+  });
+
+  // 将数据存储为 以 id 为 KEY 的 map 索引数据列
+  var map = {};
+  data.forEach(function (item) {
+    map[item.id] = item;
+  });
+  //console.log(map);
+  var val = [];
+  data.forEach(function (item) {
+    // 以当前遍历项,的pid,去map对象中找到索引的id
+    var parent = map[item.parentMenuId];
+    // 好绕啊,如果找到索引,那么说明此项不在顶级当中,那么需要把此项添加到,他对应的父级中
+    if (parent) {
+      (parent.children || (parent.children = [])).push(item);
+    } else {
+      //如果没有在map中找到对应的索引ID,那么直接把 当前的item添加到 val结果集中,作为顶级
+      val.push(item);
+    }
+  });
+  return val;
+}
+
+
+function setAsyncRouters(asyncRouterList) {
+  //const menuMap = toTree(asyncRouterList.res)
+  const menuMap = asyncRouterList
+  for (let i in menuMap) {
+    let category = menuMap[i].children
+    menuMap[i].path = `${menuMap[i].menuPath}`
+    menuMap[i].name = menuMap[i].menuCode
+    if (menuMap[i].menuContextPath) {
+      menuMap[i].redirect = menuMap[i].menuContextPath
+    }
+    if (menuMap[i].menuRemark) {
+      menuMap[i].component = menuMap[i].menuRemark
+    }
+    menuMap[i].meta = {
+      title: menuMap[i].menuName,
+      icon: menuMap[i].menuIcon,
+      permission: [menuMap[i].menuPerms],
+    }
+    for (let j in category) {
+      delete category[j].children
+      category[j].path = `${category[j].menuPath}`
+      category[j].name = category[j].menuCode
+      if (category[j].menuContextPath) {
+        category[j].redirect = category[j].menuContextPath
+      }
+      if (category[j].menuRemark) {
+        category[j].component = category[j].menuRemark
+      }
+      category[j].meta = {
+        title: category[j].menuName,
+        icon: category[j].menuIcon,
+        permission: [category[j].menuPerms],
+      }
+    }
+  }
+  for (let i in menuMap) {
+    delete menuMap[i].id
+    delete menuMap[i].addDataTime
+    delete menuMap[i].appId
+    delete menuMap[i].menuCode
+    delete menuMap[i].menuContextPath
+    delete menuMap[i].menuIcon
+    delete menuMap[i].menuName
+    delete menuMap[i].menuPath
+    delete menuMap[i].menuPerms
+    delete menuMap[i].menuRemark
+    delete menuMap[i].menuShowType
+    delete menuMap[i].menuStatus
+    delete menuMap[i].menuType
+    delete menuMap[i].modifyDataTime
+    delete menuMap[i].open
+    delete menuMap[i].parentMenuId
+    delete menuMap[i].parentMenuName
+    delete menuMap[i].sortNo
+    delete menuMap[i].subMenuList
+
+    let category = menuMap[i].children
+    for (let j in category) {
+      delete category[j].id
+      delete category[j].addDataTime
+      delete category[j].appId
+      delete category[j].menuCode
+      delete category[j].menuContextPath
+      delete category[j].menuIcon
+      delete category[j].menuName
+      delete category[j].menuPath
+      delete category[j].menuPerms
+      delete category[j].menuRemark
+      delete category[j].menuShowType
+      delete category[j].menuStatus
+      delete category[j].menuType
+      delete category[j].modifyDataTime
+      delete category[j].open
+      delete category[j].parentMenuId
+      delete category[j].parentMenuName
+      delete category[j].sortNo
+      delete category[j].subMenuList
+    }
+  }
+  return menuMap
+}
+
+const permission = {
+  state: {
+    routers: constantRouterMap,
+    addRouters: []
+  },
+  mutations: {
+    SET_ROUTERS: (state, routers) => {
+      state.addRouters = routers
+      state.routers = constantRouterMap.concat(routers)
+    }
+  },
+  actions: {
+    GenerateMenuList({
+      commit
+    }, res) {
+      return new Promise((resolve, reject) => {
+        let data = res.res
+        console.log(data)
+        if (data.code === 0) {
+          if (data.menuList.length > 0) {
+            const menuList = data.menuList
+            let accessedRouters = filterAsyncRouter(menuList)
+            commit('SET_ROUTERS', accessedRouters)
+            resolve()
+          }
+        } else {
+          this.$message.warning('还未给该用户添加菜单权限相关!');
+          reject()
+        }
+
+      })
+
+    }
+  }
+}
+
+export default permission

+ 92 - 0
src/store/modules/user.js

@@ -0,0 +1,92 @@
+import Vue from 'vue'
+import {
+  login,
+  getUserInfo,
+  getUserMenuList
+} from "@/api/login"
+import {
+  ACCESS_TOKEN
+} from "@/store/mutation-types"
+import avatar from '@/assets/logo.png'
+
+const user = {
+  state: {
+    token: '',
+    name: '',
+    welcome: '',
+    avatar: '',
+    roles: [],
+    info: {},
+  },
+
+  mutations: {
+    SET_ACCESSTOKEN: (state, accessToken) => {
+      state.accessToken = accessToken
+    },
+    SET_USER: (state, user) => {
+      state.name = user.userRealname
+      state.avatar = user.userAvatar || avatar
+      state.info = user
+    },
+  },
+
+  actions: {
+    // 登录
+    Login({
+      commit
+    }, userInfo) {
+      return new Promise((resolve, reject) => {
+        login(userInfo).then(response => {
+          if (response.code === 0) {
+            const accessToken = response.access_token
+            Vue.ls.set(ACCESS_TOKEN, accessToken, 7 * 24 * 60 * 60 * 1000)
+            commit('SET_ACCESSTOKEN', accessToken)
+            resolve(response)
+          } else {
+            reject(response)
+          }
+        })
+      })
+    },
+
+    GetUserMenuList() {
+      return new Promise((resolve, reject) => {
+        getUserMenuList().then(response => {
+          resolve(response)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    GetUserInfo({
+      commit
+    }) {
+      return new Promise((resolve, reject) => {
+        getUserInfo().then(response => {
+          if (response.code === 0) {
+            commit('SET_USER', response.user)
+            resolve(response)
+          }
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 登出
+    Logout({
+      commit
+    }) {
+      return new Promise((resolve) => {
+        commit('SET_ACCESSTOKEN', '')
+        commit('SET_USER', '')
+        Vue.ls.remove(ACCESS_TOKEN)
+        resolve()
+      })
+    },
+
+  }
+}
+
+export default user

+ 3 - 0
src/store/mutation-types.js

@@ -0,0 +1,3 @@
+export const ACCESS_TOKEN = 'Access_Token'
+export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
+export const DEFAULT_THEME = 'DEFAULT_THEME'

+ 19 - 0
src/utils/auth.js

@@ -0,0 +1,19 @@
+/**
+ * 弃用
+ */
+import { setStore, getStore, clearStore } from "@/utils/storage"
+
+export const TokenKey = 'Access_Token'
+
+export function getToken() {
+  return getStore(TokenKey)
+}
+
+export function setToken(token) {
+  // key, token, timeout = 86400s
+  return setStore(TokenKey, token, 86400)
+}
+
+export function removeToken() {
+  return clearStore(TokenKey)
+}

+ 37 - 0
src/utils/axios.js

@@ -0,0 +1,37 @@
+const VueAxios = {
+    vm: {},
+    // eslint-disable-next-line no-unused-vars
+    install(Vue, router = {}, instance) {
+        if (this.installed) {
+            return;
+        }
+        this.installed = true;
+
+        if (!instance) {
+            // eslint-disable-next-line no-console
+            console.error('You have to install axios');
+            return;
+        }
+
+        Vue.axios = instance;
+
+        Object.defineProperties(Vue.prototype, {
+            axios: {
+                get: function get() {
+                    return instance;
+                }
+            },
+            $http: {
+                get: function get() {
+                    return instance;
+                }
+            }
+        });
+    }
+};
+
+export {
+    VueAxios,
+    // eslint-disable-next-line no-undef
+   // instance as axios
+}

+ 23 - 0
src/utils/device.js

@@ -0,0 +1,23 @@
+import enquireJs from 'enquire.js'
+
+const enquireScreen = function (call) {
+  // tablet
+  const handler = {
+    match: function () {
+      call && call(0)
+    },
+    unmatch: function () {
+      call && call(-1)
+    }
+  }
+  // mobile
+  const handler2 = {
+    match: () => {
+      call && call(1)
+    }
+  }
+  enquireJs.register('screen and (max-width: 980.99px)', handler)
+  enquireJs.register('screen and (max-width: 767.99px)', handler2)
+}
+
+export default enquireScreen

+ 105 - 0
src/utils/request.js

@@ -0,0 +1,105 @@
+import Vue from 'vue'
+import axios from 'axios'
+import router from '../router/'
+import store from '../store'
+import {
+  VueAxios
+} from './axios'
+import notification from 'ant-design-vue/es/notification'
+import {
+  ACCESS_TOKEN
+} from "@/store/mutation-types"
+import {
+  BASEURL
+} from '@/api/public'
+
+
+// 创建 axios 实例
+const service = axios.create({
+  baseURL: BASEURL + '',
+  timeout: 5000 // 请求超时时间
+})
+
+const err = (error) => {
+  console.log(error)
+  if (error.response) {
+    if (error.status === 403) {
+      notification.error({
+        message: '拒绝访问',
+        description: '无权限,拒绝访问'
+      })
+    }
+    if (error.status === 401) {
+      notification.error({
+        message: '未授权',
+        description: '授权验证失败'
+      })
+      setTimeout(() => {
+        location.reload()
+      })
+    }
+  }
+  return Promise.reject(error)
+};
+
+// request 拦截器
+service.interceptors.request.use(config => {
+  const token = Vue.ls.get(ACCESS_TOKEN)
+  if (token) {
+    config.headers['token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
+  }
+  config.headers['Content-Type'] = 'application/json;charset=UTF-8'
+  return config
+}, err)
+
+// response 拦截器
+service.interceptors.response.use((response) => {
+  if (response.data.code == 401) {
+    Vue.ls.remove(ACCESS_TOKEN)
+    notification.error({
+      message: '登陆超时',
+      description: '请重新登录'
+    })
+    setTimeout(() => {
+      location.reload()
+    }, 1e3)
+  }
+  if (response.data.code === 403) {
+    notification.error({
+      message: '拒绝访问',
+      description: '无权限,拒绝访问'
+    })
+  }
+  return response.data
+}, err => {
+  try {
+    if (err.response) {
+      switch (err.response.code) {
+        case 401:
+          var baseUrl = window.location.href;
+          router.replace({
+            path: '/login',
+            query: {
+              backUrl: baseUrl
+            }
+          });
+          return;
+      }
+    }
+    return Promise.reject(err.response.data)
+  } catch (e) {
+    console.log(e)
+  }
+})
+
+const installer = {
+  vm: {},
+  install(Vue, router = {}) {
+    Vue.use(VueAxios, router, service)
+  }
+}
+
+export {
+  installer as VueAxios,
+  service as axios
+}

+ 78 - 0
src/utils/storage.js

@@ -0,0 +1,78 @@
+/**
+ * Set storage
+ *
+ * @param name
+ * @param content
+ * @param maxAge
+ */
+export const setStore = (name, content, maxAge = null) => {
+  if (!global.window || !name) {
+    return;
+  }
+
+  if (typeof content !== 'string') {
+    content = JSON.stringify(content)
+  }
+
+  let storage = global.window.localStorage
+
+  storage.setItem(name, content)
+  if (maxAge && !isNaN(parseInt(maxAge))) {
+    let timeout = parseInt(new Date().getTime() / 1000)
+    storage.setItem(`${name}_expire`, timeout + maxAge)
+  }
+};
+
+/**
+ * Get storage
+ *
+ * @param name
+ * @returns {*}
+ */
+export const getStore = name => {
+  if (!global.window || !name) {
+    return;
+  }
+
+  let content = window.localStorage.getItem(name)
+  let _expire = window.localStorage.getItem(`${name}_expire`)
+
+  if (_expire) {
+    let now = parseInt(new Date().getTime() / 1000)
+    if (now > _expire) {
+      return;
+    }
+  }
+
+  try {
+    return JSON.parse(content)
+  } catch (e) {
+    return content
+  }
+};
+
+/**
+ * Clear storage
+ *
+ * @param name
+ */
+export const clearStore = name => {
+  if (!global.window || !name) {
+    return;
+  }
+
+  window.localStorage.removeItem(name)
+  window.localStorage.removeItem(`${name}_expire`)
+};
+
+/**
+ * Clear all storage
+ */
+export const clearAll = () => {
+  if (!global.window || !name) {
+    return;
+  }
+
+  window.localStorage.clear()
+}
+

+ 76 - 0
src/utils/util.js

@@ -0,0 +1,76 @@
+
+export function timeFix() {
+  const time = new Date()
+  const hour = time.getHours()
+  return hour < 9 ? '早上好' : (hour <= 11 ? '上午好' : (hour <= 13 ? '中午好' : (hour < 20 ? '下午好' : '晚上好')))
+}
+
+export function welcome() {
+  const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 DOTA', '我猜你可能累了']
+  let index = Math.floor((Math.random() * arr.length))
+  return arr[index]
+}
+
+export const formatePhone = (value) => {
+  if (typeof (value) == "string") {
+    return value.substr(0, 3) + '*****' + value.substr(8);
+  } else {
+    return
+  }
+};
+
+export const formateEmail = (value) => {
+  if (value) {
+    let number = value.indexOf("@")
+    value = '*****' + value.substr(number)
+  } else {
+    value = '*****@**.com'
+  }
+  return value
+};
+
+export const compareTime = (startTime, endTime) => {
+  var startTimes = startTime.substring(0, 10).split('-');
+  var endTimes = endTime.substring(0, 10).split('-');
+  startTime = startTimes[1] + '-' + startTimes[2] + '-' + startTimes[0] + ' ' + startTime.substring(10, 19);
+  endTime = endTimes[1] + '-' + endTimes[2] + '-' + endTimes[0] + ' ' + endTime.substring(10, 19);
+  var thisResult = (Date.parse(endTime) - Date.parse(startTime)) / 3600 / 1000;
+  return thisResult;
+}
+//构建菜单树
+
+export const toTree = (data) => {
+  // 删除 所有 children,以防止多次调用
+  data.forEach(function (item) {
+    delete item.children;
+  });
+
+  // 将数据存储为 以 id 为 KEY 的 map 索引数据列
+  var map = {};
+  data.forEach(function (item, index) {
+    map[item.id] = item;
+    map[item.id].key = item.id;
+    map[item.id].value = item.id;
+    map[item.id].title = item.menuName;
+  });
+  // console.log(map);
+  var val = [];
+  data.forEach(function (item) {
+    // 以当前遍历项,的pid,去map对象中找到索引的id
+    var parent = map[item.parentMenuId];
+    // 好绕啊,如果找到索引,那么说明此项不在顶级当中,那么需要把此项添加到,他对应的父级中
+    if (parent) {
+      (parent.children || (parent.children = [])).push(item);
+    } else {
+      //如果没有在map中找到对应的索引ID,那么直接把 当前的item添加到 val结果集中,作为顶级
+      val.push(item);
+    }
+  });
+  return val;
+}
+
+// 手机号隐藏中间四位
+export const mobileToStar = (mobile) => {
+  var str = mobile.substring(0, 3) + "****" + mobile.substring(7, 11);
+  return str;
+}

+ 18 - 0
src/views/Home.vue

@@ -0,0 +1,18 @@
+<template>
+  <div class="home">
+    <img alt="Vue logo" src="../../public/logo.png">
+    <HelloWorld msg="Welcome to Your Vue.js App"/>
+  </div>
+</template>
+
+<script>
+// @ is an alias to /src
+import HelloWorld from '@/components/HelloWorld.vue'
+
+export default {
+  name: 'Home',
+  components: {
+    HelloWorld
+  }
+}
+</script>

+ 341 - 0
src/views/Login.vue

@@ -0,0 +1,341 @@
+<template>
+  <div id="auth">
+    <div class="container">
+      <div class="top">
+        <div class="header">
+          <a href="/">
+            <img src="~@/assets/logo.png" class="logo" alt="logo" />
+            <span class="title">SpeedLight支撑平台</span>
+          </a>
+        </div>
+        <div class="desc">专注,创新,是我们的竞争法则;
+          <br>协作,共赢,是我们的生存之道。
+        </div>
+      </div>
+      <div class="main">
+        <a-form ref="formLogin" :autoFormCreate="(form)=>{this.form = form}" id="formLogin">
+          <a-form-item fieldDecoratorId="username" :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入登录账号' }, { validator: this.handleUsernameOrEmail }], initialValue:formLogin.username, validateTrigger: 'blur'}">
+            <a-input size="large" type="text" v-model="formLogin.username" placeholder="请输入登录账号">
+              <a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }" />
+            </a-input>
+          </a-form-item>
+
+          <a-form-item fieldDecoratorId="password" :fieldDecoratorOptions="{rules: [{ required: true, message: '请输入密码' }], initialValue:formLogin.password, validateTrigger: 'blur'}">
+            <a-input size="large" type="password" v-model="formLogin.password" placeholder="请输入密码">
+              <a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }" />
+            </a-input>
+          </a-form-item>
+
+          <a-form-item>
+            <a-checkbox v-model="formLogin.rememberMe">记住账号</a-checkbox>
+          </a-form-item>
+
+          <a-form-item style="margin-top:24px">
+            <a-button size="large" type="primary" htmlType="submit" class="login-button" :loading="loginBtn" @click.stop.prevent="handleSubmit" :disabled="loginBtn">确定</a-button>
+          </a-form-item>
+        </a-form>
+      </div>
+      <div class="footer">
+        <div class="copyright">Copyright &copy; 2018 SpeedLight</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import md5 from "md5";
+import api from "../api/";
+import { mapActions } from "vuex";
+
+import { timeFix } from "../utils/util";
+
+export default {
+  data() {
+    return {
+      customActiveKey: "tab1",
+      loginBtn: false,
+      // login type: 0 email, 1 username, 2 telephone
+      loginType: 0,
+      form: null,
+      state: {
+        time: 60,
+        smsSendBtn: false
+      },
+      formLogin: {
+        username: "",
+        password: "",
+        captcha: "",
+        mobile: "",
+        rememberMe: true
+      }
+    };
+  },
+  methods: {
+    ...mapActions(["Login"]),
+    // handler
+    handleUsernameOrEmail(rule, value, callback) {
+      const regex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/;
+      if (regex.test(value)) {
+        this.loginType = 0;
+      } else {
+        this.loginType = 1;
+      }
+      callback();
+    },
+    onchangeUsername(e) {
+      console.log(this.formLogin.username);
+    },
+    handleTabClick(key) {
+      this.customActiveKey = key;
+      // this.systems.resetFields()
+    },
+    handleSubmit() {
+      let that = this;
+      let flag = false;
+
+      if (that.customActiveKey === "tab1") {
+        that.form.validateFields(
+          ["username", "password"],
+          { force: true },
+          err => {
+            if (!err) {
+              flag = true;
+            }
+          }
+        );
+      } else {
+        that.form.validateFields(
+          ["mobile", "captcha"],
+          { force: true },
+          err => {
+            if (!err) {
+              flag = true;
+              that.loginType = 2; // 登录类型修改为手机登录
+            }
+          }
+        );
+      }
+
+      if (!flag) return;
+
+      that.loginBtn = true;
+
+      let loginParams = {
+        userSecret: md5(that.formLogin.password)
+        // remember_me: that.formLogin.rememberMe
+      };
+
+      switch (that.loginType) {
+        case 0:
+          loginParams.email = that.formLogin.username;
+          break;
+        case 1:
+          loginParams.userNumber = that.formLogin.username;
+          break;
+        case 2:
+        default:
+          loginParams.mobile = that.formLogin.mobile;
+          loginParams.captcha = that.formLogin.captcha;
+          break;
+      }
+
+      that
+        .Login(loginParams)
+        .then(res => {
+          this.rememberMe();
+          that.loginBtn = false;
+          that.$router.push({ name: "appManagement" });
+          that.$message.success(timeFix() + ",欢迎回来", 3);
+        })
+        .catch(err => {
+          that.$notification.error({
+            message: "错误",
+            description: err.msg,
+            duration: 4
+          });
+          that.loginBtn = false;
+        });
+    },
+    getCaptcha(e) {
+      e.preventDefault();
+      let that = this;
+
+      this.form.validateFields(["mobile"], { force: true }, err => {
+        if (!err) {
+          this.state.smsSendBtn = true;
+
+          let interval = window.setInterval(() => {
+            if (that.state.time-- <= 0) {
+              that.state.time = 60;
+              that.state.smsSendBtn = false;
+              window.clearInterval(interval);
+            }
+          }, 1000);
+
+          const hide = this.$message.loading("验证码发送中..", 0);
+          this.$http
+            .post(api.SendSms, { mobile: that.formLogin.mobile })
+            .then(res => {
+              setTimeout(hide, 2500);
+              this.$notification["success"]({
+                message: "提示",
+                description:
+                  "验证码获取成功,您的验证码为:" + res.result.captcha,
+                duration: 8
+              });
+            })
+            .catch(err => {
+              setTimeout(hide, 1);
+              clearInterval(interval);
+              that.state.time = 60;
+              that.state.smsSendBtn = false;
+              this.requestFailed(err);
+            });
+        }
+      });
+    },
+    requestFailed(err) {
+      this.$notification["error"]({
+        message: "错误",
+        description:
+          ((err.response || {}).data || {}).message ||
+          "用户名或密码错误,请重新输入",
+        duration: 4
+      });
+      this.loginBtn = false;
+    },
+
+    getUserPass() {
+      this.formLogin.username = localStorage.getItem("sl_username") || "";
+    },
+
+    //记住账号
+    rememberMe() {
+      if (this.formLogin.rememberMe) {
+        localStorage.setItem("sl_username", this.formLogin.username);
+      } else {
+        localStorage.setItem("sl_username", "");
+      }
+    }
+  },
+  mounted() {
+    this.getUserPass();
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+#auth {
+  height: 100%;
+
+  .container {
+    width: 100%;
+    min-height: 100%;
+    background: #f0f2f5 url(~@/assets/background.svg) no-repeat 50%;
+    background-size: 100%;
+    padding: 110px 0 144px;
+    position: relative;
+
+    a {
+      text-decoration: none;
+    }
+
+    .top {
+      text-align: center;
+
+      .header {
+        height: 44px;
+        line-height: 44px;
+
+        .badge {
+          position: absolute;
+          display: inline-block;
+          line-height: 1;
+          vertical-align: middle;
+          margin-left: -12px;
+          margin-top: -10px;
+          opacity: 0.8;
+        }
+
+        .logo {
+          height: 44px;
+          vertical-align: top;
+          margin-right: 16px;
+          border-style: none;
+        }
+
+        .title {
+          font-size: 33px;
+          color: rgba(0, 0, 0, 0.85);
+          font-family: "Myriad Pro", "Helvetica Neue", Arial, Helvetica,
+            sans-serif;
+          font-weight: 600;
+          position: relative;
+          top: 2px;
+        }
+      }
+      .desc {
+        font-size: 14px;
+        color: rgba(0, 0, 0, 0.45);
+        margin-top: 12px;
+        margin-bottom: 40px;
+      }
+    }
+
+    .main {
+      width: 368px;
+      margin: 0 auto;
+
+      label {
+        font-size: 14px;
+      }
+
+      .ivu-input-prefix {
+        left: 12px;
+        font-size: 14px;
+        color: rgba(0, 0, 0, 0.25);
+      }
+      .getCaptcha {
+        display: block;
+        width: 100%;
+        height: 40px;
+      }
+
+      .forge-password {
+        font-size: 14px;
+      }
+      button.login-button {
+        padding: 0 15px;
+        font-size: 16px;
+        height: 40px;
+        width: 100%;
+      }
+    }
+
+    .footer {
+      position: absolute;
+      width: 100%;
+      bottom: 0;
+      padding: 0 16px;
+      margin: 48px 0 24px;
+      text-align: center;
+
+      .links {
+        margin-bottom: 8px;
+        font-size: 14px;
+        a {
+          color: rgba(0, 0, 0, 0.45);
+          transition: all 0.3s;
+          &:not(:last-child) {
+            margin-right: 40px;
+          }
+        }
+      }
+      .copyright {
+        color: rgba(0, 0, 0, 0.45);
+        font-size: 14px;
+      }
+    }
+  }
+}
+</style>

+ 25 - 0
src/views/account/center/Index.vue

@@ -0,0 +1,25 @@
+<template>
+  <a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
+    account center page
+  </a-card>
+</template>
+
+<script>
+  import PageLayout from '@/components/layout/PageLayout'
+  import RouteView from "@/components/layout/RouteView";
+
+  export default {
+    components: {
+      RouteView,
+      PageLayout
+    },
+    data () {
+      return {
+
+      }
+    },
+    methods: {
+
+    },
+  }
+</script>

+ 154 - 0
src/views/account/settings/BaseSetting.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="account-settings-info-view">
+    <a-row :gutter="16">
+      <a-col :md="24" :lg="16">
+
+        <a-form layout="vertical">
+          <a-form-item
+            label="昵称"
+          >
+            <a-input placeholder="给自己起个名字" />
+          </a-form-item>
+          <a-form-item
+            label="Bio"
+          >
+            <a-textarea rows="4" placeholder="You are not alone."/>
+          </a-form-item>
+
+          <a-form-item
+            label="电子邮件"
+            :required="false"
+          >
+            <a-input placeholder="exp@admin.com"/>
+          </a-form-item>
+          <a-form-item
+            label="加密方式"
+            :required="false"
+          >
+            <a-select defaultValue="aes-256-cfb">
+              <a-select-option value="aes-256-cfb">aes-256-cfb</a-select-option>
+              <a-select-option value="aes-128-cfb">aes-128-cfb</a-select-option>
+              <a-select-option value="chacha20">chacha20</a-select-option>
+            </a-select>
+          </a-form-item>
+          <a-form-item
+            label="连接密码"
+            :required="false"
+          >
+            <a-input placeholder="h3gSbecd"/>
+          </a-form-item>
+          <a-form-item
+            label="登陆密码"
+            :required="false"
+          >
+            <a-input placeholder="密码"/>
+          </a-form-item>
+
+          <a-form-item>
+            <a-button type="primary">提交</a-button>
+            <a-button style="margin-left: 8px">保存</a-button>
+          </a-form-item>
+        </a-form>
+
+      </a-col>
+      <a-col :md="24" :lg="8" :style="{ minHeight: '180px' }">
+        <div class="ant-upload-preview" >
+          <a-icon type="cloud-upload-o" class="upload-icon"/>
+          <div class="mask">
+            <a-icon type="plus" />
+          </div>
+          <img :src="option.img"/>
+        </div>
+      </a-col>
+
+    </a-row>
+  </div>
+</template>
+
+<script>
+  import VueCropper from "vue-cropper/example/src/vue-cropper/vue-cropper"
+
+  export default {
+    components: {
+      VueCropper
+    },
+    data () {
+      return {
+        // cropper
+        preview: {},
+        option: {
+          img: '/avatar2.jpg',
+          info: true,
+          size: 1,
+          outputType: 'jpeg',
+          canScale: false,
+          autoCrop: true,
+          // 只有自动截图开启 宽度高度才生效
+          autoCropWidth: 180,
+          autoCropHeight: 180,
+          fixedBox: true,
+          // 开启宽度和高度比例
+          fixed: true,
+          fixedNumber: [1, 1]
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+
+  .avatar-upload-wrapper {
+    height: 200px;
+    width: 100%;
+  }
+
+  .ant-upload-preview {
+    position: relative;
+    margin: 0 auto;
+    width: 100%;
+    max-width: 180px;
+    border-radius: 50%;
+    box-shadow: 0 0 4px #ccc;
+
+    .upload-icon {
+      position: absolute;
+      top: 0;
+      right: 10px;
+      font-size: 1.4rem;
+      padding: 0.5rem;
+      background: rgba(222, 221, 221, 0.7);
+      border-radius: 50%;
+      border: 1px solid rgba(0, 0, 0, 0.2);
+    }
+    .mask {
+      opacity: 0;
+      position: absolute;
+      background: rgba(0,0,0,0.4);
+      cursor: pointer;
+      transition: opacity 0.4s;
+
+      &:hover {
+        opacity: 1;
+      }
+
+      i {
+        font-size: 2rem;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        margin-left: -1rem;
+        margin-top: -1rem;
+        color: #d6d6d6;
+      }
+    }
+
+    img, .mask {
+      width: 100%;
+      max-width: 180px;
+      height: 100%;
+      border-radius: 50%;
+      overflow: hidden;
+    }
+  }
+</style>

+ 25 - 0
src/views/account/settings/Binding.vue

@@ -0,0 +1,25 @@
+<template>
+  <a-list
+    itemLayout="horizontal"
+    :dataSource="data"
+  >
+
+  </a-list>
+</template>
+
+<script>
+  export default {
+    data () {
+      return {
+
+      }
+    },
+    methods: {
+
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 75 - 0
src/views/account/settings/Custom.vue

@@ -0,0 +1,75 @@
+<script>
+  import { mapState } from "vuex"
+  import ASwitch from 'ant-design-vue/es/switch'
+  import AList from "ant-design-vue/es/list"
+  import AListItem from "ant-design-vue/es/list/Item"
+
+  const Meta = AListItem.Meta
+
+  export default {
+    components: {
+      AListItem,
+      AList,
+      ASwitch,
+      Meta
+    },
+    data () {
+      return {
+      }
+    },
+    computed: {
+      ...mapState({
+        theme: state => state.app.theme
+      })
+    },
+    filters: {
+      themeFilter(theme) {
+        const themeMap = {
+          'dark': '暗色',
+          'light': '白色'
+        }
+        return themeMap[theme]
+      }
+    },
+    methods: {
+      onChange (checked) {
+
+        console.log('click:', checked)
+        if (checked) {
+          this.$store.dispatch('ToggleTheme',  'dark')
+        } else {
+          this.$store.dispatch('ToggleTheme',  'light')
+        }
+      }
+    },
+    render () {
+      return (
+        <AList itemLayout="horizontal">
+          <AListItem>
+            <Meta>
+              <a slot="title">风格配色</a>
+              <span slot="description">
+                整体风格配色设置
+              </span>
+            </Meta>
+            <div slot="actions">
+              <ASwitch checkedChildren="暗色" unCheckedChildren="白色" defaultChecked={this.theme === 'dark' && true || false} onChange={this.onChange} />
+            </div>
+          </AListItem>
+          <AListItem>
+            <Meta>
+              <a slot="title">主题色</a>
+              <span slot="description">
+                页面风格配色: <a>红</a>
+              </span>
+            </Meta>
+          </AListItem>
+        </AList>
+      )
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 153 - 0
src/views/account/settings/Index.vue

@@ -0,0 +1,153 @@
+<template>
+  <a-card :bordered="false" :bodyStyle="{ padding: '16px 0', height: '100%' }" :style="{ height: '100%' }">
+    <div class="account-settings-info-main" :class="device">
+      <div class="account-settings-info-left">
+        <a-menu
+          :mode="device == 'mobile' ? 'horizontal' : 'inline'"
+          :style="{ border: '0', width: device == 'mobile' ? '560px' : 'auto'}"
+          :defaultSelectedKeys="defaultSelectedKeys"
+          type="inner"
+          @openChange="onOpenChange"
+        >
+          <a-menu-item key="/account/settings/base">
+            <router-link :to="{ name: 'BaseSettings' }">
+              基本设置
+            </router-link>
+          </a-menu-item>
+          <a-menu-item key="/account/settings/security">
+            <router-link :to="{ name: 'SecuritySettings' }">
+              安全设置
+            </router-link>
+          </a-menu-item>
+          <a-menu-item key="/account/settings/custom">
+            <router-link :to="{ name: 'CustomSettings' }">
+              个性化
+            </router-link>
+          </a-menu-item>
+          <a-menu-item key="/account/settings/binding">
+            <router-link :to="{ name: 'BindingSettings' }">
+              账户绑定
+            </router-link>
+          </a-menu-item>
+          <a-menu-item key="/account/settings/notification">
+            <router-link :to="{ name: 'NotificationSettings' }">
+              新消息通知
+            </router-link>
+          </a-menu-item>
+        </a-menu>
+      </div>
+      <div class="account-settings-info-right">
+        <div class="account-settings-info-title">
+          <span>{{ $route.meta.title }}</span>
+        </div>
+        <route-view></route-view>
+      </div>
+    </div>
+  </a-card>
+</template>
+
+<script>
+  import PageLayout from '@/components/layout/PageLayout'
+  import RouteView from "@/components/layout/RouteView"
+  import { mapState } from 'vuex'
+
+  export default {
+    components: {
+      RouteView,
+      PageLayout
+    },
+    data () {
+      return {
+        // horizontal  inline
+        mode: 'inline',
+
+        openKeys: [],
+        defaultSelectedKeys: [],
+
+        // cropper
+        preview: {},
+        option: {
+          img: '/avatar2.jpg',
+          info: true,
+          size: 1,
+          outputType: 'jpeg',
+          canScale: false,
+          autoCrop: true,
+          // 只有自动截图开启 宽度高度才生效
+          autoCropWidth: 180,
+          autoCropHeight: 180,
+          fixedBox: true,
+          // 开启宽度和高度比例
+          fixed: true,
+          fixedNumber: [1, 1]
+        },
+
+        pageTitle: ''
+      }
+    },
+    computed: {
+      ...mapState({
+        device: state => state.app.device,
+      })
+    },
+    created () {
+      this.updateMenu()
+    },
+    methods: {
+      onOpenChange (openKeys) {
+        this.openKeys = openKeys
+      },
+      updateMenu () {
+        let routes = this.$route.matched.concat()
+        this.defaultSelectedKeys = [ routes.pop().path ]
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .account-settings-info-main {
+    width: 100%;
+    display: flex;
+    height: 100%;
+    overflow: auto;
+
+    &.mobile {
+      display: block;
+
+      .account-settings-info-left {
+        border-right: unset;
+        border-bottom: 1px solid #e8e8e8;
+        width: 100%;
+        height: 48px;
+        overflow-x: hidden;
+        overflow-y: auto;
+      }
+      .account-settings-info-right {
+        padding: 20px 40px;
+      }
+    }
+
+    .account-settings-info-left {
+      border-right: 1px solid #e8e8e8;
+      width: 224px;
+    }
+
+    .account-settings-info-right {
+      flex: 1 1;
+      padding: 8px 40px;
+
+      .account-settings-info-title {
+        color: rgba(0,0,0,.85);
+        font-size: 20px;
+        font-weight: 500;
+        line-height: 28px;
+        margin-bottom: 12px;
+      }
+      .account-settings-info-view {
+        padding-top: 12px;
+      }
+    }
+  }
+
+</style>

+ 206 - 0
src/views/account/settings/IndexOld.vue

@@ -0,0 +1,206 @@
+<template>
+  <page-layout :avatar="avatar">
+    <div slot="headerContent">
+      <div class="title">{{ timeFix }},{{ user.name }},{{ welcome }}</div>
+      <div>You are not alone.</div>
+    </div>
+    <div slot="extra">
+      <a-row>
+        <a-col :sm="8" :xs="24">
+          <head-info title="可用节点" content="16" :bordered="true"/>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <head-info title="高级节点" content="7/16" :bordered="true"/>
+        </a-col>
+        <a-col :sm="8" :xs="24">
+          <head-info title="剩余流量" content="2,23Gb"/>
+        </a-col>
+      </a-row>
+    </div>
+
+    <a-card :style="{ padding: '0 15%' }">
+      <a-row :gutter="16">
+        <a-col :md="24" :lg="8" :style="{ minHeight: '180px' }">
+          <div class="ant-upload-preview" >
+            <a-icon type="cloud-upload-o" class="upload-icon"/>
+            <div class="mask">
+              <a-icon type="plus" />
+            </div>
+            <img :src="option.img"/>
+          </div>
+        </a-col>
+        <a-col :md="24" :lg="16">
+
+          <a-form layout="vertical">
+            <a-form-item
+              label="昵称"
+            >
+              <a-input placeholder="给自己起个名字" />
+            </a-form-item>
+            <a-form-item
+              label="Bio"
+            >
+              <a-textarea rows="4" placeholder="You are not alone."/>
+            </a-form-item>
+
+            <a-form-item
+              label="电子邮件"
+              :required="false"
+            >
+              <a-input placeholder="exp@admin.com"/>
+            </a-form-item>
+            <a-form-item
+              label="加密方式"
+              :required="false"
+            >
+              <a-select defaultValue="aes-256-cfb">
+                <a-select-option value="aes-256-cfb">aes-256-cfb</a-select-option>
+                <a-select-option value="aes-128-cfb">aes-128-cfb</a-select-option>
+                <a-select-option value="chacha20">chacha20</a-select-option>
+              </a-select>
+            </a-form-item>
+            <a-form-item
+              label="连接密码"
+              :required="false"
+            >
+              <a-input placeholder="h3gSbecd"/>
+            </a-form-item>
+            <a-form-item
+              label="登陆密码"
+              :required="false"
+            >
+              <a-input placeholder="密码"/>
+            </a-form-item>
+
+            <a-form-item>
+              <a-button type="primary">提交</a-button>
+              <a-button style="margin-left: 8px">保存</a-button>
+            </a-form-item>
+          </a-form>
+
+        </a-col>
+      </a-row>
+    </a-card>
+
+  </page-layout>
+</template>
+
+<script>
+  import {timeFix, welcome} from "../../../utils/util"
+  import LayoutMain from '@/components/layout/LayoutMain'
+  import PageLayout from '@/components/layout/PageLayout'
+
+  import HeadInfo from '@/components/tools/HeadInfo'
+  import ASelect from "ant-design-vue/es/select";
+  import AForm from "ant-design-vue/es/form/Form";
+  import VueCropper from "vue-cropper/example/src/vue-cropper/vue-cropper";
+
+  export default {
+    name: "Index",
+    components: {
+      VueCropper,
+      AForm,
+      ASelect,
+      LayoutMain,
+      PageLayout,
+      HeadInfo
+    },
+    data () {
+      return {
+        timeFix: timeFix(),
+        welcome: welcome(),
+        avatar: '',
+        user: {},
+
+        // cropper
+        preview: {},
+        option: {
+          img: '/avatar2.jpg',
+          info: true,
+          size: 1,
+          outputType: 'jpeg',
+          canScale: false,
+          autoCrop: true,
+          // 只有自动截图开启 宽度高度才生效
+          autoCropWidth: 180,
+          autoCropHeight: 180,
+          fixedBox: true,
+          // 开启宽度和高度比例
+          fixed: true,
+          fixedNumber: [1, 1]
+        }
+      }
+    },
+    computed: {
+      userInfo() {
+        return this.$store.getters.userInfo
+      }
+    },
+    created() {
+      this.user = this.userInfo
+      this.avatar = this.userInfo.avatar
+    },
+    methods: {
+
+      realTime (data) {
+        this.preview = data
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .avatar-upload-wrapper {
+    height: 200px;
+    width: 100%;
+  }
+
+  .ant-upload-preview {
+    position: relative;
+    margin: 0 auto;
+    width: 100%;
+    max-width: 180px;
+    border-radius: 50%;
+    box-shadow: 0 0 4px #ccc;
+
+    .upload-icon {
+      position: absolute;
+      top: 0;
+      right: 10px;
+      font-size: 1.4rem;
+      padding: 0.5rem;
+      background: rgba(222, 221, 221, 0.7);
+      border-radius: 50%;
+      border: 1px solid rgba(0, 0, 0, 0.2);
+    }
+    .mask {
+      opacity: 0;
+      position: absolute;
+      background: rgba(0,0,0,0.4);
+      cursor: pointer;
+      transition: opacity 0.4s;
+
+      &:hover {
+        opacity: 1;
+      }
+
+      i {
+        font-size: 2rem;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        margin-left: -1rem;
+        margin-top: -1rem;
+        color: #d6d6d6;
+      }
+    }
+
+    img, .mask {
+      width: 100%;
+      max-width: 180px;
+      height: 100%;
+      border-radius: 50%;
+      overflow: hidden;
+    }
+  }
+</style>

+ 25 - 0
src/views/account/settings/Notification.vue

@@ -0,0 +1,25 @@
+<template>
+  <a-list
+    itemLayout="horizontal"
+    :dataSource="data"
+  >
+
+  </a-list>
+</template>
+
+<script>
+  export default {
+    data () {
+      return {
+
+      }
+    },
+    methods: {
+
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 41 - 0
src/views/account/settings/Security.vue

@@ -0,0 +1,41 @@
+<template>
+  <a-list
+    itemLayout="horizontal"
+    :dataSource="data"
+  >
+    <a-list-item slot="renderItem" slot-scope="item, index" :key="index">
+      <a-list-item-meta>
+        <a slot="title" href="https://vuecomponent.github.io/ant-design-vue/">{{ item.title }}</a>
+        <span slot="description">
+          <span class="security-list-description">{{ item.description }}</span>
+          <span v-if="item.value"> : </span>
+          <span class="security-list-value">{{ item.value }}</span>
+        </span>
+      </a-list-item-meta>
+      <template v-if="item.actions">
+        <a slot="actions" @click="item.actions.callback">{{ item.actions.title }}</a>
+      </template>
+
+    </a-list-item>
+  </a-list>
+</template>
+
+<script>
+  export default {
+    data () {
+      return {
+        data: [
+          { title: '账户密码' , description: '当前密码强度', value: '强', actions: { title: '修改', callback: () => { this.$message.info('This is a normal message'); } } },
+          { title: '密保手机' , description: '已绑定手机', value: '138****8293', actions: { title: '修改', callback: () => { this.$message.success('This is a message of success'); } }  },
+          { title: '密保问题' , description: '未设置密保问题,密保问题可有效保护账户安全', value: '', actions: { title: '设置', callback: () => { this.$message.error('This is a message of error'); } }  },
+          { title: '备用邮箱' , description: '已绑定邮箱', value: 'ant***sign.com', actions: { title: '修改', callback: () => { this.$message.warning('This is message of warning'); } }  },
+          { title: 'MFA 设备' , description: '未绑定 MFA 设备,绑定后,可以进行二次确认', value: '', actions: { title: '绑定', callback: () => { this.$message.info('This is a normal message'); } }  },
+        ]
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 15 - 0
src/views/dashboard/Analysis.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    Monitor
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "分析盘"
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 15 - 0
src/views/dashboard/Monitor.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    Monitor
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "监控仪"
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 15 - 0
src/views/dashboard/worktop.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    Monitor
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "工作台"
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 17 - 0
src/views/exception/403.vue

@@ -0,0 +1,17 @@
+<template>
+  <exception-page type="403" />
+</template>
+
+<script>
+  import ExceptionPage from './ExceptionPage'
+
+  export default {
+    components: {
+      ExceptionPage
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 15 - 0
src/views/exception/404.vue

@@ -0,0 +1,15 @@
+<template>
+  <exception-page type="404" />
+</template>
+
+<script>
+  import ExceptionPage from './ExceptionPage'
+  export default {
+    components: {
+      ExceptionPage
+    }
+  }
+</script>
+
+<style scoped>
+</style>

+ 17 - 0
src/views/exception/500.vue

@@ -0,0 +1,17 @@
+<template>
+  <exception-page type="500" />
+</template>
+
+<script>
+  import ExceptionPage from './ExceptionPage'
+
+  export default {
+    components: {
+      ExceptionPage
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 75 - 0
src/views/exception/ExceptionPage.vue

@@ -0,0 +1,75 @@
+<template>
+  <div class="exception">
+    <div class="img">
+      <img :src="config[type].img"/>
+    </div>
+    <div class="content">
+      <h1>{{ config[type].title }}</h1>
+      <div class="desc">{{ config[type].desc }}</div>
+      <div class="action">
+        <a-button type="primary" @click="handleToHome">返回首页</a-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import types from './type'
+
+  export default {
+    name: "Exception",
+    props: {
+      type: {
+        type: String,
+        default: '404'
+      }
+    },
+    data() {
+      return {
+        config: types
+      }
+    },
+    methods: {
+      handleToHome () {
+        this.$router.push({ name: 'userManagement' })
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .exception {
+    min-height: 500px;
+    height: 80%;
+    align-items: center;
+    text-align: center;
+    margin-top: 150px;
+    .img {
+      display: inline-block;
+      padding-right: 52px;
+      zoom: 1;
+      img {
+        height: 360px;
+        max-width: 430px;
+      }
+    }
+    .content {
+      display: inline-block;
+      flex: auto;
+      h1 {
+        color: #434e59;
+        font-size: 72px;
+        font-weight: 600;
+        line-height: 72px;
+        margin-bottom: 24px;
+      }
+      .desc {
+        color: rgba(0, 0, 0, .45);
+        font-size: 20px;
+        line-height: 28px;
+        margin-bottom: 16px;
+      }
+    }
+  }
+
+</style>

+ 19 - 0
src/views/exception/type.js

@@ -0,0 +1,19 @@
+const types = {
+  403: {
+    img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
+    title: '403',
+    desc: '抱歉,你无权访问该页面'
+  },
+  404: {
+    img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
+    title: '404',
+    desc: '抱歉,你访问的页面不存在或仍在开发中'
+  },
+  500: {
+    img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
+    title: '500',
+    desc: '抱歉,服务器出错了'
+  }
+}
+
+export default types

+ 436 - 0
src/views/platform/appManagement.vue

@@ -0,0 +1,436 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用名称">
+              <a-input v-model="queryParam.appName" placeholder="请填写应用名称" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用代码">
+              <a-input v-model="queryParam.appCode" placeholder="请填写应用代码" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用状态">
+              <a-select placeholder="请选择" v-model="queryParam.appStatus">
+                <a-select-option value="">全部</a-select-option>
+                <a-select-option value="enabled">启用</a-select-option>
+                <a-select-option value="disabled">禁用</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="24" :sm="24">
+            <span class="table-page-search-submitButtons" style="float:right">
+              <a-button type="primary" @click="queryOperator">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="modifyApp('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="modifyApp('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="modifyApp('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+      <span slot="belongStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+      <span slot="appStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此用户码?</p>
+      <p v-else-if="editType=='reset'">确认重置此用户登录密码?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用名称">
+                <a-input v-model="froms.appName" placeholder="请填写应用名称" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用代码">
+                <a-input v-model="froms.appCode" placeholder="请填写应用代码(字母加‘-’或‘_’)" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用Url">
+                <a-input v-model="froms.appUrl" placeholder="请填写应用Url" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用说明">
+                <a-input v-model="froms.appIntroduce" placeholder="请填写应用说明" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用归属">
+                <a-select placeholder="请选择" v-model="froms.belongStatus">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="排序">
+                <a-input v-model="froms.sortNo" type="number" placeholder="请填写排序" />
+              </a-form-item>
+            </a-col>
+
+            <!-- <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="应用状态">
+                <a-select placeholder="请选择" v-model="froms.appStatus">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col> -->
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.appRemark" placeholder="请填写备注" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+import { toTree } from "@/utils/util";
+
+const columns = [
+  {
+    title: "应用名称",
+    width: "20%",
+    dataIndex: "appName",
+    align: "center"
+  },
+  {
+    title: "应用代码",
+    width: "20%",
+    dataIndex: "appCode",
+    align: "center"
+  },
+  {
+    title: "URL",
+    width: "10%",
+    dataIndex: "appUrl",
+    align: "center"
+  },
+
+  {
+    title: "排序",
+    width: "10%",
+    dataIndex: "sortNo",
+    align: "center"
+  },
+
+  {
+    title: "应用归属",
+    width: "15%",
+    dataIndex: "belongStatus",
+    align: "center",
+    scopedSlots: { customRender: "belongStatus" }
+  },
+  {
+    title: "状态",
+    width: "15%",
+    dataIndex: "appStatus",
+    align: "center",
+    scopedSlots: { customRender: "appStatus" }
+  },
+  {
+    title: "创建时间",
+    width: "20%",
+    dataIndex: "addDataTime",
+    align: "center"
+  }
+];
+
+export default {
+  name: "appManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      queryParam: {
+        appName: null,
+        appCode: null,
+        appStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      appList: [], //应用列表
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      treeData: [], //菜单按钮权限树结构
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //查询
+    queryOperator() {
+      this.getAppList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.appName = null;
+      this.queryParam.appCode = null;
+      this.queryParam.appStatus = "";
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteApp();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditApp();
+      }
+    },
+
+    //新建Or编辑菜单
+    modifyApp(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          appName: null,
+          appCode: null,
+          appUrl: null,
+          appIntroduce: null,
+          appRemark: null,
+          belongStatus: "enabled",
+          appStatus: "enabled"
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getAppInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      if (!this.froms.appName) {
+        flag = !1;
+        this.$message.warning("请填写应用名称!");
+        return false;
+      } else if (!this.froms.appCode) {
+        flag = !1;
+        this.$message.warning("请填写应用代码!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //新增编辑app
+    addOrEditApp() {
+      let _type = this.editType;
+      let data = this.froms;
+      console.log(data);
+      this.axios({
+        url: _type == "add" ? "basic/app/add" : "basic/app/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getAppList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除菜单
+    deleteApp() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/app/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getAppList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取应用列表
+    getAppList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/app/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取应用信息
+    getAppInfo() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/app/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.app;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getAppList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getAppList();
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 381 - 0
src/views/platform/cityManagement.vue

@@ -0,0 +1,381 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <QueryCondition
+      :queryValue = "queryValue"
+      :queryStatus = "queryStatus"
+      :appList = "appList"
+      @inquire = "inquire"
+      @changeAppID = "changeAppID"
+    >
+    </QueryCondition>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <div style="display: inline"><a-button type="primary" @click="addOrEditButton('add')" icon="plus">新建</a-button></div>
+      <div style="display: inline"><a-button type="primary" @click="addOrEditButton('edit')" icon="edit">编辑</a-button></div>
+      <AddOrEdit
+        :optionType="optionType"
+        :showDlg="showDlg"
+        :queryDataBefore="query"
+        :queryAddOrEditStatus="queryAddOrEditStatus"
+        :queryAddOrEditSupport="queryAddOrEditSupport"
+        :appList = "appList"
+        @handleAddOrEdit="handleAddOrEdit"
+        @handleCancel="handleCancel"
+      >
+      </AddOrEdit>
+      <!-- <a-dropdown>
+        <a-menu slot="overlay">
+          <a-menu-item key="1">启用</a-menu-item>
+          <a-menu-item key="2">禁用</a-menu-item>
+          <a-menu-item key="3">删除</a-menu-item>
+        </a-menu>
+        <a-button style="color: rgb(24, 144, 255)">
+          批量操作 <a-icon type="down" />
+        </a-button>
+      </a-dropdown> -->
+    </div>
+    <p style="height:40px;background:#e6f7ff;lineHeight:40px;padding:0 10px;border:1px solid #bae7ff">已选择&nbsp;<span style="color:#1890ff">{{ choose }}</span>&nbsp;项&nbsp;&nbsp;<span @click="handleDelete" style="color:#1890ff;cursor:pointer;">清空</span></p>
+    <!--表格-->
+    <a-table
+      style="background:#fff"
+      :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+      type="radio"
+      :columns="columns"
+      :dataSource="data"
+      :pagination="pagination"
+      :loading="loading"
+    >
+      <span slot="regionStatus" slot-scope="regionStatus">
+        <span v-if="regionStatus=='enabled'">启用</span>
+        <span v-else>禁用</span>
+      </span>
+      <span slot="row_handles" slot-scope="regionStatus">
+        <span v-if="regionStatus=='enabled'">禁用</span>
+        <span v-else>启用</span>
+      </span>
+    </a-table>
+    <!--分页-->
+    <Pagination
+      :current="current"
+      :pageSizeOptions="pageSizeOptions"
+      :pageSize="pageSize"
+      :total="total"
+      :totalPage="totalPage"
+      @change="change"
+    >
+    </Pagination>
+  </div>
+</template>
+
+<script>
+  import STable from '@/components/table/';
+  import Pagination from '@/components/pagination/pagination';
+  import QueryCondition from '@/components/queryCondition/queryCondition';
+  import AddOrEdit from '@/components/addOrEdit/addOrEdit';
+  import { BASEURL, METHOD_POST, METHOD_DELETE, METHOD_PUT } from '@/api/public';
+  import { queryStatus, querySupport, queryAddOrEditStatus, queryAddOrEditSupport } from '@/components/public';
+
+  const columns = [{
+    title: '区域名称',
+    dataIndex: 'regionName',
+    align:'center'
+  }, {
+    title: '区域代码',
+    dataIndex: 'regionCode',
+    align:'center'
+  }, {
+    title: '上级区域',
+    dataIndex: 'parentRegionId',
+    align:'center'
+  }, {
+    title: '排序号',
+    dataIndex: 'sortNo',
+    align:'center'
+  }, {
+    title: '分组',
+    dataIndex: 'regionGroupCode',
+    align:'center'
+  }, {
+    title: '状态',
+    dataIndex: 'regionStatus',
+    align:'center',
+    scopedSlots: { customRender: 'regionStatus' },
+  }, {
+    title: '备注',
+    dataIndex: 'regionRemark',
+    align:'center'
+  }];
+
+  const queryValue = [
+    { param: 'regionName', name: '区域名称', value: null },
+    { param: 'regionStatus', name: '状态', value: null },
+    { param: 'regionCode', name: '区域代码', value: null },
+    { param: 'regionGroupCode', name: '分组', value: null }
+  ];
+  const queryData = [
+    { param: 'id', name: '区域ID', required: true, value: null },
+    { param: 'parentRegionId', name: '上级区域ID', value: null },
+    { param: 'regionCode', name: '区域代码', required: true, value: null },
+    { param: 'regionGroupCode', name: '分组', required: true, value: 'default' },
+    { param: 'regionName', required: true, name: '区域名称', value: null },
+    { param: 'regionRemark', name: '备注', value: null },
+    { param: 'regionStatus', required: true, name: '状态', value: 'enabled' },
+    { param: 'sortNo', required: true, name: '排序号', value: null }
+  ]
+  //数据
+  const data = [{}];
+  const query = [];
+  export default {
+    name: "TableList",
+    components: {
+      STable,
+      Pagination,
+      QueryCondition,
+      AddOrEdit
+    },
+    data(){
+      return{
+        advanced:false,
+        data,//表格请求的数据
+        columns,//表头
+        pagination:false,//不显示分页
+        //分页
+        pageSizeOptions: ['10', '20', '50', '100'],
+        current: 1,//当前的页数
+        pageSize:0,//每页显示的条数
+        totalPage:0,//总页数
+        total: 0,//总条数
+        loading:true,
+        choose:0,//已选择多少项
+        showQuickJumper:true,//显示跳转页
+        optionType: '',
+        showDlg: false,
+        queryAddOrEditSupport: queryAddOrEditSupport,
+        queryAddOrEditStatus: queryAddOrEditStatus,
+        queryStatus: queryStatus,
+        querySupport: querySupport,
+        queryValue,
+        query,
+        queryData,
+        selectedRowKeys: [], // Check here to configure the default column
+        queryCondition: {},
+        appList: [],
+        appId: null
+      }
+    },
+    watch: {
+      selectedRowKeys: function(selectedRowKeys) {
+        console.log(selectedRowKeys)
+        this.choose = selectedRowKeys.length
+      }
+    },
+    methods:{
+      onSelectChange (selectedRowKeys) {
+        console.log('selectedRowKeys changed: ', selectedRowKeys);
+        this.selectedRowKeys = selectedRowKeys
+      },
+      // 清空
+      handleDelete() {
+        let that = this
+        if(that.selectedRowKeys.length < 1) {
+          this.$message.warning('请至少选择一条记录!')
+        } else {
+          this.$confirm({
+            title: '提示',
+            content: '请确定是否清空数据?',
+            onOk() {
+              let idArray = [];
+              for(let i = 0; i < that.selectedRowKeys.length; i++) {
+               let index = that.selectedRowKeys[i]
+                for(let j = 0; j < that.data.length; j++) {
+                  if(index==j){
+                  idArray.push(that.data[j].id)
+                  }
+                }
+              }
+              that.loading = true
+              that.axios({
+                url:  'basic/region/city/remove/' + idArray,
+                method: METHOD_DELETE
+              }).then((res) => {
+                //请求成功
+                that.loading = false
+                console.log(res)
+                if(res.code == 0) {
+                  that.$message.success('清空成功!');
+                  that.selectedRowKeys = []
+                  let data = { currentPage:that.current, pageSize:that.pageSize, where: that.queryCondition }
+                  that.listAPI(data);
+                } else {
+                  that.$message.success(res.msg);
+                }}).catch(() => {
+                that.loading = false;
+                that.$message.error('请求超时!');
+              })
+            },
+            onCancel() {
+              that.loading = false
+            },
+          });
+        }
+      },
+      // 取消
+      handleCancel() {
+        this.showDlg = false
+        this.query = JSON.parse(JSON.stringify(this.queryData))
+        console.log(this.queryData)
+        console.log(this.query)
+      },
+      // 新增 || 编辑 确定
+      handleAddOrEdit(data) {
+        this.showDlg = false
+        this.query = JSON.parse(JSON.stringify(this.queryData))
+        console.log(data)
+        this.loading = true
+        let queryEditCondition = {};
+        data.forEach(item => {
+          queryEditCondition[item.param] = item.value
+        })
+        if(this.optionType == 'add') {
+          // 新增
+          this.addOrEditDatalist('basic/region/city/add', queryEditCondition, METHOD_POST)
+        } else if (this.optionType == 'edit') {
+          // 编辑
+          this.addOrEditDatalist('basic/region/city/modify', queryEditCondition, METHOD_PUT)
+        }
+      },
+      // 新增数据请求
+      addOrEditDatalist(url, data , method) {
+        this.axios({
+          url:  url,
+          method: method,
+          data: data
+        }).then(res=>{
+          console.log(res)
+          this.loading=false
+          console.log(11)
+          console.log(res.code)
+          if(res.code == 0) {
+            this.$message.success("操作成功!");
+            this.selectedRowKeys = []
+            let data = { currentPage:this.current, pageSize:this.pageSize, where: this.queryCondition }
+            this.listAPI(data);
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      // 编剧数据请求
+      // 新增 || 编辑
+      addOrEditButton(e) {
+        console.log(e)
+        this.optionType = e;
+        if(this.optionType == 'edit') {
+          if(this.selectedRowKeys.length == 1) {
+            let index = this.selectedRowKeys[0]
+            console.log(index)
+            let queryEditData = this.data[index]
+            this.query.forEach(item => {
+              for(let key in queryEditData) {
+                if(item.param == key) {
+                  item.value = queryEditData[key]
+                }
+              }
+            })
+            this.showDlg = true;
+          } else {
+            this.$message.warning('请选择一条记录!')
+          }
+        } else {
+          this.showDlg = true;
+        }
+      },
+      // 头部查询
+      inquire(data) {
+        if(this.appList.length > 0) {
+          this.queryCondition["appId"] = this.appId
+        }
+        data.forEach(item => {
+          this.queryCondition[item.param] = item.value
+        })
+        this.axios({
+          url:  'basic/region/city/pageList',
+          method: METHOD_POST,
+          data: {
+            currentPage:1,
+            pageSize:10,
+            where: this.queryCondition
+          }}).then(res=>{
+          console.log(res)
+          this.loading=false
+          if(res.code == 0) {
+            this.dealData(res)
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      // 处理数据
+      dealData(res) {
+        this.data = res.page.list
+        this.current =  res.page.currentPage
+        this.totalPage = res.page.totalPage
+        this.total = res.page.totalCount
+        this.pageSize = res.page.pageSize
+      },
+      // 列表请求
+      listAPI(data) {
+        this.axios({
+          url:  'basic/region/city/pageList',
+          method: METHOD_POST,
+          data: data
+        }).then(res=>{
+          console.log(res)
+          this.loading=false
+          if(res.code == 0) {
+            this.dealData(res)
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      //分页
+      change(data) {
+        let requestData = data;
+        requestData.where = this.queryCondition
+        console.log(requestData)
+        this.listAPI(requestData);
+      },
+      // 获取应用归属id
+      changeAppID(data) {
+        console.log(data)
+        this.appId = data
+      }
+    },
+    created(){//列表数据请求
+      this.query = JSON.parse(JSON.stringify(this.queryData))
+      let data = { currentPage:1, pageSize:10, where: this.queryCondition }
+      this.listAPI(data);
+    }
+  }
+</script>
+
+<style scoped>
+  .table-operator{
+    margin-bottom: 10px;
+  }
+  .ant-pagination{
+    margin-top: 20px;
+    text-align: center
+  }
+</style>

+ 383 - 0
src/views/platform/countyManagement.vue

@@ -0,0 +1,383 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <QueryCondition
+      :queryValue = "queryValue"
+      :queryStatus = "queryStatus"
+      :appList = "appList"
+      @inquire = "inquire"
+      @changeAppID = "changeAppID"
+    >
+    </QueryCondition>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <div style="display: inline"><a-button type="primary" @click="addOrEditButton('add')" icon="plus">新建</a-button></div>
+      <div style="display: inline"><a-button type="primary" @click="addOrEditButton('edit')" icon="edit">编辑</a-button></div>
+      <AddOrEdit
+        :optionType="optionType"
+        :showDlg="showDlg"
+        :queryDataBefore="query"
+        :queryAddOrEditStatus="queryAddOrEditStatus"
+        :queryAddOrEditSupport="queryAddOrEditSupport"
+        :appList = "appList"
+        @handleAddOrEdit="handleAddOrEdit"
+        @handleCancel="handleCancel"
+      >
+      </AddOrEdit>
+      <!-- <a-dropdown>
+        <a-menu slot="overlay">
+          <a-menu-item key="1">启用</a-menu-item>
+          <a-menu-item key="2">禁用</a-menu-item>
+          <a-menu-item key="3">删除</a-menu-item>
+        </a-menu>
+        <a-button style="color: rgb(24, 144, 255)">
+          批量操作 <a-icon type="down" />
+        </a-button>
+      </a-dropdown> -->
+    </div>
+    <p style="height:40px;background:#e6f7ff;lineHeight:40px;padding:0 10px;border:1px solid #bae7ff">已选择&nbsp;<span style="color:#1890ff">{{ choose }}</span>&nbsp;项&nbsp;&nbsp;<span @click="handleDelete" style="color:#1890ff;cursor:pointer;">清空</span></p>
+    <!--表格-->
+    <a-table
+      style="background:#fff"
+      :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+      type="radio"
+      :columns="columns"
+      :dataSource="data"
+      :pagination="pagination"
+      :loading="loading"
+    >
+      <span slot="regionStatus" slot-scope="regionStatus">
+        <span v-if="regionStatus=='enabled'">启用</span>
+        <span v-else>禁用</span>
+      </span>
+      <span slot="row_handles" slot-scope="regionStatus">
+        <span v-if="regionStatus=='enabled'">禁用</span>
+        <span v-else>启用</span>
+      </span>
+    </a-table>
+    <!--分页-->
+    <Pagination
+      :current="current"
+      :pageSizeOptions="pageSizeOptions"
+      :pageSize="pageSize"
+      :total="total"
+      :totalPage="totalPage"
+      @change="change"
+    >
+    </Pagination>
+  </div>
+</template>
+
+<script>
+  import STable from '@/components/table/';
+  import Pagination from '@/components/pagination/pagination';
+  import QueryCondition from '@/components/queryCondition/queryCondition';
+  import AddOrEdit from '@/components/addOrEdit/addOrEdit';
+  import { BASEURL, METHOD_POST, METHOD_DELETE, METHOD_PUT } from '@/api/public';
+  import { queryStatus, querySupport, queryAddOrEditStatus, queryAddOrEditSupport } from '@/components/public';
+
+  const columns = [{
+    title: '区域名称',
+    dataIndex: 'regionName',
+    align:'center'
+  }, {
+    title: '区域代码',
+    dataIndex: 'regionCode',
+    align:'center'
+  }, {
+    title: '上级区域',
+    dataIndex: 'parentRegionId',
+    align:'center'
+  }, {
+    title: '排序号',
+    dataIndex: 'sortNo',
+    align:'center'
+  }, {
+    title: '分组',
+    dataIndex: 'regionGroupCode',
+    align:'center'
+  }, {
+    title: '状态',
+    dataIndex: 'regionStatus',
+    align:'center',
+    scopedSlots: { customRender: 'regionStatus' },
+  }, {
+    title: '备注',
+    dataIndex: 'regionRemark',
+    align:'center'
+  }];
+
+  const queryValue = [
+    { param: 'regionName', name: '区域名称', value: null },
+    { param: 'regionStatus', name: '状态', value: null },
+    { param: 'regionCode', name: '区域代码', value: null },
+    { param: 'regionGroupCode', name: '分组', value: null }
+  ];
+  const queryData = [
+    { param: 'id', name: '区域ID', required: true, value: null },
+    { param: 'parentRegionId', name: '上级区域ID', value: null },
+    { param: 'regionCode', name: '区域代码', required: true, value: null },
+    { param: 'regionGroupCode', name: '分组', required: true, value: 'default' },
+    { param: 'regionName', required: true, name: '区域名称', value: null },
+    { param: 'regionRemark', name: '备注', value: null },
+    { param: 'regionStatus', required: true, name: '状态', value: 'enabled' },
+    { param: 'sortNo', required: true, name: '排序号', value: null }
+  ]
+  //数据
+  const data = [{}];
+  const query = [];
+  export default {
+    name: "TableList",
+    components: {
+      STable,
+      Pagination,
+      QueryCondition,
+      AddOrEdit
+    },
+    data(){
+      return{
+        advanced:false,
+        data,//表格请求的数据
+        columns,//表头
+        pagination:false,//不显示分页
+        //分页
+        pageSizeOptions: ['10', '20', '50', '100'],
+        current: 1,//当前的页数
+        pageSize:0,//每页显示的条数
+        totalPage:0,//总页数
+        total: 0,//总条数
+        loading:true,
+        choose:0,//已选择多少项
+        showQuickJumper:true,//显示跳转页
+        optionType: '',
+        showDlg: false,
+        queryAddOrEditSupport: queryAddOrEditSupport,
+        queryAddOrEditStatus: queryAddOrEditStatus,
+        queryStatus: queryStatus,
+        querySupport: querySupport,
+        queryValue,
+        query,
+        queryData,
+        selectedRowKeys: [], // Check here to configure the default column
+        queryCondition: {},
+        appList: [],
+        appId: null
+      }
+    },
+    watch: {
+      selectedRowKeys: function(selectedRowKeys) {
+        console.log(selectedRowKeys)
+        this.choose = selectedRowKeys.length
+      }
+    },
+    methods:{
+      onSelectChange (selectedRowKeys) {
+        console.log('selectedRowKeys changed: ', selectedRowKeys);
+        this.selectedRowKeys = selectedRowKeys
+      },
+      // 清空
+      handleDelete() {
+        let that = this
+        if(that.selectedRowKeys.length < 1) {
+          this.$message.warning('请至少选择一条记录!')
+        } else {
+          this.$confirm({
+            title: '提示',
+            content: '请确定是否清空数据?',
+            onOk() {
+              let idArray = [];
+              for(let i = 0; i < that.selectedRowKeys.length; i++) {
+               let index = that.selectedRowKeys[i]
+                for(let j = 0; j < that.data.length; j++) {
+                  if(index==j){
+                    console.log(that.data[j])
+                    idArray.push(that.data[j].id)
+                  }
+                }
+              }
+              console.log(idArray)
+              that.loading = true
+              that.axios({
+                url:  'basic/region/county/remove/' + idArray,
+                method: METHOD_DELETE
+              }).then((res) => {
+                //请求成功
+                that.loading = false
+                console.log(res)
+                if(res.code == 0) {
+                  that.$message.success('清空成功!');
+                  that.selectedRowKeys = []
+                  let data = { currentPage:that.current, pageSize:that.pageSize, where: that.queryCondition }
+                  that.listAPI(data);
+                } else {
+                  that.$message.success(res.msg);
+                }}).catch(() => {
+                that.loading = false;
+                that.$message.error('请求超时!');
+              })
+            },
+            onCancel() {
+              that.loading = false
+            },
+          });
+        }
+      },
+      // 取消
+      handleCancel() {
+        this.showDlg = false
+        this.query = JSON.parse(JSON.stringify(this.queryData))
+        console.log(this.queryData)
+        console.log(this.query)
+      },
+      // 新增 || 编辑 确定
+      handleAddOrEdit(data) {
+        this.showDlg = false
+        this.query = JSON.parse(JSON.stringify(this.queryData))
+        console.log(data)
+        this.loading = true
+        let queryEditCondition = {};
+        data.forEach(item => {
+          queryEditCondition[item.param] = item.value
+        })
+        if(this.optionType == 'add') {
+          // 新增
+          this.addOrEditDatalist('basic/region/county/add', queryEditCondition, METHOD_POST)
+        } else if (this.optionType == 'edit') {
+          // 编辑
+          this.addOrEditDatalist('basic/region/county/modify', queryEditCondition, METHOD_PUT)
+        }
+      },
+      // 新增数据请求
+      addOrEditDatalist(url, data , method) {
+        this.axios({
+          url:  url,
+          method: method,
+          data: data
+        }).then(res=>{
+          console.log(res)
+          this.loading=false
+          console.log(11)
+          console.log(res.code)
+          if(res.code == 0) {
+            this.$message.success("操作成功!");
+            this.selectedRowKeys = []
+            let data = { currentPage:this.current, pageSize:this.pageSize, where: this.queryCondition }
+            this.listAPI(data);
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      // 编剧数据请求
+      // 新增 || 编辑
+      addOrEditButton(e) {
+        console.log(e)
+        this.optionType = e;
+        if(this.optionType == 'edit') {
+          if(this.selectedRowKeys.length == 1) {
+            let index = this.selectedRowKeys[0]
+            console.log(index)
+            let queryEditData = this.data[index]
+            this.query.forEach(item => {
+              for(let key in queryEditData) {
+                if(item.param == key) {
+                  item.value = queryEditData[key]
+                }
+              }
+            })
+            this.showDlg = true;
+          } else {
+            this.$message.warning('请选择一条记录!')
+          }
+        } else {
+          this.showDlg = true;
+        }
+      },
+      // 头部查询
+      inquire(data) {
+        if(this.appList.length > 0) {
+          this.queryCondition["appId"] = this.appId
+        }
+        data.forEach(item => {
+          this.queryCondition[item.param] = item.value
+        })
+        this.axios({
+          url:  'basic/region/county/pageList',
+          method: METHOD_POST,
+          data: {
+            currentPage:1,
+            pageSize:10,
+            where: this.queryCondition
+          }}).then(res=>{
+          console.log(res)
+          this.loading=false
+          if(res.code == 0) {
+            this.dealData(res)
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      // 处理数据
+      dealData(res) {
+        this.data = res.page.list
+        this.current =  res.page.currentPage
+        this.totalPage = res.page.totalPage
+        this.total = res.page.totalCount
+        this.pageSize = res.page.pageSize
+      },
+      // 列表请求
+      listAPI(data) {
+        this.axios({
+          url:  'basic/region/county/pageList',
+          method: METHOD_POST,
+          data: data
+        }).then(res=>{
+          console.log(res)
+          this.loading=false
+          if(res.code == 0) {
+            this.dealData(res)
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      //分页
+      change(data) {
+        let requestData = data;
+        requestData.where = this.queryCondition
+        console.log(requestData)
+        this.listAPI(requestData);
+      },
+      // 获取应用归属id
+      changeAppID(data) {
+        console.log(data)
+        this.appId = data
+      }
+    },
+    created(){//列表数据请求
+      this.query = JSON.parse(JSON.stringify(this.queryData))
+      let data = { currentPage:1, pageSize:10, where: this.queryCondition }
+      this.listAPI(data);
+    }
+  }
+</script>
+
+<style scoped>
+  .table-operator{
+    margin-bottom: 10px;
+  }
+  .ant-pagination{
+    margin-top: 20px;
+    text-align: center
+  }
+</style>

+ 526 - 0
src/views/platform/dictManagement.vue

@@ -0,0 +1,526 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用平台">
+              <a-select placeholder="请选择" v-model="queryParam.appId" @change="choiceAppId">
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="字典名称">
+              <a-input v-model="queryParam.dictName" placeholder="请填写字典名称" />
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item label="字典键">
+                <a-input v-model="queryParam.dictKey" placeholder="请填写字典键" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="级别">
+                <a-select placeholder="请选择" v-model="queryParam.dictLevel">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="whole">全局</a-select-option>
+                  <a-select-option value="app">应用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="状态">
+                <a-select placeholder="请选择" v-model="queryParam.dictStatus">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="!advanced && 8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+              <a-button type="primary" @click="queryDict">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+              <a @click="toggleAdvanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'" />
+              </a>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="addOrEditOrRemovDict('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="addOrEditOrRemovDict('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="addOrEditOrRemovDict('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+      <span slot="dictLevel" slot-scope="record">
+        <a-tag v-if="record=='whole'" color="#108ee9">全局</a-tag>
+        <a-tag v-else-if="record=='app'" color="#f0ad4e">应用</a-tag>
+      </span>
+
+      <span slot="dictStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项码?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用平台" :required="true">
+                <a-select placeholder="请选择" v-model="froms.appId" disabled>
+                  <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="字典名称" :required="true">
+                <a-input v-model="froms.dictName" placeholder="请填写字典名称" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="字典键" :required="true">
+                <a-input v-model="froms.dictKey" placeholder="请填写字典键(以字母及'_'链接)" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="字典名" :required="true">
+                <a-input v-model="froms.dictItemName" placeholder="请填写字典名" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="字典值" :required="true">
+                <a-input v-model="froms.dictItemValue" placeholder="请填写字典值" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="级别">
+                <a-select placeholder="请选择" v-model="froms.dictLevel">
+                  <a-select-option value="whole">全局</a-select-option>
+                  <a-select-option value="app">应用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="是否启用">
+                <a-select placeholder="请选择" v-model="froms.dictStatus">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.dictRemark" placeholder="请填写备注信息" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+import { toTree } from "@/utils/util";
+
+const columns = [
+  {
+    title: "字典名称",
+    dataIndex: "dictName",
+    width: "10%",
+    align: "center"
+  },
+  {
+    title: "字典键",
+    dataIndex: "dictKey",
+    width: "10%",
+    align: "center"
+  },
+  {
+    title: "字典名",
+    dataIndex: "dictItemName",
+    width: "10%",
+    align: "center"
+  },
+  {
+    title: "字典值",
+    dataIndex: "dictItemValue",
+    width: "10%",
+    align: "center"
+  },
+  {
+    title: "级别",
+    dataIndex: "dictLevel",
+    width: "10%",
+    align: "center",
+    scopedSlots: { customRender: "dictLevel" }
+  },
+  {
+    title: "排序",
+    dataIndex: "sortNo",
+    width: "10%",
+    align: "center"
+  },
+  {
+    title: "状态",
+    dataIndex: "dictStatus",
+    width: "10%",
+    align: "center",
+    scopedSlots: { customRender: "dictStatus" }
+  },
+  {
+    title: "备注",
+    dataIndex: "dictRemark",
+    width: "10%",
+    align: "center"
+  },
+  {
+    title: "创建时间",
+    dataIndex: "addDataTime",
+    width: "20%",
+    align: "center"
+  }
+];
+
+//数据
+const data = [{}];
+const query = [];
+export default {
+  name: "dictManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        appId: null,
+        dictName: null,
+        dictKey: null,
+        dictLevel: "",
+        dictStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      appList: [],
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //高级搜索 展开/收起
+    toggleAdvanced() {
+      this.advanced = !this.advanced;
+    },
+
+    //查询
+    queryDict() {
+      this.getDictList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.dictName = null;
+      this.queryParam.dictKey = null;
+      this.queryParam.dictLevel = "";
+      this.queryParam.dictStatus = "";
+    },
+
+    //选择appid
+    choiceAppId(id) {
+      this.queryParam.appId = id;
+      this.getDictList();
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteDict();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditDict();
+      }
+    },
+
+    //新建Or编辑字典
+    addOrEditOrRemovDict(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+
+        this.froms = {
+          appId: this.queryParam.appId,
+          dictName: null,
+          dictKey: null,
+          dictItemName: null,
+          dictItemValue: null,
+          dictLevel: "whole",
+          dictStatus: "enabled",
+          dictRemark: null
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getDictInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      let reg = /^\w+$/;
+      if (!this.froms.dictName) {
+        flag = !1;
+        this.$message.warning("请填写字典名称!");
+        return false;
+      } else if (!reg.test(this.froms.dictKey)) {
+        flag = !1;
+        this.$message.warning("请填写有效的字典键!");
+        return false;
+      } else if (!this.froms.dictItemName) {
+        flag = !1;
+        this.$message.warning("请填写字典名!");
+        return false;
+      } else if (!this.froms.dictItemValue) {
+        flag = !1;
+        this.$message.warning("请填写字典值!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加字典
+    addOrEditDict() {
+      let _type = this.editType;
+      const data = this.froms;
+      this.axios({
+        url: _type == "add" ? "basic/dict/add" : "basic/dict/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getDictList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除字典
+    deleteDict() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/dict/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getDictList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取应用列表
+    getAppList() {
+      return new Promise((resolve, reject) => {
+        this.axios({
+          url: "basic/app/select",
+          method: METHOD_GET
+        })
+          .then(res => {
+            if (res.code == 0) {
+              if (res.appList.length > 0) {
+                this.queryParam.appId = res.appList[0].id;
+                this.appList = res.appList;
+              }
+              resolve(res);
+            } else {
+              this.$message.error(res.msg);
+            }
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
+    },
+
+    // 获取字典数据列表
+    getDictList() {
+      this.initSelectedRows();
+
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/dict/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取字典信息
+    getDictInfo() {
+      const _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/dict/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.dict;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getDictList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getAppList().then(res => {
+      this.getDictList();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+.modal-container {
+  max-height: 500px;
+  padding: 0 12px;
+  overflow-y: auto;
+}
+</style>

+ 341 - 0
src/views/platform/fileManagement.vue

@@ -0,0 +1,341 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <!-- <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="原文件名">
+              <a-input v-model="queryParam.fileSourceName" placeholder="请填写原文件名" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="文件地址">
+              <a-input v-model="queryParam.fileUrl" placeholder="请填写文件地址" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="文件状态">
+              <a-select placeholder="请选择" v-model="queryParam.fileStatus">
+                <a-select-option value="">全部</a-select-option>
+                <a-select-option value="enabled">启用</a-select-option>
+                <a-select-option value="disabled">禁用</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="24" :sm="24">
+            <span class="table-page-search-submitButtons" style="float:right">
+              <a-button type="primary" @click="queryFile">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div> -->
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="cloud-upload" @click="modifyFile('add')">上传文件</a-button>
+      <a-button type="primary" icon="delete" @click="modifyFile('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'checkbox', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+
+      <span slot="fileStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+      <template slot="fileSize" slot-scope="record">
+        <span>{{parseFloat(record/1024).toFixed(2)}}</span>
+      </template>
+
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='add'?'800px':'400px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此任务?</p>
+      <div class="modal-container" v-else>
+        <div class="clearfix">
+          <a-upload :action="action" :headers="headers" listType="picture-card" :fileList="fileList" @preview="handlePreview" @change="handleChange">
+            <div v-if="fileList.length < 6">
+              <a-icon type="plus" />
+              <div class="ant-upload-text">上传</div>
+            </div>
+          </a-upload>
+
+        </div>
+      </div>
+    </a-modal>
+
+    <!-- 查看图片模态框 -->
+    <a-modal :visible="previewVisible" :footer="null" @cancel="previewCancel">
+      <img alt="example" style="width: 100%" :src="previewImage" />
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "原文件名",
+    width: "15%",
+    dataIndex: "fileSourceName",
+    align: "center"
+  },
+  {
+    title: "文件地址",
+    width: "25%",
+    dataIndex: "fileUrl",
+    align: "center"
+  },
+  {
+    title: "文件大小(kb)",
+    width: "10%",
+    dataIndex: "fileSize",
+    align: "center",
+    scopedSlots: { customRender: "fileSize" }
+  },
+  {
+    title: "文件云",
+    width: "10%",
+    dataIndex: "fileCloud",
+    align: "center"
+  },
+  {
+    title: "备注",
+    width: "10%",
+    dataIndex: "fileRemark",
+    align: "center"
+  },
+  {
+    title: "状态",
+    width: "10%",
+    dataIndex: "fileStatus",
+    align: "center",
+    scopedSlots: { customRender: "fileStatus" }
+  },
+  {
+    title: "上传时间",
+    width: "20%",
+    dataIndex: "addDataTime",
+    align: "center"
+  }
+];
+
+export default {
+  name: "fileManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        fileSourceName: null,
+        fileUrl: null,
+        fileStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "上传文件",
+      visible: !1,
+      confirmLoading: !1,
+
+      action: BASEURL + "/basic/file/upload",
+      headers: { token: this.$ls.get("Access_Token") },
+      previewVisible: !1,
+      fileList: [],
+      previewImage: ""
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //查询
+    queryFile() {
+      this.getFileList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.fileSourceName = null;
+      this.queryParam.fileUrl = null;
+      this.queryParam.fileStatus = "";
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteFile();
+      } else {
+        this.visible = !1;
+        this.getFileList();
+      }
+    },
+
+    //操作文件
+    modifyFile(e, o) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "上传文件";
+        this.visible = !0;
+      } else if (this.editType == "delete") {
+        this.modalTitle = "删除";
+        this.visible = !0;
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+
+      return flag;
+    },
+
+    previewCancel() {
+      this.previewVisible = !1;
+    },
+
+    handlePreview(file) {
+      this.previewImage = file.url || file.thumbUrl;
+      this.previewVisible = !0;
+    },
+
+    handleChange({ fileList }) {
+      this.fileList = fileList;
+    },
+
+    //删除文件
+    deleteFile() {
+      let _id = this.selectedRows[0].id;
+      let _idsArr = this.selectedRows.map(item => {
+        return item.id;
+      });
+      this.axios({
+        url: "basic/file/remove/" + _idsArr,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getFileList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取文件数据列表
+    getFileList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/file/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getFileList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getFileList();
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+.ant-upload-select-picture-card i {
+  font-size: 32px;
+  color: #999;
+}
+
+.ant-upload-select-picture-card .ant-upload-text {
+  margin-top: 8px;
+  color: #666;
+}
+</style>

+ 561 - 0
src/views/platform/menuManagement.vue

@@ -0,0 +1,561 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用平台">
+              <a-select placeholder="请选择" v-model="curAppId" @change="choiceAppId">
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="addOrEditOrRemoveMenu('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="addOrEditOrRemoveMenu('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="addOrEditOrRemoveMenu('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+      <span slot="menuType" slot-scope="record">
+        <a-tag v-if="record=='catalog'" color="#108ee9">栏目</a-tag>
+        <a-tag v-else-if="record=='menu'" color="#2db7f5">菜单</a-tag>
+        <a-tag v-else-if="record=='button'" color="#f0ad4e">按钮</a-tag>
+      </span>
+
+      <span slot="menuStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+
+      <span slot="menuShowType" slot-scope="record">
+        <a-tag v-if="record=='display'" color="#87d068">显示</a-tag>
+        <a-tag v-else-if="record=='hide'" color="#ff0000">隐藏</a-tag>
+      </span>
+    </a-table>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项码?</p>
+      <a-form v-else>
+        <a-row :gutter="24">
+          <a-col :md="12" :sm="24">
+            <a-form-item label="应用平台" :required="true">
+              <a-select placeholder="请选择" v-model="froms.appId" disabled>
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="菜单类型" :required="true">
+              <a-radio-group v-model="froms.menuType">
+                <a-radio value="catalog">栏目</a-radio>
+                <a-radio value="menu">菜单</a-radio>
+                <a-radio value="button">按钮</a-radio>
+                <a-radio value="url">URL</a-radio>
+              </a-radio-group>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item :label="froms.menuType=='catalog'?'栏目名称':froms.menuType=='menu'?'菜单名称':froms.menuType=='button'?'按钮名称':'URL名称'" :required="true">
+              <a-input v-model="froms.menuName" placeholder="请填写栏目、菜单、按钮或URL名称" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="上级菜单" :required="true">
+              <a-tree-select :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }" :treeData="menuTreeData" placeholder='请选择所属上级菜单' v-model="froms.parentMenuId" @change="onChangeParentMenu">
+              </a-tree-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item :label="froms.menuType=='button'?'按钮代码':'菜单代码'" :required="froms.menuType=='button'?false:true">
+              <a-input v-model="froms.menuCode" placeholder="请填写菜单或按钮名称(如:menuCode)" />
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="12" :sm="24">
+            <a-form-item label="菜单路径" :required="froms.menuType=='button'?false:true">
+              <a-input v-model="froms.menuPath" placeholder="请填写菜单路径(如:/system)" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="菜单重定向路径">
+              <a-input v-model="froms.menuContextPath" placeholder="请填写重定向路径(如:/system/children)" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="菜单ICON">
+              <a-input v-model="froms.menuIcon" placeholder="请填写菜单ICON" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="菜单引用组件">
+              <a-input v-model="froms.menuRemark" placeholder="请填写菜单引用组件" />
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="12" :sm="24">
+            <a-form-item label="授权标识">
+              <a-input v-model="froms.menuPerms" placeholder="请填写授权标识" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="菜单排序">
+              <a-input v-model="froms.sortNo" placeholder="请填写菜单排序(如:0,1,2...9999。)" />
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="12" :sm="24" v-show="editType=='edit'">
+            <a-form-item label="是否启用">
+              <a-select placeholder="请选择" v-model="froms.menuStatus">
+                <a-select-option value="enabled">启用</a-select-option>
+                <a-select-option value="disabled">禁用</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="12" :sm="24">
+            <a-form-item label="是否显示">
+              <a-select placeholder="请选择" v-model="froms.menuShowType">
+                <a-select-option value="display">显示</a-select-option>
+                <a-select-option value="hide">隐藏</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+
+        </a-row>
+      </a-form>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+import { toTree } from "@/utils/util";
+
+const columns = [
+  {
+    title: "菜单名称",
+    width: "18%",
+    dataIndex: "menuName"
+  },
+  {
+    title: "上级菜单",
+    width: "10%",
+    dataIndex: "parentMenuName",
+    align: "center"
+  },
+  {
+    title: "类型",
+    width: "8%",
+    dataIndex: "menuType",
+    align: "center",
+    scopedSlots: { customRender: "menuType" }
+  },
+  {
+    title: "菜单代码",
+    width: "10%",
+    dataIndex: "menuCode",
+    align: "center"
+  },
+
+  {
+    title: "图标",
+    width: "10%",
+    dataIndex: "menuIcon",
+    align: "center"
+  },
+
+  {
+    title: "排序号",
+    width: "8%",
+    dataIndex: "sortNo",
+    align: "center"
+  },
+  {
+    title: "菜单地址",
+    width: "10%",
+    dataIndex: "menuPath",
+    align: "center"
+  },
+  // {
+  //   title: "重定向路径",
+  //   width: "10%",
+  //   dataIndex: "menuContextPath",
+  //   align: "center"
+  // },
+  {
+    title: "授权标识",
+    width: "10%",
+    dataIndex: "menuPerms",
+    align: "center"
+  },
+  {
+    title: "菜单状态",
+    width: "8%",
+    dataIndex: "menuStatus",
+    align: "center",
+    scopedSlots: { customRender: "menuStatus" }
+  },
+  {
+    title: "是否显示",
+    width: "8%",
+    dataIndex: "menuShowType",
+    align: "center",
+    scopedSlots: { customRender: "menuShowType" }
+  }
+];
+
+export default {
+  name: "menuManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false,
+      loadDatas: [], //表格请求的数据
+      columns: columns, //表头
+      pagination: false, //不显示分页
+
+      loading: true,
+
+      curAppId: null,
+      appList: [],
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1,
+
+      menuTreeData: [],
+      froms: {}
+    };
+  },
+  watch: {},
+  methods: {
+    //选择appid
+    choiceAppId(id) {
+      this.curAppId = id;
+      // this.froms.appId = id;
+      this.getMenuButList();
+      this.getMenuList();
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      console.log(selectedRows);
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //新建Or编辑菜单
+    addOrEditOrRemoveMenu(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+
+        this.froms = {
+          appId: this.curAppId,
+          menuType: "catalog",
+          menuName: null,
+          parentMenuId: null,
+          parentMenuName: null,
+          menuCode: null,
+          menuPath: null,
+          menuContextPath: null,
+          menuIcon: null,
+          menuRemark: null,
+          menuPerms: null,
+          sortNo: null,
+          menuStatus: "enabled",
+          menuShowType: "display"
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getMenuInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //选择父菜单
+    onChangeParentMenu(v, l) {
+      this.froms.parentMenuId = v;
+      this.froms.parentMenuName = l.join(",");
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteMenu();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditMenu();
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      if (!this.froms.menuName) {
+        flag = !1;
+        this.$message.warning("请填写菜单名称!");
+        return false;
+      } else if (this.froms.menuType != "button" && !this.froms.menuCode) {
+        flag = !1;
+        this.$message.warning("请填写菜单代码!");
+        return false;
+      } else if (this.froms.menuType != "button" && !this.froms.menuPath) {
+        flag = !1;
+        this.$message.warning("请填写菜单路径!");
+        return false;
+      } else if (
+        (this.froms.menuType == "menu" || this.froms.menuType == "button") &&
+        !this.froms.parentMenuId
+      ) {
+        flag = !1;
+        this.$message.warning("请选择上级菜单!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加菜单
+    addOrEditMenu() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url: _type == "add" ? "basic/menu/add" : "basic/menu/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getMenuButList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除菜单
+    deleteMenu() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/menu/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getMenuButList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 查询应用列表
+    getAppList() {
+      return new Promise((resolve, reject) => {
+        this.axios({
+          url: "basic/app/select",
+          method: METHOD_GET
+        })
+          .then(res => {
+            if (res.code == 0) {
+              if (res.appList.length > 0) {
+                this.curAppId = res.appList[0].id;
+                // this.froms.appId = res.appList[0].id;
+                this.appList = res.appList;
+              }
+              resolve(res);
+            } else {
+              this.$message.error(res.msg);
+            }
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
+    },
+
+    //获取对应App菜单&按钮列表
+    getMenuButList() {
+      this.axios({
+        url: "basic/menu/list/" + this.curAppId,
+        method: METHOD_GET
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.length > 0) {
+            this.setMenuButList(res);
+          } else {
+            this.loadDatas = [];
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    setMenuButList(arr) {
+      const _menyList = toTree(arr);
+      this.loadDatas = _menyList;
+    },
+
+    getMenuInfo() {
+      const _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/menu/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          this.visible = !0;
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.menu;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取对应App菜单列表
+    getMenuList() {
+      this.axios({
+        url: "basic/menu/select/" + this.curAppId,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0 && res.menuList.length > 0)
+            this.setMenuList(res.menuList);
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    setMenuList(arr) {
+      arr.splice(arr.length - 1, 1);
+      const _pmenuList = toTree(arr);
+      _pmenuList.forEach(pitem => {
+        delete pitem.addDataTime;
+        delete pitem.modifyDataTime;
+        delete pitem.appId;
+        delete pitem.id;
+        delete pitem.menuCode;
+        delete pitem.menuContextPath;
+        delete pitem.menuIcon;
+        delete pitem.menuName;
+        delete pitem.menuPath;
+        delete pitem.menuPerms;
+        delete pitem.menuRemark;
+        delete pitem.menuShowType;
+        delete pitem.menuStatus;
+        delete pitem.menuType;
+        delete pitem.open;
+        delete pitem.parentMenuId;
+        delete pitem.parentMenuName;
+        delete pitem.sortNo;
+        delete pitem.subMenuList;
+        let _cmenyList = pitem.children;
+        _cmenyList &&
+          _cmenyList.forEach(citem => {
+            delete citem.addDataTime;
+            delete citem.modifyDataTime;
+            delete citem.appId;
+            delete citem.id;
+            delete citem.menuCode;
+            delete citem.menuContextPath;
+            delete citem.menuIcon;
+            delete citem.menuName;
+            delete citem.menuPath;
+            delete citem.menuPerms;
+            delete citem.menuRemark;
+            delete citem.menuShowType;
+            delete citem.menuStatus;
+            delete citem.menuType;
+            delete citem.open;
+            delete citem.parentMenuId;
+            delete citem.parentMenuName;
+            delete citem.sortNo;
+            delete citem.subMenuList;
+          });
+      });
+      this.menuTreeData = [
+        {
+          title: "顶级菜单",
+          value: null,
+          key: null,
+          children: _pmenuList
+        }
+      ];
+    }
+  },
+
+  created() {
+    //列表数据请求
+    this.getAppList().then(res => {
+      this.getMenuButList();
+      this.getMenuList();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 231 - 0
src/views/platform/operationLog.vue

@@ -0,0 +1,231 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用平台">
+              <a-select placeholder="请选择" v-model="queryParam.appId" @change="choiceAppId">
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="用户编号">
+              <a-input v-model="queryParam.userNumber" placeholder="请填写用户编号" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="登录账号">
+              <a-input v-model="queryParam.userLoginName" placeholder="请填写登录账号" />
+            </a-form-item>
+          </a-col>
+
+          <a-col :md="24" :sm="24">
+            <span class="table-page-search-submitButtons" style="float:right">
+              <a-button type="primary" @click="queryOperator">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination"></a-table>
+
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "用户编号",
+    width: "10%",
+    dataIndex: "userNumber"
+  },
+  {
+    title: "登录名",
+    width: "10%",
+    dataIndex: "userLoginName",
+    align: "center"
+  },
+  {
+    title: "用户操作",
+    width: "10%",
+    dataIndex: "operation",
+    align: "center"
+  },
+  {
+    title: "请求方式",
+    width: "20%",
+    dataIndex: "method",
+    align: "center"
+  },
+  {
+    title: "请求参数",
+    width: "20%",
+    dataIndex: "params",
+    align: "center"
+  },
+  {
+    title: "执行时长(毫秒)",
+    width: "8%",
+    dataIndex: "timeConsuming",
+    align: "center"
+  },
+  {
+    title: "访问IP",
+    width: "10%",
+    dataIndex: "visitIp",
+    align: "center"
+  },
+  {
+    title: "操作时间",
+    width: "12%",
+    dataIndex: "addDataTime",
+    align: "center"
+  }
+];
+
+export default {
+  name: "systemLog",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      queryParam: {
+        appId: null,
+        userNumber: null,
+        userLoginName: null
+      }, //搜索查询参数
+
+      loadDatas: [], //表格请求的数据
+      columns: columns, //表头
+      pagination: false, //不显示分页
+
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      appList: []
+    };
+  },
+  watch: {},
+  methods: {
+    //选择appid
+    choiceAppId(id) {
+      this.queryParam.appId = id;
+      this.getLogList();
+    },
+
+    //查询
+    queryOperator() {
+      this.getLogList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.userNumber = null;
+      this.queryParam.userLoginName = null;
+    },
+
+    // 查询应用列表
+    getAppList() {
+      return new Promise((resolve, reject) => {
+        this.axios({
+          url: "basic/app/select",
+          method: METHOD_GET
+        })
+          .then(res => {
+            if (res.code == 0) {
+              if (res.appList.length > 0) {
+                this.queryParam.appId = res.appList[0].id;
+                this.appList = res.appList;
+              }
+              resolve(res);
+            } else {
+              this.$message.error(res.msg);
+            }
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
+    },
+
+    //获取对应App菜单列表
+    getLogList() {
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/log/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getLogList();
+    }
+  },
+
+  created() {
+    //列表数据请求
+    this.getAppList().then(res => {
+      this.getLogList();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 730 - 0
src/views/platform/operatorManagement.vue

@@ -0,0 +1,730 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用平台">
+              <a-select placeholder="请选择" v-model="queryParam.appId" @change="choiceAppId">
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="用户手机号">
+              <a-input v-model="queryParam.userMobilePhone" placeholder="请填写手机号" />
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item label="用户编号">
+                <a-input v-model="queryParam.userNumber" placeholder="请填写用户编号" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="用户登录名">
+                <a-input v-model="queryParam.userLoginName" placeholder="请填写用户登录名" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="操作员类型">
+                <a-select placeholder="请选择" v-model="queryParam.operatorType">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option :value="v.typeCode" v-for="(v,i) of operatorTypeList" :key="i">{{v.typeName}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="操作员级别">
+                <a-select placeholder="请选择" v-model="queryParam.operatorLevel">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="super_admin">超级管理员</a-select-option>
+                  <a-select-option value="belonging_admin">归属管理员</a-select-option>
+                  <a-select-option value="ordinary_operator">普通操作员</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="操作员状态">
+                <a-select placeholder="请选择" v-model="queryParam.operatorStatus">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="!advanced && 8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+              <a-button type="primary" @click="queryOperator">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+              <a @click="toggleAdvanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'" />
+              </a>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="modifyOperator('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="modifyOperator('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="modifyOperator('delete')">删除</a-button>
+      <a-button type="primary" icon="key" @click="modifyOperator('reset')">重置登录密码</a-button>
+      <a-button type="primary" icon="setting" @click="modifyOperator('init')">初始化账号</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+      <template slot="userMobilePhone" slot-scope="record">
+        <span>{{mobileToStar(record)}}</span>
+      </template>
+
+      <template slot="operatorType" slot-scope="record">
+        <a-tag v-if="v.typeCode==record" v-for="(v,i) of operatorTypeList" :key="i">{{v.typeName}}</a-tag>
+      </template>
+
+      <span slot="operatorLevel" slot-scope="record">
+        <a-tag v-if="record=='super_admin'" color="#108ee9">超级管理员</a-tag>
+        <a-tag v-if="record=='belonging_admin'" color="#2db7f5">归属管理员</a-tag>
+        <a-tag v-if="record=='ordinary_operator'" color="#f0ad4e">普通操作员</a-tag>
+        <a-tag v-else color="#f0ad4e">其他</a-tag>
+      </span>
+
+      <span slot="operatorStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+
+      <template slot="Action" slot-scope="text,record">
+        <span>
+          <a href="javascript:;" @click="modifyOperator('detail', record)">详情</a>
+        </span>
+      </template>
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':editType=='reset'?'400px':editType=='init'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项码?</p>
+      <p v-else-if="editType=='reset'">确认重置此操作员登录密码?</p>
+      <p v-else-if="editType=='init'">确认初始化此操作员用户账号吗?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用平台" :required="true">
+                <a-select v-model="froms.appId" placeholder="请选择" disabled>
+                  <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="操作员类型" :required="true">
+                <a-select v-model="froms.operatorType" placeholder="请选择" :disabled="editType=='detail'">
+                  <a-select-option :value="v.typeCode" v-for="(v,i) of operatorTypeList" :key="i">{{v.typeName}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="操作员级别" :required="true">
+                <a-select v-model="froms.operatorLevel" placeholder="请选择" :disabled="editType=='detail'">
+                  <a-select-option value="ordinary_operator">普通操作员</a-select-option>
+                  <a-select-option value="belonging_admin">归属管理员</a-select-option>
+                  <a-select-option value="super_admin">超级管理员</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="用户手机号" :required="true">
+                <a-input v-model="froms.userMobilePhone" :placeholder="editType=='detail'?'':'请填写手机号'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="用户登录名" :required="true">
+                <a-input v-model="froms.userLoginName" :placeholder="editType=='detail'?'':'请填写登录名'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="操作员姓名" :required="true">
+                <a-input v-model="froms.operatorName" :placeholder="editType=='detail'?'':'请填写操作员姓名'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="操作员年龄">
+                <a-input v-model="froms.operatorAge" :placeholder="editType=='detail'?'':'请填写操作员年龄'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="操作员邮箱">
+                <a-input v-model="froms.operatorEmail" :placeholder="editType=='detail'?'':'请填写操作员邮箱'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="操作员身份证">
+                <a-input v-model="froms.operatorPid" :placeholder="editType=='detail'?'':'请填写操作员身份证'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.operatorRemark" :placeholder="editType=='detail'?'':'请填写备注'" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="是否启用">
+                <a-select v-model="froms.operatorStatus" placeholder="请选择" :disabled="editType=='detail'">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="24" :sm="24">
+              <a-form-item label="选择角色">
+                <a-checkbox-group :options="roleList" v-model="froms.roleIdList" :disabled="editType=='detail'" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import { mobileToStar } from "@/utils/util";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "用户编号",
+    dataIndex: "userNumber",
+    align: "center"
+  },
+  {
+    title: "用户手机号",
+    dataIndex: "userMobilePhone",
+    align: "center",
+    scopedSlots: { customRender: "userMobilePhone" }
+  },
+  {
+    title: "用户登录名",
+    dataIndex: "userLoginName",
+    align: "center"
+  },
+  {
+    title: "操作员名称",
+    dataIndex: "operatorName",
+    align: "center"
+  },
+  {
+    title: "操作员类型",
+    dataIndex: "operatorType",
+    align: "center",
+    scopedSlots: { customRender: "operatorType" }
+  },
+  {
+    title: "操作员级别",
+    dataIndex: "operatorLevel",
+    align: "center",
+    scopedSlots: { customRender: "operatorLevel" }
+  },
+  {
+    title: "状态",
+    dataIndex: "operatorStatus",
+    align: "center",
+    scopedSlots: { customRender: "operatorStatus" }
+  },
+  {
+    title: "创建时间",
+    dataIndex: "addDataTime",
+    align: "center"
+  },
+  {
+    title: "操作",
+    dataIndex: "Action",
+    align: "center",
+    scopedSlots: { customRender: "Action" }
+  }
+];
+
+export default {
+  name: "operatorManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      mobileToStar,
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        appId: null,
+        userMobilePhone: null,
+        userNumber: null,
+        userLoginName: null,
+        operatorType: "",
+        operatorLevel: "",
+        operatorStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      appList: [], //应用列表
+      operatorTypeList: [], //操作员类型
+      roleList: [], //角色配置列表
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      treeData: [], //菜单按钮权限树结构
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //高级搜索 展开/收起
+    toggleAdvanced() {
+      this.advanced = !this.advanced;
+    },
+
+    //查询
+    queryOperator() {
+      this.getOperatorList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.userMobilePhone = null;
+      this.queryParam.userLoginName = null;
+      this.queryParam.userNumber = null;
+      this.queryParam.operatorType = "";
+      this.queryParam.operatorLevel = "";
+      this.queryParam.operatorStatus = "";
+    },
+
+    //选择appid
+    choiceAppId(id) {
+      this.queryParam.appId = id;
+      this.getOperatorList();
+      this.getOperatorTypeList();
+      this.getRoleList();
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //菜单功能权限筛选
+    onCheckPermission(selectedKeys) {},
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteOperator();
+      } else if (_type == "reset") {
+        this.resetOperatorPwd();
+      } else if (_type == "init") {
+        this.initOperatorUser();
+      } else if (_type == "detail") {
+        this.handleCancel();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditOperator();
+      }
+    },
+
+    //新建Or编辑菜单
+    modifyOperator(e, o) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          appId: this.queryParam.appId,
+          operatorType: undefined,
+          operatorLevel: "ordinary_operator",
+          userMobilePhone: null,
+          userLoginName: null,
+          operatorName: null,
+          operatorAge: null,
+          operatorEmail: null,
+          operatorPid: null,
+          operatorStatus: "enabled",
+          roleRemark: null,
+          roleIdList: []
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getOperatorInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      } else if (this.editType == "reset") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择重置密码项!");
+          return false;
+        } else {
+          this.modalTitle = "重置密码";
+          this.visible = !0;
+        }
+      } else if (this.editType == "init") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择初始化项!");
+          return false;
+        } else {
+          this.modalTitle = "初始化账号";
+          this.visible = !0;
+        }
+      } else if (this.editType == "detail") {
+        this.modalTitle = "详情";
+        this.getOperatorInfo(o.id);
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      let mobileReg = /^(1)[0-9]{10}$/;
+      let emailReg = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
+      let pIdReg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/;
+      if (!this.froms.operatorType) {
+        flag = !1;
+        this.$message.warning("请选择操作员类型!");
+        return false;
+      } else if (!this.froms.operatorLevel) {
+        flag = !1;
+        this.$message.warning("请选择操作员级别!");
+        return false;
+      } else if (!mobileReg.test(this.froms.userMobilePhone)) {
+        flag = !1;
+        this.$message.warning("请填写用户有效手机号!");
+        return false;
+      } else if (!this.froms.userLoginName) {
+        flag = !1;
+        this.$message.warning("请填写用户登录名!");
+        return false;
+      } else if (!this.froms.operatorName) {
+        flag = !1;
+        this.$message.warning("请填写操作员姓名!");
+        return false;
+      } else if (this.froms.operatorEmail) {
+        if (!emailReg.test(this.froms.operatorEmail)) {
+          flag = !1;
+          this.$message.warning("请填写有效的邮箱!");
+          return false;
+        } else {
+          return flag;
+        }
+      } else if (this.froms.operatorPid) {
+        if (!pIdReg.test(this.froms.operatorEmail)) {
+          flag = !1;
+          this.$message.warning("请填写有效的身份证号!");
+          return false;
+        } else {
+          return flag;
+        }
+      } else {
+        return flag;
+      }
+    },
+
+    //添加操作员
+    addOrEditOperator() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url: _type == "add" ? "basic/operator/add" : "basic/operator/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getOperatorList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除操作员
+    deleteOperator() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/operator/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getOperatorList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //重置操作员密码
+    resetOperatorPwd() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/operator/resetLoginPwd/" + _id,
+        method: METHOD_PUT
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("重置成功!");
+            this.getOperatorList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //重置操作员账号
+    initOperatorUser() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/operator/initOperatorUser/" + _id,
+        method: METHOD_POST
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("重置成功!");
+            this.getOperatorList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取应用列表
+    getAppList() {
+      return new Promise((resolve, reject) => {
+        this.axios({
+          url: "basic/app/select",
+          method: METHOD_GET
+        })
+          .then(res => {
+            if (res.code == 0) {
+              if (res.appList.length > 0) {
+                this.queryParam.appId = res.appList[0].id;
+                this.appList = res.appList;
+              }
+              resolve(res);
+            } else {
+              this.$message.error(res.msg);
+            }
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
+    },
+
+    // 获取角色数据列表
+    getOperatorList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/operator/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getOperatorInfo(id) {
+      let _id = null;
+      if (id) _id = id;
+      else _id = this.selectedRows[0].id;
+
+      this.axios({
+        url: "basic/operator/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.operator;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取操作员类型
+    getOperatorTypeList() {
+      this.axios({
+        url: "basic/operatorType/select/" + this.queryParam.appId,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            let _list = res.typeList;
+            if (_list.length > 0) {
+              this.operatorTypeList = _list;
+            } else {
+              this.operatorTypeList = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色配置
+    getRoleList() {
+      this.axios({
+        url: "basic/role/select/" + this.queryParam.appId,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            let _list = res.list;
+            if (_list.length > 0) {
+              this.setRoleList(_list);
+            } else {
+              this.roleList = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+    //
+    setRoleList(arr) {
+      let _roleList = arr.map(item => {
+        return { label: item.roleName, value: item.id };
+      });
+      this.roleList = _roleList;
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getOperatorList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getAppList().then(res => {
+      this.getOperatorList();
+      this.getOperatorTypeList();
+      this.getRoleList();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 470 - 0
src/views/platform/operatorTypeManagement.vue

@@ -0,0 +1,470 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用平台">
+              <a-select placeholder="请选择" v-model="queryParam.appId" @change="choiceAppId">
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="类型名称">
+              <a-input v-model="queryParam.typeName" placeholder="请填写类型名称" />
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item label="类型代码">
+                <a-input v-model="queryParam.typeCode" placeholder="请填写类型代码" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="分组编号">
+                <a-input v-model="queryParam.groupNumber" placeholder="请填写分组编号" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="类型状态">
+                <a-select placeholder="请选择" v-model="queryParam.typeStatus">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="!advanced && 8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+              <a-button type="primary" @click="queryOperator">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+              <a @click="toggleAdvanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'" />
+              </a>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="addOrEditOrRemovOperator('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="addOrEditOrRemovOperator('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="addOrEditOrRemovOperator('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+
+      <span slot="typeStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项码?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用平台" :required="true">
+                <a-select placeholder="请选择" v-model="froms.appId" disabled>
+                  <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="类型名称" :required="true">
+                <a-input v-model="froms.typeName" placeholder="请填写类型名称" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="类型代码" :required="true">
+                <a-input v-model="froms.typeCode" placeholder="请填写唯一的类型代码" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="分组编号" :required="true">
+                <a-input v-model="froms.groupNumber" placeholder="请填写分组编号" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="默认角色编码">
+                <a-input v-model="froms.defaultRoleCode" placeholder="请填写默认角色编码" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.typeRemark" placeholder="请填写备注" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="是否启用">
+                <a-select placeholder="请选择" v-model="froms.typeStatus">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+import { toTree } from "@/utils/util";
+
+const columns = [
+  {
+    title: "类型名称",
+    dataIndex: "typeName",
+    align: "center"
+  },
+  {
+    title: "类型代码",
+    dataIndex: "typeCode",
+    align: "center"
+  },
+  {
+    title: "分组编号",
+    dataIndex: "groupNumber",
+    align: "center"
+  },
+  {
+    title: "默认角色编码",
+    dataIndex: "defaultRoleCode",
+    align: "center"
+  },
+  {
+    title: "备注",
+    dataIndex: "typeRemark",
+    align: "center"
+  },
+  {
+    title: "类型状态",
+    dataIndex: "typeStatus",
+    align: "center",
+    scopedSlots: { customRender: "typeStatus" }
+  }
+];
+
+export default {
+  name: "operatorTypeManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        appId: null,
+        typeName: null,
+        typeCode: null,
+        groupNumber: null,
+        typeStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      appList: [], //应用列表
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //高级搜索 展开/收起
+    toggleAdvanced() {
+      this.advanced = !this.advanced;
+    },
+
+    //查询
+    queryOperator() {
+      this.getOperatorTypeList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.typeName = null;
+      this.queryParam.typeCode = null;
+      this.queryParam.groupNumber = null;
+      this.queryParam.typeStatus = "";
+    },
+
+    //选择appid
+    choiceAppId(id) {
+      this.queryParam.appId = id;
+      this.getOperatorTypeList();
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteOperator();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditOperator();
+      }
+    },
+
+    //新建Or编辑菜单
+    addOrEditOrRemovOperator(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          appId: this.queryParam.appId,
+          typeName: null,
+          typeCode: null,
+          groupNumber: null,
+          defaultRoleCode: null,
+          typeRemark: null,
+          typeStatus: "enabled"
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getOperatorTypeInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      if (!this.froms.typeName) {
+        flag = !1;
+        this.$message.warning("请填写类型名称!");
+        return false;
+      } else if (!this.froms.typeCode) {
+        flag = !1;
+        this.$message.warning("请填写类型代码!");
+        return false;
+      } else if (!this.froms.groupNumber) {
+        flag = !1;
+        this.$message.warning("请填写分组编号!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加操作员类型
+    addOrEditOperator() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url:
+          _type == "add"
+            ? "basic/operatorType/add"
+            : "basic/operatorType/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getOperatorTypeList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除菜单
+    deleteOperator() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/operatorType/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getOperatorTypeList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取应用列表
+    getAppList() {
+      return new Promise((resolve, reject) => {
+        this.axios({
+          url: "basic/app/select",
+          method: METHOD_GET
+        })
+          .then(res => {
+            if (res.code == 0) {
+              if (res.appList.length > 0) {
+                this.queryParam.appId = res.appList[0].id;
+                this.appList = res.appList;
+              }
+              resolve(res);
+            } else {
+              this.$message.error(res.msg);
+            }
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
+    },
+
+    // 获取角色数据列表
+    getOperatorTypeList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/operatorType/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getOperatorTypeInfo() {
+      const _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/operatorType/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.app;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getOperatorTypeList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getAppList().then(res => {
+      this.getOperatorTypeList();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 388 - 0
src/views/platform/parameterManagement.vue

@@ -0,0 +1,388 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="参数键">
+              <a-input v-model="queryParam.configKey" placeholder="请填写参数键" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="状态">
+              <a-select placeholder="请选择" v-model="queryParam.resetType">
+                <a-select-option value="">全部</a-select-option>
+                <a-select-option value="enabled">启用</a-select-option>
+                <a-select-option value="disabled">禁用</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <span class="table-page-search-submitButtons" style="float:'right'">
+              <a-button type="primary" @click="queryParameter">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="modifyParameter('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="modifyParameter('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="modifyParameter('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+
+      <span slot="configStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="参数键" :required="true">
+                <a-input v-model="froms.configKey" placeholder="请填写参数键(以字母及'_'链接)" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="参数值" :required="true">
+                <a-input v-model="froms.configValue" placeholder="请填写参数值" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="参数格式" :required="true">
+                <a-input v-model="froms.configFormat" placeholder="请填写参数格式(如:“string”或“json_object”)" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="状态">
+                <a-select v-model="froms.configStatus" placeholder="请选择">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.configRemark" placeholder="请填写备注" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "参数键",
+    width: "20%",
+    dataIndex: "configKey",
+    align: "center"
+  },
+  {
+    title: "参数值",
+    width: "30%",
+    dataIndex: "configValue",
+    align: "center"
+  },
+  {
+    title: "参数格式",
+    width: "15%",
+    dataIndex: "configFormat",
+    align: "center"
+  },
+  {
+    title: "状态",
+    width: "15%",
+    dataIndex: "configStatus",
+    align: "center",
+    scopedSlots: { customRender: "configStatus" }
+  },
+  {
+    title: "备注",
+    width: "20%",
+    dataIndex: "configRemark",
+    align: "center"
+  }
+];
+
+export default {
+  name: "parameterManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      queryParam: {
+        configKey: null,
+        configStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //查询
+    queryParameter() {
+      this.getParameterList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.configKey = null;
+      this.queryParam.configStatus = "";
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteParameter();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditParameter();
+      }
+    },
+
+    //操作参数
+    modifyParameter(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          configKey: null,
+          configValue: null,
+          configFormat: null,
+          configRemark: null,
+          configStatus: "enabled"
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getParameterInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      let reg = /^\w+$/;
+
+      if (!reg.test(this.froms.configKey)) {
+        flag = !1;
+        this.$message.warning("请填写有效的参数键!");
+        return false;
+      } else if (!this.froms.configValue) {
+        flag = !1;
+        this.$message.warning("请填写参数值!");
+        return false;
+      } else if (!this.froms.configFormat) {
+        flag = !1;
+        this.$message.warning("请填写参数格式!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加参数
+    addOrEditParameter() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url: _type == "add" ? "basic/config/add" : "basic/config/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getParameterList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除参数
+    deleteParameter() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/config/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getParameterList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+
+    // 获取参数数据列表
+    getParameterList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/config/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getParameterInfo(id) {
+      let _id = null;
+      if (id) _id = id;
+      else _id = this.selectedRows[0].id;
+
+      this.axios({
+        url: "basic/config/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.config;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getParameterList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getParameterList();
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 386 - 0
src/views/platform/provinceManagement.vue

@@ -0,0 +1,386 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <QueryCondition
+      :queryValue = "queryValue"
+      :queryStatus = "queryStatus"
+      :appList = "appList"
+      @inquire = "inquire"
+      @changeAppID = "changeAppID"
+    >
+    </QueryCondition>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <div style="display: inline"><a-button type="primary" @click="addOrEditButton('add')" icon="plus">新建</a-button></div>
+      <div style="display: inline"><a-button type="primary" @click="addOrEditButton('edit')" icon="edit">编辑</a-button></div>
+      <AddOrEdit
+        :optionType="optionType"
+        :showDlg="showDlg"
+        :queryDataBefore="query"
+        :queryAddOrEditStatus="queryAddOrEditStatus"
+        :queryAddOrEditSupport="queryAddOrEditSupport"
+        :appList = "appList"
+        @handleAddOrEdit="handleAddOrEdit"
+        @handleCancel="handleCancel"
+      >
+      </AddOrEdit>
+      <!-- <a-dropdown>
+        <a-menu slot="overlay">
+          <a-menu-item key="1">启用</a-menu-item>
+          <a-menu-item key="2">禁用</a-menu-item>
+          <a-menu-item key="3">删除</a-menu-item>
+        </a-menu>
+        <a-button style="color: rgb(24, 144, 255)">
+          批量操作 <a-icon type="down" />
+        </a-button>
+      </a-dropdown> -->
+    </div>
+    <p style="height:40px;background:#e6f7ff;lineHeight:40px;padding:0 10px;border:1px solid #bae7ff">已选择&nbsp;<span style="color:#1890ff">{{ choose }}</span>&nbsp;项&nbsp;&nbsp;<span @click="handleDelete" style="color:#1890ff;cursor:pointer;">清空</span></p>
+    <!--表格-->
+    <a-table
+      style="background:#fff"
+      :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+      type="radio"
+      :columns="columns"
+      :dataSource="data"
+      :pagination="pagination"
+      :loading="loading"
+    >
+      <span slot="regionGroupCode" slot-scope="regionGroupCode">
+        <span v-if="regionGroupCode=='default'">默认</span>
+        <span v-else>其他</span>
+      </span>
+      <span slot="regionStatus" slot-scope="regionStatus">
+        <span v-if="regionStatus=='enabled'">启用</span>
+        <span v-else>禁用</span>
+      </span>
+      <span slot="row_handles" slot-scope="regionStatus">
+        <span v-if="regionStatus=='enabled'">禁用</span>
+        <span v-else>启用</span>
+      </span>
+    </a-table>
+    <!--分页-->
+    <Pagination
+      :current="current"
+      :pageSizeOptions="pageSizeOptions"
+      :pageSize="pageSize"
+      :total="total"
+      :totalPage="totalPage"
+      @change="change"
+    >
+    </Pagination>
+  </div>
+</template>
+
+<script>
+  import STable from '@/components/table/';
+  import Pagination from '@/components/pagination/pagination';
+  import QueryCondition from '@/components/queryCondition/queryCondition';
+  import AddOrEdit from '@/components/addOrEdit/addOrEdit';
+  import { BASEURL, METHOD_POST, METHOD_DELETE, METHOD_PUT } from '@/api/public';
+  import { queryStatus, querySupport, queryAddOrEditStatus, queryAddOrEditSupport } from '@/components/public';
+
+  const columns = [{
+    title: '区域名称',
+    dataIndex: 'regionName',
+    align:'center'
+  }, {
+    title: '区域代码',
+    dataIndex: 'regionCode',
+    align:'center'
+  }, {
+    title: '上级区域',
+    dataIndex: 'parentRegionId',
+    align:'center'
+  }, {
+    title: '排序号',
+    dataIndex: 'sortNo',
+    align:'center'
+  }, {
+    title: '分组',
+    dataIndex: 'regionGroupCode',
+    align:'center',
+    scopedSlots: { customRender: 'regionGroupCode' },
+  }, {
+    title: '状态',
+    dataIndex: 'regionStatus',
+    align:'center',
+    scopedSlots: { customRender: 'regionStatus' },
+  }, {
+    title: '备注',
+    dataIndex: 'regionRemark',
+    align:'center'
+  }];
+
+  const queryValue = [
+    { param: 'regionName', name: '区域名称', value: null },
+    { param: 'regionStatus', name: '状态', value: null },
+    { param: 'regionCode', name: '区域代码', value: null },
+    { param: 'regionGroupCode', name: '分组', value: null }
+  ];
+  const queryData = [
+    { param: 'id', name: '区域ID', required: true, value: null },
+    { param: 'parentRegionId', name: '上级区域ID', value: null },
+    { param: 'regionCode', name: '区域代码', required: true, value: null },
+    { param: 'regionGroupCode', name: '分组', required: true, value: 'default' },
+    { param: 'regionName', required: true, name: '区域名称', value: null },
+    { param: 'regionRemark', name: '备注', value: null },
+    { param: 'regionStatus', required: true, name: '状态', value: 'enabled' },
+    { param: 'sortNo', required: true, name: '排序号', value: null }
+  ]
+  //数据
+  const data = [{}];
+  const query = [];
+  export default {
+    name: "TableList",
+    components: {
+      STable,
+      Pagination,
+      QueryCondition,
+      AddOrEdit
+    },
+    data(){
+      return{
+        advanced:false,
+        data,//表格请求的数据
+        columns,//表头
+        pagination:false,//不显示分页
+        //分页
+        pageSizeOptions: ['10', '20', '50', '100'],
+        current: 1,//当前的页数
+        pageSize:0,//每页显示的条数
+        totalPage:0,//总页数
+        total: 0,//总条数
+        loading:true,
+        choose:0,//已选择多少项
+        showQuickJumper:true,//显示跳转页
+        optionType: '',
+        showDlg: false,
+        queryAddOrEditSupport: queryAddOrEditSupport,
+        queryAddOrEditStatus: queryAddOrEditStatus,
+        queryStatus: queryStatus,
+        querySupport: querySupport,
+        queryValue,
+        query,
+        queryData,
+        selectedRowKeys: [], // Check here to configure the default column
+        queryCondition: {},
+        appList: [],
+        appId: null
+      }
+    },
+    watch: {
+      selectedRowKeys: function(selectedRowKeys) {
+        console.log(selectedRowKeys)
+        this.choose = selectedRowKeys.length
+      }
+    },
+    methods:{
+      onSelectChange (selectedRowKeys) {
+        console.log('selectedRowKeys changed: ', selectedRowKeys);
+        this.selectedRowKeys = selectedRowKeys
+      },
+      // 清空
+      handleDelete() {
+        let that = this
+        if(that.selectedRowKeys.length < 1) {
+          this.$message.warning('请至少选择一条记录!')
+        } else {
+          this.$confirm({
+            title: '提示',
+            content: '请确定是否清空数据?',
+            onOk() {
+              let idArray = [];
+              for(let i = 0; i < that.selectedRowKeys.length; i++) {
+               let index = that.selectedRowKeys[i]
+                for(let j = 0; j < that.data.length; j++) {
+                  if(index==j){
+                  idArray.push(that.data[j].id)
+                  }
+                }
+              }
+              that.loading = true
+              that.axios({
+                url:  'basic/region/province/remove/' + idArray,
+                method: METHOD_DELETE
+              }).then((res) => {
+                //请求成功
+                that.loading = false
+                console.log(res)
+                if(res.code == 0) {
+                  that.$message.success('清空成功!');
+                  that.selectedRowKeys = []
+                  let data = { currentPage:that.current, pageSize:that.pageSize, where: that.queryCondition }
+                  that.listAPI(data);
+                } else {
+                  that.$message.success(res.msg);
+                }}).catch(() => {
+                that.loading = false;
+                that.$message.error('请求超时!');
+              })
+            },
+            onCancel() {
+              that.loading = false
+            },
+          });
+        }
+      },
+      // 取消
+      handleCancel() {
+        this.showDlg = false
+        this.query = JSON.parse(JSON.stringify(this.queryData))
+        console.log(this.queryData)
+        console.log(this.query)
+      },
+      // 新增 || 编辑 确定
+      handleAddOrEdit(data) {
+        this.showDlg = false
+        this.query = JSON.parse(JSON.stringify(this.queryData))
+        console.log(data)
+        this.loading = true
+        let queryEditCondition = {};
+        data.forEach(item => {
+          queryEditCondition[item.param] = item.value
+        })
+        if(this.optionType == 'add') {
+          // 新增
+          this.addOrEditDatalist('basic/region/province/add', queryEditCondition, METHOD_POST)
+        } else if (this.optionType == 'edit') {
+          // 编辑
+          this.addOrEditDatalist('basic/region/province/modify', queryEditCondition, METHOD_PUT)
+        }
+      },
+      // 新增数据请求
+      addOrEditDatalist(url, data , method) {
+        this.axios({
+          url:  url,
+          method: method,
+          data: data
+        }).then(res=>{
+          console.log(res)
+          this.loading=false
+          console.log(11)
+          console.log(res.code)
+          if(res.code == 0) {
+            this.$message.success("操作成功!");
+            this.selectedRowKeys = []
+            let data = { currentPage:this.current, pageSize:this.pageSize, where: this.queryCondition }
+            this.listAPI(data);
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      // 编剧数据请求
+      // 新增 || 编辑
+      addOrEditButton(e) {
+        console.log(e)
+        this.optionType = e;
+        if(this.optionType == 'edit') {
+          if(this.selectedRowKeys.length == 1) {
+            let index = this.selectedRowKeys[0]
+            console.log(index)
+            let queryEditData = this.data[index]
+            this.query.forEach(item => {
+              for(let key in queryEditData) {
+                if(item.param == key) {
+                  item.value = queryEditData[key]
+                }
+              }
+            })
+            this.showDlg = true;
+          } else {
+            this.$message.warning('请选择一条记录!')
+          }
+        } else {
+          this.showDlg = true;
+        }
+      },
+      // 头部查询
+      inquire(data) {
+        if(this.appList.length > 0) {
+          this.queryCondition["appId"] = this.appId
+        }
+        data.forEach(item => {
+          this.queryCondition[item.param] = item.value
+        })
+        this.axios({
+          url:  'basic/region/province/pageList',
+          method: METHOD_POST,
+          data: {
+            currentPage:1,
+            pageSize:10,
+            where: this.queryCondition
+          }}).then(res=>{
+          console.log(res)
+          this.loading=false
+          if(res.code == 0) {
+            this.dealData(res)
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      // 处理数据
+      dealData(res) {
+        this.data = res.page.list
+        this.current =  res.page.currentPage
+        this.totalPage = res.page.totalPage
+        this.total = res.page.totalCount
+        this.pageSize = res.page.pageSize
+      },
+      // 列表请求
+      listAPI(data) {
+        this.axios({
+          url:  'basic/region/province/pageList',
+          method: METHOD_POST,
+          data: data
+        }).then(res=>{
+          console.log(res)
+          this.loading=false
+          if(res.code == 0) {
+            this.dealData(res)
+          } else {
+            this.$message.error(res.msg);
+          }
+        }).catch(() => {
+          this.loading = false;
+          this.$message.error('请求超时!');
+        })
+      },
+      //分页
+      change(data) {
+        let requestData = data;
+        requestData.where = this.queryCondition
+        console.log(requestData)
+        this.listAPI(requestData);
+      },
+      // 获取应用归属id
+      changeAppID(data) {
+        console.log(data)
+        this.appId = data
+      }
+    },
+    created(){//列表数据请求
+      this.query = JSON.parse(JSON.stringify(this.queryData))
+      let data = { currentPage:1, pageSize:10, where: this.queryCondition }
+      this.listAPI(data);
+    }
+  }
+</script>
+
+<style scoped>
+  .table-operator{
+    margin-bottom: 10px;
+  }
+  .ant-pagination{
+    margin-top: 20px;
+    text-align: center
+  }
+</style>

+ 520 - 0
src/views/platform/roleManagement.vue

@@ -0,0 +1,520 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="应用平台">
+              <a-select placeholder="请选择" v-model="queryParam.appId" @change="choiceAppId">
+                <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="角色代码">
+              <a-input v-model="queryParam.roleCode" placeholder="请填写角色代码" />
+            </a-form-item>
+          </a-col>
+          <template v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item label="角色名称">
+                <a-input v-model="queryParam.roleName" placeholder="请填写角色名称" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="角色类型">
+                <a-select placeholder="请选择" v-model="queryParam.roleType">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="default">系统默认</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="角色状态">
+                <a-select placeholder="请选择" v-model="queryParam.roleStatus">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="!advanced && 8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+              <a-button type="primary" @click="queryRole">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+              <a @click="toggleAdvanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'" />
+              </a>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="addOrEditOrRemovRole('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="addOrEditOrRemovRole('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="addOrEditOrRemovRole('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+      <span slot="roleType" slot-scope="record">
+        <a-tag v-if="record=='default'" color="#108ee9">默认</a-tag>
+        <a-tag v-else color="#f0ad4e">其他</a-tag>
+      </span>
+
+      <span slot="roleStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项码?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="应用平台" :required="true">
+                <a-select placeholder="请选择" v-model="froms.appId" disabled>
+                  <a-select-option :value="v.id" v-for="(v,i) of appList" :key="i">{{v.appName}}</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="角色代码" :required="true">
+                <a-input v-model="froms.roleCode" placeholder="请填写角色代码(如:role_code)" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="角色名称" :required="true">
+                <a-input v-model="froms.roleName" placeholder="请填写角色名称" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="角色类型">
+                <a-select placeholder="请选择" v-model="froms.roleType">
+                  <a-select-option value="default">默认</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="是否启用">
+                <a-select placeholder="请选择" v-model="froms.roleStatus">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.roleRemark" placeholder="请填写备注信息" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="24" :sm="24">
+              <a-form-item label="菜单功能权限配置">
+                <a-tree checkable @check="onCheckPermission" v-model="froms.menuIdList" :defaultExpandAll="true" :checkStrictly="true" :treeData="treeData" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+import { toTree } from "@/utils/util";
+
+const columns = [
+  {
+    title: "角色代码",
+    dataIndex: "roleCode",
+    align: "center"
+  },
+  {
+    title: "角色名称",
+    dataIndex: "roleName",
+    align: "center"
+  },
+  {
+    title: "角色类型",
+    dataIndex: "roleType",
+    align: "center",
+    scopedSlots: { customRender: "roleType" }
+  },
+  {
+    title: "角色状态",
+    dataIndex: "roleStatus",
+    align: "center",
+    scopedSlots: { customRender: "roleStatus" }
+  },
+  {
+    title: "备注",
+    dataIndex: "roleRemark",
+    align: "center"
+  },
+  {
+    title: "创建时间",
+    dataIndex: "addDataTime",
+    align: "center"
+  }
+];
+
+//数据
+const data = [{}];
+const query = [];
+export default {
+  name: "roleManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        appId: null,
+        roleCode: null,
+        roleName: null,
+        roleType: "",
+        roleStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      appList: [],
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      treeData: [], //菜单按钮权限树结构
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+  watch: {
+    checkedKeys(val) {
+      console.log("onCheck", val);
+    }
+  },
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //高级搜索 展开/收起
+    toggleAdvanced() {
+      this.advanced = !this.advanced;
+    },
+
+    //查询
+    queryRole() {
+      this.getRoleList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.roleCode = null;
+      this.queryParam.roleName = null;
+      this.queryParam.roleType = null;
+      this.queryParam.roleStatus = null;
+    },
+
+    //选择appid
+    choiceAppId(id) {
+      this.queryParam.appId = id;
+      this.getRoleList();
+      this.getRoleTreeData();
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //菜单功能权限筛选
+    onCheckPermission(selectedKeys, e) {
+      // let _menuIdList = [...selectedKeys, ...e.halfCheckedKeys];
+      //this.froms.menuIdList = _menuIdList;
+      this.froms.menuIdList = selectedKeys.checked;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteRole();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditRole();
+      }
+    },
+
+    //新建Or编辑角色
+    addOrEditOrRemovRole(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+
+        this.froms = {
+          appId: this.queryParam.appId,
+          roleCode: null,
+          roleName: null,
+          roleBelongId: null,
+          roleType: "default",
+          menuIdList: [],
+          roleStatus: "enabled",
+          roleRemark: null
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getRoleInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      if (!this.froms.roleCode) {
+        flag = !1;
+        this.$message.warning("请填写角色代码!");
+        return false;
+      } else if (!this.froms.roleName) {
+        flag = !1;
+        this.$message.warning("请填写角色名称!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加菜单
+    addOrEditRole() {
+      let _type = this.editType;
+      const data = this.froms;
+      console.log(data);
+      this.axios({
+        url: _type == "add" ? "basic/role/add" : "basic/role/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getRoleList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除菜单
+    deleteRole() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/role/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getRoleList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取应用列表
+    getAppList() {
+      return new Promise((resolve, reject) => {
+        this.axios({
+          url: "basic/app/select",
+          method: METHOD_GET
+        })
+          .then(res => {
+            if (res.code == 0) {
+              if (res.appList.length > 0) {
+                this.queryParam.appId = res.appList[0].id;
+                this.appList = res.appList;
+              }
+              resolve(res);
+            } else {
+              this.$message.error(res.msg);
+            }
+          })
+          .catch(err => {
+            reject(err);
+          });
+      });
+    },
+
+    // 获取角色数据列表
+    getRoleList() {
+      this.initSelectedRows();
+
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/role/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getRoleInfo() {
+      const _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/role/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.role;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取用户权限配置树结构
+    getRoleTreeData() {
+      this.axios({
+        url: "basic/menu/list/" + this.queryParam.appId,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.length > 0) this.setRoleTree(res);
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+    //构建树结构
+    setRoleTree(arr) {
+      const _menyList = toTree(arr);
+      this.treeData = _menyList;
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getRoleList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getAppList().then(res => {
+      this.getRoleList();
+      this.getRoleTreeData();
+    });
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+.modal-container {
+  max-height: 500px;
+  padding: 0 12px;
+  overflow-y: auto;
+}
+</style>

+ 546 - 0
src/views/platform/scheduleTask.vue

@@ -0,0 +1,546 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="任务名称">
+              <a-input v-model="queryParam.taskName" placeholder="请填写任务名称" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="bean名称">
+              <a-input v-model="queryParam.beanName" placeholder="请填写bean名称" />
+            </a-form-item>
+          </a-col>
+
+          <template v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item label="cron表达式">
+                <a-input v-model="queryParam.cronExpression" placeholder="请填写cron表达式" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="任务状态">
+                <a-select placeholder="请选择" v-model="queryParam.taskStatus">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </template>
+          <a-col :md="!advanced && 8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+              <a-button type="primary" @click="queryTask">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+              <a @click="toggleAdvanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'" />
+              </a>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="modifyTask('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="modifyTask('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="modifyTask('delete')">删除</a-button>
+      <a-button type="primary" icon="setting" @click="modifyTask('run')">立即执行</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+
+      <span slot="taskStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+        <a-tag v-else-if="record=='paused'" color="#ff976a">已暂停</a-tag>
+      </span>
+
+      <template slot="Action" slot-scope="text,record,index">
+        <span>
+          <a href="javascript:;" @click="modifyTask('pause', record, index)">暂停</a>
+          <a-divider type="vertical" />
+          <a href="javascript:;" @click="modifyTask('resume', record, index)">恢复</a>
+        </span>
+      </template>
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='add'?'800px':editType=='edit'?'800px':'400px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此任务?</p>
+      <p v-else-if="editType=='run'">确认立即执行此任务?</p>
+      <p v-else-if="editType=='pause'">确认暂停此任务?</p>
+      <p v-else-if="editType=='resume'">确认恢复此任务?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="任务名称" :required="true">
+                <a-input v-model="froms.taskName" placeholder="请填写任务名称" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="bean名称" :required="true">
+                <a-input v-model="froms.beanName" placeholder="请填写登录名" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="cron表达式" :required="true">
+                <a-input v-model="froms.cronExpression" placeholder="请填写cron表达式" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="方式名" :required="true">
+                <a-input v-model="froms.methodName" placeholder="请填写方式名" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="参数">
+                <a-input v-model="froms.methodParams" placeholder="请填写参数" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.taskRemark" placeholder="请填写备注" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="是否启用">
+                <a-select v-model="froms.taskStatus" placeholder="请选择">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "任务名称",
+    width: "10%",
+    dataIndex: "taskName",
+    align: "center"
+  },
+  {
+    title: "bean名称",
+    width: "15%",
+    dataIndex: "beanName",
+    align: "center"
+  },
+  {
+    title: "Cron表达式",
+    width: "15%",
+    dataIndex: "cronExpression",
+    align: "center"
+  },
+  {
+    title: "方式名",
+    width: "10%",
+    dataIndex: "methodName",
+    align: "center"
+  },
+  {
+    title: "参数",
+    width: "15%",
+    dataIndex: "methodParams",
+    align: "center"
+  },
+  {
+    title: "状态",
+    width: "8%",
+    dataIndex: "taskStatus",
+    align: "center",
+    scopedSlots: { customRender: "taskStatus" }
+  },
+  {
+    title: "创建时间",
+    width: "15%",
+    dataIndex: "addDataTime",
+    align: "center"
+  },
+  {
+    title: "操作",
+    width: "12%",
+    dataIndex: "Action",
+    align: "center",
+    scopedSlots: { customRender: "Action" }
+  }
+];
+
+export default {
+  name: "scheduleTask",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        taskName: null,
+        beanName: null,
+        cronExpression: null,
+        taskStatus: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //高级搜索 展开/收起
+    toggleAdvanced() {
+      this.advanced = !this.advanced;
+    },
+
+    //查询
+    queryTask() {
+      this.getTaskList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.taskName = null;
+      this.queryParam.beanName = null;
+      this.queryParam.cronExpression = null;
+      this.queryParam.taskStatus = "";
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteTask();
+      } else if (_type == "run") {
+        this.runTask();
+      } else if (_type == "pause") {
+        this.pauseTask();
+      } else if (_type == "resume") {
+        this.resumeTask();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditTask();
+      }
+    },
+
+    //操作任务
+    modifyTask(e, o, index) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          taskName: null,
+          beanName: null,
+          cronExpression: null,
+          methodName: null,
+          methodParams: null,
+          taskRemark: null,
+          taskStatus: 'enabled'
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getTaskInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      } else if (this.editType == "run") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择立即执行项!");
+          return false;
+        } else {
+          this.modalTitle = "立即执行";
+          this.visible = !0;
+        }
+      } else if (this.editType == "pause") {
+        this.modalTitle = "暂停";
+        this.visible = !0;
+        this.selectedRowKeys[0] = index;
+        this.selectedRows[0] = o;
+      } else if (this.editType == "resume") {
+        this.modalTitle = "恢复";
+        this.visible = !0;
+        this.selectedRowKeys[0] = index;
+        this.selectedRows[0] = o;
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      if (!this.froms.taskName) {
+        flag = !1;
+        this.$message.warning("请填写任务名称!");
+        return false;
+      } else if (!this.froms.beanName) {
+        flag = !1;
+        this.$message.warning("请填写bean名称!");
+        return false;
+      } else if (!this.froms.cronExpression) {
+        flag = !1;
+        this.$message.warning("请填写cron表达式!");
+        return false;
+      } else if (!this.froms.methodName) {
+        flag = !1;
+        this.$message.warning("请填写方式名!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加任务
+    addOrEditTask() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url: _type == "add" ? "task/schedule/add" : "task/schedule/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getTaskList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除任务
+    deleteTask() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "task/schedule/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getTaskList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //立即执行任务
+    runTask() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "task/schedule/run/" + _id,
+        method: METHOD_POST
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("任务已执行!");
+            this.getTaskList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //暂停任务
+    pauseTask() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "task/schedule/pause/" + _id,
+        method: METHOD_PUT
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("任务已暂停!");
+            this.getTaskList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //恢复任务
+    resumeTask() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "task/schedule/resume/" + _id,
+        method: METHOD_PUT
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("任务已恢复!");
+            this.getTaskList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取任务数据列表
+    getTaskList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "task/schedule/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getTaskInfo(id) {
+      let _id = null;
+      if (id) _id = id;
+      else _id = this.selectedRows[0].id;
+
+      this.axios({
+        url: "task/schedule/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.schedule;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getTaskList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getTaskList();
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 458 - 0
src/views/platform/sequenceManagement.vue

@@ -0,0 +1,458 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+          <a-col :md="8" :sm="24">
+            <a-form-item label="序列码">
+              <a-input v-model="queryParam.sequenceCode" placeholder="请填写序列码" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="重置类型">
+              <a-select placeholder="请选择" v-model="queryParam.resetType">
+                <a-select-option value="">全部</a-select-option>
+                <a-select-option value="default">默认</a-select-option>
+                <a-select-option value="month">月重置</a-select-option>
+                <a-select-option value="day">日重置</a-select-option>
+                <a-select-option value="hour">时重置</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <span class="table-page-search-submitButtons" style="float:'right'">
+              <a-button type="primary" @click="querySequence">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="modifySequence('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="modifySequence('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="modifySequence('delete')">删除</a-button>
+      <a-button type="primary" icon="setting" @click="modifySequence('reset')">重置值</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+
+      <span slot="resetType" slot-scope="record">
+        <a-tag v-if="record=='default'" color="#87d068">默认</a-tag>
+        <a-tag v-else-if="record=='month'" color="#ff0000">月重置</a-tag>
+        <a-tag v-else-if="record=='day'" color="#ff976a">日重置</a-tag>
+        <a-tag v-else-if="record=='hour'" color="#ff976a">时重置</a-tag>
+      </span>
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':editType=='reset'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此序列?</p>
+      <p v-else-if="editType=='reset'">确认重置此序列?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="序列名" :required="true">
+                <a-input v-model="froms.sequenceName" placeholder="请填写序列名" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="序列码" :required="true">
+                <a-input v-model="froms.sequenceCode" placeholder="请填写序列码(以字母及'_'链接)" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="序列值" :required="true">
+                <a-input v-model="froms.sequenceValue" type="number" placeholder="请填写序列值(只能为数字)" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="流水号头" :required="true">
+                <a-input v-model="froms.serialNumberHead" placeholder="请填写流水号头(如:A、B、C)" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="流水号长度" :required="true">
+                <a-input v-model="froms.serialNumberLength" type="number" placeholder="请填写流水号长度" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="重置类型">
+                <a-select v-model="froms.resetType" placeholder="请选择">
+                  <a-select-option value="default">默认</a-select-option>
+                  <a-select-option value="month">月重置</a-select-option>
+                  <a-select-option value="day">日重置</a-select-option>
+                  <a-select-option value="hour">时重置</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.sequenceRemark" placeholder="请填写备注" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "序列名",
+    width: "15%",
+    dataIndex: "sequenceName",
+    align: "center"
+  },
+  {
+    title: "序列码",
+    width: "15%",
+    dataIndex: "sequenceCode",
+    align: "center"
+  },
+  {
+    title: "序列值",
+    width: "15%",
+    dataIndex: "sequenceValue",
+    align: "center"
+  },
+  {
+    title: "流水号头",
+    width: "10%",
+    dataIndex: "serialNumberHead",
+    align: "center"
+  },
+  {
+    title: "流水号长度",
+    width: "10%",
+    dataIndex: "serialNumberLength",
+    align: "center"
+  },
+  {
+    title: "重置类型",
+    width: "15%",
+    dataIndex: "resetType",
+    align: "center",
+    scopedSlots: { customRender: "resetType" }
+  },
+  {
+    title: "创建时间",
+    width: "20%",
+    dataIndex: "addDataTime",
+    align: "center"
+  }
+];
+
+export default {
+  name: "sequenceManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      queryParam: {
+        sequenceCode: null,
+        resetType: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //查询
+    querySequence() {
+      this.getSequenceList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.sequenceCode = null;
+      this.queryParam.resetType = "";
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteSequence();
+      } else if (_type == "reset") {
+        this.resetSequence();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditSequence();
+      }
+    },
+
+    //操作序列
+    modifySequence(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          sequenceName: null,
+          sequenceCode: null,
+          sequenceValue: null,
+          serialNumberHead: null,
+          serialNumberLength: null,
+          sequenceRemark: null,
+          resetType: "default"
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getSequenceInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      } else if (this.editType == "reset") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择重置项!");
+          return false;
+        } else {
+          this.modalTitle = "重置";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      let reg = /^[A-Z]+$/;
+      let regN = /^\d+$/;
+
+      if (!this.froms.sequenceName) {
+        flag = !1;
+        this.$message.warning("请填写序列名!");
+        return false;
+      } else if (!this.froms.sequenceCode) {
+        flag = !1;
+        this.$message.warning("请填写序列码!");
+        return false;
+      } else if (!regN.test(this.froms.sequenceValue)) {
+        flag = !1;
+        this.$message.warning("请填写数字序列值!");
+        return false;
+      } else if (!reg.test(this.froms.serialNumberHead)) {
+        flag = !1;
+        this.$message.warning("请填写流水号头需大写字母!");
+        return false;
+      } else if (!this.froms.serialNumberLength) {
+        flag = !1;
+        this.$message.warning("请填写流水号长度!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加序列
+    addOrEditSequence() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url: _type == "add" ? "basic/sequence/add" : "basic/sequence/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getSequenceList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除序列
+    deleteSequence() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/sequence/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getSequenceList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //重置序列
+    resetSequence() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/sequence/reset/" + _id,
+        method: METHOD_PUT
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("序列已重置!");
+            this.getSequenceList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取序列数据列表
+    getSequenceList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/sequence/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getSequenceInfo(id) {
+      let _id = null;
+      if (id) _id = id;
+      else _id = this.selectedRows[0].id;
+
+      this.axios({
+        url: "basic/sequence/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.sequence;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getSequenceList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getSequenceList();
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

+ 519 - 0
src/views/platform/smsChannelManagement.vue

@@ -0,0 +1,519 @@
+<template>
+  <div style="background:#fff ;padding:25px;position: relative">
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline">
+        <a-row :gutter="48">
+
+          <a-col :md="8" :sm="24">
+            <a-form-item label="渠道名称">
+              <a-input v-model="queryParam.upstreamChannelName" placeholder="请填写渠道名称" />
+            </a-form-item>
+          </a-col>
+          <!-- <a-col :md="8" :sm="24">
+            <a-form-item label="渠道代码">
+              <a-input v-model="queryParam.upstreamChannelCode" placeholder="请填写渠道代码" />
+            </a-form-item>
+          </a-col>
+          <a-col :md="8" :sm="24">
+            <a-form-item label="状态">
+              <a-select placeholder="请选择" v-model="queryParam.upstreamChannelStatus">
+                <a-select-option value="">全部</a-select-option>
+                <a-select-option value="enabled">启用</a-select-option>
+                <a-select-option value="disabled">禁用</a-select-option>
+              </a-select>
+            </a-form-item>
+          </a-col> -->
+          <!-- <template v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item label="签名自定义">
+                <a-select placeholder="请选择" v-model="queryParam.supportCustomSign">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="support">支持</a-select-option>
+                  <a-select-option value="not_support">不支持</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item label="余量查询">
+                <a-select placeholder="请选择" v-model="queryParam.supportQueryBalance">
+                  <a-select-option value="">全部</a-select-option>
+                  <a-select-option value="support">支持</a-select-option>
+                  <a-select-option value="not_support">不支持</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </template> -->
+
+          <a-col :md="!advanced && 8 || 24" :sm="24">
+            <span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
+              <a-button type="primary" @click="querySmsChannel">查询</a-button>
+              <a-button style="margin-left: 8px" @click="resetQueryParam">重置</a-button>
+              <!-- <a @click="toggleAdvanced" style="margin-left: 8px">
+                {{ advanced ? '收起' : '展开' }}
+                <a-icon :type="advanced ? 'up' : 'down'" />
+              </a> -->
+            </span>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+
+    <!--功能按钮-->
+    <div class="table-operator">
+      <a-button type="primary" icon="plus" @click="modifySmsChannel('add')">新建</a-button>
+      <a-button type="primary" icon="edit" @click="modifySmsChannel('edit')">编辑</a-button>
+      <a-button type="primary" icon="delete" @click="modifySmsChannel('delete')">删除</a-button>
+    </div>
+
+    <!--表格-->
+    <a-table size="middle" :columns="columns" :dataSource="loadDatas" :loading="loading" :pagination="pagination" :rowSelection="{type:'radio', selectedRowKeys: selectedRowKeys, onChange: updateSelect }">
+
+      <span slot="supportCustomSign" slot-scope="record">
+        <a-tag v-if="record=='support'" color="#87d068">支持</a-tag>
+        <a-tag v-else-if="record=='not_support'" color="#ff0000">不支持</a-tag>
+      </span>
+      <span slot="supportQueryBalance" slot-scope="record">
+        <a-tag v-if="record=='support'" color="#87d068">支持</a-tag>
+        <a-tag v-else-if="record=='not_support'" color="#ff0000">不支持</a-tag>
+      </span>
+      <span slot="upstreamChannelStatus" slot-scope="record">
+        <a-tag v-if="record=='enabled'" color="#87d068">启用</a-tag>
+        <a-tag v-else-if="record=='disabled'" color="#ff0000">禁用</a-tag>
+      </span>
+    </a-table>
+    <!--分页-->
+    <Pagination :current="currentPage" :pageSizeOptions="pageSizeOptions" :pageSize="pageSize" :total="totalCount" :totalPage="totalPage" @change="changePage"></Pagination>
+
+    <!-- 新建编辑模态框 -->
+    <a-modal :width="editType=='delete'?'400px':'800px'" :title="modalTitle" :visible="visible" @ok="handleOk" :confirmLoading="confirmLoading" @cancel="handleCancel">
+      <p v-if="editType=='delete'">确认删除此项?</p>
+      <div class="modal-container" v-else>
+        <a-form>
+          <a-row :gutter="24">
+            <a-col :md="12" :sm="24">
+              <a-form-item label="渠道名称" :required="true">
+                <a-input v-model="froms.upstreamChannelName" placeholder="请填写渠道名称" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="渠道代码" :required="true">
+                <a-input v-model="froms.upstreamChannelCode" placeholder="请填写渠道代码(以字母及'_'链接)" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="签名类型" :required="true">
+                <a-input v-model="froms.supportSignType" placeholder="请填写签名类型" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24" :required="true">
+              <a-form-item label="签名自定义">
+                <a-select v-model="froms.supportCustomSign" placeholder="请选择">
+                  <a-select-option value="support">支持</a-select-option>
+                  <a-select-option value="not_support">不支持</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24" :required="true">
+              <a-form-item label="余量查询">
+                <a-select v-model="froms.supportQueryBalance" placeholder="请选择">
+                  <a-select-option value="support">支持</a-select-option>
+                  <a-select-option value="not_support">不支持</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="余量最小预警" :required="true">
+                <a-input v-model="froms.balanceAlarmMin" type="number" placeholder="请填写余量最小预警数值" />
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="余量接收预警" :required="true">
+                <a-input v-model="froms.balanceAlarmReceiver" type="number" placeholder="请填写余量接收预警数值" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24">
+              <a-form-item label="排序" :required="true">
+                <a-input v-model="froms.sortNo" type="number" placeholder="请填写排序数值" />
+              </a-form-item>
+            </a-col>
+
+            <a-col :md="12" :sm="24" v-show="editType=='edit'">
+              <a-form-item label="状态">
+                <a-select v-model="froms.upstreamChannelStatus" placeholder="请选择">
+                  <a-select-option value="enabled">启用</a-select-option>
+                  <a-select-option value="disabled">禁用</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="12" :sm="24">
+              <a-form-item label="备注">
+                <a-input v-model="froms.upstreamChannelRemark" placeholder="请填写备注" />
+              </a-form-item>
+            </a-col>
+
+          </a-row>
+        </a-form>
+      </div>
+    </a-modal>
+  </div>
+</template>
+
+<script>
+import Pagination from "@/components/pagination/pagination";
+import {
+  BASEURL,
+  METHOD_GET,
+  METHOD_POST,
+  METHOD_DELETE,
+  METHOD_PUT
+} from "@/api/public";
+
+const columns = [
+  {
+    title: "渠道名称",
+    width: "10%",
+    dataIndex: "upstreamChannelName",
+    align: "center"
+  },
+  {
+    title: "渠道代码",
+    width: "10%",
+    dataIndex: "upstreamChannelCode",
+    align: "center"
+  },
+  {
+    title: "签名类型",
+    width: "10%",
+    dataIndex: "supportSignType",
+    align: "center"
+  },
+  {
+    title: "签名自定义",
+    width: "10%",
+    dataIndex: "supportCustomSign",
+    align: "center",
+    scopedSlots: { customRender: "supportCustomSign" }
+  },
+  {
+    title: "余量查询",
+    width: "10%",
+    dataIndex: "supportQueryBalance",
+    align: "center",
+    scopedSlots: { customRender: "supportQueryBalance" }
+  },
+  {
+    title: "余量最小预警",
+    width: "10%",
+    dataIndex: "balanceAlarmMin",
+    align: "center"
+  },
+  {
+    title: "余量接收预警",
+    width: "10%",
+    dataIndex: "balanceAlarmReceiver",
+    align: "center"
+  },
+  {
+    title: "排序",
+    width: "10%",
+    dataIndex: "sortNo",
+    align: "center"
+  },
+  {
+    title: "状态",
+    width: "10%",
+    dataIndex: "upstreamChannelStatus",
+    align: "center",
+    scopedSlots: { customRender: "upstreamChannelStatus" }
+  },
+  {
+    title: "备注",
+    width: "10%",
+    dataIndex: "upstreamChannelRemark",
+    align: "center"
+  }
+];
+
+export default {
+  name: "smsChannelManagement",
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advanced: false, // 高级搜索 展开/关闭
+      queryParam: {
+        upstreamChannelName: null,
+        // upstreamChannelCode: null,
+        // upstreamChannelStatus: "",
+        // supportCustomSign: "",
+        // supportQueryBalance: ""
+      }, //搜索查询参数
+
+      columns, //表头
+      loadDatas: [], //表格请求的数据
+      pagination: false, //不显示分页
+
+      //分页
+      pageSizeOptions: ["10", "20", "50", "100"],
+      currentPage: 1, //当前的页数
+      pageSize: 10, //每页显示的条数
+      totalPage: 0, //总页数
+      totalCount: 0, //总条数
+      loading: true,
+
+      selectedRowKeys: [], //选中行键
+      selectedRows: [], //选中行键值,
+
+      froms: {},
+      editType: "add",
+      modalTitle: "新建",
+      visible: !1,
+      confirmLoading: !1
+    };
+  },
+
+  methods: {
+    initSelectedRows() {
+      this.selectedRowKeys = [];
+      this.selectedRows = [];
+    },
+
+    //高级搜索 展开/收起
+    toggleAdvanced() {
+      this.advanced = !this.advanced;
+    },
+
+    //查询
+    querySmsChannel() {
+      this.getSmsChannelList();
+    },
+
+    //重置
+    resetQueryParam() {
+      this.queryParam.upstreamChannelName = null;
+      this.queryParam.upstreamChannelCode = null;
+      this.queryParam.supportCustomSign = "";
+      this.queryParam.supportQueryBalance = "";
+      this.queryParam.upstreamChannelStatus = "";
+    },
+
+    //选择跟新table中的某项
+    updateSelect(selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys;
+      this.selectedRows = selectedRows;
+    },
+
+    //取消
+    handleCancel() {
+      this.visible = !1;
+    },
+
+    //确认
+    handleOk() {
+      let _type = this.editType;
+      if (_type == "delete") {
+        this.deleteSmsChannel();
+      } else {
+        const flag = this.checkData();
+        flag && this.addOrEditSmsChannel();
+      }
+    },
+
+    //操作参数
+    modifySmsChannel(e) {
+      this.editType = e;
+      if (this.editType == "add") {
+        this.modalTitle = "新建";
+        this.visible = !0;
+        this.froms = {
+          upstreamChannelName: null,
+          upstreamChannelCode: null,
+          supportSignType: null,
+          supportCustomSign: "support",
+          supportQueryBalance: "support",
+          balanceAlarmMin: null,
+          balanceAlarmReceiver: null,
+          sortNo: null,
+          upstreamChannelStatus: "default",
+          upstreamChannelRemark: null
+        };
+      } else if (this.editType == "edit") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择编辑项!");
+          return false;
+        } else {
+          this.modalTitle = "编辑";
+          this.getSmsChannelInfo();
+        }
+      } else if (this.editType == "delete") {
+        if (this.selectedRows.length < 1) {
+          this.$message.warning("请选择删除项!");
+          return false;
+        } else {
+          this.modalTitle = "删除";
+          this.visible = !0;
+        }
+      }
+    },
+
+    //数据校验
+    checkData() {
+      let flag = !0;
+      let reg = /^\w+$/;
+
+      if (!this.froms.upstreamChannelName) {
+        flag = !1;
+        this.$message.warning("请填写渠道名称!");
+        return false;
+      } else if (!reg.test(this.froms.upstreamChannelCode)) {
+        flag = !1;
+        this.$message.warning("请填写有效的渠道代码!");
+        return false;
+      } else if (!this.froms.supportSignType) {
+        flag = !1;
+        this.$message.warning("请填写签名类型!");
+        return false;
+      } else if (!this.froms.balanceAlarmMin) {
+        flag = !1;
+        this.$message.warning("请填写余量最小预警值!");
+        return false;
+      } else if (!this.froms.balanceAlarmReceiver) {
+        flag = !1;
+        this.$message.warning("请填写余量接收预警值!");
+        return false;
+      } else {
+        return flag;
+      }
+    },
+
+    //添加参数
+    addOrEditSmsChannel() {
+      let _type = this.editType;
+      let data = this.froms;
+      this.axios({
+        url:
+          _type == "add"
+            ? "basic/sms/upstreamChannel/add"
+            : "basic/sms/upstreamChannel/modify",
+        method: _type == "add" ? METHOD_POST : METHOD_PUT,
+        data: data
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("操作成功!");
+            this.getSmsChannelList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //删除参数
+    deleteSmsChannel() {
+      let _id = this.selectedRows[0].id;
+      this.axios({
+        url: "basic/sms/upstreamChannel/remove/" + _id,
+        method: METHOD_DELETE
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !1;
+            this.$message.success("删除成功!");
+            this.getSmsChannelList();
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    // 获取参数数据列表
+    getSmsChannelList() {
+      this.initSelectedRows();
+      let _data = {
+        pageSize: this.pageSize,
+        currentPage: this.currentPage,
+        where: this.queryParam
+      };
+      this.axios({
+        url: "basic/sms/upstreamChannel/pageList",
+        method: METHOD_POST,
+        data: _data
+      })
+        .then(res => {
+          this.loading = !1;
+          if (res.code == 0) {
+            this.currentPage = res.page.currentPage;
+            this.pageSize = res.page.pageSize;
+            this.totalPage = res.page.totalPage;
+            this.totalCount = res.page.totalCount;
+            if (res.page.list.length > 0) {
+              this.loadDatas = res.page.list;
+            } else {
+              this.loadDatas = [];
+            }
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //获取角色信息
+    getSmsChannelInfo(id) {
+      let _id = null;
+      if (id) _id = id;
+      else _id = this.selectedRows[0].id;
+
+      this.axios({
+        url: "basic/sms/upstreamChannel/info/" + _id,
+        method: METHOD_GET
+      })
+        .then(res => {
+          if (res.code == 0) {
+            this.visible = !0;
+            this.froms = res.upstreamChannel;
+          } else {
+            this.$message.error(res.msg);
+          }
+        })
+        .catch(err => {
+          console.log(err);
+        });
+    },
+
+    //分页
+    changePage(obj) {
+      this.currentPage = obj.currentPage;
+      this.pageSize = obj.pageSize;
+      this.getSmsChannelList();
+    }
+  },
+  created() {
+    //列表数据请求
+    this.getSmsChannelList();
+  }
+};
+</script>
+
+<style scoped>
+.table-operator {
+  margin-bottom: 10px;
+}
+.ant-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+</style>

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