浏览代码

new file: admin-code/.browserslistrc
new file: admin-code/.editorconfig
new file: admin-code/.env
new file: admin-code/.eslintignore
new file: admin-code/.eslintrc.js
new file: admin-code/.gitignore
new file: admin-code/README.md
new file: admin-code/babel.config.js
new file: admin-code/package-lock.json
new file: admin-code/package.json
new file: admin-code/public/favicon.ico
new file: admin-code/public/index.html
new file: admin-code/src/App.vue
new file: admin-code/src/assets/logo.png
new file: admin-code/src/main.js
new file: admin-code/src/public-path.js
new file: admin-code/src/router/index.js
new file: admin-code/src/store/index.js
new file: admin-code/src/views/Home.vue
new file: admin-code/vue.config.js
new file: admin-content/.browserslistrc
new file: admin-content/.editorconfig
new file: admin-content/.env
new file: admin-content/.eslintignore
new file: admin-content/.eslintrc.js
new file: admin-content/.gitignore
new file: admin-content/README.md
new file: admin-content/babel.config.js
new file: admin-content/package-lock.json
new file: admin-content/package.json
new file: admin-content/public/favicon.ico
new file: admin-content/public/index.html
new file: admin-content/src/App.vue
new file: admin-content/src/assets/logo.png
new file: admin-content/src/main.js
new file: admin-content/src/public-path.js
new file: admin-content/src/router/index.js
new file: admin-content/src/store/index.js
new file: admin-content/src/views/home.vue
new file: admin-content/vue.config.js
new file: admin-files/.browserslistrc
new file: admin-files/.editorconfig
new file: admin-files/.eslintignore
new file: admin-files/.eslintrc.js
new file: admin-files/.gitignore
new file: admin-files/README.md
new file: admin-files/babel.config.js
new file: admin-files/package-lock.json
new file: admin-files/package.json
new file: admin-files/public/favicon.ico
new file: admin-files/public/index.html
new file: admin-files/src/App.vue
new file: admin-files/src/assets/logo.png
new file: admin-files/src/main.js
new file: admin-files/src/public-path.js
new file: admin-files/src/router/index.js
new file: admin-files/src/store/index.js
new file: admin-files/src/views/home.vue
new file: admin-files/vue.config.js
new file: admin-frame/.browserslistrc
new file: admin-frame/.editorconfig
new file: admin-frame/.env
new file: admin-frame/.env.development
new file: admin-frame/.env.pre
new file: admin-frame/.eslintrc.js
new file: admin-frame/.gitignore
new file: admin-frame/README.md
new file: admin-frame/babel.config.js
new file: admin-frame/lib/apps.js
new file: admin-frame/lib/axios.js
new file: admin-frame/lib/dict.js
new file: admin-frame/lib/qiankun.js
new file: admin-frame/lib/resChange.js
new file: admin-frame/lib/tree.js
new file: admin-frame/mock/menu.js
new file: admin-frame/package-lock.json
new file: admin-frame/package.json
new file: admin-frame/public/favicon.ico
new file: admin-frame/public/index.html
new file: admin-frame/src/App.vue
new file: admin-frame/src/assets/bg2.jpg
new file: admin-frame/src/assets/code.png
new file: admin-frame/src/assets/home.png
new file: admin-frame/src/assets/logo-xr.png
new file: admin-frame/src/assets/logo-xr2.png
new file: admin-frame/src/assets/logo.png
new file: admin-frame/src/components/deepTree.vue
new file: admin-frame/src/components/dialogAndDrawer.vue
new file: admin-frame/src/components/editoritem.vue
new file: admin-frame/src/components/exports.vue
new file: admin-frame/src/components/filterList/index.vue
new file: admin-frame/src/components/filterList/pagination.vue
new file: admin-frame/src/components/filterList/search.vue
new file: admin-frame/src/components/filterList/table.vue
new file: "admin-frame/src/components/filterList/\350\260\203\347\224\250\345\256\236\344\276\213.md"
new file: admin-frame/src/components/formData/index.vue
new file: admin-frame/src/components/header/breadcrumb.vue
new file: admin-frame/src/components/header/headerUser.vue
new file: admin-frame/src/components/header/index.vue
new file: admin-frame/src/components/header/logo.vue
new file: admin-frame/src/components/menu/index.vue
new file: admin-frame/src/components/menu/menuItem.vue
new file: admin-frame/src/components/transfer.vue
new file: admin-frame/src/components/upload.vue
new file: admin-frame/src/main.js
new file: admin-frame/src/router/index.js
new file: admin-frame/src/store/index.js
new file: admin-frame/src/views/Home.vue
new file: admin-frame/src/views/login.vue
new file: admin-frame/style/index.module.scss
new file: admin-frame/style/index.scss
new file: admin-frame/vue.config.js
new file: admin-img-news/.browserslistrc
new file: admin-img-news/.editorconfig
new file: admin-img-news/.env
new file: admin-img-news/.eslintignore
new file: admin-img-news/.eslintrc.js
new file: admin-img-news/.gitignore
new file: admin-img-news/README.md
new file: admin-img-news/babel.config.js
new file: admin-img-news/package-lock.json
new file: admin-img-news/package.json
new file: admin-img-news/public/favicon.ico
new file: admin-img-news/public/index.html
new file: admin-img-news/src/App.vue
new file: admin-img-news/src/assets/logo.png
new file: admin-img-news/src/main.js
new file: admin-img-news/src/public-path.js
new file: admin-img-news/src/router/index.js
new file: admin-img-news/src/store/index.js
new file: admin-img-news/src/views/home.vue
new file: admin-img-news/vue.config.js
new file: admin-log/.browserslistrc
new file: admin-log/.editorconfig
new file: admin-log/.env
new file: admin-log/.eslintignore
new file: admin-log/.eslintrc.js
new file: admin-log/.gitignore
new file: admin-log/README.md
new file: admin-log/babel.config.js
new file: admin-log/package-lock.json
new file: admin-log/package.json
new file: admin-log/public/favicon.ico
new file: admin-log/public/index.html
new file: admin-log/src/App.vue
new file: admin-log/src/assets/logo.png
new file: admin-log/src/main.js
new file: admin-log/src/public-path.js
new file: admin-log/src/router/index.js
new file: admin-log/src/store/index.js
new file: admin-log/src/views/home.vue
new file: admin-log/vue.config.js
new file: admin-menu/.browserslistrc
new file: admin-menu/.editorconfig
new file: admin-menu/.env
new file: admin-menu/.eslintignore
new file: admin-menu/.eslintrc.js
new file: admin-menu/.gitignore
new file: admin-menu/README.md
new file: admin-menu/babel.config.js
new file: admin-menu/package-lock.json
new file: admin-menu/package.json
new file: admin-menu/public/favicon.ico
new file: admin-menu/public/index.html
new file: admin-menu/src/App.vue
new file: admin-menu/src/assets/logo.png
new file: admin-menu/src/main.js
new file: admin-menu/src/public-path.js
new file: admin-menu/src/router/index.js
new file: admin-menu/src/store/index.js
new file: admin-menu/src/views/home.vue
new file: admin-menu/vue.config.js
new file: admin-page/.browserslistrc
new file: admin-page/.editorconfig
new file: admin-page/.env
new file: admin-page/.eslintignore
new file: admin-page/.eslintrc.js
new file: admin-page/.gitignore
new file: admin-page/README.md
new file: admin-page/babel.config.js
new file: admin-page/package-lock.json
new file: admin-page/package.json
new file: admin-page/public/favicon.ico
new file: admin-page/public/index.html
new file: admin-page/src/App.vue
new file: admin-page/src/assets/logo.png
new file: admin-page/src/main.js
new file: admin-page/src/public-path.js
new file: admin-page/src/router/index.js
new file: admin-page/src/store/index.js
new file: admin-page/src/views/home.vue
new file: admin-page/vue.config.js
new file: admin-role-menu/.browserslistrc
new file: admin-role-menu/.editorconfig
new file: admin-role-menu/.env
new file: admin-role-menu/.eslintignore
new file: admin-role-menu/.eslintrc.js
new file: admin-role-menu/.gitignore
new file: admin-role-menu/README.md
new file: admin-role-menu/babel.config.js
new file: admin-role-menu/package-lock.json
new file: admin-role-menu/package.json
new file: admin-role-menu/public/favicon.ico
new file: admin-role-menu/public/index.html
new file: admin-role-menu/src/App.vue
new file: admin-role-menu/src/assets/logo.png
new file: admin-role-menu/src/main.js
new file: admin-role-menu/src/public-path.js
new file: admin-role-menu/src/router/index.js
new file: admin-role-menu/src/store/index.js
new file: admin-role-menu/src/views/home.vue
new file: admin-role-menu/vue.config.js
new file: admin-role/.browserslistrc
new file: admin-role/.editorconfig
new file: admin-role/.env
new file: admin-role/.eslintignore
new file: admin-role/.eslintrc.js
new file: admin-role/.gitignore
new file: admin-role/README.md
new file: admin-role/babel.config.js
new file: admin-role/package-lock.json
new file: admin-role/package.json
new file: admin-role/public/favicon.ico
new file: admin-role/public/index.html
new file: admin-role/src/App.vue
new file: admin-role/src/assets/logo.png
new file: admin-role/src/main.js
new file: admin-role/src/public-path.js
new file: admin-role/src/router/index.js
new file: admin-role/src/store/index.js
new file: admin-role/src/views/home.vue
new file: admin-role/vue.config.js
new file: admin-toconfig/.browserslistrc
new file: admin-toconfig/.editorconfig
new file: admin-toconfig/.env
new file: admin-toconfig/.eslintignore
new file: admin-toconfig/.eslintrc.js
new file: admin-toconfig/.gitignore
new file: admin-toconfig/README.md
new file: admin-toconfig/babel.config.js
new file: admin-toconfig/package-lock.json
new file: admin-toconfig/package.json
new file: admin-toconfig/public/favicon.ico
new file: admin-toconfig/public/index.html
new file: admin-toconfig/src/App.vue
new file: admin-toconfig/src/assets/logo.png
new file: admin-toconfig/src/main.js
new file: admin-toconfig/src/public-path.js
new file: admin-toconfig/src/router/index.js
new file: admin-toconfig/src/store/index.js
new file: admin-toconfig/src/views/home.vue
new file: admin-toconfig/vue.config.js
new file: admin-user/.browserslistrc
new file: admin-user/.editorconfig
new file: admin-user/.env
new file: admin-user/.eslintignore
new file: admin-user/.eslintrc.js
new file: admin-user/.gitignore
new file: admin-user/README.md
new file: admin-user/babel.config.js
new file: admin-user/package-lock.json
new file: admin-user/package.json
new file: admin-user/public/favicon.ico
new file: admin-user/public/index.html
new file: admin-user/src/App.vue
new file: admin-user/src/assets/logo.png
new file: admin-user/src/main.js
new file: admin-user/src/public-path.js
new file: admin-user/src/router/index.js
new file: admin-user/src/store/index.js
new file: admin-user/src/views/home.vue
new file: admin-user/vue.config.js
new file: admin.code-workspace

