wena 1 week ago
commit
c30636fe36
100 changed files with 4041 additions and 0 deletions
  1. 2 0
      .cursorindexingignore
  2. 1 0
      .dockerignore
  3. 14 0
      .editorconfig
  4. 18 0
      .env.ack
  5. 18 0
      .env.development
  6. 18 0
      .env.pre
  7. 18 0
      .env.pre2
  8. 17 0
      .env.production
  9. 18 0
      .env.staging
  10. 18 0
      .env.uat
  11. 7 0
      .eslintignore
  12. 200 0
      .eslintrc.js
  13. 23 0
      .gitignore
  14. 1 0
      .nvmrc
  15. 28 0
      .project
  16. 5 0
      .travis.yml
  17. BIN
      Desktop.ini
  18. 1 0
      HEAD
  19. 21 0
      LICENSE
  20. 74 0
      README.CN.md
  21. 220 0
      README.md
  22. 20 0
      babel.config.js
  23. 35 0
      build/index.js
  24. 6 0
      config
  25. 1 0
      description
  26. 9 0
      fsmanager.iml
  27. BIN
      git.ico
  28. 15 0
      hooks/applypatch-msg.sample
  29. 24 0
      hooks/commit-msg.sample
  30. 114 0
      hooks/fsmonitor-watchman.sample
  31. 8 0
      hooks/post-update.sample
  32. 14 0
      hooks/pre-applypatch.sample
  33. 49 0
      hooks/pre-commit.sample
  34. 53 0
      hooks/pre-push.sample
  35. 169 0
      hooks/pre-rebase.sample
  36. 24 0
      hooks/pre-receive.sample
  37. 42 0
      hooks/prepare-commit-msg.sample
  38. 128 0
      hooks/update.sample
  39. 6 0
      info/exclude
  40. 24 0
      jest.config.js
  41. 9 0
      jsconfig.json
  42. 152 0
      package.json
  43. 26 0
      plop-templates/component/index.hbs
  44. 55 0
      plop-templates/component/prompt.js
  45. 26 0
      plop-templates/table-view/README.md
  46. 74 0
      plop-templates/table-view/components/conditions.hbs
  47. 248 0
      plop-templates/table-view/components/detail.hbs
  48. 141 0
      plop-templates/table-view/components/table.hbs
  49. 99 0
      plop-templates/table-view/index.hbs
  50. 81 0
      plop-templates/table-view/prompt.js
  51. 9 0
      plop-templates/utils.js
  52. 26 0
      plop-templates/view/index.hbs
  53. 55 0
      plop-templates/view/prompt.js
  54. 12 0
      plopfile.js
  55. 5 0
      postcss.config.js
  56. BIN
      public/favicon.ico
  57. 24 0
      public/index.html
  58. 1 0
      public/js/index.min.js
  59. 6 0
      public/js/vue.min.js
  60. 12 0
      script/Dockerfile
  61. 46 0
      script/Jenkinsfile
  62. 22 0
      script/build_docker.sh
  63. 70 0
      script/config.conf
  64. 30 0
      script/deploy_k8s.sh
  65. 32 0
      script/deployment.yaml
  66. 97 0
      src/2.html
  67. 165 0
      src/App.vue
  68. 9 0
      src/api/equipment/model.js
  69. 34 0
      src/apiV2/common.js
  70. 83 0
      src/apiV2/company.js
  71. 15 0
      src/apiV2/data.js
  72. 41 0
      src/apiV2/dept.js
  73. 85 0
      src/apiV2/doc.md
  74. 18 0
      src/apiV2/exportlist.js
  75. 29 0
      src/apiV2/log.js
  76. 163 0
      src/apiV2/menuManage.js
  77. 16 0
      src/apiV2/park.js
  78. 134 0
      src/apiV2/parkingManagement.js
  79. 99 0
      src/apiV2/parkrecord.js
  80. 17 0
      src/apiV2/project.js
  81. 71 0
      src/apiV2/projectManage.js
  82. 25 0
      src/apiV2/role.js
  83. 45 0
      src/apiV2/rolemanage.js
  84. 33 0
      src/apiV2/systemConfig.js
  85. 137 0
      src/apiV2/user.js
  86. BIN
      src/assets/401_images/401.gif
  87. BIN
      src/assets/404_images/404.png
  88. BIN
      src/assets/404_images/404_cloud.png
  89. BIN
      src/assets/custom-theme/fonts/element-icons.ttf
  90. BIN
      src/assets/custom-theme/fonts/element-icons.woff
  91. 1 0
      src/assets/custom-theme/index.css
  92. BIN
      src/assets/default_graph/graph_car_big.png
  93. BIN
      src/assets/default_graph/graph_car_small.png
  94. BIN
      src/assets/ent.png
  95. BIN
      src/assets/faceImages/deleted.png
  96. BIN
      src/assets/faceImages/edit.png
  97. BIN
      src/assets/fengmap/2D.png
  98. BIN
      src/assets/fengmap/3D.png
  99. BIN
      src/assets/fengmap/arrow1.png
  100. 0 0
      src/assets/fengmap/arrow2.png

+ 2 - 0
.cursorindexingignore