asd123a20 2 年之前
当前提交
7ded7c1895
共有 100 个文件被更改,包括 114211 次插入0 次删除
  1. 3 0
      admin-code/.browserslistrc
  2. 5 0
      admin-code/.editorconfig
  3. 2 0
      admin-code/.env
  4. 1 0
      admin-code/.eslintignore
  5. 23 0
      admin-code/.eslintrc.js
  6. 23 0
      admin-code/.gitignore
  7. 24 0
      admin-code/README.md
  8. 5 0
      admin-code/babel.config.js
  9. 28032 0
      admin-code/package-lock.json
  10. 35 0
      admin-code/package.json
  11. 二进制
      admin-code/public/favicon.ico
  12. 17 0
      admin-code/public/index.html
  13. 24 0
      admin-code/src/App.vue
  14. 二进制
      admin-code/src/assets/logo.png
  15. 48 0
      admin-code/src/main.js
  16. 3 0
      admin-code/src/public-path.js
  17. 10 0
      admin-code/src/router/index.js
  18. 79 0
      admin-code/src/store/index.js
  19. 200 0
      admin-code/src/views/Home.vue
  20. 33 0
      admin-code/vue.config.js
  21. 3 0
      admin-content/.browserslistrc
  22. 5 0
      admin-content/.editorconfig
  23. 2 0
      admin-content/.env
  24. 1 0
      admin-content/.eslintignore
  25. 23 0
      admin-content/.eslintrc.js
  26. 23 0
      admin-content/.gitignore
  27. 24 0
      admin-content/README.md
  28. 5 0
      admin-content/babel.config.js
  29. 27332 0
      admin-content/package-lock.json
  30. 35 0
      admin-content/package.json
  31. 二进制
      admin-content/public/favicon.ico
  32. 17 0
      admin-content/public/index.html
  33. 24 0
      admin-content/src/App.vue
  34. 二进制
      admin-content/src/assets/logo.png
  35. 48 0
      admin-content/src/main.js
  36. 3 0
      admin-content/src/public-path.js
  37. 11 0
      admin-content/src/router/index.js
  38. 78 0
      admin-content/src/store/index.js
  39. 303 0
      admin-content/src/views/home.vue
  40. 33 0
      admin-content/vue.config.js
  41. 3 0
      admin-files/.browserslistrc
  42. 5 0
      admin-files/.editorconfig
  43. 1 0
      admin-files/.eslintignore
  44. 23 0
      admin-files/.eslintrc.js
  45. 23 0
      admin-files/.gitignore
  46. 24 0
      admin-files/README.md
  47. 5 0
      admin-files/babel.config.js
  48. 27317 0
      admin-files/package-lock.json
  49. 35 0
      admin-files/package.json
  50. 二进制
      admin-files/public/favicon.ico
  51. 17 0
      admin-files/public/index.html
  52. 24 0
      admin-files/src/App.vue
  53. 二进制
      admin-files/src/assets/logo.png
  54. 48 0
      admin-files/src/main.js
  55. 3 0
      admin-files/src/public-path.js
  56. 11 0
      admin-files/src/router/index.js
  57. 40 0
      admin-files/src/store/index.js
  58. 72 0
      admin-files/src/views/home.vue
  59. 33 0
      admin-files/vue.config.js
  60. 3 0
      admin-frame/.browserslistrc
  61. 5 0
      admin-frame/.editorconfig
  62. 14 0
      admin-frame/.env
  63. 1 0
      admin-frame/.env.development
  64. 1 0
      admin-frame/.env.pre
  65. 24 0
      admin-frame/.eslintrc.js
  66. 23 0
      admin-frame/.gitignore
  67. 27 0
      admin-frame/README.md
  68. 5 0
      admin-frame/babel.config.js
  69. 86 0
      admin-frame/lib/apps.js
  70. 51 0
      admin-frame/lib/axios.js
  71. 9 0
      admin-frame/lib/dict.js
  72. 11 0
      admin-frame/lib/qiankun.js
  73. 17 0
      admin-frame/lib/resChange.js
  74. 26 0
      admin-frame/lib/tree.js
  75. 42 0
      admin-frame/mock/menu.js
  76. 28157 0
      admin-frame/package-lock.json
  77. 40 0
      admin-frame/package.json
  78. 二进制
      admin-frame/public/favicon.ico
  79. 17 0
      admin-frame/public/index.html
  80. 225 0
      admin-frame/src/App.vue
  81. 二进制
      admin-frame/src/assets/bg2.jpg
  82. 二进制
      admin-frame/src/assets/code.png
  83. 二进制
      admin-frame/src/assets/home.png
  84. 二进制
      admin-frame/src/assets/logo-xr.png
  85. 二进制
      admin-frame/src/assets/logo-xr2.png
  86. 二进制
      admin-frame/src/assets/logo.png
  87. 74 0
      admin-frame/src/components/deepTree.vue
  88. 51 0
      admin-frame/src/components/dialogAndDrawer.vue
  89. 132 0
      admin-frame/src/components/editoritem.vue
  90. 148 0
      admin-frame/src/components/exports.vue
  91. 123 0
      admin-frame/src/components/filterList/index.vue
  92. 47 0
      admin-frame/src/components/filterList/pagination.vue
  93. 85 0
      admin-frame/src/components/filterList/search.vue
  94. 133 0
      admin-frame/src/components/filterList/table.vue
  95. 53 0
      admin-frame/src/components/filterList/调用实例.md
  96. 130 0
      admin-frame/src/components/formData/index.vue
  97. 55 0
      admin-frame/src/components/header/breadcrumb.vue
  98. 52 0
      admin-frame/src/components/header/headerUser.vue
  99. 123 0
      admin-frame/src/components/header/index.vue
  100. 0 0
      admin-frame/src/components/header/logo.vue

+ 3 - 0
admin-code/.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 5 - 0
admin-code/.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 2 - 0
admin-code/.env

@@ -0,0 +1,2 @@
+# 窗口使用弹出还是抽屉 (dialog And drawer)
+VUE_APP_WINDOW=dialog

+ 1 - 0
admin-code/.eslintignore

@@ -0,0 +1 @@
+public-path.js

+ 23 - 0
admin-code/.eslintrc.js

@@ -0,0 +1,23 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  extends: [
+    'plugin:vue/essential',
+    '@vue/standard'
+  ],
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  rules: {
+    'no-console': 0,
+    'no-debugger': 0,
+    'comma-dangle': [2, 'never'],
+    'no-extra-parens': 2,
+    'no-extra-semi': 2,
+    semi: [2, 'always'],
+    'space-before-function-paren': [0, 'always'],
+    eqeqeq: 0
+  }
+};

+ 23 - 0
admin-code/.gitignore

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

+ 24 - 0
admin-code/README.md

@@ -0,0 +1,24 @@
+# admin-code
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
admin-code/babel.config.js

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

文件差异内容过多而无法显示
+ 28032 - 0
admin-code/package-lock.json


+ 35 - 0
admin-code/package.json

@@ -0,0 +1,35 @@
+{
+  "name": "admin-code",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "core-js": "^3.6.5",
+    "element-ui": "^2.15.6",
+    "vue": "^2.6.11",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/eslint-config-standard": "^5.1.2",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-node": "^11.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "eslint-plugin-vue": "^6.2.2",
+    "sass": "^1.45.1",
+    "sass-loader": "^10.0.0",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

二进制
admin-code/public/favicon.ico


+ 17 - 0
admin-code/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 24 - 0
admin-code/src/App.vue

@@ -0,0 +1,24 @@
+<template>
+  <div id="app">
+    <router-view></router-view>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  computed: {},
+  data() {
+    return {};
+  },
+  mounted() {},
+  methods: {}
+};
+</script>
+
+<style lang="scss" scoped>
+#app {
+  width: 100%;
+  height: 100%;
+}
+</style>

二进制
admin-code/src/assets/logo.png


+ 48 - 0
admin-code/src/main.js

@@ -0,0 +1,48 @@
+import Vue from 'vue';
+import App from './App.vue';
+import VueRouter from 'vue-router';
+import routes from './router';
+import store from './store';
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+import './public-path.js';
+import dict from '@lib/dict.js';
+import tree from '@lib/tree.js';
+import resChange from '@lib/resChange.js';
+Vue.config.productionTip = false;
+Vue.use(VueRouter);
+Vue.use(ElementUI);
+Vue.use(dict);
+Vue.use(tree);
+Vue.use(resChange);
+let router = null;
+let instance = null;
+function render (props = {}) {
+  const { container } = props;
+  router = new VueRouter({
+    base: window.__POWERED_BY_QIANKUN__ ? '/admin/code/' : '/',
+    mode: 'history',
+    routes
+  });
+  instance = new Vue({
+    router,
+    store,
+    render: (h) => h(App)
+  }).$mount(container ? container.querySelector('#app') : '#app');
+}
+
+// 独立运行时
+if (!window.__POWERED_BY_QIANKUN__) {
+  render();
+}
+
+export async function bootstrap () {}
+export async function mount (props) {
+  render(props);
+}
+export async function unmount () {
+  instance.$destroy();
+  instance.$el.innerHTML = '';
+  instance = null;
+  router = null;
+}

+ 3 - 0
admin-code/src/public-path.js

@@ -0,0 +1,3 @@
+if (window.__POWERED_BY_QIANKUN__) {
+  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
+}

+ 10 - 0
admin-code/src/router/index.js

@@ -0,0 +1,10 @@
+import home from '../views/Home.vue';
+const routes = [
+  {
+    path: '/home',
+    name: 'home',
+    component: home
+  }
+];
+
+export default routes;

+ 79 - 0
admin-code/src/store/index.js

@@ -0,0 +1,79 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import $axios from '@lib/axios.js';
+Vue.use(Vuex);
+const api = {
+  typeCreate: '/api/code/type/create',
+  typeUpdate: '/api/code/type/update',
+  typeDelete: '/api/code/type/delete',
+  typeQuery: '/api/code/type/query',
+  codeCreate: '/api/code/dictionary/create',
+  codeUpdate: '/api/code/dictionary/update',
+  codeDelete: '/api/code/dictionary/delete',
+  codeQuery: '/api/code/dictionary/query'
+};
+
+const state = () => ({
+  dict: {},
+  typeList: [],
+  typeTotal: 0,
+  codeList: [],
+  codeTotal: 0
+});
+
+const actions = {
+  async typeQuery({ commit }) {
+    const res = await $axios.get(api.typeQuery);
+    commit('typeQuery', res);
+    return res;
+  },
+  async typeCreate({ commit }, payload) {
+    const res = await $axios.post(api.typeCreate, payload);
+    return res;
+  },
+  async typeUpdate({ commit }, payload) {
+    payload = { ...payload, id: payload._id };
+    const res = await $axios.post(api.typeUpdate, payload);
+    return res;
+  },
+  async typeDelete({ commit }, { id }) {
+    const res = await $axios.delete(`${api.typeDelete}/${id}`);
+    return res;
+  },
+  async codeQuery({ commit }, { filter, paging } = {}) {
+    const res = await $axios.get(api.codeQuery, { ...filter, skip: paging.page, limit: paging.size });
+    commit('codeQuery', res);
+    return res;
+  },
+  async codeCreate({ commit }, payload) {
+    const res = await $axios.post(api.codeCreate, payload);
+    return res;
+  },
+  async codeUpdate({ commit }, payload) {
+    payload = { ...payload, id: payload._id };
+    const res = await $axios.post(api.codeUpdate, payload);
+    return res;
+  },
+  async codeDelete({ commit }, { id }) {
+    const res = await $axios.delete(`${api.codeDelete}/${id}`);
+    return res;
+  }
+};
+
+const mutations = {
+  typeQuery(state, payload) {
+    state.typeList = payload.data;
+    state.typeTotal = payload.total;
+  },
+  codeQuery(state, payload) {
+    state.codeList = payload.data;
+    state.codeTotal = payload.total;
+  }
+};
+
+export default new Vuex.Store({
+  state,
+  mutations,
+  actions,
+  modules: {}
+});

+ 200 - 0
admin-code/src/views/Home.vue

@@ -0,0 +1,200 @@
+<template>
+  <div class="code-home">
+    <el-card class="box-card-left">
+      <div slot="header">
+        <span>字典类别</span>
+        <el-tooltip effect="dark" content="添加类型" placement="top-start">
+          <el-button style="float: right; padding: 3px 0" icon="el-icon-plus" type="text" @click="treeTypeAdd">添加类型</el-button>
+        </el-tooltip>
+      </div>
+      <deepTree :operation="true" @edit="treeEdit" @remove="treeRemove" @nodeClick="treeClick" class="deepTree" :data="treeList"></deepTree>
+    </el-card>
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span>数据字典</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="filterAdd" icon="el-icon-plus">添加字典</el-button>
+      </div>
+      <filterList ref="filterList" :tableData="tableData" :filed="filed" @edit="filtereEdit" @delete="filterDelete" @query="filterQuery" :total="codeTotal"></filterList>
+    </el-card>
+    <dialogAndDrawer :title="title" :visibleSync="visibleSync" v-if="visibleSync" @close="visibleSync = false">
+      <template v-slot:windowMain>
+        <formData :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave"></formData>
+      </template>
+    </dialogAndDrawer>
+  </div>
+</template>
+
+<script>
+import filterList from '@components/filterList/index.vue';
+import deepTree from '@components/deepTree.vue';
+import dialogAndDrawer from '@components/dialogAndDrawer.vue';
+import formData from '@components/formData/index.vue';
+import { mapState, mapActions } from 'vuex';
+export default {
+  name: 'Home',
+  components: {
+    filterList,
+    deepTree,
+    dialogAndDrawer,
+    formData
+  },
+  computed: {
+    ...mapState({ tableData: 'codeList', treeList: 'typeList', codeTotal: 'codeTotal', typeTotal: 'typeTotal' })
+  },
+  data() {
+    return {
+      type: null,
+      title: '',
+      visibleSync: false,
+      formdata: {},
+      formrules: {
+        name: [
+          { required: true, message: '请输入名称', trigger: 'blur' }
+        ],
+        code: [
+          { required: true, message: '请输入编码', trigger: 'blur' }
+        ]
+      },
+      formfiled: [
+        { label: '名称', name: 'name' },
+        { label: '编码', name: 'code' }
+      ],
+      filed: [
+        { label: '类型', name: 'parentCode' },
+        { label: '名称', name: 'name', filter: true },
+        { label: '编码', name: 'code', filter: true }
+      ]
+    };
+  },
+  mounted() {
+    this.treeQuery();
+  },
+  methods: {
+    ...mapActions(['typeQuery', 'typeCreate', 'typeUpdate', 'typeDelete', 'codeQuery', 'codeCreate', 'codeUpdate', 'codeDelete']),
+    // filter
+    // 添加
+    filterAdd() {
+      if (this.type == null) {
+        this.$message.warning('请先选择类别');
+        return;
+      }
+      this.formdata = {};
+      this.title = '添加字典';
+      this.visibleSync = true;
+    },
+    // 修改
+    filtereEdit(e) {
+      this.formdata = e;
+      this.title = '修改字典';
+      this.visibleSync = true;
+    },
+    // 删除
+    async filterDelete(e) {
+      const res = await this.codeDelete({ id: e?._id });
+      this.$resChange(res, '删除成功');
+      this.filterQuery();
+    },
+    // 查询
+    async filterQuery({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
+      if (this.type == null) {
+        this.$message.error('请先选择类别');
+        return;
+      }
+      filter.parentCode = this.type;
+      await this.codeQuery({ filter, paging });
+    },
+    // tree
+    // 查询
+    async treeQuery(e) {
+      await this.typeQuery({ filter: {} });
+    },
+    // 添加
+    treeTypeAdd() {
+      this.type = null;
+      this.formdata = {};
+      this.title = '添加类别';
+      this.visibleSync = true;
+    },
+    // 修改
+    treeEdit(e) {
+      this.type = null;
+      this.formdata = e;
+      this.title = '修改类别';
+      this.visibleSync = true;
+    },
+    // 删除
+    async treeRemove(e) {
+      this.type = null;
+      const res = await this.typeDelete({ id: e?._id });
+      this.$resChange(res, '删除成功');
+      this.treeQuery();
+    },
+    // 选择
+    treeClick(e) {
+      this.type = e.data.code;
+      this.filterQuery();
+    },
+    // 表单保存
+    async formSave(e) {
+      if (e.isRevise && e?.isRevise == false) {
+        this.$message.warning('未作修改');
+        return;
+      }
+      this.$delete(e, 'isRevise');
+      let res, msg;
+      if (this.type !== null) {
+        // 字典
+        this.$set(e, 'parentCode', this.type);
+        if (e._id) {
+          // 字典修改
+          res = await this.codeUpdate(e);
+          msg = '字典修改成功';
+        } else {
+          // 字典添加
+          res = await this.codeCreate(e);
+          msg = '字典添加成功';
+        }
+        this.filterQuery();
+      } else {
+        // 字典类别
+        if (e._id) {
+          // 类别修改
+          res = await this.typeUpdate(e);
+          msg = '类别修改成功';
+        } else {
+          // 类别添加
+          res = await this.typeCreate(e);
+          msg = '类别添加成功';
+        }
+        this.treeQuery();
+      }
+      this.$resChange(res, msg);
+      this.visibleSync = false;
+    }
+  }
+};
+</script>
+<style lang="scss">
+.code-home {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  .box-card {
+    width: 84%;
+    height: 100%;
+  }
+  .box-card-left {
+    width: 15%;
+    height: 100%;
+    .el-card__body {
+      height: 88%;
+      .deepTree {
+        width: 100%;
+        height: 100%;
+        overflow-y: auto;
+      }
+    }
+  }
+}
+
+</style>

+ 33 - 0
admin-code/vue.config.js

@@ -0,0 +1,33 @@
+const path = require('path');
+const frameSrc = path.resolve(__dirname, '../admin-frame');
+const packageName = require('./package.json').name;
+module.exports = {
+  publicPath: `/${packageName}/`,
+  outputDir: path.join(frameSrc, `../../admin-web/${packageName}/`),
+  devServer: {
+    port: 3001,
+    headers: {
+      'Access-Control-Allow-Origin': '*'
+    },
+    proxy: {
+      '/api/': {
+        // target: 'http://192.168.0.45:18090'
+        target: 'http://127.0.0.1:18090'
+      }
+    }
+  },
+  configureWebpack: {
+    output: {
+      library: `${packageName}-[name]`,
+      libraryTarget: 'umd',
+      jsonpFunction: `webpackJsonp_${packageName}`
+    },
+    resolve: {
+      alias: {
+        '@components': path.join(frameSrc, '/src/components'),
+        '@style': path.join(frameSrc, '/style'),
+        '@lib': path.join(frameSrc, '/lib')
+      }
+    }
+  }
+};

+ 3 - 0
admin-content/.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 5 - 0
admin-content/.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 2 - 0
admin-content/.env

@@ -0,0 +1,2 @@
+# 窗口使用弹出还是抽屉 (dialog And drawer)
+VUE_APP_WINDOW=dialog

+ 1 - 0
admin-content/.eslintignore

@@ -0,0 +1 @@
+public-path.js

+ 23 - 0
admin-content/.eslintrc.js

@@ -0,0 +1,23 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  extends: [
+    'plugin:vue/essential',
+    '@vue/standard'
+  ],
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  rules: {
+    'no-console': 0,
+    'no-debugger': 0,
+    'comma-dangle': [2, 'never'],
+    'no-extra-parens': 2,
+    'no-extra-semi': 2,
+    semi: [2, 'always'],
+    'space-before-function-paren': [0, 'always'],
+    eqeqeq: 0
+  }
+};

+ 23 - 0
admin-content/.gitignore

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

+ 24 - 0
admin-content/README.md

@@ -0,0 +1,24 @@
+# admin-role
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
admin-content/babel.config.js

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

文件差异内容过多而无法显示
+ 27332 - 0
admin-content/package-lock.json


+ 35 - 0
admin-content/package.json

@@ -0,0 +1,35 @@
+{
+  "name": "admin-contents",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "core-js": "^3.6.5",
+    "element-ui": "^2.15.6",
+    "sass": "^1.48.0",
+    "sass-loader": "^10.0.0",
+    "vue": "^2.6.11",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/eslint-config-standard": "^5.1.2",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-node": "^11.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "eslint-plugin-vue": "^6.2.2",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

二进制
admin-content/public/favicon.ico


+ 17 - 0
admin-content/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 24 - 0
admin-content/src/App.vue

@@ -0,0 +1,24 @@
+<template>
+  <div id="app">
+    <router-view></router-view>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  computed: {},
+  data() {
+    return {};
+  },
+  mounted() {},
+  methods: {}
+};
+</script>
+
+<style lang="scss" scoped>
+#app {
+  width: 100%;
+  height: 100%;
+}
+</style>

二进制
admin-content/src/assets/logo.png


+ 48 - 0
admin-content/src/main.js

@@ -0,0 +1,48 @@
+import Vue from 'vue';
+import App from './App.vue';
+import VueRouter from 'vue-router';
+import routes from './router';
+import store from './store';
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+import './public-path.js';
+import dict from '@lib/dict.js';
+import tree from '@lib/tree.js';
+import resChange from '@lib/resChange.js';
+Vue.config.productionTip = false;
+Vue.use(VueRouter);
+Vue.use(ElementUI);
+Vue.use(dict);
+Vue.use(tree);
+Vue.use(resChange);
+let router = null;
+let instance = null;
+function render (props = {}) {
+  const { container } = props;
+  router = new VueRouter({
+    base: window.__POWERED_BY_QIANKUN__ ? '/admin/contents/' : '/',
+    mode: 'history',
+    routes
+  });
+  instance = new Vue({
+    router,
+    store,
+    render: (h) => h(App)
+  }).$mount(container ? container.querySelector('#app') : '#app');
+}
+
+// 独立运行时
+if (!window.__POWERED_BY_QIANKUN__) {
+  render();
+}
+
+export async function bootstrap () {}
+export async function mount (props) {
+  render(props);
+}
+export async function unmount () {
+  instance.$destroy();
+  instance.$el.innerHTML = '';
+  instance = null;
+  router = null;
+}

+ 3 - 0
admin-content/src/public-path.js

@@ -0,0 +1,3 @@
+if (window.__POWERED_BY_QIANKUN__) {
+  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
+}

+ 11 - 0
admin-content/src/router/index.js

@@ -0,0 +1,11 @@
+import home from '../views/home.vue';
+
+const routes = [
+  {
+    path: '/home',
+    name: 'home',
+    component: home
+  }
+];
+
+export default routes;

+ 78 - 0
admin-content/src/store/index.js

@@ -0,0 +1,78 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import $axios from '@lib/axios.js';
+const api = {
+  contentsCreate: '/api/cms/contents/create',
+  contentsUpdate: '/api/cms/contents/update',
+  contentsDelete: '/api/cms/contents/delete',
+  contentsQuery: '/api/cms/contents/query',
+  contentsFetch: '/api/cms/contents/fetch',
+  menusQuery: '/api/cms/menus/query',
+  userQuery: '/api/reader/user/query'
+};
+Vue.use(Vuex);
+const state = () => ({
+  Total: 0,
+  contentsList: [],
+  menusList: [],
+  dict: {},
+  userList: [],
+  userTotal: 0
+});
+
+const actions = {
+  async userQuery ({ commit }, { filter, paging } = {}) {
+    const res = await $axios.get(api.userQuery, { ...filter, skip: paging.page, limit: paging.size });
+    commit('userQuery', res);
+    return res;
+  },
+  async contentsCreate ({ commit }, payload) {
+    const res = await $axios.post(api.contentsCreate, payload);
+    return res;
+  },
+  async contentsUpdate ({ commit }, payload) {
+    const res = await $axios.post(api.contentsUpdate, { ...payload, id: payload._id });
+    return res;
+  },
+  async contentsDelete ({ commit }, { id }) {
+    const res = await $axios.delete(`${api.contentsDelete}/${id}`);
+    return res;
+  },
+  async contentsQuery ({ commit }, { filter, paging } = {}) {
+    const res = await $axios.get(api.contentsQuery, { ...filter, skip: paging.page, limit: paging.size });
+    commit('contentsQuery', res);
+    return res;
+  },
+  async contentsFetch ({ commit }, payload) {
+    const res = await $axios.get(api.contentsFetch, payload);
+    return res;
+  },
+  async menusQuery ({ commit }) {
+    const res = await $axios.get(api.menusQuery);
+    commit('menusQuery', res);
+    return res;
+  }
+};
+
+const mutations = {
+  contentsQuery(state, payload) {
+    state.contentsList = payload.data;
+    state.Total = payload.total;
+  },
+  menusQuery(state, payload) {
+    state.menusList = payload.data;
+    state.dict.menus = payload.data.filter(e => e.parentCode !== 'null' && e.type == 1);
+    console.log(state.dict.menus);
+  },
+  userQuery(state, payload) {
+    state.userList = payload.data.map(e => e.userList[0]);
+    state.userTotal = payload.total;
+  }
+};
+
+export default new Vuex.Store({
+  state,
+  actions,
+  mutations,
+  modules: {}
+});

+ 303 - 0
admin-content/src/views/home.vue