@@ -0,0 +1,2 @@
+# Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references
+.specstory/**

+ 1 - 0
.dockerignore

@@ -0,0 +1 @@
+node_modules

+ 14 - 0
.editorconfig

@@ -0,0 +1,14 @@
+# https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 18 - 0
.env.ack

@@ -0,0 +1,18 @@
+NODE_ENV = production
+
+# just a flag
+VUE_APP_MODE = 'ack'
+
+# base api
+VUE_APP_BASE_API = 'https://ack-fsmanager.fujica.com.cn'
+#跳转H5地址
+VUE_APP_H5_URL='https://ack-fsh5.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='https://ack-fsmanager.fujica.com.cn'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+VUE_APP_HOST = 'ws://139.159.247.254:9083/mqtt'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 18 - 0
.env.development

@@ -0,0 +1,18 @@
+VUE_APP_MODE = 'development'
+
+#统一请求服务器地址
+VUE_APP_BASE_API = 'http://192.168.12.139:10001/transfer/manage'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+#跳转H5地址
+VUE_APP_H5_URL='http://fspay-test.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='http://119.23.214.109:30056'
+#非标上传图片
+VUE_APP_HOST = 'ws://139.159.247.254:9083/mqtt'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 18 - 0
.env.pre

@@ -0,0 +1,18 @@
+NODE_ENV = production
+
+# just a flag
+VUE_APP_MODE = 'pre'
+
+# base api
+VUE_APP_BASE_API = 'http://pre-fsmanager.fujica.com.cn'
+#跳转H5地址
+VUE_APP_H5_URL='https://pre-fsh5.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='http://pre-fsmanager.fujica.com.cn'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+VUE_APP_HOST = 'ws://139.159.247.254:9083/mqtt'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 18 - 0
.env.pre2

@@ -0,0 +1,18 @@
+NODE_ENV = production
+
+# just a flag
+VUE_APP_MODE = 'pre2'
+
+# base api
+VUE_APP_BASE_API = 'https://pre2-fsmanager.fujica.com.cn'
+#跳转H5地址
+VUE_APP_H5_URL='https://pre2-fsh5.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='https://pre2-fsmanager.fujica.com.cn'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+VUE_APP_HOST = 'ws://139.159.247.254:9083/mqtt'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 17 - 0
.env.production

@@ -0,0 +1,17 @@
+# just a flag
+VUE_APP_MODE = 'production'
+
+# base api
+#VUE_APP_BASE_API = 'http://fspay-test.fujica.com.cn:30056'
+VUE_APP_BASE_API = 'https://fsm.fujica.com.cn'
+#跳转H5地址
+VUE_APP_H5_URL='https://fsabk.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='https://fsm.fujica.com.cn'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+VUE_APP_HOST = 'ws://mqtt-cn-st21wpitz0u.mqtt.aliyuncs.com'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 18 - 0
.env.staging

@@ -0,0 +1,18 @@
+NODE_ENV = production
+
+# just a flag
+VUE_APP_MODE = 'staging'
+
+# base api
+VUE_APP_BASE_API = 'http://master-test.fujica.com.cn:30056'
+#跳转H5地址
+VUE_APP_H5_URL='http://master-test.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='http://three-test.fujica.com.cn:30056'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+VUE_APP_HOST = 'ws://139.159.247.254:9083/mqtt'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 18 - 0
.env.uat

@@ -0,0 +1,18 @@
+NODE_ENV = production
+
+# just a flag
+VUE_APP_MODE = 'uat'
+
+# base api
+VUE_APP_BASE_API = 'http://localhost:10001'
+#跳转H5地址
+VUE_APP_H5_URL='http://uat-fsh5.fujica.com.cn'
+#上传图片
+VUE_APP_IMG_URL='http://uat-fsmanager.fujica.com.cn'
+VUE_APP_INSTANCEID = 'mqtt-cn-st21wpitz0u'
+VUE_APP_HOST = 'ws://139.159.247.254:9083/mqtt'
+VUE_APP_ACCESSKEY = 'LTAI4G68VTSdqkBxsmoxPSYq'
+VUE_APP_SECRETKEY = 'SnIlhU8MupYyRQrymSo7ysYz2gWkk4'
+
+# 是否包含上富士LOGO
+VUE_APP_SHOW_LOGO = true

+ 7 - 0
.eslintignore

@@ -0,0 +1,7 @@
+build/*.js
+src/assets
+public
+dist
+src/utils
+src/main.js
+src/store/modules

+ 200 - 0
.eslintrc.js

@@ -0,0 +1,200 @@
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint',
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  rules: {
+    "vue/max-attributes-per-line": [2, {
+      "singleline": 10,
+      "multiline": {
+        "max": 1,
+        "allowFirstLine": false
+      }
+    }],
+    "vue/singleline-html-element-content-newline": "off",
+    "vue/multiline-html-element-content-newline": "off",
+    "vue/name-property-casing": "off",//关闭帕卡斯命名,支持name为中文
+    "vue/no-v-html": "off",
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': ["error", "always", { "null": "ignore" }],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        'files': ['src/views/V1'],
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.VUE_APP_MODE === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never'],
+    "no-mixed-spaces-and-tabs": [0],
+    "eqeqeq": "off"
+  }
+}

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+.specstory
+package-lock.json
+yarn.lock

+ 1 - 0
.nvmrc

@@ -0,0 +1 @@
+14.16.1

+ 28 - 0
.project

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>fsmanager</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>com.aptana.ide.core.unifiedBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>com.aptana.projects.webnature</nature>
+	</natures>
+	<filteredResources>
+		<filter>
+			<id>1620380171874</id>
+			<name></name>
+			<type>26</type>
+			<matcher>
+				<id>org.eclipse.ui.ide.multiFilter</id>
+				<arguments>1.0-name-matches-false-false-node_modules</arguments>
+			</matcher>
+		</filter>
+	</filteredResources>
+</projectDescription>

+ 5 - 0
.travis.yml

@@ -0,0 +1,5 @@
+language: node_js
+node_js: 10
+script: npm run test
+notifications:
+  email: false

BIN
Desktop.ini


+ 1 - 0
HEAD

@@ -0,0 +1 @@
+ref: refs/heads/master

+ 21 - 0
LICENSE

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

File diff suppressed because it is too large
+ 74 - 0
README.CN.md


File diff suppressed because it is too large
+ 220 - 0
README.md


+ 20 - 0
babel.config.js

@@ -0,0 +1,20 @@
+// 所有生产环境
+const prodPlugin = ['@babel/plugin-proposal-optional-chaining', '@babel/plugin-proposal-nullish-coalescing-operator']
+if (process.env.VUE_APP_MODE === 'production') {
+// 如果是生产环境,则自动清理掉打印的日志,但保留error 与 warn
+  prodPlugin.push([
+    'transform-remove-console',
+    {
+      // 保留 console.error 与 console.warn
+      exclude: ['error', 'warn']
+    }
+  ])
+}
+module.exports = {
+  presets: [
+    '@vue/app'
+  ],
+  plugins: [
+    ...prodPlugin
+  ]
+}

+ 35 - 0
build/index.js

@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+  const report = rawArgv.includes('--report')
+
+  run(`vue-cli-service build ${args}`)
+
+  const port = 9526
+  const publicPath = config.publicPath
+
+  var connect = require('connect')
+  var serveStatic = require('serve-static')
+  const app = connect()
+
+  app.use(
+    publicPath,
+    serveStatic('./dist', {
+      index: ['index.html', '/']
+    })
+  )
+
+  app.listen(port, function () {
+    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
+    if (report) {
+      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
+    }
+
+  })
+} else {
+  run(`vue-cli-service build ${args}`)
+}

+ 6 - 0
config

@@ -0,0 +1,6 @@
+[core]
+	bare = true
+	repositoryformatversion = 0
+	filemode = false
+	symlinks = false
+	ignorecase = true

+ 1 - 0
description

@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.

+ 9 - 0
fsmanager.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <output url="file://$MODULE_DIR$/bin" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

BIN
git.ico


+ 15 - 0
hooks/applypatch-msg.sample

@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.  The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
+test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
+:

+ 24 - 0
hooks/commit-msg.sample

@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by "git commit" with one argument, the name of the file
+# that has the commit message.  The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit.  The hook is allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "commit-msg".
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
+	echo >&2 Duplicate Signed-off-by lines.
+	exit 1
+}

+ 114 - 0
hooks/fsmonitor-watchman.sample

@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use IPC::Open2;
+
+# An example hook script to integrate Watchman
+# (https://facebook.github.io/watchman/) with git to speed up detecting
+# new and modified files.
+#
+# The hook is passed a version (currently 1) and a time in nanoseconds
+# formatted as a string and outputs to stdout all files that have been
+# modified since the given time. Paths must be relative to the root of
+# the working tree and separated by a single NUL.
+#
+# To enable this hook, rename this file to "query-watchman" and set
+# 'git config core.fsmonitor .git/hooks/query-watchman'
+#
+my ($version, $time) = @ARGV;
+
+# Check the hook interface version
+
+if ($version == 1) {
+	# convert nanoseconds to seconds
+	$time = int $time / 1000000000;
+} else {
+	die "Unsupported query-fsmonitor hook version '$version'.\n" .
+	    "Falling back to scanning...\n";
+}
+
+my $git_work_tree;
+if ($^O =~ 'msys' || $^O =~ 'cygwin') {
+	$git_work_tree = Win32::GetCwd();
+	$git_work_tree =~ tr/\\/\//;
+} else {
+	require Cwd;
+	$git_work_tree = Cwd::cwd();
+}
+
+my $retry = 1;
+
+launch_watchman();
+
+sub launch_watchman {
+
+	my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
+	    or die "open2() failed: $!\n" .
+	    "Falling back to scanning...\n";
+
+	# In the query expression below we're asking for names of files that
+	# changed since $time but were not transient (ie created after
+	# $time but no longer exist).
+	#
+	# To accomplish this, we're using the "since" generator to use the
+	# recency index to select candidate nodes and "fields" to limit the
+	# output to file names only. Then we're using the "expression" term to
+	# further constrain the results.
+	#
+	# The category of transient files that we want to ignore will have a
+	# creation clock (cclock) newer than $time_t value and will also not
+	# currently exist.
+
+	my $query = <<"	END";
+		["query", "$git_work_tree", {
+			"since": $time,
+			"fields": ["name"],
+			"expression": ["not", ["allof", ["since", $time, "cclock"], ["not", "exists"]]]
+		}]
+	END
+
+	print CHLD_IN $query;
+	close CHLD_IN;
+	my $response = do {local $/; <CHLD_OUT>};
+
+	die "Watchman: command returned no output.\n" .
+	    "Falling back to scanning...\n" if $response eq "";
+	die "Watchman: command returned invalid output: $response\n" .
+	    "Falling back to scanning...\n" unless $response =~ /^\{/;
+
+	my $json_pkg;
+	eval {
+		require JSON::XS;
+		$json_pkg = "JSON::XS";
+		1;
+	} or do {
+		require JSON::PP;
+		$json_pkg = "JSON::PP";
+	};
+
+	my $o = $json_pkg->new->utf8->decode($response);
+
+	if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
+		print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
+		$retry--;
+		qx/watchman watch "$git_work_tree"/;
+		die "Failed to make watchman watch '$git_work_tree'.\n" .
+		    "Falling back to scanning...\n" if $? != 0;
+
+		# Watchman will always return all files on the first query so
+		# return the fast "everything is dirty" flag to git and do the
+		# Watchman query just to get it over with now so we won't pay
+		# the cost in git to look up each individual file.
+		print "/\0";
+		eval { launch_watchman() };
+		exit 0;
+	}
+
+	die "Watchman: $o->{error}.\n" .
+	    "Falling back to scanning...\n" if $o->{error};
+
+	binmode STDOUT, ":utf8";
+	local $, = "\0";
+	print @{$o->{files}};
+}

+ 8 - 0
hooks/post-update.sample

@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, rename this file to "post-update".
+
+exec git update-server-info

+ 14 - 0
hooks/pre-applypatch.sample

@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-applypatch".
+
+. git-sh-setup
+precommit="$(git rev-parse --git-path hooks/pre-commit)"
+test -x "$precommit" && exec "$precommit" ${1+"$@"}
+:

+ 49 - 0
hooks/pre-commit.sample

@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=$(git hash-object -t tree /dev/null)
+fi
+
+# If you want to allow non-ASCII filenames set this variable to true.
+allownonascii=$(git config --bool hooks.allownonascii)
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Cross platform projects tend to avoid non-ASCII filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+	# Note that the use of brackets around a tr range is ok here, (it's
+	# even required, for portability to Solaris 10's /usr/bin/tr), since
+	# the square bracket bytes happen to fall in the designated range.
+	test $(git diff --cached --name-only --diff-filter=A -z $against |
+	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+then
+	cat <<\EOF
+Error: Attempt to add a non-ASCII file name.
+
+This can cause problems if you want to work with people on other platforms.
+
+To be portable it is advisable to rename the file.
+
+If you know what you are doing you can disable this check using:
+
+  git config hooks.allownonascii true
+EOF
+	exit 1
+fi
+
+# If there are whitespace errors, print the offending file names and fail.
+exec git diff-index --check --cached $against --

+ 53 - 0
hooks/pre-push.sample

@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# An example hook script to verify what is about to be pushed.  Called by "git
+# push" after it has checked the remote status, but before anything has been
+# pushed.  If this script exits with a non-zero status nothing will be pushed.
+#
+# This hook is called with the following parameters:
+#
+# $1 -- Name of the remote to which the push is being done
+# $2 -- URL to which the push is being done
+#
+# If pushing without using a named remote those arguments will be equal.
+#
+# Information about the commits which are being pushed is supplied as lines to
+# the standard input in the form:
+#
+#   <local ref> <local sha1> <remote ref> <remote sha1>
+#
+# This sample shows how to prevent push of commits where the log message starts
+# with "WIP" (work in progress).
+
+remote="$1"
+url="$2"
+
+z40=0000000000000000000000000000000000000000
+
+while read local_ref local_sha remote_ref remote_sha
+do
+	if [ "$local_sha" = $z40 ]
+	then
+		# Handle delete
+		:
+	else
+		if [ "$remote_sha" = $z40 ]
+		then
+			# New branch, examine all commits
+			range="$local_sha"
+		else
+			# Update to existing branch, examine new commits
+			range="$remote_sha..$local_sha"
+		fi
+
+		# Check for WIP commit
+		commit=`git rev-list -n 1 --grep '^WIP' "$range"`
+		if [ -n "$commit" ]
+		then
+			echo >&2 "Found WIP commit in $local_ref, not pushing"
+			exit 1
+		fi
+	fi
+done
+
+exit 0

+ 169 - 0
hooks/pre-rebase.sample

@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2006, 2008 Junio C Hamano
+#
+# The "pre-rebase" hook is run just before "git rebase" starts doing
+# its job, and can prevent the command from running by exiting with
+# non-zero status.
+#
+# The hook is called with the following parameters:
+#
+# $1 -- the upstream the series was forked from.
+# $2 -- the branch being rebased (or empty when rebasing the current branch).
+#
+# This sample shows how to prevent topic branches that are already
+# merged to 'next' branch from getting rebased, because allowing it
+# would result in rebasing already published history.
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+	topic="refs/heads/$2"
+else
+	topic=`git symbolic-ref HEAD` ||
+	exit 0 ;# we do not interrupt rebasing detached HEAD
+fi
+
+case "$topic" in
+refs/heads/??/*)
+	;;
+*)
+	exit 0 ;# we do not interrupt others.
+	;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master.  Is it OK to rebase it?
+
+# Does the topic really exist?
+git show-ref -q "$topic" || {
+	echo >&2 "No such branch $topic"
+	exit 1
+}
+
+# Is topic fully merged to master?
+not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+	echo >&2 "$topic is fully merged to master; better remove it."
+	exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next?  If so you should not be rebasing it.
+only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git rev-list ^master           ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+	not_in_topic=`git rev-list "^$topic" master`
+	if test -z "$not_in_topic"
+	then
+		echo >&2 "$topic is already up to date with master"
+		exit 1 ;# we could allow it, but there is no point.
+	else
+		exit 0
+	fi
+else
+	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
+	/usr/bin/perl -e '
+		my $topic = $ARGV[0];
+		my $msg = "* $topic has commits already merged to public branch:\n";
+		my (%not_in_next) = map {
+			/^([0-9a-f]+) /;
+			($1 => 1);
+		} split(/\n/, $ARGV[1]);
+		for my $elem (map {
+				/^([0-9a-f]+) (.*)$/;
+				[$1 => $2];
+			} split(/\n/, $ARGV[2])) {
+			if (!exists $not_in_next{$elem->[0]}) {
+				if ($msg) {
+					print STDERR $msg;
+					undef $msg;
+				}
+				print STDERR " $elem->[1]\n";
+			}
+		}
+	' "$topic" "$not_in_next" "$not_in_master"
+	exit 1
+fi
+
+<<\DOC_END
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+   merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+   it is deleted.  If you need to build on top of it to correct
+   earlier mistakes, a new topic branch is created by forking at
+   the tip of the "master".  This is not strictly necessary, but
+   it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+   branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next".  Young
+    topic branches can have stupid mistakes you would rather
+    clean up before publishing, and things that have not been
+    merged into other branches can be easily rebased without
+    affecting other people.  But once it is published, you would
+    not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+    Then you can delete it.  More importantly, you should not
+    build on top of it -- other people may already want to
+    change things related to the topic as patches against your
+    "master", so if you need further changes, it is better to
+    fork the topic (perhaps with the same name) afresh from the
+    tip of "master".
+
+Let's look at this example:
+
+		   o---o---o---o---o---o---o---o---o---o "next"
+		  /       /           /           /
+		 /   a---a---b A     /           /
+		/   /               /           /
+	       /   /   c---c---c---c B         /
+	      /   /   /             \         /
+	     /   /   /   b---b C     \       /
+	    /   /   /   /             \     /
+    ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished.  It has been fully merged up to "master" and "next",
+   and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+	git rev-list ^master ^topic next
+	git rev-list ^master        next
+
+	if these match, topic has not merged in next at all.
+
+To compute (2):
+
+	git rev-list master..topic
+
+	if this is empty, it is fully merged to "master".
+
+DOC_END

+ 24 - 0
hooks/pre-receive.sample

@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to make use of push options.
+# The example simply echoes all push options that start with 'echoback='
+# and rejects all pushes when the "reject" push option is used.
+#
+# To enable this hook, rename this file to "pre-receive".
+
+if test -n "$GIT_PUSH_OPTION_COUNT"
+then
+	i=0
+	while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
+	do
+		eval "value=\$GIT_PUSH_OPTION_$i"
+		case "$value" in
+		echoback=*)
+			echo "echo from the pre-receive-hook: ${value#*=}" >&2
+			;;
+		reject)
+			exit 1
+		esac
+		i=$((i + 1))
+	done
+fi

+ 42 - 0
hooks/prepare-commit-msg.sample

@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by "git commit" with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source.  The hook's purpose is to edit the commit
+# message file.  If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, rename this file to "prepare-commit-msg".
+
+# This hook includes three examples. The first one removes the
+# "# Please enter the commit message..." help message.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output.  It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited.  This is rarely a good idea.
+
+COMMIT_MSG_FILE=$1
+COMMIT_SOURCE=$2
+SHA1=$3
+
+/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
+
+# case "$COMMIT_SOURCE,$SHA1" in
+#  ,|template,)
+#    /usr/bin/perl -i.bak -pe '
+#       print "\n" . `git diff --cached --name-status -r`
+# 	 if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
+#  *) ;;
+# esac
+
+# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
+# if test -z "$COMMIT_SOURCE"
+# then
+#   /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
+# fi

+ 128 - 0
hooks/update.sample

@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# An example hook script to block unannotated tags from entering.
+# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, rename this file to "update".
+#
+# Config
+# ------
+# hooks.allowunannotated
+#   This boolean sets whether unannotated tags will be allowed into the
+#   repository.  By default they won't be.
+# hooks.allowdeletetag
+#   This boolean sets whether deleting tags will be allowed in the
+#   repository.  By default they won't be.
+# hooks.allowmodifytag
+#   This boolean sets whether a tag may be modified after creation. By default
+#   it won't be.
+# hooks.allowdeletebranch
+#   This boolean sets whether deleting branches will be allowed in the
+#   repository.  By default they won't be.
+# hooks.denycreatebranch
+#   This boolean sets whether remotely creating branches will be denied
+#   in the repository.  By default this is allowed.
+#
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+	echo "Don't run this script from the command line." >&2
+	echo " (if you want, you could supply GIT_DIR then run" >&2
+	echo "  $0 <ref> <oldrev> <newrev>)" >&2
+	exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+	echo "usage: $0 <ref> <oldrev> <newrev>" >&2
+	exit 1
+fi
+
+# --- Config
+allowunannotated=$(git config --bool hooks.allowunannotated)
+allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
+allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
+
+# check for no description
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+case "$projectdesc" in
+"Unnamed repository"* | "")
+	echo "*** Project description file hasn't been set" >&2
+	exit 1
+	;;
+esac
+
+# --- Check types
+# if $newrev is 0000...0000, it's a commit to delete a ref.
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
+	newrev_type=delete
+else
+	newrev_type=$(git cat-file -t $newrev)
+fi
+
+case "$refname","$newrev_type" in
+	refs/tags/*,commit)
+		# un-annotated tag
+		short_refname=${refname##refs/tags/}
+		if [ "$allowunannotated" != "true" ]; then
+			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
+			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,delete)
+		# delete tag
+		if [ "$allowdeletetag" != "true" ]; then
+			echo "*** Deleting a tag is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,tag)
+		# annotated tag
+		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+		then
+			echo "*** Tag '$refname' already exists." >&2
+			echo "*** Modifying a tag is not allowed in this repository." >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,commit)
+		# branch
+		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+			echo "*** Creating a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,delete)
+		# delete branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/remotes/*,commit)
+		# tracking branch
+		;;
+	refs/remotes/*,delete)
+		# delete tracking branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	*)
+		# Anything else (is there anything else?)
+		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
+		exit 1
+		;;
+esac
+
+# --- Finished
+exit 0

+ 6 - 0
info/exclude

@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~

+ 24 - 0
jest.config.js

@@ -0,0 +1,24 @@
+module.exports = {
+  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
+  transform: {
+    '^.+\\.vue$': 'vue-jest',
+    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
+      'jest-transform-stub',
+    '^.+\\.jsx?$': 'babel-jest'
+  },
+  moduleNameMapper: {
+    '^@/(.*)$': '<rootDir>/src/$1'
+  },
+  snapshotSerializers: ['jest-serializer-vue'],
+  testMatch: [
+    '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
+  ],
+  collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
+  coverageDirectory: '<rootDir>/tests/unit/coverage',
+  // 'collectCoverage': true,
+  'coverageReporters': [
+    'lcov',
+    'text-summary'
+  ],
+  testURL: 'http://localhost/'
+}

+ 9 - 0
jsconfig.json

@@ -0,0 +1,9 @@
+{ 
+  "compilerOptions": {
+    "baseUrl": "./",
+    "paths": {
+        "@/*": ["src/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"]
+}

+ 152 - 0
package.json

@@ -0,0 +1,152 @@
+{
+  "name": "vue-element-admin",
+  "version": "4.2.1",
+  "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
+  "author": "Pan <panfree23@gmail.com>",
+  "license": "MIT",
+  "scripts": {
+    "dev": "vue-cli-service serve --open --mode development",
+    "build": "cross-env NODE_ENV=production vue-cli-service build --mode development",
+    "build:prod": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "build:uat": "vue-cli-service build --mode uat",
+    "build:pre": "vue-cli-service build --mode pre",
+    "build:pre2": "vue-cli-service build --mode pre2",
+    "build:ack": "vue-cli-service build --mode ack",
+    "preview": "node build/index.js --preview --mode development",
+    "lint": "eslint --fix --ext .js,.vue src",
+    "report": "eslint -f html src -o fsmanager-总部端代码走查报告.html",
+    "test:unit": "jest --clearCache && vue-cli-service test:unit",
+    "test:ci": "npm run lint && npm run test:unit",
+    "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+    "new": "plop"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  },
+  "lint-staged": {
+    "src/**/*.{js,vue}": [
+      "eslint --fix",
+      "git add"
+    ]
+  },
+  "keywords": [
+    "vue",
+    "admin",
+    "dashboard",
+    "element-ui",
+    "boilerplate",
+    "admin-template",
+    "management-system"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
+  },
+  "bugs": {
+    "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
+  },
+  "dependencies": {
+    "@fujica/utils": "^1.1.4",
+    "@icon-park/vue": "^1.4.2",
+    "@jiaminghi/data-view": "^2.10.0",
+    "@kangc/v-md-editor": "^1.7.11",
+    "ali-oss": "^6.8.0",
+    "axios": "0.18.1",
+    "clipboard": "2.0.4",
+    "codemirror": "5.45.0",
+    "currency.js": "^2.0.4",
+    "dayjs": "^1.10.5",
+    "dingtalk-jsapi": "^2.13.7",
+    "driver.js": "0.9.5",
+    "dropzone": "5.5.1",
+    "echarts": "^5.1.2",
+    "echarts-gl": "^2.0.9",
+    "el-tree-transfer": "^2.4.7",
+    "element-ui": "^2.13.0",
+    "file-saver": "2.0.1",
+    "fuse.js": "3.4.4",
+    "jquery": "^3.5.1",
+    "js-cookie": "2.2.0",
+    "js-md5": "^0.7.3",
+    "jsencrypt": "^3.2.0",
+    "jsonlint": "1.6.3",
+    "jszip": "3.2.1",
+    "moment": "^2.29.4",
+    "mqtt": "^3.0.0",
+    "normalize.css": "7.0.0",
+    "nprogress": "0.2.0",
+    "particles.js": "^2.0.0",
+    "path-to-regexp": "2.4.0",
+    "postcss-pxtorem": "^5.1.1",
+    "qrcode": "^1.5.3",
+    "quill": "^1.3.7",
+    "screenfull": "4.2.0",
+    "scss": "^0.2.4",
+    "scss-loader": "0.0.1",
+    "showdown": "^1.9.1",
+    "sortablejs": "1.8.4",
+    "v-distpicker": "^1.2.7",
+    "vue": "2.6.10",
+    "vue-bus": "^1.2.1",
+    "vue-count-to": "1.0.13",
+    "vue-dompurify-html": "^2.5.2",
+    "vue-jsonp": "^2.0.0",
+    "vue-quill-editor": "^3.0.6",
+    "vue-router": "3.0.2",
+    "vue-seamless-scroll": "^1.1.23",
+    "vue-splitpane": "1.0.4",
+    "vuedraggable": "^2.20.0",
+    "vuex": "3.1.0",
+    "webpack-retry-chunk-load-plugin": "^1.5.0",
+    "xlsx": "0.14.1"
+  },
+  "devDependencies": {
+    "@babel/core": "7.0.0",
+    "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
+    "@babel/plugin-proposal-optional-chaining": "^7.18.6",
+    "@babel/register": "7.0.0",
+    "@vue/cli-plugin-babel": "3.5.3",
+    "@vue/cli-plugin-eslint": "^3.9.1",
+    "@vue/cli-plugin-unit-jest": "3.5.3",
+    "@vue/cli-service": "3.5.3",
+    "@vue/test-utils": "1.0.0-beta.29",
+    "autoprefixer": "^9.5.1",
+    "babel-core": "7.0.0-bridge.0",
+    "babel-eslint": "10.0.1",
+    "babel-jest": "23.6.0",
+    "babel-plugin-transform-remove-console": "^6.9.4",
+    "chalk": "2.4.2",
+    "chokidar": "2.1.5",
+    "compression-webpack-plugin": "^6.1.1",
+    "connect": "3.6.6",
+    "cross-env": "^7.0.3",
+    "eslint": "5.15.3",
+    "eslint-plugin-vue": "5.2.2",
+    "html-webpack-plugin": "3.2.0",
+    "lint-staged": "8.1.5",
+    "node-sass": "^4.14.1",
+    "plop": "2.3.0",
+    "quill-image-extend-module": "^1.1.2",
+    "runjs": "^4.3.2",
+    "sass-loader": "^7.3.1",
+    "script-ext-html-webpack-plugin": "2.1.3",
+    "script-loader": "0.7.2",
+    "serve-static": "^1.13.2",
+    "svg-sprite-loader": "4.1.3",
+    "svgo": "^1.2.0",
+    "vue-img-inputer": "^2.1.6",
+    "vue-template-compiler": "2.6.10",
+    "webpack-bundle-analyzer": "^4.4.2"
+  },
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ]
+}

+ 26 - 0
plop-templates/component/index.hbs

@@ -0,0 +1,26 @@
+{{#if template}}
+<template>
+  <div />
+</template>
+{{/if}}
+
+{{#if script}}
+<script>
+export default {
+  name: '{{ properCase name }}',
+  props: {},
+  data() {
+    return {}
+  },
+  created() {},
+  mounted() {},
+  methods: {}
+}
+</script>
+{{/if}}
+
+{{#if style}}
+<style lang="scss" scoped>
+
+</style>
+{{/if}}

+ 55 - 0
plop-templates/component/prompt.js

@@ -0,0 +1,55 @@
+const { notEmpty } = require('../utils.js')
+
+module.exports = {
+  description: 'generate vue component',
+  prompts: [{
+    type: 'input',
+    name: 'name',
+    message: 'component name please',
+    validate: notEmpty('name')
+  },
+  {
+    type: 'checkbox',
+    name: 'blocks',
+    message: 'Blocks:',
+    choices: [{
+      name: '<template>',
+      value: 'template',
+      checked: true
+    },
+    {
+      name: '<script>',
+      value: 'script',
+      checked: true
+    },
+    {
+      name: 'style',
+      value: 'style',
+      checked: true
+    }
+    ],
+    validate(value) {
+      if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
+        return 'Components require at least a <script> or <template> tag.'
+      }
+      return true
+    }
+  }
+  ],
+  actions: data => {
+    const name = '{{properCase name}}'
+    const actions = [{
+      type: 'add',
+      path: `src/components/${name}/index.vue`,
+      templateFile: 'plop-templates/component/index.hbs',
+      data: {
+        name: name,
+        template: data.blocks.includes('template'),
+        script: data.blocks.includes('script'),
+        style: data.blocks.includes('style')
+      }
+    }]
+
+    return actions
+  }
+}

+ 26 - 0
plop-templates/table-view/README.md

@@ -0,0 +1,26 @@
+# 使用说明(table-view模板)
+npm run new
+
+1. 选择模板
+`
+  view - generate a view 
+  table-view - generate a table-view 
+  component - generate vue component 
+`
+
+选择table-view
+
+2. 请输入组件目录名
+输入要新建的文件夹名称,src/view下名称
+例如输入:userCenter/mypage
+则会在src/view/userCenter/mypage建立模板
+
+3. 请输入表格标题
+例如输入:车场配置列表
+
+4. 请选择侧边树
+按需选择。
+> none为不带树的,需要自己找地方调用search()或getList()建议在conditions组件中mounted调用,不需要conditions组件的直接在index中调用
+
+
+以上流程可以在plop-templates/table-view/prompt.js中进行更改

+ 74 - 0
plop-templates/table-view/components/conditions.hbs

@@ -0,0 +1,74 @@
+<template>
+  <el-row>
+    <!-- 搜索用表单 -->
+    <search-fold-form ref="searchForm" :model="searchParams" class="search" @search="searchClick">
+      <el-form-item label="编号">
+        <el-input v-model.trim="searchParams.id" placeholder="请输入编号" clearable size="small" />
+      </el-form-item>
+      <el-form-item label="类型">
+        <el-select v-model.trim="searchParams.type">
+          <el-option
+            v-for="(item, index) in global.type"
+            :key="index"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="时间">
+        <el-date-picker v-model.trim="searchParams.timerange" value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" :default-time="['00:00:00', '23:59:59']" :clearable="false" />
+      </el-form-item>
+      <el-form-item>
+        <el-button :loading="global.loading" type="primary" @click="search"> 查询 </el-button>
+        <el-button :loading="global.loading" @click="reset">重置</el-button>
+      </el-form-item>
+    </search-fold-form>
+  </el-row>
+</template>
+
+<script>
+import SearchFoldForm from '@/components/SearchFoldForm/index.vue'
+import { deepClone } from '@/utils'
+const defaultSearchParams = { // 搜索栏初始值
+  id: '',
+  type: '',
+  timerange: ''
+}
+export default {
+  inject: ['global'],
+  components: { SearchFoldForm },
+  props: {
+    searchParams: {
+      require: true,
+      type: Object,
+      default: () => deepClone(defaultSearchParams)
+    }
+  },
+  data() {
+    return {
+    }
+  },
+  created() {
+  {{#unless (equal treeType '')}}
+    this.$emit('search', deepClone(defaultSearchParams))
+  {{/unless}}
+  },
+  mounted() {
+  {{#if (equal treeType '')}}
+    this.$emit('search', deepClone(defaultSearchParams))
+  {{/if}}
+  },
+  methods: {
+    search() {
+      this.$emit('search', this.searchParams)
+    },
+    reset() {
+      this.$refs.searchForm.resetFields()
+      this.$emit('search', deepClone(defaultSearchParams))
+    }
+  }
+}
+</script>
+
+<style scoped>
+</style>

+ 248 - 0
plop-templates/table-view/components/detail.hbs

@@ -0,0 +1,248 @@
+<template>
+  <div>
+    <!-- 增改查弹窗 -->
+    <el-dialog :title="titles[mode] || '详情'" :visible.sync="formVisible" class="finish-dialog" :class="mode" width="960px" append-to-body :close-on-click-modal="false">
+      {{!-- <div v-if="mode === 'add'" class="alert-box">说明:xxxx</div> --}}
+      <el-form v-if="formVisible" ref="detailForm" v-loading="detailLoading" :model="formData" :rules="rules" label-position="right" inline class="detail-dialog" label-width="140px">
+        <el-form-item label="名称:">
+          <span>
+            \{{ formData.name || '--' }}
+          </span>
+        </el-form-item>
+        <el-form-item label="手机号:" prop="phonenum">
+          <el-input v-if="isEditAdd" v-model.trim="formData.phonenum" placeholder="请输入" type="number" />
+          <span v-else>
+            \{{ formData.phonenum || '--' }}
+          </span>
+        </el-form-item>
+        <el-form-item label="开始日期:" prop="startdate">
+          <el-date-picker v-if="isEditAdd" v-model.trim="formData.startdate" type="date" value-format="yyyy-MM-dd" placeholder="请输入" :disabled="hadConsume" />
+          <span v-else>
+            \{{ formData.startdate || '--' }}
+          </span>
+        </el-form-item>
+        <el-form-item label="方案:" prop="consumeway">
+          <el-checkbox-group v-model.trim="formData.consumeway" :disabled="!isEditAdd || hadConsume" @change="formData.consumeway = $event">
+            <el-checkbox :label="1">方案1</el-checkbox>
+            <el-checkbox :label="2">方案2</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="权限开关:" class="fit-width">
+          <el-switch v-if="isEditAdd" v-model.trim="formData.isgreater" active-value="1" :inactive-value="2" />
+          <span v-else>
+            \{{ options.isgreater[formData.isgreater] }}
+          </span>
+        </el-form-item>
+        <el-form-item label="模式:" prop="swapmode" style="width: 100%">
+          <template v-if="isEditAdd">
+            <el-radio v-model.trim="formData.swapmode" :label="1">模式1</el-radio>
+            <el-radio v-model.trim="formData.swapmode" :label="2">模式2</el-radio>
+          </template>
+          <span v-else>
+            \{{ options.swapmode[formData.swapmode] || '--' }}
+          </span>
+        </el-form-item>
+        <el-form-item label="描述:" prop="remark" style="width: 100%">
+          <el-input
+            v-if="isEditAdd"
+            v-model.trim="formData.remark"
+            placeholder="请输入"
+            type="textarea"
+            show-word-limit
+            :autosize="{ minRows: 3, maxRows: 4 }"
+            :maxlength="100"
+          />
+          <span v-else>
+            \{{ formData.remark || '--' }}
+          </span>
+        </el-form-item>
+        <!-- <el-row class="mb-20">
+          <span class="list-title">其他信息</span>
+        </el-row> -->
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button :loading="detailLoading" @click="formVisible = false">关闭</el-button>
+        <el-button v-if="isEditAdd" type="primary" :loading="detailLoading" @click="submit">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import dayjs from 'dayjs'
+import { deepClone } from '@/utils'
+
+const defaultFormData = { // 表单初始数据
+}
+
+export default {
+  name: '',
+  inject: ['global', 'refresh'],
+  data() {
+    const validateDateRange = (rule, value, callback) => {
+      if (!this.formData.authorizationstart || !this.formData.authorizationend) {
+        return callback()
+      } else if (
+        dayjs(this.formData.authorizationend).isBefore(this.formData.authorizationstart) &&
+        this.formData.authorizationend !== this.formData.authorizationstart
+      ) { // 触发条件:开始在结束后 && 开始不等于结束
+        return callback(new Error('结束时间不可早于开始时间!'))
+      } else {
+        const isStartTimeValid = !(dayjs(this.formData.authorizationstart).isBefore(dayjs()) && !dayjs(this.formData.authorizationstart).isSame(dayjs(), 'date'))
+        isStartTimeValid && this.$refs.detailForm.clearValidate('authorizationstart')
+        this.$refs.detailForm.clearValidate('authorizationend')
+        return callback()
+      }
+    }
+    const validateStartTime = (rule, value, callback) => {
+      if (this.mode === 'add' && dayjs(value).isBefore(dayjs(), 'date')) {
+        return callback(new Error('开始时间不能早于当前时间!'))
+      } else {
+        return validateDateRange(rule, value, callback)
+      }
+    }
+    const validateEndTime = (rule, value, callback) => {
+      if (this.mode === 'add' && dayjs(value).isBefore(dayjs(), 'date')) {
+        return callback(new Error('结束时间不能早于当前时间!'))
+      } else {
+        return validateDateRange(rule, value, callback)
+      }
+    }
+    return {
+      detailLoading: false,
+      mode: 'see', // 查看see / 编辑edit / 添加add
+      titles: { // 弹窗标题(动态)
+        see: '查看',
+        add: '新增',
+        edit: '编辑'
+      },
+      formVisible: false, // 弹窗显示
+      formConfig: {}, // 表单配置
+      formData: {}, // 表单数据
+      rules: {
+        // TODO: 校验规则
+        // userid: [
+        //   { required: true, message: '用户不能为空', trigger: 'change' }
+        // ],
+        // starttime: [
+        //   { required: true, message: '开始时间不能为空', trigger: 'change' },
+        //   { validator: validateStartTime, trigger: 'change' }
+        // ],
+        // endtime: [
+        //   { required: true, message: '结束时间不能为空', trigger: 'change' },
+        //   { validator: validateEndTime, trigger: 'change' }
+        // ]
+      }
+    }
+  },
+  computed: {
+    isEditAdd() {
+      return this.mode === 'edit' || this.mode === 'add'
+    }
+  },
+  methods: {
+    showDialog({ mode, formConfig, formData, formTitle }) {
+      this.mode = mode || (this.formData.id ? 'edit' : 'add')
+      if (this.mode === 'add') {
+        this.formData = { ...defaultFormData }
+      } else {
+        this.formData = { ...formData }
+      }
+      this.initFormData()
+      this.formVisible = true
+    },
+    initFormData() { // 表单数据初始化
+      // TODO: init formData
+      // const {} = this.formData
+      // this.$set(this.formData, 'authorizationtype', authorizationtype || 1)
+    },
+    filterFormData(formData) { // 提交数据过滤
+      const data = deepClone(formData)
+      // TODO: 自定义数据过滤
+      return data
+    },
+    submit() {
+      console.log('output->formData', this.formData)
+      this.$refs.detailForm.validate(async(valid) => {
+        if (valid) {
+          const formData = this.filterFormData(this.formData)
+          console.log('FORM', formData)
+          this.detailLoading = true
+          try {
+            let res = {}
+            if (this.mode === 'add') {
+              // TODO: 提交接口
+              // res = await addInvitation(formData)
+            } else {
+              // TODO: 修改接口
+              // res = await updateInvitation(formData)
+            }
+            if (res.success) {
+              this.formVisible = false
+              this.refresh()
+            }
+          } finally {
+            this.detailLoading = false
+          }
+        } else {
+          this.$message.warning('校验失败')
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+
+.width-clear {
+  width: auto
+}
+.finish-dialog {
+  /deep/ .el-form-item {
+    &__content  {
+      width: calc(100% - 180px); // 减去label宽
+      max-width: none;
+      .el-checkbox-group {
+        line-height: normal;
+      }
+    }
+    &__label {
+      padding-right: 12px !important;
+    }
+    &.fit-width {
+      .el-form-item__content {
+        width: fit-content;
+      }
+    }
+  }
+  &.edit, &.add {
+    /deep/ .el-form-item {
+      margin-bottom: 22px;
+    }
+  }
+  &.see {
+    .detail-dialog {
+      // background-color: #f8f8f8;
+      padding: 20px;
+    }
+    /deep/ .el-form-item {
+      &__label, &__content { // 统一行高
+        line-height: 2;
+      }
+      margin-bottom: 10px;
+    }
+  }
+}
+
+/* 穿梭框 */
+/deep/ .el-transfer {
+  &__buttons {
+    display: inline-flex;
+    flex-direction: column;
+    .el-button + .el-button {
+      margin-left: 0;
+    }
+  }
+}
+</style>

+ 141 - 0
plop-templates/table-view/components/table.hbs

@@ -0,0 +1,141 @@
+<template>
+  <el-row>
+    <!-- 表格头部 -->
+    <el-row class="mb-20">
+      <span class="list-title">
+        {{ title }}
+        <Lookicon v-if="filterButton('lookicon')" ref="Lookicon" :look-status="searchParams.lookStatus" @changeLook="changeLook" />
+      </span>
+      <el-button v-if="filterButton('add')" type="primary" :loading="global.loading" @click="$emit('rowOperation', {}, -1, 'add')">新增</el-button>
+      <!-- <el-button v-if="filterButton('export')" :loading="global.loading" @click="exportExcel">导出</el-button> -->
+    </el-row>
+    <!-- 表格内容 -->
+    <TableElement
+      :table-data="list"
+      :colum-obj="columObj"
+      :page-obj="pageObj"
+      :loading="global.loading"
+      @rowOperation="rowOperation"
+      @selectionChange="selectionChange"
+      @getList="getList()"
+    />
+  </el-row>
+</template>
+<script>
+import TableElement from '@/components/ElmTable/index.vue'
+import request from '@/utils/request'
+import { deepClone } from '@/utils'
+
+export default {
+  components: { TableElement },
+  inject: ['global'],
+  props: {
+    treeIds: { // 侧边栏
+      type: String,
+      default: ''
+    },
+    searchParams: { // 搜索栏
+      type: Object,
+      default: () => ({})
+    }
+  },
+  data() {
+    return {
+      openExport: false,
+      list: [], // 数据
+      selectedList: [], // 选中的数据
+      pageObj: { // 分页配置
+        current: 1,
+        size: 10,
+        total: 0,
+        pages: 0
+      },
+      columObj: { // 表格配置
+        lazy: 'true',
+        columnData: [
+          { text: true, prop: 'id', label: '序号' },
+          {
+            isOperation: true, prop: 'operation', label: '操作', align: 'center', sortable: false, fixed: 'right',
+            operation: [
+              { operation: 'see', type: 'text', label: '查看', isShow: (row) => this.filterButton('see') },
+              { operation: 'edit', type: 'text', label: '编辑', isShow: (row) => this.filterButton('edit') },
+              { operation: 'delete', type: 'text', label: '删除', isShow: (row) => this.filterButton('delete') },
+            ]
+          }
+        ]
+      }
+    }
+  },
+  methods: {
+    async getList(params) { // 表格数据 - 获取
+      this.global.loading = true
+      if (params != null) this.searchParams = params
+      try {
+        // TODO: 获取数据
+        const { data } = { data: { records: [{ name: 'test' }], pages: 1, total: 1 }}
+        // const { data } = await request('/fs/personinout/tvoucherrecords/freezeList', { params: this.genQuery() })
+        // const { data } = await getInvitationPage(this.genQuery())
+        const { records, pages, total } = data
+        this.list = this.filterTabledata(records)
+        Object.assign(this.pageObj, { pages, total })
+      } finally {
+        this.global.loading = false
+      }
+    },
+    filterTabledata(list) { // 表格数据 - 过滤
+      return list.map(item => ({
+        ...item
+        // TODO: 表格数据展示是否要转换(看情况)
+      }))
+    },
+    async exportExcel() { // 导出
+      this.global.loading = true
+      try {
+        // TODO: 导出接口
+        // const res = await request('/fs/personinout/tvoucherrecords/freezeExport', { params: this.genQuery() })
+        // const res = await exportExchangeOrder(this.genQuery())
+        // this.downloadExcel(res)
+      } finally {
+        this.global.loading = false
+      }
+    },
+    genQuery() { // 产生最终参数
+      const { current, size } = this.pageObj
+      const query = Object.assign({ current, size }, this.filterSearchParams()) // 分页 & 查询
+      return query
+    },
+    filterSearchParams() { // 查询字段过滤(请求数据过滤查询不影响原数据)
+      // 复制一份
+      const params = deepClone(this.searchParams)
+      // 自定义部分
+      // TODO: 搜索数据过滤
+      // if (this.searchParams.timerange?.length) {
+      //   params['starttime'] = this.searchParams.timerange[0]
+      //   params['endtime'] = this.searchParams.timerange[1]
+      //   delete params.timerange
+      // }
+      // 过滤空数据
+      Object.entries(params).forEach(([key, val]) => {
+        if (val == null || val === '') delete params[key]
+      })
+      return params
+    },
+    rowOperation(row, idx, actionName, params) { // 行操作
+      console.log(actionName, row)
+      this.$emit('rowOperation', row, idx, actionName, params)
+    },
+    selectionChange(list) { // 行选择
+      this.selectedList = list
+    },
+    changeLook(e) {
+      this.searchParams.lookStatus = e
+      this.getList()
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>
+

+ 99 - 0
plop-templates/table-view/index.hbs

@@ -0,0 +1,99 @@
+<!-- {{ title }} -->
+<template>
+  <div class="app-container">
+    <el-container>
+
+      <el-main>
+        <!-- 查询 -->
+        <Conditions ref="conditions" :search-params.sync="searchParams" @search="search" />
+        <!-- 表格 -->
+        <Tables ref="dyTable" :search-params="searchParams" @rowOperation="rowOperation" />
+        <!-- 弹窗 -->
+        <Details ref="detail" />
+      </el-main>
+
+    </el-container>
+  </div>
+</template>
+
+<script>
+import Tables from './components/table.vue'
+import Conditions from './components/conditions.vue'
+import Details from './components/detail.vue'
+
+export default {
+  name: '{{ properCase name }}',
+  components: { Conditions, Tables, Details },
+  data() {
+    return {
+      global: {
+        loading: true,
+      },
+      searchParams: {} // 查询(此处不赋值)
+    }
+  },
+  provide() {
+    return {
+      global: this.global, // 全局数据对象
+      reload: this.reload, // 重置
+      refresh: this.refresh // 刷新
+    }
+  },
+  created() {
+    this.updateOptions()
+  },
+  methods: {
+    /* common */
+    reload() { // 重置搜索 回到第一页
+      this.$refs.conditions.reset()
+    },
+    refresh() { // 不重置搜索 刷新当前页
+      this.$refs.dyTable.getList(this.searchParams)
+    },
+    /* search -> table */
+    search(params) { // 搜索
+      this.searchParams = params
+      this.$refs.dyTable.pageObj.current = 1
+      this.$refs.dyTable.getList(this.searchParams)
+    },
+    /* table -> dialog */
+    async rowOperation(row, idx, actionName, params = {}) {
+      if (['add', 'edit', 'see'].includes(actionName)) { // 增改查统一
+        this.$refs['detail'].showDialog({
+          mode: actionName,
+          formData: row || {},
+          ...params // 自定义字段
+        })
+      } else if (actionName === 'delete') { // 删除
+        const txt = `<p class="delText">您确定要删除该条记录吗?</p>`
+        await this.$confirm(txt, '温馨提示', {
+          dangerouslyUseHTMLString: true,
+          type: 'warning'
+        })
+        try {
+          this.loading = true
+          // TODO: 删除
+          // const res = await deleteInvitation({ id: row.id })
+          if (res.success) {
+            this.reload()
+          }
+        } finally {
+          this.loading = false
+        }
+      } else { // 表格其它操作
+        this.$refs[actionName].showDialog({
+          formData: row || {},
+          ...params // 自定义字段
+        })
+      }
+    },
+    updateOptions() {
+
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 81 - 0
plop-templates/table-view/prompt.js

@@ -0,0 +1,81 @@
+const { notEmpty } = require('../utils.js')
+
+module.exports = {
+  description: 'generate a table-view',
+  prompts: [{
+    type: 'input',
+    name: 'name',
+    message: '请输入组件目录名',
+    validate: notEmpty('name')
+  }, {
+    type: 'input',
+    name: 'title',
+    message: '请输入表格标题'
+  }, {
+    type: 'list',
+    name: 'treeType',
+    message: '请选择侧边树',
+    choices: [{
+      name: '<HybridTree>',
+      value: 'hybridTree'
+    },
+    {
+      name: '<ParkTree>',
+      value: 'parkTree'
+    },
+    {
+      name: 'none',
+      value: ''
+    }],
+    validate(value) {
+      if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
+        return 'View require at least a <script> or <template> tag.'
+      }
+      return true
+    }
+  }],
+  actions: data => {
+    const name = '{{name}}'
+    const title = '{{title}}'
+    const treeType = '{{treeType}}'
+    const actions = [{
+      type: 'add',
+      path: `src/views/${name}/index.vue`,
+      templateFile: 'plop-templates/table-view/index.hbs',
+      data: {
+        name: name,
+        title: title,
+        treeType: treeType
+      }
+    }, {
+      type: 'add',
+      path: `src/views/${name}/components/table.vue`,
+      templateFile: 'plop-templates/table-view/components/table.hbs',
+      data: {
+        name: name,
+        title: title,
+        treeType: treeType
+      }
+    }, {
+      type: 'add',
+      path: `src/views/${name}/components/conditions.vue`,
+      templateFile: 'plop-templates/table-view/components/conditions.hbs',
+      data: {
+        name: name,
+        title: title,
+        treeType: treeType
+      }
+    }, {
+      type: 'add',
+      path: `src/views/${name}/components/detail.vue`,
+      templateFile: 'plop-templates/table-view/components/detail.hbs',
+      data: {
+        name: name,
+        title: title,
+        treeType: treeType
+      }
+    }]
+
+    return actions
+  }
+}

+ 9 - 0
plop-templates/utils.js

@@ -0,0 +1,9 @@
+exports.notEmpty = name => {
+  return v => {
+    if (!v || v.trim === '') {
+      return `${name} is required`
+    } else {
+      return true
+    }
+  }
+}

+ 26 - 0
plop-templates/view/index.hbs

@@ -0,0 +1,26 @@
+{{#if template}}
+<template>
+  <div />
+</template>
+{{/if}}
+
+{{#if script}}
+<script>
+export default {
+  name: '{{ properCase name }}',
+  props: {},
+  data() {
+    return {}
+  },
+  created() {},
+  mounted() {},
+  methods: {}
+}
+</script>
+{{/if}}
+
+{{#if style}}
+<style lang="scss" scoped>
+
+</style>
+{{/if}}

+ 55 - 0
plop-templates/view/prompt.js

@@ -0,0 +1,55 @@
+const { notEmpty } = require('../utils.js')
+
+module.exports = {
+  description: 'generate a view',
+  prompts: [{
+    type: 'input',
+    name: 'name',
+    message: 'view name please',
+    validate: notEmpty('name')
+  },
+  {
+    type: 'checkbox',
+    name: 'blocks',
+    message: 'Blocks:',
+    choices: [{
+      name: '<template>',
+      value: 'template',
+      checked: true
+    },
+    {
+      name: '<script>',
+      value: 'script',
+      checked: true
+    },
+    {
+      name: 'style',
+      value: 'style',
+      checked: true
+    }
+    ],
+    validate(value) {
+      if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
+        return 'View require at least a <script> or <template> tag.'
+      }
+      return true
+    }
+  }
+  ],
+  actions: data => {
+    const name = '{{name}}'
+    const actions = [{
+      type: 'add',
+      path: `src/views/${name}/index.vue`,
+      templateFile: 'plop-templates/view/index.hbs',
+      data: {
+        name: name,
+        template: data.blocks.includes('template'),
+        script: data.blocks.includes('script'),
+        style: data.blocks.includes('style')
+      }
+    }]
+
+    return actions
+  }
+}

+ 12 - 0
plopfile.js

@@ -0,0 +1,12 @@
+const viewGenerator = require('./plop-templates/view/prompt')
+const tableViewGenerator = require('./plop-templates/table-view/prompt')
+const componentGenerator = require('./plop-templates/component/prompt')
+
+module.exports = function(plop) {
+  plop.setGenerator('view', viewGenerator)
+  plop.setGenerator('table-view', tableViewGenerator)
+  plop.setGenerator('component', componentGenerator)
+  plop.setHelper('equal', function(a, b) {
+    return a === b
+  })
+}

+ 5 - 0
postcss.config.js

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

BIN
public/favicon.ico


+ 24 - 0
public/index.html

@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="zh-CN" translate="no">
+  <head>
+    <meta charset="utf-8">
+    <meta name="referrer" content="no-referrer">
+    <!--<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="renderer" content="webkit">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">-->
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <meta http-equiv="pragram" content="no-cache">
+    <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= webpackConfig.name %></title>
+	 <!-- 全局引入 所需外部链接 -->
+	  <script src="js/vue.min.js"></script>
+    <script src="js/index.min.js"></script>
+  </head>
+  <body>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+  <script charset="utf-8" src="https://map.qq.com/api/js?v=2.exp&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77&libraries=place,search,drawing"></script>
+  <!-- <script src="https://map.brtbeacon.net/js-sdk/3.0/brtmap-3.0.0.js"></script> -->
+</html>

File diff suppressed because it is too large
+ 1 - 0
public/js/index.min.js


File diff suppressed because it is too large
+ 6 - 0
public/js/vue.min.js


+ 12 - 0
script/Dockerfile

@@ -0,0 +1,12 @@
+FROM registry-vpc.cn-shenzhen.aliyuncs.com/fsserver/nginx:1.17.3-alpine
+
+MAINTAINER caidongqiang@hotmail.com
+
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+ADD dist/  /usr/share/nginx/html/
+
+COPY script/config.conf /etc/nginx/nginx.conf
+
+EXPOSE 80

+ 46 - 0
script/Jenkinsfile

@@ -0,0 +1,46 @@
+pipeline {
+    agent any
+    parameters {
+            gitParameter (branch:'', branchFilter: 'origin/(.*)', defaultValue: 'master', description: '选择将要构建的分支', name: 'branch', selectedValue: 'TOP', sortMode: 'DESCENDING_SMART', type: 'PT_BRANCH')
+            gitParameter (branch:'', branchFilter: 'origin/(.*)', defaultValue: 'V1.0.0', description: '选择将要构建的TAG', name: 'tag', quickFilterEnabled: true, selectedValue: 'TOP', sortMode: 'DESCENDING_SMART', type: 'PT_TAG')
+    //         gitParameter (branch:'', branchFilter: 'origin/(.*)', defaultValue: 'master', description: '选择将要构建的分支或标签', name: 'tag', selectedValue: 'TOP', sortMode: 'DESCENDING_SMART', type: 'PT_BRANCH_TAG')
+    }
+    stages {
+        stage('Checkout') {
+                steps {
+                    echo '1.Checkout'
+                    checkout([$class: 'GitSCM',
+                        branches: [[name: "${params.tag}"]],
+                        doGenerateSubmoduleConfigurations: false,
+                        extensions: [],
+                        gitTool: 'Default',
+                        submoduleCfg: [],
+                        userRemoteConfigs: [[url: 'http://fsadmin:Fs123456@119.23.214.109:30032/guosy/fsmanager.git',credentialsId: 'git',]]
+                  ])
+                }
+        }
+        stage('Build') {
+            steps {
+                echo '2.Building'
+                 sh "npm install && npm run build"
+
+            }
+        }
+        stage('Docker') {
+            steps {
+                echo '3.Docker'
+                sh 'chmod 777 script/build_docker.sh'
+                sh "script/build_docker.sh fsmanager dev ${tag}"
+
+            }
+        }
+        stage('Deploy') {
+            steps {
+                echo '4.Deploying'
+                sh 'chmod 777 script/deploy_k8s.sh'
+                sh "script/deploy_k8s.sh web-fsmanager dev fsmanager:${tag}"
+
+            }
+        }
+    }
+}

+ 22 - 0
script/build_docker.sh

@@ -0,0 +1,22 @@
+#! /bin/sh
+### 接收参数
+env=$2
+ver=$3
+echo 'current env is ' + $env
+echo 'current ver is ' + $ver
+imagename=''
+nexusip=''
+if [ $env = 'dev' ]; then
+  nexusip='dockerlib.fujica.com.cn:8082'
+elif [ $env = 'test' ]; then
+  nexusip='172.16.0.232:8082'
+elif [ $env = 'pro' ]; then
+  nexusip='172.16.0.224:8082'
+else
+  imagename="fsserver/$1:$ver"
+fi
+imagename="fsserver/$1:$ver"
+echo 'imagename is ' + $imagename
+docker build -t $imagename --rm -f script/Dockerfile .
+docker tag $imagename $nexusip/$imagename
+docker push $nexusip/$imagename

+ 70 - 0
script/config.conf

@@ -0,0 +1,70 @@
+user  nginx;
+worker_processes  auto;
+
+error_log  /var/log/nginx/error.log warn;
+pid        /var/run/nginx.pid;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       /etc/nginx/mime.types;
+    default_type  application/octet-stream;
+    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+                      '$status $body_bytes_sent "$http_referer" '
+                      '"$http_user_agent" "$http_x_forwarded_for"';
+
+    client_max_body_size 1000m;
+    client_body_buffer_size 600m;
+    client_header_buffer_size 8m;
+
+    access_log  /var/log/nginx/access.log  main;
+    sendfile        on;
+    keepalive_timeout  65;
+    gzip_static  on;
+
+    #include /etc/nginx/conf.d/*.conf;
+    server {
+    listen       80;
+    server_name  localhost;
+
+    access_log  /var/log/nginx/host.access.log  main;
+    error_log  /var/log/nginx/error.log  error;
+
+    location / {
+        root   /usr/share/nginx/html;
+        index  index.html index.htm;
+        error_page 405 =200 $request_uri;
+    }
+    location /api56/open/common/ {
+      proxy_pass http://gatewayservice:10001/open/common/;
+      proxy_redirect off;
+      proxy_set_header Host $host;
+    }
+    location /api56/ {
+      proxy_pass http://gatewayservice:10001/transfer/manage/;
+      proxy_redirect off;
+      proxy_set_header Host $host;
+    #location ~ .*ping?$ {
+    #   return 404;
+    #}
+
+    #if ($request_uri ~* ^/\?ping(.*)$) {
+    #    return 404;
+    #}
+    }
+
+    error_page   500 502 503 504  /50x.html;
+    location = /50x.html {
+        root   /usr/share/nginx/html;
+    }
+    #location ~ .*ping?$ {
+    #   return 404;
+    #}
+
+    #if ($request_uri ~* ^/\?ping(.*)$) {
+    #     return 404;
+    #}
+    }
+}

+ 30 - 0
script/deploy_k8s.sh

@@ -0,0 +1,30 @@
+#! /bin/sh
+### 接收参数
+#Deployment name
+app=$1
+env=$2
+ver=$3
+echo 'current env is ' + $env
+imagename="fsserver/$app:$ver"
+nexusip=''
+if [ $env = 'dev' ]; then
+  nexusip='dockerlib.fujica.com.cn:8082'
+elif [ $env = 'test' ]; then
+  nexusip='172.16.0.232:8082'
+elif [ $env = 'pro' ]; then
+  nexusip='172.16.0.224:8082'
+else
+  nexusip='172.16.0.232:8082'
+fi
+
+sed -i "/namespacelabel/s/namespacelabel/fsprod/g" script/deployment.yaml
+
+echo 'imagename is ' + $imagename
+
+sed -i "/myapp/s/myapp/$app/g" script/deployment.yaml
+sed -i "/imagename/s/imagename/$ver/g" script/deployment.yaml
+
+sed -i "s/nexusip/$nexusip/g" script/deployment.yaml
+
+kubectl delete -f script/deployment.yaml
+kubectl apply -f script/deployment.yaml

+ 32 - 0
script/deployment.yaml

@@ -0,0 +1,32 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: myapp
+  namespace: fsprod
+  labels:
+    app: myapp
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      name: myapp
+  template:
+    metadata:
+      labels:
+        name: myapp
+    spec:
+      containers:
+        - name: myapp
+          image: nexusip/fsserver/imagename
+          imagePullPolicy: Always
+          securityContext:
+            runAsUser: 0                      #设置以ROOT用户运行容器
+            privileged: true
+          ports:
+            - containerPort: 80
+      imagePullSecrets:
+        - name: fsregsecret
+      volumes:
+        - name: localtime
+          hostPath:
+            path: /etc/localtime

+ 97 - 0
src/2.html

@@ -0,0 +1,97 @@
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>XMLHttpRequest上传文件</title>
+    <script type="text/javascript">
+        //图片上传
+        var xhr;
+        //上传文件方法
+        function UpladFile() {
+            var fileObj = document.getElementById("file").files[0]; // js 获取文件对象
+          //  var url =  "http://localhost:8081" + "/desks/upload"; // 接收上传文件的后台地址
+            var url =  "http://localhost:8081" + "/desks/importDesksByExcel"; // 接收上传文件的后台地址
+
+            var form = new FormData(); // FormData 对象
+            form.append("file", fileObj); // 文件对象
+
+            xhr = new XMLHttpRequest();  // XMLHttpRequest 对象
+            xhr.open("post", url, true); //post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。
+            xhr.onload = uploadComplete; //请求完成
+            xhr.onerror =  uploadFailed; //请求失败
+
+            xhr.upload.onprogress = progressFunction;//【上传进度调用方法实现】
+            xhr.upload.onloadstart = function(){//上传开始执行方法
+                ot = new Date().getTime();   //设置上传开始时间
+                oloaded = 0;//设置上传开始时,以上传的文件大小为0
+            };
+
+            xhr.send(form); //开始上传,发送form数据
+        }
+
+        //上传成功响应
+        function uploadComplete(evt) {
+            //服务断接收完文件返回的结果
+            alert(evt);
+            var data = JSON.parse(evt.target.responseText);
+            if(data.success) {
+                alert("上传成功!");
+            }else{
+                alert("上传失败!2222");
+            }
+
+        }
+        //上传失败
+        function uploadFailed(evt) {
+            alert("上传失败!111");
+        }
+        //取消上传
+        function cancleUploadFile(){
+            xhr.abort();
+        }
+
+
+        //上传进度实现方法,上传过程中会频繁调用该方法
+        function progressFunction(evt) {
+            var progressBar = document.getElementById("progressBar");
+            var percentageDiv = document.getElementById("percentage");
+            // event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
+            if (evt.lengthComputable) {//
+                progressBar.max = evt.total;
+                progressBar.value = evt.loaded;
+                percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
+            }
+            var time = document.getElementById("time");
+            var nt = new Date().getTime();//获取当前时间
+            var pertime = (nt-ot)/1000; //计算出上次调用该方法时到现在的时间差,单位为s
+            ot = new Date().getTime(); //重新赋值时间,用于下次计算
+            var perload = evt.loaded - oloaded; //计算该分段上传的文件大小,单位b
+            oloaded = evt.loaded;//重新赋值已上传文件大小,用以下次计算
+            //上传速度计算
+            var speed = perload/pertime;//单位b/s
+            var bspeed = speed;
+            var units = 'b/s';//单位名称
+            if(speed/1024>1){
+                speed = speed/1024;
+                units = 'k/s';
+            }
+            if(speed/1024>1){
+                speed = speed/1024;
+                units = 'M/s';
+            }
+            speed = speed.toFixed(1);
+            //剩余时间
+            var resttime = ((evt.total-evt.loaded)/bspeed).toFixed(1);
+            time.innerHTML = ',速度:'+speed+units+',剩余时间:'+resttime+'s';
+            if(bspeed==0) time.innerHTML = '上传已取消';
+        }
+    </script>
+</head>
+<body>
+<progress id="progressBar" value="0" max="100" style="width: 300px;"></progress>
+<span id="percentage"></span><span id="time"></span>
+<br /><br />
+<input type="file" id="file" name="myfile" />
+<input type="button" onclick="UpladFile()" value="上传" />
+<input type="button" onclick="cancleUploadFile()" value="取消" />
+</body>
+</html>

+ 165 - 0
src/App.vue

@@ -0,0 +1,165 @@
+<template>
+  <div id="app" :class="device">
+    <router-view v-if="isRouterAlive" />
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'App',
+  data() {
+    return {
+      isRouterAlive: true
+    }
+  },
+  computed: {
+    device() {
+      return this.$store.state.app.device
+    }
+  },
+  provide() {
+    return {
+      reload: this.reload
+    }
+  },
+  methods: {
+    reload() {
+      this.isRouterAlive = false
+      this.$nextTick(function() {
+        this.isRouterAlive = true
+      })
+    }
+  }
+}
+</script>
+<style>
+#nprogress .bar { background: #b4c9fe !important;}
+ .tree-container{
+    padding:0;
+  }
+  .el-container{
+    height:100%;
+}
+#fmap canvas{
+  width: 100% !important;
+  height: 100% !important;
+}
+#fmap .fm-control-groups-layer{
+  background: url('../src/assets/fengmap/layer.png') no-repeat center center;
+  text-indent: -999em;
+}
+  path { fill: inherit !important }
+  #app .sidebar-container .is-active.is-opened .el-submenu__title,#app .sidebar-container .is-active.is-opened .el-submenu__title i,#app .sidebar-container .is-active .el-submenu__title,#app .sidebar-container .is-active .el-submenu__title i,.el-menu-item.is-active{
+    color: #2F71FF !important;
+  }
+  #app .sidebar-container .el-submenu .el-submenu__title{
+  border-radius: 0px 28px 28px 0px;
+  }
+  #app .sidebar-container .is-active.is-opened .el-submenu__title,#app .sidebar-container .is-active .el-submenu__title{
+    background: #DAE4FF !important;
+  }
+  .distpicker-address-wrapper select{
+      width: 90px;
+      padding: 0 !important;
+      height: 36px !important;
+      line-height: 36px !important;
+      font-size: 14px !important;
+  }
+  .el-table .cell .dotDot::after{
+    content:'...';
+    display:inline-block;
+    vertical-align:bottom;
+    overflow:hidden;
+    width:15px;
+    animation:dotDotDoting 2s infinite step-start;
+  }
+ @keyframes dotDotDoting{
+  0%
+  {
+    width:0px;
+    margin-right:15px;
+  }
+
+  25%
+  {
+    width:5px;
+    margin-right:15px;
+  }
+
+  50%
+  {
+    width:8px;
+    margin-right:10px;
+  }
+
+  75%
+  {
+    width:10px;
+    margin-right:5px;
+  }
+
+  100%
+  {
+    width:15px;
+    margin-right:0;
+  }
+}
+  .drawerbox .el-dialog{
+    width: 570px !important;
+  }
+  @media(max-width:750px){
+    .diaboxM-Main .el-dialog{
+     width: 90% !important;
+   }
+   .el-button{
+     margin-bottom: 10px;
+   }
+   .el-select{
+     margin-bottom: 20px;
+   }
+   .radTypeBTab .el-radio-group{
+     width: 100%;
+   }
+   .radTypeBTab .el-radio-button{
+     width: 25%;
+   }
+  .radTypeBTab .el-radio-button__inner{
+      width: 100%;
+      padding: 10px 0;
+      text-align: center;
+  }
+  .statTab .el-radio-button__inner{
+    width: 100%;
+    padding: 10px 0;
+    text-align: center;
+    border-left: 1px solid #DCDFE6;
+    border-radius: 4px !important;
+    border-top: 0;
+  }
+  .statTab .el-radio-button:first-child .el-radio-button__inner{
+    border-top: 1px solid #DCDFE6;
+  }
+  .app-container{
+    padding: 15px;
+    height: auto !important;
+  }
+  .distpicker-address-wrapper select{
+      width: 90px;
+      padding: 0 !important;
+      height: 36px !important;
+      line-height: 36px !important;
+      font-size: 14px !important;
+  }
+  .el-pagination .el-pagination__jump{
+        margin-left: 0;
+        margin-top: 10px;
+    }
+    .repBox canvas{
+      width: 100% !important;
+    }
+    .el-dialog__wrapper{
+      margin-top: 10vh !important;
+      align-items: flex-start !important;
+    }
+  }
+</style>

+ 9 - 0
src/api/equipment/model.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+export function upload(data) {
+  return request({
+    url: `/file/uploadFile`,
+    method: 'POST',
+    data,
+    toast: false
+  })
+}

+ 34 - 0
src/apiV2/common.js

@@ -0,0 +1,34 @@
+/* 通用接口 */
+import request from '@/utils/request'
+
+/* 获取省市区级联树 */
+export function getRegionTree(params) {
+  return request({
+    url: '/sys/region/tree',
+    method: 'GET',
+    params
+  })
+}
+
+/* 获取字典列表通过字典类型Code */
+export function getDictByTypeCode(typeCode) {
+  return request({
+    url: `/sys/dictdetail/valid/${typeCode}`,
+    method: 'GET'
+  })
+}
+
+export function getIntDictByTypeCode(typeCode) {
+  return request({
+    url: `/sys/dictdetail/valid/int/${typeCode}`,
+    method: 'GET'
+  })
+}
+
+
+export function downloadStatic(code) {
+  return request({
+    url: `/sys/resource/static/`+code,
+    method: 'GET'
+  })
+}

+ 83 - 0
src/apiV2/company.js

@@ -0,0 +1,83 @@
+/* 企业管理通用接口 */
+import request from '@/utils/request'
+
+/* 添加企业 */
+export function addCompany(data, toast = true) {
+  return request({
+    url: '/sys/company',
+    method: 'POST',
+    data,
+    toast
+  })
+}
+/* 编辑企业 */
+export function updateCompany(data) {
+  return request({
+    url: '/sys/company',
+    method: 'PUT',
+    data
+  })
+}
+/* 获取企业列表 */
+export function getCompanyPage(params) {
+  return request({
+    url: '/sys/company/page',
+    method: 'GET',
+    params
+  })
+}
+/* 查看企业 */
+export function getCompany(id) {
+  return request({
+    url: `/sys/company/${id}`,
+    method: 'GET'
+  })
+}
+/* 删除企业 */
+export function deleteCompany(id) {
+  return request({
+    url: `/sys/company/${id}`,
+    method: 'DELETE'
+  })
+}
+/* 启用企业 */
+export function enableCompany(id) {
+  return request({
+    url: `/sys/company/enable/${id}`,
+    method: 'PUT'
+  })
+}
+/* 禁用企业 */
+export function disableCompany(id) {
+  return request({
+    url: `/sys/company/disable/${id}`,
+    method: 'PUT'
+  })
+}
+
+/* 重置企业密码 */
+export function resetCompanyPwd(data) {
+  return request({
+    url: `/sys/company/reset`,
+    method: 'PUT',
+    data
+  })
+}
+
+/**
+ * 开通服务
+ * @param {object} params 参数对象
+ * @param {Number} params.companyId 企业ID
+ * @param {String} params.contractNo 实收金额
+ * @param {Number} params.amount 应收金额
+ * @param {Number} params.amountReceivable 合同编号
+ * @param {Array} params.contractProjectPackList 注销【项目服务记录】ID列表
+ * @returns {object}
+ */
+export function openService(data) {
+  return request({
+    url: '/sys/contract/open',
+    method: 'POST',
+    data
+  })
+}

+ 15 - 0
src/apiV2/data.js

@@ -0,0 +1,15 @@
+import request from '@/utils/request'
+
+export function clear(data) {
+  return request({
+    url: '/sys/data/clear',
+    method: 'post',
+    data
+  })
+}
+export function getClear() {
+  return request({
+    url: '/sys/data/clear',
+    method: 'get'
+  })
+}

+ 41 - 0
src/apiV2/dept.js

@@ -0,0 +1,41 @@
+/* 组织机构通用接口 */
+import request from '@/utils/request'
+
+export function getDeptPage(params) { // 获取组织机构(数组)
+  return request({
+    url: '/sys/dept/page',
+    method: 'GET',
+    params
+  })
+}
+
+export function getDeptTree(params) { // 获取组织机构(树)
+  return request({
+    url: '/sys/dept/tree',
+    method: 'GET',
+    params
+  })
+}
+
+export function addDept(data) {
+  return request({
+    url: '/sys/dept',
+    method: 'POST',
+    data
+  })
+}
+
+export function deleteDept(id) {
+  return request({
+    url: `/sys/dept/${id}`,
+    method: 'DELETE'
+  })
+}
+
+export function updateDept(data) {
+  return request({
+    url: `/sys/dept`,
+    method: 'PUT',
+    data
+  })
+}

+ 85 - 0
src/apiV2/doc.md

@@ -0,0 +1,85 @@
+
+
+## 获取企业超管默认角色
+
+
+**接口地址**:`/sys/role/company/list`
+
+
+**请求方式**:`GET`
+
+
+**请求数据类型**:`application/x-www-form-urlencoded`
+
+
+**响应数据类型**:`*/*`
+
+
+**接口描述**:
+
+
+**请求参数**:
+
+
+**请求参数**:
+
+
+暂无
+
+
+**响应状态**:
+
+
+| 状态码 | 说明 | schema |
+| -------- | -------- | ----- | 
+|200|OK|R«List«Role»»|
+|401|Unauthorized||
+|403|Forbidden||
+|404|Not Found||
+
+
+**响应参数**:
+
+
+| 参数名称 | 参数说明 | 类型 | schema |
+| -------- | -------- | ----- |----- | 
+|code||integer(int32)|integer(int32)|
+|data||array|Role|
+|&emsp;&emsp;companyId|所属企业|integer(int32)||
+|&emsp;&emsp;createName|创建者|string||
+|&emsp;&emsp;createTime|创建时间|string(date-time)||
+|&emsp;&emsp;deptId|所属组织|integer(int32)||
+|&emsp;&emsp;id|角色id|integer(int32)||
+|&emsp;&emsp;isDefault|角色类型 0自定义 1内置角色|integer(int32)||
+|&emsp;&emsp;name|角色名称|string||
+|&emsp;&emsp;remark|备注|string||
+|&emsp;&emsp;updateName|修改人|string||
+|&emsp;&emsp;updateTime|修改时间|string(date-time)||
+|msg||string||
+|reqId||string||
+|success||boolean||
+
+
+**响应示例**:
+```javascript
+{
+	"code": 0,
+	"data": [
+		{
+			"companyId": 0,
+			"createName": "",
+			"createTime": "",
+			"deptId": 0,
+			"id": 0,
+			"isDefault": 0,
+			"name": "",
+			"remark": "",
+			"updateName": "",
+			"updateTime": ""
+		}
+	],
+	"msg": "",
+	"reqId": "",
+	"success": true
+}
+```

+ 18 - 0
src/apiV2/exportlist.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 查询导入导出列表
+export function getexportlist(params) {
+  return request({
+    url: '/sys/fileRecord/page',
+    method: 'get',
+    params
+  })
+}
+
+// 下载错误数据
+export function getdownload(query) {
+  return request({
+    url: '/sys/fileRecord/' + query,
+    method: 'get'
+  })
+}

+ 29 - 0
src/apiV2/log.js

@@ -0,0 +1,29 @@
+/* 日志管理-相关接口 */
+import request from '@/utils/request'
+
+/**
+ * 分页查询登录日志
+ * @param {object} params 搜索&页码参数
+ * @returns {object}
+ */
+export function getlogloginPage(params) {
+  return request({
+    url: `/sys/loglogin/page`,
+    method: 'GET',
+    params
+  })
+}
+
+/**
+ * 分页查询操作日志
+ * @param {object} params 搜索&页码参数
+ * @returns {object}
+ */
+export function getlogPage(params) {
+  return request({
+    url: `/sys/log/page`,
+    method: 'GET',
+    params
+  })
+}
+

+ 163 - 0
src/apiV2/menuManage.js

@@ -0,0 +1,163 @@
+import request from '@/utils/request'
+
+// //  获得Menu清单	结构体	GET	Menu清单		/tmenulists/getMenuList
+// //  新增一个	结构体	POST	新增一个Menu	成功,失败	/tmenulists/addOneMenu
+// //  获得一个Menu	myid	GET	获得单个Menu		/tmenulists/getOneMenu/??
+// //  更新Menu信息	结构体	POST	更新某一个Menu信息	成功,失败	/tmenulists/updateOneMenu
+// //  删除一个	myid	GET	不能删除		/tmenulists/delOneMenu/??
+
+// // 获取
+export function getMenuList(query) {
+  return request({
+    url: '/sys/menu/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function menuDetail(id) {
+  return request({
+    url: '/sys/menu/'+id,
+    method: 'get',
+    // params: query
+  })
+}
+
+export function getMenuTree(query) {
+  return request({
+    url: '/sys/menu/tree',
+    method: 'get',
+    params: query
+  })
+}
+
+// // 新增
+export function addOneMenu(data) {
+  return request({
+    url: '/sys/menu',
+    method: 'post',
+    data
+  })
+}
+
+export function down(params) {
+  return request({
+    url: '/sys/menu/down/' + params.ID,
+    method: 'GET',
+    params
+  })
+}
+
+export function up(params) {
+  return request({
+    url: '/sys/menu/up/' + params.ID,
+    method: 'GET',
+    params
+  })
+}
+
+export function enable(data) {
+  return request({
+    url: '/sys/menu/enable/'+data.id,
+    method: 'PUT',
+    data
+  })
+}
+
+
+// // 更新
+export function updateOneMenu(data) {
+  return request({
+    url: '/sys/menu/'+data.id,
+    method: 'PUT',
+    data
+  })
+}
+
+// // 下拉获取上级菜单 /tprivilegelists/getAllprivilegelist
+// export function getAllprivilegelist() {
+//   return request({
+//     url: '/tprivilegelists/getAllprivilegelist',
+//     method: 'get'
+//   })
+// }
+
+// 禁用菜单/tmenulists/disableMenu/{{id}}
+export function disableMenu(data) {
+  return request({
+    url: '/sys/menu/disable/'+data.id,
+    method: 'PUT',
+    data
+  })
+}
+
+// // /entMenus/getAllParentMenu
+// export function getAllParentMenu() {
+//   return request({
+//     url: '/entMenus/getAllParentMenu',
+//     method: 'get'
+//   })
+// }
+
+// // /entMenus/getAllViewRole
+// export function getAllViewRole() {
+//   return request({
+//     url: '/entMenus/getAllViewRole',
+//     method: 'get'
+//   })
+// }
+
+// // 查询某个 /tmenulists/getOneMenu/{{id}}
+// export function getOneMenu(id) {
+//   return request({
+//     url: '/tmenulists/getOneMenu/' + id,
+//     method: 'get'
+//   })
+// }
+
+// // 删除菜单 /tmenulists/delOneMenu/452
+export function delOneMenu(data) {
+  return request({
+    url: '/sys/menu/' + data.id,
+    method: 'DELETE',
+    data
+  })
+}
+
+// // 上下移/tmenulists/moveMenuSort
+// export function moveMenuSort(data) {
+//   return request({
+//     url: '/tmenulists/moveMenuSort/' + data.id + '?operate=' + data.operate,
+//     method: 'post'
+//   })
+// }
+
+// // 菜单导入 - /tmenulists/importMenu
+export function importMenu(data) {
+  return request({
+    url: '/sys/menu/input',
+    method: 'post',
+    // toast: false,
+    errtoast: false,
+    data,
+    cache: false,
+    processData: false,
+    contentType: false
+  })
+}
+
+// // 导出 - /tmenulists/exportMenu
+export function exportMenu(data) {
+  return request({
+    url: '/sys/menu/export',
+    method: 'POST',
+    data
+  })
+}
+
+export function menuChildList(id) {
+  return request({
+    url: '/sys/role/menu/childList/'+id,
+    method: 'GET',
+  })
+}

+ 16 - 0
src/apiV2/park.js

@@ -0,0 +1,16 @@
+/* 车场管理通用接口 */
+import request from '@/utils/request'
+
+/**
+ * 车场列表-下拉框
+ * @param {object} params 参数对象
+ * @param {object} params.id 商户ID
+ * @param {object} params.status 商户状态 1-启用 2禁用(默认启用)
+ * @returns {object}
+ */
+export function getParkOptions(projectNo) {
+  return request({
+    url: `/park/customer/park/select/${projectNo}`,
+    method: 'GET'
+  })
+}

+ 134 - 0
src/apiV2/parkingManagement.js

@@ -0,0 +1,134 @@
+/**
+ * 车场管理
+ */
+import request from '@/utils/request'
+
+
+// 获取车场列表
+export function getParkList(query) {
+  return request({
+    url: '/park/leader/park/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getDictList(query) {
+  return request({
+    url: '/sys/dictdetail/valid/'+query.typeCode,
+    method: 'get',
+    // params: query
+  })
+}
+
+ // 根据id获取车场信息
+export function getOneParkByid(id) {
+  return request({
+    url: `/park/leader/park/detail/`+id,
+    method: 'get',
+  })
+}
+
+ // 修改车场状态(启用/禁用)
+export function changeSetting(data) {
+  return request({
+    url: '/park/leader/setting/park',
+    method: 'post',
+    data: data
+  })
+}
+export function getSetting(parkId) {
+  return request({
+    url: '/park/leader/setting/park/'+parkId,
+    method: 'GET',
+  })
+}
+// // 删除车场(启用/禁用)
+export function delOnePark(id) {
+  return request({
+    url: `/park/leader/park/${id}`,
+    method: 'DELETE'
+  })
+}
+
+export function getProjectList(query) {
+  return request({
+    url: `/sys/project/page`,
+    method: 'GET',
+    params: query
+  })
+}
+
+
+// // 获取车道信息
+export function getRoadList(params) {
+  return request({
+    url: `/park/leader/lane/page`,
+    method: 'get',
+    params: params
+  })
+}
+
+// // 下载二维码
+export function download(params) {
+  return request({
+    url: '/park/leader/qrcode/down',
+    method: 'get',
+    responseType: 'blob',
+    params
+  })
+}
+
+// // 根据车场id重置密码 - /tuserlists/resetPassword
+// export function resetPassword(data) {
+//   return request({
+//     url: `/tuserlists/resetPassword`,
+//     method: 'post',
+//     data
+//   })
+// }
+// // 设置车场是否展示异常记录
+// export function updateAbnormal(params) {
+//   return request({
+//     url: '/managepark/updateAbnormal',
+//     method: 'get',
+//     params
+//   })
+// }
+// export function setOrderLockTime(data) {
+//   return request({
+//     url: `/managepark/setOrderLockTime`,
+//     method: 'post',
+//     data
+//   })
+// }
+// export function getOrderLockTime(parkid) {
+//   return request({
+//     url: `/managepark/getOrderLockTime/` + parkid,
+//     method: 'get'
+//   })
+// }
+export function getProvinceListAll(parkid) {
+  return request({
+    url: `/sys/region/tree`,
+    method: 'get'
+  })
+}
+
+// 获取数据中台车场列表
+export function getDataCenterParkList(query) {
+  return request({
+    url: '/park/leader/park/datacenter/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 获取数据中台车道信息
+export function getDataCenterRoadList(params) {
+  return request({
+    url: `/park/leader/lane/datacenter/page`,
+    method: 'get',
+    params: params
+  })
+}

+ 99 - 0
src/apiV2/parkrecord.js

@@ -0,0 +1,99 @@
+import request from '@/utils/request'
+// 车道列表-下拉框
+export function getLaneList(params) {
+  return request({
+    url: '/inout/query/getLaneList',
+    method: 'GET',
+    params
+  })
+}
+// 查询入场流水记录
+export function parkInRecord(params) {
+  return request({
+    url: '/inout/query/parkInRecord',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 导出入场流水记录
+export function exportParkInRecord(params) {
+  return request({
+    url: '/inout/query/export/parkInRecord',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 查询出场流水记录
+export function parkOutRecord(params) {
+  return request({
+    url: '/inout/query/parkOutRecord',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 导出出场流水记录
+export function exportParkOutRecord(params) {
+  return request({
+    url: '/inout/query/export/parkOutRecord',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 查询已完成记录
+export function parkFinishOrder(params) {
+  return request({
+    url: '/inout/query/parkFinishOrder',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 导出已完成记录
+export function exportParkFinishOrder(params) {
+  return request({
+    url: '/inout/query/export/parkFinishOrder',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 查询场内车记录
+export function parkIn(params) {
+  return request({
+    url: '/inout/query/parkIn',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 导出场内车记录
+export function exportParkIn(params) {
+  return request({
+    url: '/inout/query/export/parkIn',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 查询临停支付订单
+export function carFeeOrder(params) {
+  return request({
+    url: '/inout/query/carFeeOrder',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}
+// 导出临停支付订单
+export function exportCarFeeOrder(params) {
+  return request({
+    url: '/inout/query/export/carFeeOrder',
+    method: 'get',
+    params,
+    projectNo: true
+  })
+}

+ 17 - 0
src/apiV2/project.js

@@ -0,0 +1,17 @@
+
+/* 项目管理通用接口 */
+import request from '@/utils/request'
+
+/**
+ * 获取项目列表
+ * @param {object} params 参数对象
+ * @param {object} params.companyId 企业ID
+ * @returns {object}
+ */
+export function getProjectList(params) {
+  return request({
+    url: '/sys/project',
+    method: 'GET',
+    params
+  })
+}

+ 71 - 0
src/apiV2/projectManage.js

@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+export function getProjectList(data) {
+  return request({
+    url: `/sys/project/page`,
+    method: 'get',
+    params:data
+  })
+}
+
+export function getEntList(data) {
+  return request({
+    url: `/sys/company/page`,
+    method: 'get',
+    params:data
+  })
+}
+
+export function addProject(data) {
+  return request({
+    url: `/sys/project`,
+    method: 'post',
+    data:data
+  })
+}
+
+export function editProject(data) {
+  return request({
+    url: `/sys/project`,
+    method: 'PUT',
+    data:data
+  })
+}
+
+export function cloud(data) {
+  return request({
+    url: `/sys/project/cloud/`+data,
+    method: 'get',
+  })
+}
+
+export function cloudpage(data) {
+  return request({
+    url: `/sys/cloud/page`,
+    method: 'get',
+    params:data
+  })
+}
+
+export function cloudconfig(data) {
+  return request({
+    url: `/sys/project/cloud`,
+    method: 'PUT',
+    data
+  })
+}
+
+export function disable(data) {
+  return request({
+    url: `/sys/project/disable/`+data.id,
+    method: 'PUT',
+    data
+  })
+}
+
+export function enable(data) {
+  return request({
+    url: `/sys/project/enable/`+data.id,
+    method: 'PUT',
+    data
+  })
+}

+ 25 - 0
src/apiV2/role.js

@@ -0,0 +1,25 @@
+/* 角色管理通用接口 */
+import request from '@/utils/request'
+
+export function getRolePage(data) { // 获取角色列表
+  return request({
+    url: '/sys/role/page',
+    method: 'get',
+    params: data
+  })
+}
+
+export function getUserRole(data) { // 获取当前用户角色列表
+  return request({
+    url: '/sys/role/userRole',
+    method: 'get',
+    params: data
+  })
+}
+
+export function roleCompanyList() { // 获取当前用户角色列表
+  return request({
+    url: '/sys/role/company/list',
+    method: 'get'
+  })
+}

+ 45 - 0
src/apiV2/rolemanage.js

@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+
+export function roleList(query) {
+    return request({
+      url: '/sys/role/page',
+      method: 'get',
+      params: query
+    })
+}
+export function add(data) {
+    return request({
+      url: '/sys/role',
+      method: 'post',
+      data
+    })
+}
+export function edit(data) {
+    return request({
+      url: '/sys/role',
+      method: 'PUT',
+      data
+    })
+}
+
+export function detail(data) {
+    return request({
+      url: '/sys/role/'+data,
+      method: 'GET',
+    })
+}
+
+export function del(data) {
+    return request({
+      url: '/sys/role/'+data,
+      method: 'DELETE',
+    })
+}
+
+export function menuTree(params) {
+    return request({
+      url: '/sys/menu/tree',
+      method: 'GET',
+      params
+    })
+}

+ 33 - 0
src/apiV2/systemConfig.js

@@ -0,0 +1,33 @@
+import request from '@/utils/request'
+export function paramconfig(data) {
+    return request({
+      url: '/sys/paramconfig',
+      method: 'post',
+      data
+    })
+  }
+  
+  // 根据车场ID查名称
+  export function findByModule(params) {
+    return request({
+      url: '/sys/paramconfig/findByModule',
+      method: 'get',
+      params
+    })
+  }
+
+  export function uploadfile(data) {
+    return request({
+      url: '/sys/file/containPath',
+      method: 'post',
+      data
+    })
+  }
+
+  export function buildImageUrl(params) {
+    return request({
+      url: '/sys/file/buildImageUrl/batch',
+      method: 'get',
+      params
+    })
+  }

+ 137 - 0
src/apiV2/user.js

@@ -0,0 +1,137 @@
+import request from '@/utils/request'
+
+/* 用户登录 */
+export function login(data) {
+  return request({
+    url: '/sys/user/login',
+    method: 'post',
+    data: data,
+    toast: false
+  })
+}
+/* 添加用户 */
+export function addUser(data) {
+  return request({
+    url: '/sys/user',
+    method: 'POST',
+    data: data
+  })
+}
+/* 获取用户详情 */
+export function getUser(id) {
+  return request({
+    url: `/sys/user/${id}`,
+    method: 'GET'
+  })
+}
+/* 编辑用户 */
+export function updateUser(data) {
+  return request({
+    url: '/sys/user',
+    method: 'PUT',
+    data: data
+  })
+}
+/* 删除用户 */
+export function deleteUser(id) {
+  return request({
+    url: `/sys/user/${id}`,
+    method: 'DELETE'
+  })
+}
+/* 启用用户 */
+export function enableUser(id) {
+  return request({
+    url: `/sys/user/enable/${id}`,
+    method: 'PUT'
+  })
+}
+/* 禁用用户 */
+export function disableUser(id) {
+  return request({
+    url: `/sys/user/disable/${id}`,
+    method: 'PUT'
+  })
+}
+/* 重置用户密码 */
+export function resetUserPwd(userId) {
+  return request({
+    url: `/sys/user/resetPassword/${userId}`,
+    method: 'PUT'
+  })
+}
+
+export function authConfig(code) { // 获取是否展示密码眼睛配置
+  return request({
+    url: '/tparameters/systemConfig?codes=' + code,
+    method: 'get',
+    errtoast: false
+  })
+}
+export function sendSmsCode(data) { // 获取短信验证码
+  return request({
+    url: '/auth/sendSmsCode',
+    method: 'get',
+    params: data
+  })
+}
+
+export function getInfo(token) {
+  return request({
+    url: '/sys/user',
+    method: 'get',
+    // params: { token },
+    toast: false
+  })
+}
+
+export function logout() {
+  return request({
+    url: '/sys/user/logout',
+    method: 'put',
+    toast: false
+  })
+}
+
+// 拉取左边菜单
+export function getMenueList() {
+  return request({
+    url: '/sys/user/menuTree',
+    method: 'get',
+    toast: false
+  })
+}
+
+// 修改密码
+export function updatePassword(data) {
+  return request({
+    url: '/sys/user/updatePassword',
+    method: 'put',
+    data,
+    toast: false
+  })
+}
+
+// 获取验证码
+export function getBufferImage() {
+  return request({
+    url: '/sys/verifyCode',
+    method: 'get',
+    responseType: 'blob'
+  })
+}
+
+// 坐席人员 - /tcloudservicecustomers/getCloudCustomer/{centerid}
+export function getCloudCustomer(id) {
+  return request({
+    url: '/tcloudservicecustomers/getCloudCustomer/' + id,
+    method: 'get'
+  })
+}
+// 坐席人员 - /tcloudservicecustomers/getCloudCustomerList/{centerid}
+export function getCloudCustomerList(id) {
+  return request({
+    url: '/tcloudservicecustomers/getCloudCustomerList/' + id,
+    method: 'get'
+  })
+}

BIN
src/assets/401_images/401.gif


BIN
src/assets/404_images/404.png


BIN
src/assets/404_images/404_cloud.png


BIN
src/assets/custom-theme/fonts/element-icons.ttf


BIN
src/assets/custom-theme/fonts/element-icons.woff


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


BIN
src/assets/default_graph/graph_car_big.png


BIN
src/assets/default_graph/graph_car_small.png


BIN
src/assets/ent.png


BIN
src/assets/faceImages/deleted.png


BIN
src/assets/faceImages/edit.png


BIN
src/assets/fengmap/2D.png


BIN
src/assets/fengmap/3D.png


BIN
src/assets/fengmap/arrow1.png


+ 0 - 0
src/assets/fengmap/arrow2.png


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