@@ -0,0 +1,303 @@
+<template>
+  <div class="contentBox">
+    <el-card class="box-card-left">
+      <div slot="header">
+        <span>菜单列表</span>
+      </div>
+      <deepTree @nodeClick="treeClick" class="deepTree" :data="treeList"></deepTree>
+    </el-card>
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span>文章管理</span>
+        <el-button style="float: right; padding: 3px 0" type="text" @click="addcontents" icon="el-icon-plus">添加文章</el-button>
+      </div>
+      <div class="main">
+        <filterList ref="filterList" :operation="operation" :tableData="contents" :filed="filed" @edit="filtereEdit" @delete="filterDelete" @query="filterQuery" :total="Total">
+          <template v-slot:search="{ item, formInline }">
+            <el-select v-model="formInline[item.name]" placeholder="请选择菜单" v-if="item.name == 'bind'">
+              <el-option v-for="item in menus" :key="item.code" :label="item.name" :value="item.code"></el-option>
+            </el-select>
+          </template>
+        </filterList>
+      </div>
+    </el-card>
+    <dialogAndDrawer :width="'35%'" :title="title" :visibleSync="visibleSync" v-if="visibleSync" @close="visibleSync = false, lookUser = false">
+      <template v-slot:windowMain>
+        <formData v-if="!lookUser" ref="formData" :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave">
+          <template v-slot:formItem="{ item, formdata }">
+            <el-switch v-if="item.name == 'istop'" v-model="formdata[item.name]" active-color="#13ce66" inactive-color="#ff4949" :active-value="true" :inactive-value="false"></el-switch>
+            <!-- 缩略图 -->
+            <el-upload
+              v-if="item.name == 'thumbnail'"
+              class="avatar-uploader"
+              action="/api/files/avatar/upload"
+              :show-file-list="false"
+              :headers="myHeaders"
+              :on-success="handleAvatarSuccess"
+              :before-upload="beforeAvatarUpload">
+              <img v-if="formdata[item.name] && formdata[item.name] !== ''" :src="formdata[item.name]" class="avatar">
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <!-- 富文本 -->
+            <editoritem v-if="item.name == 'content'" @change="editChage" :value="formdata[item.name]"></editoritem>
+            <!-- 附件上传 -->
+            <el-upload
+              v-if="item.name == 'annex'"
+              :headers="myHeaders"
+              class="upload-demo"
+              action="/api/files/avatar/upload"
+              :on-success="handleAnnexSuccess"
+              :on-remove="handleRemove"
+              :file-list="fileList">
+              <el-button size="small" type="primary">附件上传</el-button>
+            </el-upload>
+          </template>
+        </formData>
+        <filterList v-else ref="filterList" :tableData="userList"  :filter="false" :readOnly="true" :filed="userfiled" @query="userfilterQuery" :total="userTotal"></filterList>
+      </template>
+    </dialogAndDrawer>
+  </div>
+</template>
+<script>
+import filterList from '@components/filterList/index.vue';
+import dialogAndDrawer from '@components/dialogAndDrawer.vue';
+import formData from '@components/formData/index.vue';
+import editoritem from '@components/editoritem.vue';
+import deepTree from '@components/deepTree.vue';
+import { mapState, mapActions } from 'vuex';
+const token = sessionStorage.getItem('token');
+export default {
+  components: {
+    filterList,
+    dialogAndDrawer,
+    formData,
+    editoritem,
+    deepTree
+  },
+  data() {
+    return {
+      types: null,
+      info: {},
+      lookUser: false,
+      fileList: [],
+      myHeaders: { Authorization: token },
+      title: '',
+      visibleSync: false,
+      filed: [
+        { name: 'title', label: '标题', filter: true },
+        // { name: 'bind', label: '绑定栏目', formater: 'slot', filter: true },
+        { name: 'visit', label: '访问量' }
+      ],
+      formdata: {},
+      userfiled: [
+        { name: 'name', label: '名称' },
+        { name: 'phone', label: '手机号' }
+      ],
+      formfiled: [
+        { name: 'thumbnail', label: '缩略图', formater: 'slot' },
+        { name: 'title', label: '标题' },
+        { name: 'describe', label: '描述' },
+        { name: 'bind', label: '绑定菜单', formater: 'dict:menus' },
+        { name: 'date', label: '时间', formater: 'date:datetime' },
+        { name: 'istop', label: '置顶', formater: 'slot' },
+        { name: 'content', label: '内容', formater: 'slot' },
+        { name: 'annex', label: '附件', formater: 'slot' }
+      ],
+      formrules: {
+        thumbnail: [
+          { required: true, message: '请上传缩略图', trigger: 'chage' }
+        ],
+        title: [
+          { required: true, message: '请输入标题', trigger: 'blur' }
+        ],
+        describe: [
+          { required: true, message: '请输入描述', trigger: 'blur' }
+        ],
+        bind: [
+          { required: true, message: '请绑定菜单', trigger: 'chage' }
+        ],
+        date: [
+          { required: true, message: '请输入时间', trigger: 'blur' }
+        ],
+        content: [
+          { required: true, message: '请输入内容', trigger: 'blur' }
+        ]
+      },
+      operation: [
+        { name: 'edit', label: '修改', icon: 'el-icon-edit' },
+        { name: 'delete', label: '删除', icon: 'el-icon-delete' }
+      ]
+    };
+  },
+  computed: {
+    ...mapState(['contentsList', 'Total', 'menusList', 'userList', 'userTotal', 'dict']),
+    contents() {
+      this.contentsList.map(p => {
+        const findName = this.menusList.find(e => e.code == p.bind);
+        console.log(findName);
+        if (findName) p.bind = findName?.name;
+        return p;
+      });
+      return this.contentsList;
+    },
+    menus() {
+      const menus = this.menusList.filter(e => e.parentCode !== 'null' && e.type == 1);
+      return menus;
+    },
+    treeList() {
+      const menusall = this.menusList.filter(e => (e.type !== 2 && e.type !== '2'));
+      return this.$tree(menusall);
+    }
+  },
+  async created() {
+    await this.filterQuery();
+    await this.menusQuery();
+  },
+  methods: {
+    ...mapActions(['contentsQuery', 'contentsCreate', 'contentsUpdate', 'contentsDelete', 'contentsQuery', 'contentsFetch', 'menusQuery', 'userQuery']),
+    // 添加
+    addcontents () {
+      this.formdata = {};
+      this.title = '添加文章';
+      this.visibleSync = true;
+      if (this.types !== null) this.$set(this.formdata, 'bind', this.types);
+    },
+    // 修改
+    async filtereEdit (e) {
+      const res = await this.contentsFetch({ id: e._id });
+      this.formdata = res.data;
+      this.title = '修改文章';
+      this.visibleSync = true;
+    },
+    // 删除
+    async filterDelete (e) {
+      const res = await this.contentsDelete({ id: e?._id });
+      this.$resChange(res, '删除成功');
+      this.filterQuery();
+    },
+    // 查询
+    async filterQuery ({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
+      // filter.istop = true;
+      await this.contentsQuery({ filter, paging });
+    },
+    // 表单保存
+    async formSave (e) {
+      if (e.isRevise && e?.isRevise == false) {
+        this.$message.warning('未作修改');
+        return;
+      }
+      this.$delete(e, 'isRevise');
+      let res, msg;
+      // 修改
+      if (e._id) {
+        delete e.svip;
+        delete e.isShow;
+        res = await this.contentsUpdate(e);
+        msg = '文章修改成功';
+      } else {
+        res = await this.contentsCreate(e);
+        msg = '文章修改成功';
+      }
+      this.$resChange(res, msg);
+      const filter = { bind: this.types };
+      this.filterQuery({ filter });
+      this.visibleSync = false;
+    },
+    // 富文本改变
+    editChage (e) {
+      this.$refs.formData.setForm('content', e);
+    },
+    // 附件上传
+    handleAnnexSuccess(res, file) {
+      this.$refs.formData.setForm('annex', res.data.filePath);
+      this.fileList.push({ name: res.data.name, url: res.data.filePath });
+    },
+    // 删除附件列表
+    handleRemove(file, fileList) {
+      console.log(123);
+      this.$refs.formData.setForm('annex', null);
+      delete this.fileList[0];
+    },
+    // 缩略图上传
+    handleAvatarSuccess(res, file) {
+      this.$refs.formData.setForm('thumbnail', res.data.filePath);
+    },
+    // 缩略图上传限制
+    beforeAvatarUpload(file) {
+      const isJPG = file.type === 'image/jpeg';
+      const isLt2M = file.size / 1024 / 1024 < 2;
+
+      if (!isJPG) {
+        this.$message.error('上传头像图片只能是 JPG 格式!');
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!');
+      }
+      return isJPG && isLt2M;
+    },
+    async treeClick({ data, node }) {
+      if (data.children) return;
+      this.types = data.code;
+      const filter = { bind: data.code };
+      await this.filterQuery({ filter });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.contentBox {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  .box-card {
+    width: 80%;
+    height: 100%;
+    .el-card__body {
+      height: 100%;
+    }
+  }
+  .box-card-left {
+    width: 20%;
+    height: 100%;
+    ::v-deep .el-card__body {
+      height: 88%;
+      .deepTree {
+        width: 100%;
+        height: 100%;
+        overflow-y: auto;
+      }
+      .deepTree::-webkit-scrollbar {
+        width: 0px;
+        height: 0px;
+      }
+    }
+  }
+}
+.el-dialog {
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 120px;
+    height: 120px;
+    line-height: 120px;
+    text-align: center;
+  }
+  .avatar {
+    width: 120px;
+    height: 120px;
+    display: block;
+  }
+}
+</style>
+<style>
+.el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.el-upload:hover {
+  border-color: #409EFF;
+}
+</style>

+ 33 - 0
admin-content/vue.config.js

@@ -0,0 +1,33 @@
+const path = require('path');
+const frameSrc = path.resolve(__dirname, '../admin-frame');
+const packageName = require('./package.json').name;
+module.exports = {
+  publicPath: `/${packageName}/`,
+  outputDir: path.join(frameSrc, `../../admin-web/${packageName}/`),
+  devServer: {
+    port: 3007,
+    headers: {
+      'Access-Control-Allow-Origin': '*'
+    },
+    proxy: {
+      '/api/': {
+        target: 'http://192.168.0.45:18090'
+        // target: 'http://192.168.3.45:18090'
+      }
+    }
+  },
+  configureWebpack: {
+    output: {
+      library: `${packageName}-[name]`,
+      libraryTarget: 'umd',
+      jsonpFunction: `webpackJsonp_${packageName}`
+    },
+    resolve: {
+      alias: {
+        '@components': path.join(frameSrc, '/src/components'),
+        '@style': path.join(frameSrc, '/style'),
+        '@lib': path.join(frameSrc, '/lib')
+      }
+    }
+  }
+};

+ 3 - 0
admin-files/.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 5 - 0
admin-files/.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 1 - 0
admin-files/.eslintignore

@@ -0,0 +1 @@
+public-path.js

+ 23 - 0
admin-files/.eslintrc.js

@@ -0,0 +1,23 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  extends: [
+    'plugin:vue/essential',
+    '@vue/standard'
+  ],
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  rules: {
+    'no-console': 0,
+    'no-debugger': 0,
+    'comma-dangle': [2, 'never'],
+    'no-extra-parens': 2,
+    'no-extra-semi': 2,
+    semi: [2, 'always'],
+    'space-before-function-paren': [0, 'always'],
+    eqeqeq: 0
+  }
+};

+ 23 - 0
admin-files/.gitignore

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

+ 24 - 0
admin-files/README.md

@@ -0,0 +1,24 @@
+# admin-code
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
admin-files/babel.config.js

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

文件差异内容过多而无法显示
+ 27317 - 0
admin-files/package-lock.json


+ 35 - 0
admin-files/package.json

@@ -0,0 +1,35 @@
+{
+  "name": "admin-files",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "core-js": "^3.6.5",
+    "element-ui": "^2.15.6",
+    "sass": "^1.48.0",
+    "sass-loader": "^10.0.0",
+    "vue": "^2.6.11",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/eslint-config-standard": "^5.1.2",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-node": "^11.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "eslint-plugin-vue": "^6.2.2",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

二进制
admin-files/public/favicon.ico


+ 17 - 0
admin-files/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 24 - 0
admin-files/src/App.vue

@@ -0,0 +1,24 @@
+<template>
+  <div id="app">
+    <router-view></router-view>
+  </div>
+</template>
+
+<script>
+export default {
+  components: {},
+  computed: {},
+  data() {
+    return {};
+  },
+  mounted() {},
+  methods: {}
+};
+</script>
+
+<style lang="scss" scoped>
+#app {
+  width: 100%;
+  height: 100%;
+}
+</style>

二进制
admin-files/src/assets/logo.png


+ 48 - 0
admin-files/src/main.js

@@ -0,0 +1,48 @@
+import Vue from 'vue';
+import App from './App.vue';
+import VueRouter from 'vue-router';
+import routes from './router';
+import store from './store';
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+import './public-path.js';
+import dict from '@lib/dict.js';
+import tree from '@lib/tree.js';
+import resChange from '@lib/resChange.js';
+Vue.config.productionTip = false;
+Vue.use(VueRouter);
+Vue.use(ElementUI);
+Vue.use(dict);
+Vue.use(tree);
+Vue.use(resChange);
+let router = null;
+let instance = null;
+function render (props = {}) {
+  const { container } = props;
+  router = new VueRouter({
+    base: window.__POWERED_BY_QIANKUN__ ? '/admin/files/' : '/',
+    mode: 'history',
+    routes
+  });
+  instance = new Vue({
+    router,
+    store,
+    render: (h) => h(App)
+  }).$mount(container ? container.querySelector('#app') : '#app');
+}
+
+// 独立运行时
+if (!window.__POWERED_BY_QIANKUN__) {
+  render();
+}
+
+export async function bootstrap () {}
+export async function mount (props) {
+  render(props);
+}
+export async function unmount () {
+  instance.$destroy();
+  instance.$el.innerHTML = '';
+  instance = null;
+  router = null;
+}

+ 3 - 0
admin-files/src/public-path.js

@@ -0,0 +1,3 @@
+if (window.__POWERED_BY_QIANKUN__) {
+__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
+}

+ 11 - 0
admin-files/src/router/index.js

@@ -0,0 +1,11 @@
+import home from '../views/home.vue';
+
+const routes = [
+  {
+    path: '/home',
+    name: 'home',
+    component: home
+  }
+];
+
+export default routes;

+ 40 - 0
admin-files/src/store/index.js

@@ -0,0 +1,40 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import $axios from '@lib/axios.js';
+const api = {
+  filesDelete: '/api/files/filestore/delete',
+  filesQuery: '/api/files/filestore/query'
+};
+Vue.use(Vuex);
+const state = () => ({
+  Total: 0,
+  filesList: [],
+  columnList: [],
+  dict: {}
+});
+
+const actions = {
+  async filesDelete ({ commit }, payload) {
+    const res = await $axios.post(api.filesDelete, payload);
+    return res;
+  },
+  async filesQuery ({ commit }, { filter, paging } = {}) {
+    const res = await $axios.get(api.filesQuery, { ...filter, skip: paging.page, limit: paging.size });
+    commit('filesQuery', res);
+    return res;
+  }
+};
+
+const mutations = {
+  filesQuery(state, payload) {
+    state.filesList = payload.data;
+    state.Total = payload.total;
+  }
+};
+
+export default new Vuex.Store({
+  state,
+  actions,
+  mutations,
+  modules: {}
+});

+ 72 - 0
admin-files/src/views/home.vue

@@ -0,0 +1,72 @@
+<template>
+  <div class="box">
+    <el-card class="box-card">
+      <div slot="header" class="clearfix">
+        <span>文件管理</span>
+      </div>
+      <div class="main">
+        <filterList ref="filterList" :operation="operation" :tableData="filesList" :filed="filed" @delete="filterDelete" @download="download" @query="filterQuery" :total="Total"></filterList>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import filterList from '@components/filterList/index.vue';
+import { mapState, mapActions } from 'vuex';
+export default {
+  components: {
+    filterList
+  },
+  name: 'files',
+  data () {
+    return {
+      filed: [
+        // { name: 'url', label: '预览', formater: 'slot' },
+        { name: 'fileName', label: '文件名', filter: true },
+        { name: 'name', label: '名称', filter: true },
+        { name: 'filePath', label: '地址' }
+      ],
+      operation: [
+        { name: 'download', label: '下载', icon: 'el-icon-download' },
+        { name: 'delete', label: '删除', icon: 'el-icon-delete' }
+      ]
+    };
+  },
+  computed: {
+    ...mapState(['filesList', 'Total'])
+  },
+  async created() {
+    await this.filterQuery();
+  },
+  methods: {
+    ...mapActions(['filesDelete', 'filesQuery']),
+    download (e) {
+      window.open(`/api/files/filestore/filesDownload?filePath=${e.filePath}`);
+    },
+    async filterDelete(e) {
+      const res = await this.filesDelete({ id: e?._id });
+      this.$resChange(res, '删除成功');
+      this.filterQuery();
+    },
+    async filterQuery({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
+      await this.filesQuery({ filter, paging });
+    },
+    views () {
+
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.box {
+  width: 100%;
+  height: 100%;
+  .box-card {
+    height: 100%;
+    .el-card__body {
+      height: 100%;
+    }
+  }
+}
+</style>

+ 33 - 0
admin-files/vue.config.js

@@ -0,0 +1,33 @@
+const path = require('path')
+const frameSrc = path.resolve(__dirname, '../admin-frame')
+const packageName = require('./package.json').name
+module.exports = {
+  publicPath: `/${packageName}/`,
+  outputDir: path.join(frameSrc, `../../admin-web/${packageName}/`),
+  devServer: {
+    port: 3023,
+    headers: {
+      'Access-Control-Allow-Origin': '*'
+    },
+    proxy: {
+      '/api/': {
+        target: 'http://192.168.0.45:18090'
+        // target: 'http://127.0.0.1:18090'
+      }
+    }
+  },
+  configureWebpack: {
+    output: {
+      library: `${packageName}-[name]`,
+      libraryTarget: 'umd',
+      jsonpFunction: `webpackJsonp_${packageName}`
+    },
+    resolve: {
+      alias: {
+        '@components': path.join(frameSrc, '/src/components'),
+        '@style': path.join(frameSrc, '/style'),
+        '@lib': path.join(frameSrc, '/lib')
+      }
+    }
+  }
+}

+ 3 - 0
admin-frame/.browserslistrc

@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead

+ 5 - 0
admin-frame/.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 14 - 0
admin-frame/.env

@@ -0,0 +1,14 @@
+# 设置是否使用tab选项卡
+VUE_APP_TABS=true
+# tabs 卡片类型 (card, border-card)
+VUE_APP_TABS_CARD=card
+# 设置头部使用高的还是矮的 (max, min )
+VUE_APP_HEADER=min
+# 首页标题
+VUE_APP_HOME_TITLE=社会科学联合会信息管理系统
+# 首页描述
+VUE_APP_HOME_DESCRIDE=基于内容管理、系统管理、等功能的优秀网站管理系统。
+# 窗口使用弹出还是抽屉 (dialog And drawer)
+VUE_APP_WINDOW=dialog
+# 文件上传地址 (app = 各模块自行配置名称)
+VUE_APP_FILE_UPLOAD=/api/files/frame/upload

+ 1 - 0
admin-frame/.env.development

@@ -0,0 +1 @@
+VUE_APP_DEV=true

+ 1 - 0
admin-frame/.env.pre

@@ -0,0 +1 @@
+VUE_APP_DEV=false

+ 24 - 0
admin-frame/.eslintrc.js

@@ -0,0 +1,24 @@
+module.exports = {
+  root: true,
+  env: {
+    node: true
+  },
+  extends: [
+    'plugin:vue/essential',
+    '@vue/standard'
+  ],
+  parserOptions: {
+    parser: 'babel-eslint'
+  },
+  rules: {
+    'no-console': 0,
+    'no-debugger': 0,
+    'comma-dangle': [2, 'never'],
+    'no-extra-parens': 2,
+    'no-extra-semi': 2,
+    semi: [2, 'always'],
+    'space-before-function-paren': [0, 'always'],
+    eqeqeq: 0,
+    'no-eval': [0, { allowIndirect: true }]
+  }
+};

+ 23 - 0
admin-frame/.gitignore

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

+ 27 - 0
admin-frame/README.md

@@ -0,0 +1,27 @@
+# admin-frame
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).
+
+### qiankun渲染注意事项
+渲染子应用ID不能嵌套到路由内或者不能在组件内,存在以上情况会找不到ID

+ 5 - 0
admin-frame/babel.config.js

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

+ 86 - 0
admin-frame/lib/apps.js

@@ -0,0 +1,86 @@
+// .env配置
+const config = {
+  tabs: eval(process.env.VUE_APP_TABS ?? false),
+  dev: eval(process.env.VUE_APP_DEV ?? false)
+};
+// const ip = 'localhost';
+const ip = '192.168.0.37';
+export default [
+  {
+    // 子应用名称
+    name: 'admin-code',
+    // 子应用入口
+    entry: config.dev ? `//${ip}:3001/admin-code/` : './admin-code',
+    // 子应用渲染ID
+    container: config.tabs ? '#code' : '#content',
+    // 路由匹配规则
+    activeRule: '/admin/code'
+  },
+  // {
+  //   name: 'admin-files',
+  //   entry: '//${ip}:3002',
+  //   container: config.tabs ? '#files' : '#content',
+  //   activeRule: '/admin/files'
+  // },
+  {
+    name: 'admin-user',
+    entry: config.dev ? `//${ip}:3003/admin-user/` : 'admin-user',
+    container: config.tabs ? '#adminUser' : '#content',
+    activeRule: '/admin/adminUser'
+  },
+  {
+    name: 'admin-role',
+    entry: config.dev ? `//${ip}:3004/admin-role/` : 'admin/role',
+    container: config.tabs ? '#role' : '#content',
+    activeRule: '/admin/role'
+  },
+  // 内容管理
+  {
+    name: 'admin-menus',
+    entry: config.dev ? `//${ip}:3005/admin-menus/` : 'admin-menus',
+    container: config.tabs ? '#menus' : '#content',
+    activeRule: '/admin/menus'
+  },
+  {
+    name: 'admin-contents',
+    entry: config.dev ? `//${ip}:3007/admin-contents/` : 'admin-contents',
+    container: config.tabs ? '#contents' : '#content',
+    activeRule: '/admin/contents'
+  },
+  {
+    name: 'admin-pages',
+    entry: config.dev ? `//${ip}:3008/admin-pages` : 'admin-pages',
+    container: config.tabs ? '#pages' : '#content',
+    activeRule: '/admin/pages'
+  },
+  {
+    name: 'admin-imgNews',
+    entry: config.dev ? `//${ip}:3009/admin-imgNews/` : 'admin-imgNews',
+    container: config.tabs ? '#imgNews' : '#content',
+    activeRule: '/admin/imgNews'
+  },
+  {
+    name: 'admin-toConfig',
+    entry: config.dev ? `//${ip}:3010/admin-toConfig/` : 'admin-toConfig',
+    container: config.tabs ? '#toConfig' : '#content',
+    activeRule: '/admin/toConfig'
+  },
+  {
+    name: 'admin-log',
+    entry: config.dev ? `//${ip}:3011/admin-log/` : 'admin-log',
+    container: config.tabs ? '#log' : '#content',
+    activeRule: '/admin/log'
+  },
+  {
+    name: 'admin-files',
+    entry: config.dev ? `//${ip}:3023/admin-files/` : 'admin-files',
+    container: config.tabs ? '#files' : '#content',
+    activeRule: '/admin/files'
+  },
+  {
+    name: 'admin-role-menu',
+    entry: config.dev ? `//${ip}:3026/admin-role-menu/` : 'admin-role-menu',
+    container: config.tabs ? '#roleMenu' : '#content',
+    activeRule: '/admin/roleMenu'
+  }
+];

+ 51 - 0
admin-frame/lib/axios.js

@@ -0,0 +1,51 @@
+import axios from 'axios';
+import router from '../src/router/index';
+import { Message } from 'element-ui';
+// 添加请求拦截器
+axios.interceptors.request.use(function (config) {
+  const token = sessionStorage.getItem('token');
+  if (token) config.headers.authorization = token;
+  return config;
+}, function (error) {
+  // 对请求错误做些什么
+  return Promise.reject(error);
+});
+
+// 添加响应拦截器
+axios.interceptors.response.use(function (response) {
+  if (response.status == 401) {
+    // 返回登录处理
+    sessionStorage.removeItem('token');
+    router.replace('/frame/login');
+  }
+  if (response.status == 500) {
+    // 错误处理
+    response.data.data = { errcode: -1001, errmsg: '服务器错误' };
+  }
+  return response.data;
+}, function (error) {
+  Message.error('服务器错误');
+  // 对响应错误做点什么
+  return Promise.reject(error);
+});
+
+// 私有方法
+const request = async ({ url, method, params, data, headers }) => {
+  return await axios.request({ url, method, params, data, headers });
+};
+
+// 定义类
+class Point {
+  get(url, params, headers) {
+    return request({ url, params, headers });
+  }
+
+  post(url, data, params, headers) {
+    return request({ url, method: 'post', data, params, headers });
+  }
+
+  delete(url, params, headers) {
+    return request({ url, method: 'delete', params, headers });
+  }
+}
+export default new Point();

+ 9 - 0
admin-frame/lib/dict.js

@@ -0,0 +1,9 @@
+const dict = {
+  install (vue) {
+    vue.prototype.$dict = function (item) {
+      const dict = this.$store.state.dict;
+      return dict[item];
+    };
+  }
+};
+export default dict;

+ 11 - 0
admin-frame/lib/qiankun.js

@@ -0,0 +1,11 @@
+import { registerMicroApps, start } from 'qiankun';
+import apps from './apps';
+// .env配置
+const config = {
+  tabs: eval(process.env.VUE_APP_TABS ?? false)
+};
+const qiankunInit = () => {
+  registerMicroApps(apps);
+  start({ singular: !config.tabs, sandbox: true });
+};
+export default qiankunInit;

+ 17 - 0
admin-frame/lib/resChange.js

@@ -0,0 +1,17 @@
+const resChange = {
+  install (vue) {
+    vue.prototype.$resChange = function (data, msg) {
+      if (data.errcode !== 0) {
+        this.$message.error(data.errmsg);
+        return;
+      }
+      if (data.errcode == 0 || !data.errcode) {
+        this.$message({
+          message: msg,
+          type: 'success'
+        });
+      }
+    };
+  }
+};
+export default resChange;

+ 26 - 0
admin-frame/lib/tree.js

@@ -0,0 +1,26 @@
+// 树状结构构建插件
+const tree = {
+  install (Vue) {
+    Vue.prototype.$tree = function(options) {
+      // 子级菜单构建函数
+      const children = items => {
+        /*
+        * 根据items.code与所有菜单parentCode比较
+        * 如果相等所有菜单当前项就是子级菜单
+        * 同时调用当前函数创建多级菜单
+        */
+        const childrenList = options.filter(j => items.code == j.parentCode).map(e => children(e));
+        // 如果当前子菜单项存在 就添加children属性
+        if (childrenList.length > 0) {
+          return { ...items, children: childrenList };
+        }
+        // 不存在就不添加
+        return { ...items };
+      };
+      // 过滤一级菜单并添加子级菜单
+      const list = options.filter(e => e.parentCode == null || e.parentCode == '' || e.parentCode == 'null').map(e => children(e));
+      return list;
+    };
+  }
+};
+export default tree;

+ 42 - 0
admin-frame/mock/menu.js

@@ -0,0 +1,42 @@
+export default [
+  {
+    module: 'frame',
+    path: '/frame/home',
+    title: '首页',
+    code: 'frameHome',
+    parentCode: null,
+    icon: 'el-icon-star-on'
+  },
+  {
+    module: 'gaf',
+    path: '',
+    title: '系统管理',
+    code: 'gaf',
+    parentCode: null,
+    icon: 'el-icon-star-on'
+  },
+  {
+    module: 'code',
+    path: '/code/home',
+    title: '字典管理',
+    code: 'code',
+    parentCode: 'gaf',
+    icon: 'el-icon-star-on'
+  },
+  {
+    module: 'adminUser',
+    path: '/adminUser/home',
+    title: '系统用户',
+    code: 'adminUser',
+    parentCode: 'gaf',
+    icon: 'el-icon-star-on'
+  },
+  {
+    module: 'role',
+    path: '/role/home',
+    title: '系统角色',
+    code: 'role',
+    parentCode: 'gaf',
+    icon: 'el-icon-star-on'
+  }
+];

文件差异内容过多而无法显示
+ 28157 - 0
admin-frame/package-lock.json


+ 40 - 0
admin-frame/package.json

@@ -0,0 +1,40 @@
+{
+  "name": "admin-frame",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve --mode development",
+    "build": "vue-cli-service build --mode pre",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.24.0",
+    "core-js": "^3.6.5",
+    "element-ui": "^2.15.6",
+    "lodash": "^4.17.21",
+    "qiankun": "^2.6.0",
+    "uuid": "^8.3.2",
+    "vue": "^2.6.11",
+    "vue-router": "^3.2.0",
+    "vuex": "^3.4.0",
+    "wangeditor": "^4.7.11"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-plugin-vuex": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/eslint-config-standard": "^5.1.2",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-node": "^11.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "eslint-plugin-vue": "^6.2.2",
+    "sass": "^1.45.0",
+    "sass-loader": "^10.0.0",
+    "vue-template-compiler": "^2.6.11"
+  }
+}

二进制
admin-frame/public/favicon.ico


+ 17 - 0
admin-frame/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= htmlWebpackPlugin.options.title %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 225 - 0
admin-frame/src/App.vue

@@ -0,0 +1,225 @@
+<template>
+  <div id="app">
+    <router-view v-if="$route.path == '/frame/login'"></router-view>
+    <div v-else class="main">
+      <div class="left" :style="{ 'width': is_collapse.leftWidth }">
+        <logo :isCollapse="isCollapse" class="logo" :style="{ 'height': computedHeigth.headerHeigth }"></logo>
+        <menus ref="menus" :menuList="menuList" :isCollapse="isCollapse" class="menu" :style="{ 'height': computedHeigth.menuHeigth }" @menuSelect="menuSelect"></menus>
+      </div>
+      <div class="right" :style="{ 'width': is_collapse.rightWidth }">
+        <headers class="header" :style="{ 'height': computedHeigth.headerHeigth }" @isCollapseChage="isCollapse = $event"></headers>
+        <!-- 非标签页时使用 -->
+        <breadcrumb v-if="!config.tabs" :menuList="menuList" :home="frameTabs"></breadcrumb>
+        <!-- 标签页 -->
+        <el-tabs v-if="config.tabs" class="tabBox" :style="{ 'height': computedHeigth.contentHeigth }" v-model="editableTabsValue" :type="config.tabs_card" @tab-remove="removeTab" @tab-click="clickTab">
+          <el-tab-pane
+            v-for="item in frameTabs"
+            :key="item.code"
+            :label="item.title"
+            :name="item.code"
+          >
+            <router-view></router-view>
+          </el-tab-pane>
+          <el-tab-pane
+            closable
+            v-for="item in editableTabs"
+            :key="item.code"
+            :label="item.title"
+            :name="item.code"
+          >
+            <template v-if="editableTabsValue == item.code">
+              <div :id="item.module" class="content"></div>
+            </template>
+          </el-tab-pane>
+        </el-tabs>
+        <!-- 非标签页时使用 -->
+        <router-view v-if="is_frame && !config.tabs"></router-view>
+        <div v-show="!is_frame" v-if="!config.tabs" id="content" class="content"></div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+/* 此处进行菜单数据模拟,正式调试后删除 */
+// import menuList from '@mock/menu.js';
+/* 调试结束符号 */
+import style from '@style/index.module.scss';
+import headers from '@components/header';
+import menus from '@components/menu';
+import logo from '@components/header/logo';
+import breadcrumb from '@components/header/breadcrumb';
+import { mapState, mapActions } from 'vuex';
+// .env配置
+const config = {
+  tabs: eval(process.env.VUE_APP_TABS ?? false),
+  headerHeigth: process.env.VUE_APP_HEADER,
+  tabs_card: process.env.VUE_APP_TABS_CARD
+};
+export default {
+  components: {
+    headers,
+    menus,
+    logo,
+    breadcrumb
+  },
+  computed: {
+    ...mapState(['menuList']),
+    // 切换路由或dom对象计算属性 如果当前选项包含frame 使用路由 否则 使用dom
+    is_frame() {
+      return this.editableTabsValue.includes('frame');
+    },
+    // 切换菜单宽度计算属性
+    is_collapse() {
+      return { leftWidth: this.isCollapse ? style.minLeftWidth : style.maxLeftWidth, rightWidth: this.isCollapse ? style.maxRightWidth : style.minRightWidth };
+    },
+    // 切换header高度 与 menu高度
+    computedHeigth() {
+      if (config.headerHeigth == 'max') {
+        return { headerHeigth: style.maxHeaderHeigth, menuHeigth: style.minMenuHeigth, contentHeigth: style.minContentHeigth };
+      }
+      return { headerHeigth: style.minHeaderHeigth, menuHeigth: style.maxMenuHeigth, contentHeigth: style.maxContentHeigth };
+    }
+  },
+  data() {
+    return {
+      // .env配置
+      config,
+      // 折叠收起菜单
+      isCollapse: false,
+      // tabs当前选项
+      editableTabsValue: '',
+      // 默认不可关闭页面数组
+      frameTabs: [
+        { module: 'frame', path: '/frame/home', title: '首页', code: 'frameHome', parentCode: null }
+      ],
+      // 可关闭页面数组
+      editableTabs: []
+    };
+  },
+  async mounted() {
+    if (sessionStorage.userInfo) {
+      const { id } = JSON.parse(sessionStorage.userInfo);
+      await this.queryUserMenu({ userId: id });
+    }
+    if (this.$route.path !== '/frame/login') this.menuInit();
+  },
+  methods: {
+    ...mapActions(['queryUserMenu']),
+    // 初始化菜单点击
+    menuInit() {
+      // 获取当前选中tab 没有默认设置Home页
+      this.editableTabsValue = sessionStorage.getItem('tabs') ?? 'frameHome';
+      // 调用菜单点击函数
+      this.$refs.menus.menuSelect(this.editableTabsValue);
+    },
+    // 菜单选择函数
+    menuSelect(e) {
+      // 赋值当前选项
+      this.editableTabsValue = e.code;
+      // 不是子应用向选项组添加当前选项
+      if (!this.is_frame && !this.editableTabs.includes(e)) {
+        this.editableTabs.push(e);
+      }
+      this.clickTab(e);
+    },
+    // tab点击函数
+    clickTab (e) {
+      // 解决点击tab标签是导航不跟随切换问题
+      if (this.$refs.menus.defaultActiveItem !== this.editableTabsValue) {
+        this.$refs.menus.menuSelect(this.editableTabsValue);
+      }
+      // 解决tab标签实例不存在code属性
+      if (!e.code) e.code = e.name;
+      // 存储 sessionStorage
+      sessionStorage.setItem('tabs', e.code);
+      let item;
+      // 判断是不是子应用
+      if (!this.is_frame) {
+        item = this.editableTabs.find(i => i.code == e.code);
+      } else {
+        item = this.frameTabs.find(i => i.code == e.code);
+      }
+      // 如果是当前路由,直接返回
+      if (item.path == this.$route.path) return;
+      // 路由跳转
+      this.$router.push(item.path);
+    },
+    // 移除tab标签函数
+    removeTab (index) {
+      // 删除当前选项
+      this.editableTabs = this.editableTabs.filter(e => e.code !== index);
+      // 删除后选择打开的最后一项 或 首页
+      this.editableTabsValue = this.editableTabs[this.editableTabs.length - 1]?.code ?? 'frameHome';
+      this.$refs.menus.menuSelect(this.editableTabsValue);
+    }
+  },
+  watch: {
+    $route(to) {
+      if (this.$route.path == '/') this.$router.go(0);
+    }
+  }
+};
+</script>
+
+<style lang="scss">
+@import '@style/index.scss';
+body {
+  margin: 0;
+  padding: 0;
+}
+#app {
+  width: 100vw;
+  height: 100vh;
+  .main {
+    display: flex;
+    overflow: hidden;
+    width: 100%;
+    height: 100%;
+    .left {
+      height: 100vh;
+      .logo {
+        width: 100%;
+        background: $menuBackgroundColor;
+      }
+      .menu {
+        width: 100%;
+      }
+    }
+    .right {
+      height: 100%;
+      .header {
+        height: 10vh;
+      }
+      .tabBox {
+        width: 100%;
+        .el-tabs__header {
+          margin: 0;
+        }
+        .el-tabs__content {
+          width: 100%;
+          height: 97%;
+          .el-tab-pane {
+            width: 100%;
+            height: 100%;
+          }
+        }
+        .content {
+          height: 100%;
+          width: 100%;
+          > div {
+            height: 98%;
+          }
+        }
+      }
+      #content {
+        height: 100%;
+        width: 100%;
+        > div {
+          height: 98%;
+        }
+      }
+    }
+  }
+}
+</style>

二进制
admin-frame/src/assets/bg2.jpg


二进制
admin-frame/src/assets/code.png


二进制
admin-frame/src/assets/home.png


二进制
admin-frame/src/assets/logo-xr.png


二进制
admin-frame/src/assets/logo-xr2.png


二进制
admin-frame/src/assets/logo.png


+ 74 - 0
admin-frame/src/components/deepTree.vue

@@ -0,0 +1,74 @@
+<template>
+  <el-tree
+    :data="treeList"
+    :props="defaultProps"
+    accordion
+    :expand-on-click-node="false"
+    node-key="code"
+    default-expand-all
+  >
+    <span class="custom-tree-node" slot-scope="{ node, data }">
+      <el-tooltip v-if="node.label.length > 8" effect="dark" :content="node.label" placement="top-start">
+        <span @click="handleNodeClick(node, data)">{{ node.label.slice(0, 5) + '...' }}</span>
+      </el-tooltip>
+      <span @click="handleNodeClick(node, data)" v-else>{{ node.label }}</span>
+      <span v-if="operation">
+        <el-button @click="edit(node)" type="text" size="mini" icon="el-icon-edit"></el-button>
+        <el-button @click="remove(data)" type="text" size="mini" icon="el-icon-delete"></el-button>
+      </span>
+    </span>
+  </el-tree>
+</template>
+
+<script>
+export default {
+  props: {
+    // 控件渲染数据源
+    data: { type: Array, default: () => [] },
+    // 是否启用修改删除操作
+    operation: { type: Boolean, default: false }
+  },
+  computed: {
+    treeList() {
+      return this.$tree(this.data) ?? [];
+    }
+  },
+  data() {
+    return {
+      defaultProps: {
+        children: 'children',
+        label: 'name'
+      }
+    };
+  },
+  mounted() {},
+  methods: {
+    // 选择事件
+    handleNodeClick(node, data) {
+      this.$emit('nodeClick', { node, data });
+    },
+    // 修改事件
+    edit(node) {
+      this.$emit('edit', node?.data);
+    },
+    // 删除事件
+    remove(data) {
+      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', { type: 'warning' })
+        .then(_ => {
+          this.$emit('remove', data);
+        })
+        .catch(_ => {});
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.custom-tree-node {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  padding-right: 8px;
+}
+</style>

+ 51 - 0
admin-frame/src/components/dialogAndDrawer.vue

@@ -0,0 +1,51 @@
+<template>
+  <el-drawer
+    v-if="!config.window"
+    :title="title"
+    :visible.sync="visibleSync"
+    :direction="direction"
+    :size="width"
+    :before-close="handleClose">
+    <slot name="windowMain"></slot>
+  </el-drawer>
+  <el-dialog
+    v-else
+    :title="title"
+    :visible.sync="visibleSync"
+    :width="width"
+    :before-close="handleClose">
+    <slot name="windowMain"></slot>
+  </el-dialog>
+</template>
+
+<script>
+const config = {
+  window: process.env.VUE_APP_WINDOW == 'dialog'
+};
+export default {
+  props: {
+    // 是否显示窗口
+    visibleSync: { type: Boolean, default: false },
+    // 抽屉弹出方向 默认右向左
+    direction: { type: String, default: 'rtl' },
+    // 窗口标题
+    title: { type: String, default: '' },
+    // 窗口宽度
+    width: { type: String, default: '30%' }
+  },
+  computed: {},
+  data() {
+    return {
+      config
+    };
+  },
+  mounted() {},
+  methods: {
+    handleClose() {
+      this.$emit('close');
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+</style>

+ 132 - 0
admin-frame/src/components/editoritem.vue

@@ -0,0 +1,132 @@
+<template lang="html">
+  <div class="editor">
+    <div ref="toolbar" class="toolbar">
+    </div>
+    <div ref="editor" class="text">
+    </div>
+  </div>
+</template>
+
+<script>
+import E from 'wangeditor';
+import $axios from '@lib/axios.js';
+export default {
+  name: 'editoritem',
+  data () {
+    return {
+      editor: null,
+      info_: null
+    };
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
+  props: {
+    value: {
+      type: String,
+      default: ''
+    },
+    isClear: {
+      type: Boolean,
+      default: false
+    }
+  },
+  watch: {
+    isClear (val) {
+      // 触发清除文本域内容
+      if (val) {
+        this.editor.txt.clear();
+        this.info_ = null;
+      }
+    },
+    value: function (value) {
+      if (value !== this.editor.txt.html()) {
+        this.editor.txt.html(this.value);
+      }
+    }
+    // value为编辑框输入的内容,这里我监听了一下值,当父组件调用得时候,如果给value赋值了,子组件将会显示父组件赋给的值
+  },
+  mounted () {
+    this.seteditor();
+    this.editor.txt.html(this.value);
+  },
+  methods: {
+    seteditor () {
+      this.editor = new E(this.$refs.toolbar, this.$refs.editor);
+      this.editor.config.uploadImgShowBase64 = false; // base 64 存储图片
+      this.editor.config.uploadImgMaxSize = 50 * 1024 * 1024; // 将图片大小限制为 2M
+      this.editor.config.uploadImgMaxLength = 1; // 限制一次最多上传 3 张图片
+      this.editor.config.uploadImgTimeout = 3 * 60 * 1000; // 设置超时时间
+      this.editor.config.showLinkImg = false;
+      // 配置菜单
+      this.editor.config.menus = [
+        'head', // 标题
+        'bold', // 粗体
+        'fontSize', // 字号
+        'fontName', // 字体
+        'italic', // 斜体
+        'underline', // 下划线
+        'strikeThrough', // 删除线
+        'foreColor', // 文字颜色
+        'backColor', // 背景颜色
+        'link', // 插入链接
+        'list', // 列表
+        'justify', // 对齐方式
+        'quote', // 引用
+        'emoticon', // 表情
+        'image', // 插入图片
+        'table', // 表格
+        'video', // 插入视频
+        'code', // 插入代码
+        'undo', // 撤销
+        'redo', // 重复
+        'fullscreen' // 全屏
+      ];
+      // 自定义文件上传
+      this.editor.config.customUploadImg = async function (resultFiles, insertImgFn) {
+        // resultFiles 是 input 中选中的文件列表
+        var data = new FormData();
+        const filesUpload = '/api/files/filestore/upload';
+        data.append('file', resultFiles[0]);
+        const headers = {
+          'Content-Type': 'multipart/form-data'
+        };
+        const res = await $axios.post(filesUpload, data, null, headers);
+        // insertImgFn 是获取图片 url 后,插入到编辑器的方法
+        const url = `http://127.0.0.1:9002${res.data.filePath}`;
+        console.log(url);
+        // 上传图片,返回结果,将图片插入到编辑器中
+        insertImgFn(url);
+      };
+      // this.editor.config.onlineVideoCheck = (src) => {
+      //   const videoMod = `<iframe src="${src}"> </iframe>`;
+      //   // this.editor.txt.append(videoMod);
+      //   this.editor.cmd.do('insertHTML', videoMod);
+      // };
+      this.editor.config.onchange = (html) => {
+        this.info_ = html; // 绑定当前逐渐地值
+        this.$emit('change', this.info_); // 将内容同步到父组件中
+      };
+      // 创建富文本编辑器
+      this.editor.create();
+    }
+  }
+};
+</script>
+
+<style lang="css">
+  .editor {
+    width: 100%;
+    margin: 0 auto;
+    position: relative;
+    z-index: 0;
+  }
+  .toolbar {
+    border: 1px solid #ccc;
+  }
+  .text {
+    border: 1px solid #ccc;
+    min-height: 300px;
+  }
+</style>

+ 148 - 0
admin-frame/src/components/exports.vue

@@ -0,0 +1,148 @@
+<template>
+  <div class="upload_box">
+    <el-button :disabled="existence" type="text" @click="upload"><i class="el-dropdown-link el-icon-download"></i>{{ typeName || '文件导出' }}</el-button>
+    <el-dialog :close-on-click-modal="false" :title="typeName" :visible.sync="dialogVisible" width="400px" @close="closes">
+      <div>
+        <el-input size="small" v-model="fileName" placeholder="请选输入导出文件名"></el-input>
+        <div style="margin: 30px 0;"></div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button size="small" @click="dialogVisible = false">取 消</el-button>
+        <el-button size="small" type="primary" @click="uploadFile">确 定</el-button>
+      </span>
+    </el-dialog>
+    <el-dialog :close-on-click-modal="false" :title="successDate ? '数据导出进度' : '数据导出结果'" :visible.sync="progress" width="400px">
+      <!-- 显示进度 -->
+      <div v-if="successDate">
+        <h3>{{ typeName }}</h3>
+        <div style="margin: 30px 0;"></div>
+        <el-progress :percentage="percentage"></el-progress>
+        <div style="margin: 30px 0;"></div>
+      </div>
+      <!-- 显示成功后信息下载日志 -->
+      <div v-else>
+        <h3 class="success">{{ summary }}</h3>
+        <div style="margin: 30px 0;"></div>
+        <span slot="footer" class="dialog-footer">
+          <el-button type="text" @click="btn">导出文件下载</el-button>
+        </span>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { mapActions } from 'vuex';
+export default {
+  props: {
+    // 数据导入类型 (user,vip)
+    type: String,
+    // 业务名称
+    typeName: { type: String, default: '' }
+  },
+  data() {
+    return {
+      // 下载文件类型
+      fileType: 'excel',
+      // 选择信息弹出
+      dialogVisible: false,
+      // 按钮禁用
+      existence: false,
+      // 进度
+      percentage: 0,
+      // 上传前选择
+      option: 'overwrite',
+      // 进度弹出
+      progress: false,
+      // 成功后切换
+      successDate: true,
+      // 成功后文字
+      summary: null,
+      // 任务id
+      id: null,
+      // 导入模板命名
+      fileName: null,
+      // 文件流
+      file: null
+    };
+  },
+  methods: {
+    ...mapActions(['exports', 'progressInfo']),
+    // 点击上传按钮
+    upload() {
+      this.dialogVisible = true;
+    },
+    // 确定
+    async uploadFile() {
+      this.dialogVisible = false;
+      this.summary = null;
+      const res = await this.exports({ type: this.type, fileType: this.fileType });
+      if (res && !res.errcode) {
+        this.progress = true;
+        this.timeout(res.taskId);
+      } else {
+        this.$message.error(res.errmsg);
+      }
+    },
+    timeout(res) {
+      const Interval = setTimeout(async () => {
+        const info = await this.progressInfo({ taskId: res });
+        console.log(info);
+        if (info && info.status !== 'error') {
+          this.percentage = info.progress || 0;
+          if (info.progress == 100) {
+            this.id = info.taskId;
+            this.successDate = false;
+            this.summary = '导出成功';
+            clearInterval(Interval);
+            this.$emit('refreshData');
+            this.percentage = 0;
+          } else {
+            this.timeout(info.taskId);
+          }
+        } else {
+          clearInterval(Interval);
+          this.$message.error(info?.errmsg || '错误');
+        }
+      }, 1000);
+    },
+    // 详情下载
+    async btn() {
+      window.open(`/api/importandexport/handle/exportsDownload?fileName=${this.typeName}&taskId=${this.id}`);
+    },
+    // 关闭窗口
+    closes() {
+      this.successDate = true;
+      this.file = null;
+      this.fileName = null;
+      this.$emit('closes');
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+input {
+  display: none;
+}
+.el-button--text {
+  padding: 0;
+}
+.upload_box {
+  line-height: 0;
+}
+.success {
+  width: 100%;
+  color: #67c23a;
+}
+.error {
+  width: 100%;
+  color: #f56c6c;
+}
+.jump {
+  width: 100%;
+  color: #e6a23c;
+}
+.left-footer {
+  float: left;
+  margin-top: 10px;
+}
+</style>

+ 123 - 0
admin-frame/src/components/filterList/index.vue

@@ -0,0 +1,123 @@
+<template>
+  <div class="filter-box">
+    <search v-if="filter" :filed="filterFiled" @query="searchQuery">
+      <template v-slot:search="{ item, formInline }">
+        <slot v-bind="{ item, formInline }" name="search"></slot>
+      </template>
+    </search>
+    <tables
+      :selection="selection"
+      :readOnly="readOnly"
+      :tableData="tableData"
+      :operation="operation"
+      :filed="filed"
+      :options="options"
+      @handle="handle"
+      @handleSelectionChange="$emit('handleSelectionChange', $event)"
+      @dblclick="$emit('dblclick', $event)"
+    >
+    <template v-slot:tablesPre>
+      <slot name="tablesPre"></slot>
+    </template>
+    <template v-slot:tablesScope="{ item }">
+      <slot name="tablesScope" v-bind="{ item }"></slot>
+    </template>
+    <template v-slot:tablesExt>
+      <slot name="tablesExt"></slot>
+    </template>
+    </tables>
+    <pagination ref="pagination" v-if="pagination" :total="total" :pageSize="pageSize" @query="paginationsQuery"></pagination>
+  </div>
+</template>
+<script>
+import tables from './table.vue';
+import search from './search.vue';
+import pagination from './pagination.vue';
+// import _ from 'lodash';
+export default {
+  components: {
+    tables,
+    search,
+    pagination
+  },
+  props: {
+    // 是否使用分页
+    pagination: { type: Boolean, default: true },
+    // 是否使用查询
+    filter: { type: Boolean, default: true },
+    // 多选属性
+    selection: { type: Boolean, default: false },
+    // 只读属性
+    readOnly: { type: Boolean, default: false },
+    // 数据
+    tableData: { type: Array, default: () => [] },
+    // 操作选项
+    operation: {
+      type: Array,
+      default: () => [
+        { name: 'edit', label: '修改', icon: 'el-icon-edit' },
+        { name: 'delete', label: '删除', icon: 'el-icon-delete' }
+      ]
+    },
+    // 列表循环项
+    filed: { type: Array, default: () => [] },
+    // 分页总数
+    total: { type: Number, default: 0 },
+    // 每页条数
+    pageSize: { type: Number, default: 10 },
+    options: {
+      type: Object,
+      default: () => ({
+        size: 'mini',
+        width: 150
+      })
+    }
+  },
+  data() {
+    return {
+      filters: {},
+      paging: {}
+    };
+  },
+  computed: {
+    filterFiled() {
+      return this.filed.filter(e => e.filter == true);
+    }
+  },
+  mounted() {},
+  methods: {
+    // 操作函数
+    handle({ row, item }) {
+      if (item.name == 'delete') {
+        this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', { type: 'warning' })
+          .then(_ => {
+            this.$emit(item.name, row);
+          })
+          .catch(_ => {});
+        return;
+      }
+      this.$emit(item.name, row);
+    },
+    // 搜索函数
+    searchQuery(e) {
+      this.filters = e;
+      this.$refs.pagination.resetPage(-1);
+    },
+    // 分页函数
+    paginationsQuery(e) {
+      this.paging = e;
+      this.query();
+    },
+    // 查询函数(分页加搜索)
+    query() {
+      this.$emit('query', { filter: this.filters, paging: this.paging });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.filter-box {
+  width: 100%;
+  margin: 0 auto;
+}
+</style>

+ 47 - 0
admin-frame/src/components/filterList/pagination.vue

@@ -0,0 +1,47 @@
+<template>
+  <div class="pagination-box">
+    <el-pagination
+      @current-change="handleCurrentChange"
+      :current-page="currentPage"
+      :page-size="pageSize"
+      layout="total, prev, pager, next, jumper"
+      :total="total">
+    </el-pagination>
+  </div>
+</template>
+<script>
+export default {
+  components: {},
+  props: {
+    total: { type: Number, default: 0 },
+    pageSize: { type: Number, default: 10 }
+  },
+  data() {
+    return {
+      currentPage: 1
+    };
+  },
+  computed: {},
+  mounted() {},
+  methods: {
+    handleCurrentChange(e) {
+      this.currentPage = e;
+      // const currentPage = e > 0 ? e - 1 : 0;
+      this.$emit('query', { page: e > 0 ? e - 1 : 0, size: this.pageSize });
+    },
+    resetPage(e) {
+      if (e == -1) {
+        this.currentPage = 0;
+      } else {
+        this.currentPage = Math.ceil(this.total / this.pageSize);
+      }
+      this.$emit('query', { page: this.currentPage, size: this.pageSize });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.pagination-box {
+  margin-top: 10px;
+}
+</style>

+ 85 - 0
admin-frame/src/components/filterList/search.vue

@@ -0,0 +1,85 @@
+<template>
+  <el-form size="mini" ref="ruleForm" :inline="true" :model="formInline" class="demo-form-inline search">
+    <!-- 控件 -->
+    <el-form-item v-for="(item, index) in filterFiled" :key="index" :label="`${item.label}:`" :prop="item.name" v-show="index + 1 <= itemLength">
+      <!-- 输入框 -->
+      <el-input v-if="!item.formater" v-model="formInline[item.name]" :placeholder="item.placeholder || `请输入${item.label}`" clearable></el-input>
+      <!-- 选择器控件 -->
+      <el-select v-if="item.formater == 'dict'" v-model="formInline[item.name]" :placeholder="item.placeholder || `请选择${item.label}`" clearable>
+        <el-option v-for="(e, i) in item.dict" :key="`option${i}`" :label="e.name" :value="e.code"></el-option>
+      </el-select>
+      <!-- 时间控件 -->
+      <el-date-picker
+        clearable
+        value-format="timestamp"
+        v-if="item.formater == 'date'"
+        v-model="formInline[item.name]"
+        :type="item.dateType"
+        :placeholder="item.placeholder || `选择${item.dateType == 'data' ? '日期' : '日期时间'}`"
+        format="yyyy 年 MM 月 dd 日"
+      >
+      </el-date-picker>
+      <slot v-bind="{ item, formInline }" v-if="item.formater == 'slot'" name="search"></slot>
+    </el-form-item>
+    <!-- 按钮 -->
+    <el-form-item>
+      <el-button type="primary" @click="onSubmit">查询</el-button>
+      <el-button type="primary" @click="resetForm('ruleForm')">重置</el-button>
+      <el-button type="primary" v-if="filterFiled.length > 3" @click="itemLength = itemLength > 3 ? 3 : 8">{{ itemLength > 3 ? '收起' : '更多' }}</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import _ from 'lodash';
+export default {
+  name: 'filter-box',
+  props: {
+    filed: { type: Array, default: () => [] }
+  },
+  data() {
+    return {
+      formInline: {},
+      more: false,
+      itemLength: 3
+    };
+  },
+  computed: {
+    filterFiled() {
+      const fileds = _.cloneDeep(this.filed);
+      return fileds.map(e => {
+        if (e.formater && e.formater.includes('dict')) {
+          e.dict = this.$dict(e.formater.split(':')[1]) || [];
+          e.formater = 'dict';
+        }
+        if (e.formater && e.formater.includes('date')) {
+          e.dateType = e.formater.split(':')[1];
+          e.formater = 'date';
+        }
+        if (e.formater && e.formater.includes('slot')) {
+          e.formater = 'slot';
+        }
+        return ({ ...e });
+      });
+    }
+  },
+  methods: {
+    onSubmit() {
+      const filter = {};
+      for (const i in this.formInline) {
+        if (this.formInline[i] ?? false) filter[i] = this.formInline[i];
+      }
+      this.$emit('query', filter);
+    },
+    resetForm(formName) {
+      this.$refs[formName].resetFields();
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.search {
+  width: 68%;
+}
+</style>

+ 133 - 0
admin-frame/src/components/filterList/table.vue

@@ -0,0 +1,133 @@
+<template>
+  <el-table
+    class="tableBox"
+    size="mini"
+    :border="true"
+    :data="listFields"
+    style="width: 100%"
+    @selection-change="handleSelectionChange"
+    @row-dblclick="dblclick"
+    v-bind="options">
+  >
+    <!-- 多选列 -->
+    <el-table-column v-if="selection" type="selection" stripe width="55"></el-table-column>
+
+    <!-- 前插槽 -->
+    <slot name="tablesPre"> </slot>
+
+    <!-- 列表 -->
+    <el-table-column v-for="(item, index) in filed" :key="index" :label="item.label" label-class-name="labelName">
+      <template slot-scope="scope">
+        <i v-if="item.icon && item.formater !== 'slot'" :class="item.icon"></i>
+        <span v-if="item.formater !== 'slot'" class="text" style="margin-left: 10px">{{ scope.row[item.name] }}</span>
+        <slot name="tablesScope" v-bind="{ item }" v-if="item.formater == 'slot'"></slot>
+      </template>
+    </el-table-column>
+
+    <!-- 后插槽 -->
+    <slot name="tablesExt"></slot>
+
+    <!-- 操作列 -->
+    <el-table-column v-if="!readOnly" :align="'left'" :width="options.width" label="操作" label-class-name="labelName">
+      <template slot-scope="scope">
+        <el-tooltip
+          v-for="(item, index) in operation"
+          :key="index"
+          class="item"
+          effect="dark"
+          :content="item.label"
+          placement="top-start"
+        >
+          <el-button type="text" v-if="item.icon" :class="item.icon" :size="options.size" @click="handle(scope.row, item)">{{ item.label }}</el-button>
+          <el-button type="text" v-else  :size="options.size" @click="handle(scope.row, item)">{{ item.label }}</el-button>
+        </el-tooltip>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+
+<script>
+import _ from 'lodash';
+export default {
+  props: {
+    // 多选属性
+    selection: { type: Boolean, default: false },
+    // 只读属性
+    readOnly: { type: Boolean, default: false },
+    // 数据
+    tableData: { type: Array, default: () => [] },
+    // 操作按钮选项
+    operation: {
+      type: Array,
+      default: () => [
+        { name: 'edit', label: '修改', icon: 'el-icon-edit' },
+        { name: 'delete', label: '删除', icon: 'el-icon-delete' }
+      ]
+    },
+    // 列表循环项
+    filed: { type: Array, default: () => [] },
+    // 操作列属性选项
+    options: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {};
+  },
+  computed: {
+    listFields() {
+      let fileds = _.cloneDeep(this.filed);
+      fileds = fileds.map(e => {
+        if (e.formater && e.formater.includes('dict')) {
+          e.dict = this.$dict(e.formater.split(':')[1]);
+          e.formater = 'dict';
+        }
+        return e;
+      });
+      this.tableData.map(i => {
+        fileds.find(e => {
+          if (e.formater == 'dict' && e.dict) {
+            e.dict.find(k => {
+              if (k.code == i[e.name]) i[e.name] = k.name;
+            });
+          }
+        });
+        return i;
+      });
+      return this.tableData;
+    }
+  },
+  mounted() {},
+  methods: {
+    // 操作函数
+    handle(row, item) {
+      this.$emit('handle', { row, item });
+    },
+    // 多选函数
+    handleSelectionChange(val) {
+      this.$emit('handleSelectionChange', val);
+    },
+    // 单元行双击
+    dblclick(row, column, event) {
+      this.$emit('dblclick', { row, column, event });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.tableBox {
+  ::v-deep .labelName {
+    font-size: 15px;
+    font-weight: 900;
+    color: #666;
+  }
+}
+.text {
+  width: 100%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  border: none;
+}
+</style>

+ 53 - 0
admin-frame/src/components/filterList/调用实例.md

@@ -0,0 +1,53 @@
+# 操作按钮选项
+operation: [
+    { name: 'edit', label: '修改', icon: 'el-icon-edit' },
+## name = delete 时 会出现二次确认
+    { name: 'delete', label: '删除', icon: 'el-icon-delete' }
+],
+# 列表filed渲染 formater为搜索使用
+filed: [
+## 日期类型
+    { label: '日期', name: 'date', icon: 'el-icon-time', filter: true, formater: 'date:datetime' },
+## 普通输入类型
+    { label: '名字', name: 'name', filter: true, placeholder: '输入名字' },
+<!-- ## 选择类型
+    { label: '地址', name: 'address', filter: true, formater: 'dict:status' }
+], -->
+# 列表显示数据
+tableData: [
+    { date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' },
+    { date: '2016-05-04', name: '王小虎', address: '上海市普陀区金沙江路 1517 弄' },
+    { date: '2016-05-01', name: '王小虎', address: '上海市普陀区金沙江路 1519 弄' }
+]
+# 调用
+<filterList :tableData="tableData" :filed="filed" :operation="operation" @edit="filtereEdit" @delete="filterDelete" @query="filterQuery"></filterList>
+
+# 参数详情
+    // 是否使用分页
+    pagination: { type: Boolean, default: true },
+    // 是否使用查询
+    filter: { type: Boolean, default: true },
+    // 多选属性
+    selection: { type: Boolean, default: false },
+    // 只读属性
+    readOnly: { type: Boolean, default: false },
+    // 数据
+    tableData: { type: Array, default: () => [] },
+    // 操作选项
+    operation: {
+        type: Array,
+        default: () => [
+        { name: 'edit', label: '修改', icon: 'el-icon-edit' },
+        { name: 'delete', label: '删除', icon: 'el-icon-delete' }
+        ]
+    },
+    // 列表循环项
+    filed: { type: Array, default: () => [] },
+    // 分页总数
+    total: { type: Number, default: 111 },
+    // 每页条数
+    pageSize: { type: Number, default: 10 }
+# 默认返回函数
+    edit
+    delete
+    query

+ 130 - 0
admin-frame/src/components/formData/index.vue

@@ -0,0 +1,130 @@
+<template>
+  <el-form :model="formdata" :rules="rules" ref="form" :label-width="labelWidth" class="demo-formdata" size="mini">
+    <el-form-item v-for="(item, index) in filterFiled" :key="`item-${index}`" :label="item.label" :prop="item.name">
+      <!-- 输入控件 -->
+      <el-input v-if="!item.formater" v-model="formdata[item.name]" :placeholder="item.placeholder || `请输入${item.label}`"></el-input>
+      <!-- 选择控件 -->
+      <el-select v-if="item.formater == 'dict'" v-model="formdata[item.name]" :placeholder="item.placeholder || `请选择${item.label}`">
+        <el-option v-for="(e, i) in item.dict" :key="`option${i}`" :label="e.name" :value="e.code"></el-option>
+      </el-select>
+      <!-- 时间控件 -->
+      <el-date-picker
+        clearable
+        value-format="timestamp"
+        v-if="item.formater == 'date'"
+        v-model="formdata[item.name]"
+        :type="item.dateType"
+        :placeholder="item.placeholder || `选择${item.dateType == 'date' ? '日期' : '日期时间'}`"
+      >
+      </el-date-picker>
+      <!-- 插槽 -->
+      <slot v-bind="{ item, formdata }" v-if="item.formater == 'slot'" name="formItem"></slot>
+    </el-form-item>
+    <slot name="ext" v-bind="{ formdata }"></slot>
+    <el-form-item>
+      <el-button v-for="(item, index) in operation" :key="index" :type="item.name !== 'resetForm' ? 'primary' : ''" @click="formBtnClick(item.name, 'form')">{{ item.label }}</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import _ from 'lodash';
+export default {
+  name: 'forms',
+  props: {
+    // 数据源
+    data: { type: Object, default: () => {} },
+    // 渲染项
+    filed: { type: Array, default: () => [] },
+    // 规则项
+    rules: { type: Object, default: () => [] },
+    // label宽度
+    labelWidth: { type: String, default: '100px' },
+    // 操作按钮选项
+    operation: {
+      type: Array,
+      default: () => [
+        { name: 'save', label: '提交' },
+        { name: 'resetForm', label: '重置' }
+      ]
+    }
+  },
+  components: {},
+  computed: {
+    filterFiled() {
+      const fileds = _.cloneDeep(this.filed);
+      return fileds.map(e => {
+        if (e.formater && e.formater.includes('dict')) {
+          e.dict = this.$dict(e.formater.split(':')[1]);
+          e.formater = 'dict';
+        }
+        if (e.formater && e.formater.includes('date')) {
+          e.dateType = e.formater.split(':')[1];
+          e.formater = 'date';
+        }
+        if (e.formater && e.formater.includes('slot')) {
+          e.formater = 'slot';
+        }
+        return ({ ...e });
+      });
+    }
+  },
+  data() {
+    return {
+      formdata: { ...this.data }
+    };
+  },
+  mounted() {},
+  methods: {
+    formBtnClick(name, formName) {
+      if (name == 'resetForm') {
+        this.resetForm(formName);
+        return;
+      }
+      if (name == 'save') {
+        this.submitForm(formName);
+        return;
+      }
+      this.$emit(name, this.formdata);
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (!valid) {
+          return false;
+        }
+        // 此处处理正确
+        const keyList = Object.keys(this.data);
+        // 修改的情况
+        if (keyList.length > 0) {
+          let isRevise = false;
+          keyList.forEach(e => {
+            // 有修改
+            if (this.data[e] !== this.formdata[e]) {
+              isRevise = true;
+              return false;
+            }
+            // 无修改
+            return false;
+          });
+          // 如果无修改,传出时增加无修改属性
+          if (!isRevise) {
+            this.$emit('save', { ...this.formdata, isRevise });
+            return;
+          }
+        }
+        this.$emit('save', this.formdata);
+      });
+    },
+    resetForm(formName) {
+      // 重置为空状态
+      this.formdata = {};
+      // 重置到默认值状态
+      // this.$refs[formName].resetFields();
+    },
+    setForm(key, value) {
+      this.$set(this.formdata, key, value);
+    }
+  }
+};
+</script>
+<style lang="scss" scoped></style>

+ 55 - 0
admin-frame/src/components/header/breadcrumb.vue

@@ -0,0 +1,55 @@
+<template>
+  <div class="breadcrumb-box">
+    <el-breadcrumb separator="/">
+      <el-breadcrumb-item v-for="item in breadcrumbList" :key="item.code">{{ item.title }}</el-breadcrumb-item>
+    </el-breadcrumb>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    // 菜单数组
+    menuList: { type: Array, default: () => [] },
+    // 默认的首页
+    home: { type: Array, default: () => [] }
+  },
+  data() {
+    return {
+      breadcrumbList: [...this.home]
+    };
+  },
+  methods: {
+    getParentItems(e) {
+      if (e.path == '/frame/home') {
+        this.breadcrumbList = [...this.home];
+        return;
+      }
+      if (!this.breadcrumbList.includes(e)) this.breadcrumbList.splice(1, 0, e);
+      if (e.parentCode !== null || e.parentCode !== '') {
+        const parentitem = this.menuList.find(j => j.code == e.parentCode);
+        if (parentitem) this.getParentItems(parentitem);
+      }
+    }
+  },
+  mounted() {
+    const item = this.menuList.find(e => e.path == this.$route.path);
+    this.getParentItems(item);
+  },
+  watch: {
+    $route(to) {
+      const item = this.menuList.find(e => e.path == to.path);
+      this.getParentItems(item);
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.breadcrumb-box {
+  padding-left: 2em;
+  width: 100%;
+  border-bottom: 1px solid #cccbcb;
+  .el-breadcrumb {
+    line-height: 2em;
+  }
+}
+</style>

+ 52 - 0
admin-frame/src/components/header/headerUser.vue

@@ -0,0 +1,52 @@
+<template>
+  <div class="head-user-box">
+    <el-dropdown trigger="click" @command="commandChage">
+      <span class="el-dropdown-link">
+        <el-image>
+          <div slot="error" class="image-slot">
+            <i class="el-icon-user"></i>
+          </div>
+        </el-image>
+        {{ names }}
+        <i class="el-icon-arrow-down el-icon--right"></i>
+      </span>
+      <el-dropdown-menu slot="dropdown">
+        <el-dropdown-item v-for="item in list" :key="item.command" :command="item.command">{{ item.name }}</el-dropdown-item>
+      </el-dropdown-menu>
+    </el-dropdown>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      names: 'admin',
+      list: [
+        { name: '修改密码', command: 'pwd' },
+        // { name: '系统消息', command: 'msg' },
+        // { name: '系统任务', command: 'task' },
+        { name: '退出', command: 'signOut' }
+      ]
+    };
+  },
+  methods: {
+    commandChage (e) {
+      this.$emit(e);
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.el-dropdown-link {
+  color: #fff;
+  line-height: 4em;
+  cursor: pointer;
+  display: flex;
+  .el-image {
+    margin-right: 5px;
+  }
+  i {
+    line-height: 4em;
+  }
+}
+</style>

+ 123 - 0
admin-frame/src/components/header/index.vue

@@ -0,0 +1,123 @@
+<template>
+  <div class="header-box" :style="{ 'background-color': style.headerBackgroundColor }">
+    <!-- 切换菜单按钮 -->
+    <el-button v-if="config.headerHeigth !== 'max'" class="is_collapse" type="primary" size="mini" :icon="icon" @click="switchClick"></el-button>
+    <!-- 用户修改密码 -->
+    <header-user v-if="config.headerHeigth !== 'max'" class="headerUser" @pwd="reviseUserPassword" @msg="system_message" @task="system_task" @signOut="sign_out"></header-user>
+    <dialog-and-drawer :visibleSync="visible" title="修改密码" @close="visible = false">
+      <template v-slot:windowMain>
+        <el-form ref="form" :rules="rules" :model="form" label-width="80px">
+          <el-form-item label="原密码" prop="oldpassword">
+            <el-input v-model="form.oldpassword"></el-input>
+          </el-form-item>
+          <el-form-item label="新密码" prop="password">
+            <el-input v-model="form.password"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="onSubmit">提交</el-button>
+          </el-form-item>
+        </el-form>
+      </template>
+    </dialog-and-drawer>
+  </div>
+</template>
+
+<script>
+import style from '@style/index.module.scss';
+import headerUser from './headerUser.vue';
+import { mapActions } from 'vuex';
+import DialogAndDrawer from '../dialogAndDrawer.vue';
+// .env配置
+const config = {
+  headerHeigth: process.env.VUE_APP_HEADER
+};
+export default {
+  components: {
+    headerUser,
+    DialogAndDrawer
+  },
+  data() {
+    return {
+      form: {},
+      visible: false,
+      config,
+      style,
+      is_collapse: false,
+      rules: {
+        oldpassword: [
+          { required: true, message: '请输入原密码', trigger: 'blur' }
+        ],
+        password: [
+          { required: true, message: '请输入新密码', trigger: 'blur' }
+        ]
+      }
+    };
+  },
+  computed: {
+    icon() {
+      return this.is_collapse ? 'el-icon-s-unfold' : 'el-icon-s-fold';
+    }
+  },
+  methods: {
+    ...mapActions(['updatePwd']),
+    // 缩小放大菜单
+    switchClick() {
+      this.is_collapse = !this.is_collapse;
+      this.$emit('isCollapseChage', this.is_collapse);
+    },
+    // 修改密码
+    reviseUserPassword() {
+      // 修改密码
+      this.visible = true;
+    },
+    // 系统消息
+    system_message() {
+      console.log('系统消息');
+    },
+    // 系统任务
+    system_task() {
+      console.log('系统任务');
+    },
+    // 退出登录
+    sign_out() {
+      console.log('退出登录');
+      sessionStorage.clear();
+      this.$router.push('/frame/login');
+    },
+    // 修改密码提交
+    async onSubmit() {
+      const userInfo = sessionStorage.getItem('userInfo');
+      const { id } = JSON.parse(userInfo);
+      const res = await this.updatePwd({ ...this.form, id });
+      console.log(res);
+      if (res.errcode === 0) {
+        this.$message({
+          message: '修改成功',
+          type: 'success'
+        });
+        sessionStorage.clear();
+      } else {
+        this.$message.error(res.errmsg);
+      }
+      this.visible = false;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.header-box {
+  width: 100%;
+  border-left: 1px solid #999;
+  justify-content: space-between;
+  display: flex;
+  .is_collapse {
+    margin-left: 1%;
+    margin-top: 1%;
+    height: 2.5em;
+  }
+  .headerUser {
+    margin-right: 2%;
+  }
+}
+</style>

+ 0 - 0
admin-frame/src/components/header/logo.vue


部分文件因为文件数量过多而无法显示