ming 4 vuotta sitten
commit
4fbc3f9e01
100 muutettua tiedostoa jossa 2838 lisäystä ja 0 poistoa
  1. 14 0
      .editorconfig
  2. 5 0
      .env.development
  3. 6 0
      .env.production
  4. 8 0
      .env.staging
  5. 4 0
      .eslintignore
  6. 198 0
      .eslintrc.js
  7. 16 0
      .gitignore
  8. 5 0
      .travis.yml
  9. 21 0
      LICENSE
  10. 102 0
      README-zh.md
  11. 90 0
      README.md
  12. 14 0
      babel.config.js
  13. 35 0
      build/index.js
  14. 24 0
      jest.config.js
  15. 9 0
      jsconfig.json
  16. 57 0
      mock/index.js
  17. 81 0
      mock/mock-server.js
  18. 29 0
      mock/table.js
  19. 84 0
      mock/user.js
  20. 25 0
      mock/utils.js
  21. 64 0
      package.json
  22. 8 0
      postcss.config.js
  23. BIN
      public/favicon.ico
  24. 17 0
      public/index.html
  25. 11 0
      src/App.vue
  26. 16 0
      src/api/orgnization.js
  27. 15 0
      src/api/table.js
  28. 24 0
      src/api/user.js
  29. BIN
      src/assets/404_images/404.png
  30. BIN
      src/assets/404_images/404_cloud.png
  31. BIN
      src/assets/code.png
  32. BIN
      src/assets/img.png
  33. BIN
      src/assets/logo.png
  34. BIN
      src/assets/route.png
  35. 1 0
      src/assets/tree-user.svg
  36. BIN
      src/assets/video.png
  37. 78 0
      src/components/Breadcrumb/index.vue
  38. 44 0
      src/components/Hamburger/index.vue
  39. 62 0
      src/components/SvgIcon/index.vue
  40. 9 0
      src/icons/index.js
  41. 28 0
      src/icons/svg/account-manage.svg
  42. 20 0
      src/icons/svg/alarm-log.svg
  43. 17 0
      src/icons/svg/alarm-task.svg
  44. 16 0
      src/icons/svg/alarm.svg
  45. 1 0
      src/icons/svg/auth-icon.svg
  46. 15 0
      src/icons/svg/auth-manage.svg
  47. 14 0
      src/icons/svg/camera.svg
  48. 0 0
      src/icons/svg/dashboard.svg
  49. 11 0
      src/icons/svg/device-manage.svg
  50. 14 0
      src/icons/svg/elect.svg
  51. 1 0
      src/icons/svg/example.svg
  52. 1 0
      src/icons/svg/export.svg
  53. 1 0
      src/icons/svg/eye-open.svg
  54. 1 0
      src/icons/svg/eye.svg
  55. 0 0
      src/icons/svg/form.svg
  56. 17 0
      src/icons/svg/guard.svg
  57. 17 0
      src/icons/svg/home.svg
  58. 0 0
      src/icons/svg/home1.svg
  59. 1 0
      src/icons/svg/link.svg
  60. 28 0
      src/icons/svg/log-manage.svg
  61. 1 0
      src/icons/svg/nested.svg
  62. 13 0
      src/icons/svg/organization.svg
  63. 1 0
      src/icons/svg/orgnization-icon.svg
  64. 1 0
      src/icons/svg/password.svg
  65. 15 0
      src/icons/svg/patrol-manage.svg
  66. 13 0
      src/icons/svg/patrol-plan.svg
  67. 15 0
      src/icons/svg/patrol-point.svg
  68. 17 0
      src/icons/svg/patrol-route.svg
  69. 0 0
      src/icons/svg/per-manage-icon.svg
  70. 49 0
      src/icons/svg/per-manage.svg
  71. 0 0
      src/icons/svg/security-icon.svg
  72. 18 0
      src/icons/svg/security.svg
  73. 1 0
      src/icons/svg/system-icon.svg
  74. 40 0
      src/icons/svg/system-manage.svg
  75. 1 0
      src/icons/svg/table.svg
  76. 20 0
      src/icons/svg/team.svg
  77. 1 0
      src/icons/svg/tree-user.svg
  78. 1 0
      src/icons/svg/tree.svg
  79. 1 0
      src/icons/svg/unit-info-icon.svg
  80. 18 0
      src/icons/svg/unit.svg
  81. 15 0
      src/icons/svg/user-manage.svg
  82. 1 0
      src/icons/svg/user.svg
  83. 22 0
      src/icons/svgo.yml
  84. 46 0
      src/layout/components/AppMain.vue
  85. 203 0
      src/layout/components/Navbar.vue
  86. 26 0
      src/layout/components/Sidebar/FixiOSBug.js
  87. 41 0
      src/layout/components/Sidebar/Item.vue
  88. 43 0
      src/layout/components/Sidebar/Link.vue
  89. 82 0
      src/layout/components/Sidebar/Logo.vue
  90. 142 0
      src/layout/components/Sidebar/SidebarItem.vue
  91. 58 0
      src/layout/components/Sidebar/index.vue
  92. 3 0
      src/layout/components/index.js
  93. 94 0
      src/layout/index.vue
  94. 45 0
      src/layout/mixin/ResizeHandler.js
  95. 43 0
      src/main.js
  96. 64 0
      src/permission.js
  97. 262 0
      src/router/index.js
  98. 16 0
      src/settings.js
  99. 8 0
      src/store/getters.js
  100. 19 0
      src/store/index.js

+ 14 - 0
.editorconfig

@@ -0,0 +1,14 @@
+# http://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

+ 5 - 0
.env.development

@@ -0,0 +1,5 @@
+# just a flag
+ENV = 'development'
+
+# base api
+VUE_APP_BASE_API = 'http://127.0.0.1:8080/Device_Manager/'

+ 6 - 0
.env.production

@@ -0,0 +1,6 @@
+# just a flag
+ENV = 'production'
+
+# base api
+VUE_APP_BASE_API = '/prod-api'
+

+ 8 - 0
.env.staging

@@ -0,0 +1,8 @@
+NODE_ENV = production
+
+# just a flag
+ENV = 'staging'
+
+# base api
+VUE_APP_BASE_API = '/stage-api'
+

+ 4 - 0
.eslintignore

@@ -0,0 +1,4 @@
+build/*.js
+src/assets
+public
+dist

+ 198 - 0
.eslintrc.js

@@ -0,0 +1,198 @@
+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": ["error", "PascalCase"],
+    "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-mixed-spaces-and-tabs': 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',
+        ':': '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.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}

+ 16 - 0
.gitignore

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

+ 5 - 0
.travis.yml

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

+ 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.

+ 102 - 0
README-zh.md

@@ -0,0 +1,102 @@
+# vue-admin-template
+
+> 这是一个极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
+
+[线上地址](http://panjiachen.github.io/vue-admin-template)
+
+[国内访问](https://panjiachen.gitee.io/vue-admin-template)
+
+目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。
+
+## Extra
+
+如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
+
+## 相关项目
+
+- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
+
+- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
+
+- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
+
+- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
+
+写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
+
+- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
+- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
+- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
+- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板,专门针对本项目的文章,算作是一篇文档)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
+- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
+
+## Build Setup
+
+```bash
+# 克隆项目
+git clone https://github.com/PanJiaChen/vue-admin-template.git
+
+# 进入项目目录
+cd vue-admin-template
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 [http://localhost:9528](http://localhost:9528)
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
+```
+
+## 其它
+
+```bash
+# 预览发布环境效果
+npm run preview
+
+# 预览发布环境效果 + 静态资源分析
+npm run preview -- --report
+
+# 代码格式检查
+npm run lint
+
+# 代码格式检查并自动修复
+npm run lint -- --fix
+```
+
+更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
+
+## 购买贴纸
+
+你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。
+
+## Demo
+
+![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif)
+
+## Browsers support
+
+Modern browsers and Internet Explorer 10+.
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| --------- | --------- | --------- | --------- |
+| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
+
+## License
+
+[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
+
+Copyright (c) 2017-present PanJiaChen

+ 90 - 0
README.md

@@ -0,0 +1,90 @@
+# vue-admin-template
+
+English | [简体中文](./README-zh.md)
+
+> A minimal vue admin template with Element UI & axios & iconfont & permission control & lint
+
+**Live demo:** http://panjiachen.github.io/vue-admin-template
+
+
+**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`**
+
+## Build Setup
+
+```bash
+# clone the project
+git clone https://github.com/PanJiaChen/vue-admin-template.git
+
+# enter the project directory
+cd vue-admin-template
+
+# install dependency
+npm install
+
+# develop
+npm run dev
+```
+
+This will automatically open http://localhost:9528
+
+## Build
+
+```bash
+# build for test environment
+npm run build:stage
+
+# build for production environment
+npm run build:prod
+```
+
+## Advanced
+
+```bash
+# preview the release environment effect
+npm run preview
+
+# preview the release environment effect + static resource analysis
+npm run preview -- --report
+
+# code format check
+npm run lint
+
+# code format check and auto fix
+npm run lint -- --fix
+```
+
+Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
+
+## Demo
+
+![demo](https://github.com/PanJiaChen/PanJiaChen.github.io/blob/master/images/demo.gif)
+
+## Extra
+
+If you want router permission && generate menu by user roles , you can use this branch [permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
+
+For `typescript` version, you can use [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
+
+## Related Project
+
+- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
+
+- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
+
+- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
+
+- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
+
+## Browsers support
+
+Modern browsers and Internet Explorer 10+.
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| --------- | --------- | --------- | --------- |
+| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
+
+## License
+
+[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
+
+Copyright (c) 2017-present PanJiaChen

+ 14 - 0
babel.config.js

@@ -0,0 +1,14 @@
+module.exports = {
+  presets: [
+    // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
+    '@vue/cli-plugin-babel/preset'
+  ],
+  'env': {
+    'development': {
+      // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+      // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+      // https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
+      'plugins': ['dynamic-import-node']
+    }
+  }
+}

+ 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}`)
+}

+ 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"]
+}

+ 57 - 0
mock/index.js

@@ -0,0 +1,57 @@
+const Mock = require('mockjs')
+const { param2Obj } = require('./utils')
+
+const user = require('./user')
+const table = require('./table')
+
+const mocks = [
+  ...user,
+  ...table
+]
+
+// for front mock
+// please use it cautiously, it will redefine XMLHttpRequest,
+// which will cause many of your third-party libraries to be invalidated(like progress event).
+function mockXHR() {
+  // mock patch
+  // https://github.com/nuysoft/Mock/issues/300
+  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
+  Mock.XHR.prototype.send = function() {
+    if (this.custom.xhr) {
+      this.custom.xhr.withCredentials = this.withCredentials || false
+
+      if (this.responseType) {
+        this.custom.xhr.responseType = this.responseType
+      }
+    }
+    this.proxy_send(...arguments)
+  }
+
+  function XHR2ExpressReqWrap(respond) {
+    return function(options) {
+      let result = null
+      if (respond instanceof Function) {
+        const { body, type, url } = options
+        // https://expressjs.com/en/4x/api.html#req
+        result = respond({
+          method: type,
+          body: JSON.parse(body),
+          query: param2Obj(url)
+        })
+      } else {
+        result = respond
+      }
+      return Mock.mock(result)
+    }
+  }
+
+  for (const i of mocks) {
+    Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
+  }
+}
+
+module.exports = {
+  mocks,
+  mockXHR
+}
+

+ 81 - 0
mock/mock-server.js

@@ -0,0 +1,81 @@
+const chokidar = require('chokidar')
+const bodyParser = require('body-parser')
+const chalk = require('chalk')
+const path = require('path')
+const Mock = require('mockjs')
+
+const mockDir = path.join(process.cwd(), 'mock')
+
+function registerRoutes(app) {
+  let mockLastIndex
+  const { mocks } = require('./index.js')
+  const mocksForServer = mocks.map(route => {
+    return responseFake(route.url, route.type, route.response)
+  })
+  for (const mock of mocksForServer) {
+    app[mock.type](mock.url, mock.response)
+    mockLastIndex = app._router.stack.length
+  }
+  const mockRoutesLength = Object.keys(mocksForServer).length
+  return {
+    mockRoutesLength: mockRoutesLength,
+    mockStartIndex: mockLastIndex - mockRoutesLength
+  }
+}
+
+function unregisterRoutes() {
+  Object.keys(require.cache).forEach(i => {
+    if (i.includes(mockDir)) {
+      delete require.cache[require.resolve(i)]
+    }
+  })
+}
+
+// for mock server
+const responseFake = (url, type, respond) => {
+  return {
+    url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
+    type: type || 'get',
+    response(req, res) {
+      console.log('request invoke:' + req.path)
+      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
+    }
+  }
+}
+
+module.exports = app => {
+  // parse app.body
+  // https://expressjs.com/en/4x/api.html#req.body
+  app.use(bodyParser.json())
+  app.use(bodyParser.urlencoded({
+    extended: true
+  }))
+
+  const mockRoutes = registerRoutes(app)
+  var mockRoutesLength = mockRoutes.mockRoutesLength
+  var mockStartIndex = mockRoutes.mockStartIndex
+
+  // watch files, hot reload mock server
+  chokidar.watch(mockDir, {
+    ignored: /mock-server/,
+    ignoreInitial: true
+  }).on('all', (event, path) => {
+    if (event === 'change' || event === 'add') {
+      try {
+        // remove mock routes stack
+        app._router.stack.splice(mockStartIndex, mockRoutesLength)
+
+        // clear routes cache
+        unregisterRoutes()
+
+        const mockRoutes = registerRoutes(app)
+        mockRoutesLength = mockRoutes.mockRoutesLength
+        mockStartIndex = mockRoutes.mockStartIndex
+
+        console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed  ${path}`))
+      } catch (error) {
+        console.log(chalk.redBright(error))
+      }
+    }
+  })
+}

+ 29 - 0
mock/table.js

@@ -0,0 +1,29 @@
+const Mock = require('mockjs')
+
+const data = Mock.mock({
+  'items|30': [{
+    id: '@id',
+    title: '@sentence(10, 20)',
+    'status|1': ['published', 'draft', 'deleted'],
+    author: 'name',
+    display_time: '@datetime',
+    pageviews: '@integer(300, 5000)'
+  }]
+})
+
+module.exports = [
+  {
+    url: '/vue-admin-template/table/list',
+    type: 'get',
+    response: config => {
+      const items = data.items
+      return {
+        code: 20000,
+        data: {
+          total: items.length,
+          items: items
+        }
+      }
+    }
+  }
+]

+ 84 - 0
mock/user.js

@@ -0,0 +1,84 @@
+
+const tokens = {
+  admin: {
+    token: 'admin-token'
+  },
+  editor: {
+    token: 'editor-token'
+  }
+}
+
+const users = {
+  'admin-token': {
+    roles: ['admin'],
+    introduction: 'I am a super administrator',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Super Admin'
+  },
+  'editor-token': {
+    roles: ['editor'],
+    introduction: 'I am an editor',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Normal Editor'
+  }
+}
+
+module.exports = [
+  // user login
+  {
+    url: '/vue-admin-template/user/login',
+    type: 'post',
+    response: config => {
+      const { username } = config.body
+      const token = tokens[username]
+
+      // mock error
+      if (!token) {
+        return {
+          code: 60204,
+          message: 'Account and password are incorrect.'
+        }
+      }
+
+      return {
+        code: 20000,
+        data: token
+      }
+    }
+  },
+
+  // get user info
+  {
+    url: '/vue-admin-template/user/info\.*',
+    type: 'get',
+    response: config => {
+      const { token } = config.query
+      const info = users[token]
+
+      // mock error
+      if (!info) {
+        return {
+          code: 50008,
+          message: 'Login failed, unable to get user details.'
+        }
+      }
+
+      return {
+        code: 20000,
+        data: info
+      }
+    }
+  },
+
+  // user logout
+  {
+    url: '/vue-admin-template/user/logout',
+    type: 'post',
+    response: _ => {
+      return {
+        code: 20000,
+        data: 'success'
+      }
+    }
+  }
+]

+ 25 - 0
mock/utils.js

@@ -0,0 +1,25 @@
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+function param2Obj(url) {
+  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+  if (!search) {
+    return {}
+  }
+  const obj = {}
+  const searchArr = search.split('&')
+  searchArr.forEach(v => {
+    const index = v.indexOf('=')
+    if (index !== -1) {
+      const name = v.substring(0, index)
+      const val = v.substring(index + 1, v.length)
+      obj[name] = val
+    }
+  })
+  return obj
+}
+
+module.exports = {
+  param2Obj
+}

+ 64 - 0
package.json

@@ -0,0 +1,64 @@
+{
+    "name": "security-admin",
+    "version": "1.0.1",
+    "description": "security-admin project",
+    "author": "julia-Yuan",
+    "scripts": {
+        "dev": "vue-cli-service serve",
+        "build:prod": "vue-cli-service build",
+        "build:stage": "vue-cli-service build --mode staging",
+        "preview": "node build/index.js --preview",
+        "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+        "lint": "eslint --ext .js,.vue src",
+        "test:unit": "jest --clearCache && vue-cli-service test:unit",
+        "test:ci": "npm run lint && npm run test:unit"
+    },
+    "dependencies": {
+        "axios": "0.18.1",
+        "core-js": "3.6.5",
+        "element-ui": "2.13.2",
+        "file-saver": "^2.0.5",
+        "js-cookie": "2.2.0",
+        "normalize.css": "7.0.0",
+        "nprogress": "0.2.0",
+        "path-to-regexp": "2.4.0",
+        "vue": "2.6.10",
+        "vue-router": "3.0.6",
+        "vuex": "3.1.0",
+        "xlsx": "^0.16.9"
+    },
+    "devDependencies": {
+        "@vue/cli-plugin-babel": "4.4.4",
+        "@vue/cli-plugin-eslint": "4.4.4",
+        "@vue/cli-plugin-unit-jest": "4.4.4",
+        "@vue/cli-service": "4.4.4",
+        "@vue/test-utils": "1.0.0-beta.29",
+        "autoprefixer": "9.5.1",
+        "babel-eslint": "10.1.0",
+        "babel-jest": "23.6.0",
+        "babel-plugin-dynamic-import-node": "2.3.3",
+        "chalk": "2.4.2",
+        "connect": "3.6.6",
+        "eslint": "6.7.2",
+        "eslint-plugin-vue": "6.2.2",
+        "html-webpack-plugin": "3.2.0",
+        "mockjs": "1.0.1-beta3",
+        "runjs": "4.3.2",
+        "sass": "1.26.8",
+        "sass-loader": "8.0.2",
+        "script-ext-html-webpack-plugin": "2.1.3",
+        "serve-static": "1.13.2",
+        "svg-sprite-loader": "4.1.3",
+        "svgo": "1.2.2",
+        "vue-template-compiler": "2.6.10"
+    },
+    "browserslist": [
+        "> 1%",
+        "last 2 versions"
+    ],
+    "engines": {
+        "node": ">=8.9",
+        "npm": ">= 3.0.0"
+    },
+    "license": "MIT"
+}

+ 8 - 0
postcss.config.js

@@ -0,0 +1,8 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  'plugins': {
+    // to edit target browsers: use "browserslist" field in package.json
+    'autoprefixer': {}
+  }
+}

BIN
public/favicon.ico


+ 17 - 0
public/index.html

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

+ 11 - 0
src/App.vue

@@ -0,0 +1,11 @@
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'App'
+}
+</script>

+ 16 - 0
src/api/orgnization.js

@@ -0,0 +1,16 @@
+import request from '@/utils/request'
+
+export function getList(query, current = 1, page_size = 10) {
+    return request({
+        // url: '/vue-admin-template/table/list',
+        url: 'companyManagement/queryCompanyList',
+        method: 'post',
+        // params
+        data: {
+
+            ...query,
+            current,
+            page_size
+        }
+    })
+}

+ 15 - 0
src/api/table.js

@@ -0,0 +1,15 @@
+import request from '@/utils/request'
+
+export function getList(query, current = 1, page_size = 10) {
+    return request({
+        url: '/vue-admin-template/table/list',
+        method: 'get',
+        // params
+        data: {
+
+            ...query,
+            current,
+            page_size
+        }
+    })
+}

+ 24 - 0
src/api/user.js

@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+
+export function login(data) {
+  return request({
+    url: '/vue-admin-template/user/login',
+    method: 'post',
+    data
+  })
+}
+
+export function getInfo(token) {
+  return request({
+    url: '/vue-admin-template/user/info',
+    method: 'get',
+    params: { token }
+  })
+}
+
+export function logout() {
+  return request({
+    url: '/vue-admin-template/user/logout',
+    method: 'post'
+  })
+}

BIN
src/assets/404_images/404.png


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


BIN
src/assets/code.png


BIN
src/assets/img.png


BIN
src/assets/logo.png


BIN
src/assets/route.png


+ 1 - 0
src/assets/tree-user.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1611017063399" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="941" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M593.066667 499.2C695.466667 465.066667 768 369.066667 768 256c0-140.8-115.2-256-256-256S256 115.2 256 256c0 113.066667 72.533333 209.066667 174.933333 243.2C249.6 535.466667 85.333333 689.066667 85.333333 874.666667c0 83.2 66.133333 149.333333 149.333334 149.333333h554.666666c83.2 0 149.333333-66.133333 149.333334-149.333333 0-185.6-164.266667-339.2-345.6-375.466667zM298.666667 256c0-117.333333 96-213.333333 213.333333-213.333333s213.333333 96 213.333333 213.333333-96 213.333333-213.333333 213.333333-213.333333-96-213.333333-213.333333z m490.666666 725.333333H234.666667c-59.733333 0-106.666667-46.933333-106.666667-106.666666 0-196.266667 202.666667-341.333333 384-341.333334s384 145.066667 384 341.333334c0 59.733333-46.933333 106.666667-106.666667 106.666666z" fill="#515151" p-id="942"></path></svg>

BIN
src/assets/video.png


+ 78 - 0
src/components/Breadcrumb/index.vue

@@ -0,0 +1,78 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
+        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+import pathToRegexp from 'path-to-regexp'
+
+export default {
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route() {
+      this.getBreadcrumb()
+    }
+  },
+  created() {
+    this.getBreadcrumb()
+  },
+  methods: {
+    getBreadcrumb() {
+      // only show routes with meta.title
+      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
+      const first = matched[0]
+
+      if (!this.isDashboard(first)) {
+        matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
+      }
+
+      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+    },
+    isDashboard(route) {
+      const name = route && route.name
+      if (!name) {
+        return false
+      }
+      return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
+    },
+    pathCompile(path) {
+      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
+      const { params } = this.$route
+      var toPath = pathToRegexp.compile(path)
+      return toPath(params)
+    },
+    handleLink(item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect)
+        return
+      }
+      this.$router.push(this.pathCompile(path))
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: 50px;
+  margin-left: 8px;
+
+  .no-redirect {
+    color: #97a8be;
+    cursor: text;
+  }
+}
+</style>

+ 44 - 0
src/components/Hamburger/index.vue

@@ -0,0 +1,44 @@
+<template>
+  <div style="padding: 0 15px;" @click="toggleClick">
+    <svg
+      :class="{'is-active':isActive}"
+      class="hamburger"
+      viewBox="0 0 1024 1024"
+      xmlns="http://www.w3.org/2000/svg"
+      width="64"
+      height="64"
+    >
+      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  methods: {
+    toggleClick() {
+      this.$emit('toggleClick')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+  display: inline-block;
+  vertical-align: middle;
+  width: 20px;
+  height: 20px;
+}
+
+.hamburger.is-active {
+  transform: rotate(180deg);
+}
+</style>

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

@@ -0,0 +1,62 @@
+<template>
+  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
+import { isExternal } from '@/utils/validate'
+
+export default {
+  name: 'SvgIcon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String,
+      default: ''
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.iconClass)
+    },
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    },
+    styleExternalIcon() {
+      return {
+        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+
+.svg-external-icon {
+  background-color: currentColor;
+  mask-size: cover!important;
+  display: inline-block;
+}
+</style>

+ 9 - 0
src/icons/index.js

@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)

+ 28 - 0
src/icons/svg/account-manage.svg

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M16,2.8C16,1.26,14.74,0,13.2,0c-0.82,0-1.55,0.35-2.06,0.91c-1.02-0.46-2.11-0.69-3.24-0.69C3.54,0.21,0,3.75,0,8.11
+		C0,12.46,3.54,16,7.89,16s7.89-3.54,7.89-7.89c0-1.13-0.23-2.22-0.69-3.24C15.65,4.35,16,3.62,16,2.8z M13.2,0.79
+		c1.11,0,2.02,0.9,2.02,2.02c0,1.11-0.9,2.02-2.02,2.02c-1.11,0-2.02-0.9-2.02-2.02C11.18,1.69,12.08,0.79,13.2,0.79z M7.89,15.21
+		c-3.92,0-7.1-3.19-7.1-7.1c0-3.92,3.19-7.1,7.1-7.1c0.97,0,1.91,0.19,2.79,0.57c-0.18,0.37-0.29,0.79-0.29,1.24
+		c0,1.55,1.26,2.8,2.8,2.8c0.44,0,0.86-0.1,1.24-0.29C14.81,6.2,15,7.14,15,8.11C15,12.02,11.81,15.21,7.89,15.21z"/>
+	<path d="M14.24,2.41h-0.65V1.76c0-0.22-0.18-0.39-0.39-0.39c-0.22,0-0.39,0.18-0.39,0.39v0.65h-0.65c-0.22,0-0.39,0.18-0.39,0.39
+		c0,0.22,0.18,0.39,0.39,0.39h0.65v0.65c0,0.22,0.18,0.39,0.39,0.39c0.22,0,0.39-0.18,0.39-0.39V3.2h0.65
+		c0.22,0,0.39-0.18,0.39-0.39S14.46,2.41,14.24,2.41z"/>
+	<path d="M10.32,9.52c-0.01,0-0.97,0.03-1.25-0.98c0.18-0.14,0.35-0.31,0.5-0.51c0.32-0.43,0.53-0.97,0.61-1.55
+		c0.02-0.03,0.04-0.06,0.06-0.09c0.14-0.33,0.21-0.67,0.21-1.03c0-1.39-1.05-2.52-2.34-2.52c-0.33,0-0.65,0.07-0.96,0.22
+		C7.02,3.07,6.91,3.09,6.81,3.12C5.73,3.43,5.11,4.74,5.44,6.03C5.48,6.16,5.56,6.4,5.62,6.49c0.12,0.88,0.53,1.61,1.1,2.04
+		C6.44,9.57,5.48,9.52,5.47,9.52c-0.93,0.03-1.68,0.8-1.68,1.74v1.14c0,0.43,0.35,0.77,0.77,0.77h6.67c0.43,0,0.77-0.35,0.77-0.77
+		v-1.14C12,10.32,11.25,9.55,10.32,9.52z M7,3.8c0.08-0.02,0.16-0.04,0.24-0.04c0.05,0,0.1-0.02,0.15-0.04
+		c0.22-0.12,0.46-0.18,0.7-0.18c0.85,0,1.55,0.73,1.62,1.65C9.54,5.08,9.33,5.02,9.11,5.02H7.5C7.43,5.02,7.36,5,7.31,4.96
+		C7.26,4.92,7.22,4.87,7.2,4.82C7.14,4.66,6.97,4.55,6.8,4.56C6.62,4.58,6.47,4.7,6.43,4.87c-0.07,0.26-0.19,0.5-0.35,0.72
+		C5.97,4.76,6.36,3.99,7,3.8z M6.32,6.38c0.25-0.23,0.46-0.51,0.61-0.82C7.1,5.67,7.29,5.73,7.5,5.73h1.61
+		c0.17,0,0.32,0.1,0.39,0.24C9.49,6.9,9.1,7.7,8.53,8.05C8.51,8.06,8.26,8.24,7.89,8.24C7.13,8.24,6.46,7.43,6.32,6.38z M8.94,9.69
+		c-0.3,0.22-0.67,0.34-1.05,0.34c-0.38,0-0.75-0.12-1.05-0.34c0.23-0.22,0.41-0.5,0.52-0.82c0.17,0.05,0.35,0.08,0.53,0.08
+		c0.18,0,0.36-0.03,0.53-0.08C8.53,9.19,8.71,9.47,8.94,9.69z M11.29,12.39L11.29,12.39c0,0.03-0.03,0.06-0.06,0.06H4.56
+		c-0.03,0-0.06-0.03-0.06-0.06v-1.14c0-0.57,0.46-1.03,1.03-1.03c0.01,0,0.34-0.01,0.69-0.14c0.46,0.42,1.06,0.65,1.68,0.65
+		c0.62,0,1.22-0.23,1.68-0.65c0.35,0.14,0.68,0.14,0.69,0.14c0.57,0,1.03,0.46,1.03,1.03V12.39L11.29,12.39z"/>
+</g>
+</svg>

+ 20 - 0
src/icons/svg/alarm-log.svg

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M9.51,14.86c0.33,0,0.6,0.26,0.6,0.57c0,0.32-0.27,0.57-0.6,0.57H1.79C0.8,16,0,15.23,0,14.29V1.71C0,0.77,0.8,0,1.79,0
+		h10.12c0.99,0,1.79,0.77,1.79,1.71c0,0.32-0.27,0.57-0.6,0.57s-0.6-0.26-0.6-0.57c0-0.32-0.27-0.57-0.6-0.57H1.79
+		c-0.33,0-0.6,0.26-0.6,0.57v12.57c0,0.32,0.27,0.57,0.6,0.57H9.51z M13.7,9.32v2.62c0,0.76-1.19,0.76-1.19,0V9.32
+		C12.5,8.55,13.7,8.55,13.7,9.32z"/>
+	<path d="M3.57,4.57c-0.33,0-0.6-0.26-0.6-0.57s0.27-0.57,0.6-0.57h4.17c0.33,0,0.6,0.26,0.6,0.57s-0.27,0.57-0.6,0.57H3.57z
+		 M3.57,7.43c-0.33,0-0.6-0.26-0.6-0.57s0.27-0.57,0.6-0.57h2.38c0.33,0,0.6,0.26,0.6,0.57s-0.27,0.57-0.6,0.57H3.57z M10.11,15.4
+		c0,0.32-0.27,0.57-0.6,0.57c-0.33,0-0.6-0.26-0.6-0.57l0.01-2.26c0-0.95,0.8-1.71,1.79-1.71l2.38,0.02c0.33,0,0.6,0.26,0.6,0.57
+		c0,0.32-0.27,0.57-0.6,0.57l-2.38-0.02c-0.33,0-0.6,0.26-0.6,0.57L10.11,15.4L10.11,15.4z"/>
+	<path d="M10.08,15.78C9.85,16,9.47,15.99,9.24,15.76c-0.23-0.23-0.22-0.59,0.02-0.81l3.36-3.09c0.23-0.22,0.61-0.22,0.84,0
+		c0.23,0.22,0.23,0.58,0,0.81c-0.01,0.01-0.01,0.01-0.02,0.02L10.08,15.78z M14.61,4.83c0.25-0.2,0.27-0.56,0.06-0.79c0,0,0,0,0,0
+		l-0.01-0.01c-0.21-0.24-0.59-0.26-0.84-0.06l-8.01,6.54l-0.28,0.93l1.09-0.08L14.61,4.83z M15.57,3.29
+		c0.64,0.71,0.56,1.78-0.18,2.4l-8.15,6.65c-0.1,0.08-0.21,0.13-0.34,0.13l-2.14,0.16c-0.33,0.02-0.61-0.21-0.64-0.53
+		c-0.01-0.07,0-0.14,0.02-0.21l0.58-1.88c0.03-0.11,0.1-0.2,0.19-0.27l8.15-6.65C13.8,2.49,14.92,2.57,15.57,3.29L15.57,3.29z"/>
+</g>
+</svg>

+ 17 - 0
src/icons/svg/alarm-task.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M13.71,0H2.29C1.02,0,0,1.02,0,2.29v11.43C0,14.98,1.02,16,2.29,16h11.43c1.26,0,2.29-1.02,2.29-2.29V2.29
+		C16,1.02,14.98,0,13.71,0z M14.86,13.72c0,0.63-0.51,1.14-1.14,1.14c0,0,0,0,0,0H2.29c-0.31,0-0.59-0.12-0.81-0.33
+		s-0.34-0.5-0.34-0.81V2.29c0-0.63,0.51-1.14,1.15-1.15h11.43c0.63,0,1.14,0.51,1.14,1.14c0,0,0,0,0,0V13.72z"/>
+	<path d="M13,5.14H8.43c-0.32,0-0.57,0.26-0.57,0.57c0,0.32,0.26,0.57,0.57,0.57H13c0.32,0,0.57-0.26,0.57-0.57
+		C13.57,5.4,13.32,5.14,13,5.14z M13,9.72H8.43c-0.32,0-0.57,0.26-0.57,0.57s0.26,0.57,0.57,0.57H13c0.32,0,0.57-0.26,0.57-0.57
+		S13.32,9.72,13,9.72z M5,8.29c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C7,9.18,6.11,8.29,5,8.29z M5.61,10.89
+		c-0.34,0.34-0.88,0.33-1.21,0c-0.33-0.34-0.33-0.88,0-1.21c0.34-0.34,0.88-0.33,1.21,0c0.16,0.16,0.25,0.38,0.25,0.61
+		C5.86,10.52,5.77,10.73,5.61,10.89L5.61,10.89z M6.31,4.17L4.43,6.05L3.69,5.31c-0.22-0.22-0.58-0.22-0.81,0
+		c-0.22,0.22-0.22,0.58,0,0.81l1.14,1.14c0.22,0.22,0.58,0.22,0.81,0l0,0l2.29-2.29c0.22-0.22,0.22-0.59-0.01-0.81
+		C6.89,3.95,6.53,3.95,6.31,4.17z"/>
+</g>
+</svg>

+ 16 - 0
src/icons/svg/alarm.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M10.49,0H3.67C2.48,0,1.5,0.96,1.5,2.15v11.71C1.5,15.04,2.48,16,3.67,16h8.65c1.2,0,2.17-0.96,2.17-2.15V4.42L10.49,0z
+		 M10.8,2.02l1.87,2.06H10.8V2.02z M13.37,13.85c0,0.57-0.47,1.03-1.04,1.03H3.67c-0.58,0-1.04-0.46-1.04-1.03V2.15
+		c0-0.57,0.47-1.03,1.04-1.03h6v4.08h3.7V13.85L13.37,13.85z"/>
+	<path d="M6.78,11.86h5.26v1.12H6.78V11.86z"/>
+	<path d="M6.78,9.19h5.26v1.11H6.78V9.19z"/>
+	<path d="M6.78,6.52h5.26v1.11H6.78V6.52z"/>
+	<path d="M4.49,7.08L4.12,6.73L3.59,7.27L4.5,8.13l1.32-1.32L5.28,6.29L4.49,7.08z"/>
+	<path d="M4.49,9.76L4.12,9.4L3.59,9.94L4.5,10.8l1.32-1.32L5.28,8.96L4.49,9.76z"/>
+	<path d="M4.49,12.42l-0.37-0.35L3.59,12.6l0.91,0.86l1.32-1.32l-0.54-0.52L4.49,12.42z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/auth-icon.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1610929295625" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1099" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M891.2 348.8H728V296c0-120-96-216-216-216s-216 96-216 216v57.6H132.8C104 348.8 80 372.8 80 406.4v484.8c0 28.8 24 52.8 52.8 52.8h758.4c28.8 0 52.8-24 52.8-52.8V406.4c0-33.6-24-57.6-52.8-57.6zM348.8 296c0-91.2 72-163.2 163.2-163.2s163.2 72 163.2 163.2v52.8H348.8V296z m542.4 566.4c0 14.4-14.4 28.8-28.8 28.8H161.6c-14.4 0-28.8-14.4-28.8-28.8v-432c0-14.4 14.4-28.8 28.8-28.8h700.8c14.4 0 28.8 14.4 28.8 28.8v432z" fill="#ffffff" p-id="1100"></path><path d="M516.8 512c-52.8 0-91.2 43.2-91.2 91.2 0 38.4 24 72 62.4 86.4V728c0 19.2 14.4 28.8 28.8 28.8 19.2 0 28.8-14.4 28.8-28.8v-38.4c33.6-14.4 62.4-48 62.4-86.4 0-48-38.4-91.2-91.2-91.2z"  p-id="1101"></path></svg>

+ 15 - 0
src/icons/svg/auth-manage.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M8,8.65c-0.9,0-1.64,0.71-1.64,1.59c0,0.43,0.19,0.85,0.51,1.15v1.43c0,0.6,0.51,1.09,1.13,1.09
+		c0.62,0,1.13-0.49,1.13-1.09v-1.43c0.33-0.3,0.51-0.72,0.51-1.15C9.64,9.36,8.9,8.65,8,8.65z M8.58,10.83
+		c-0.16,0.14-0.25,0.34-0.25,0.55v1.44c0,0.18-0.15,0.32-0.33,0.32c-0.18,0-0.33-0.14-0.33-0.32v-1.44c0-0.21-0.09-0.4-0.25-0.55
+		c-0.17-0.16-0.27-0.37-0.27-0.6c0-0.45,0.38-0.82,0.85-0.82c0.47,0,0.85,0.37,0.85,0.82C8.85,10.46,8.75,10.67,8.58,10.83z"/>
+	<path d="M12.81,6.56h-1.19V3.5C11.62,1.57,9.99,0,8,0C6.01,0,4.38,1.57,4.38,3.5v3.06H3.19C2.53,6.56,2,7.08,2,7.71v7.13
+		C2,15.48,2.53,16,3.19,16h9.62c0.66,0,1.19-0.52,1.19-1.15V7.71C14,7.08,13.47,6.56,12.81,6.56z M5.18,3.5C5.18,2,6.44,0.77,8,0.77
+		S10.82,2,10.82,3.5v3.06H5.18V3.5z M13.21,14.85L13.21,14.85c0,0.21-0.18,0.38-0.4,0.38H3.19c-0.22,0-0.4-0.17-0.4-0.38V7.71
+		c0-0.21,0.18-0.38,0.4-0.38h9.62c0.22,0,0.4,0.17,0.4,0.38V14.85z"/>
+</g>
+</svg>

+ 14 - 0
src/icons/svg/camera.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M12.81,8.97L5.72,1.49L4.1,3.22l6.19,6.55L12.81,8.97z M9.7,10.89L2.86,3.65c-0.23-0.24-0.23-0.63,0-0.87l2.46-2.6
+		c0.23-0.24,0.6-0.24,0.84,0c0,0,0,0,0,0l8.17,8.65c0.23,0.24,0.22,0.63-0.01,0.87c-0.07,0.07-0.15,0.12-0.23,0.15l-3.79,1.23
+		C10.08,11.14,9.85,11.06,9.7,10.89z M1.5,7.38c0-0.34,0.26-0.62,0.59-0.62c0.33,0,0.59,0.28,0.59,0.62v8
+		c0,0.34-0.26,0.62-0.59,0.62c-0.33,0-0.59-0.28-0.59-0.62V7.38z"/>
+	<path d="M4.04,10.02c0.23-0.24,0.61-0.24,0.84,0c0.23,0.24,0.23,0.63,0,0.87l-0.59,0.62c-0.11,0.12-0.26,0.18-0.42,0.18H2.09
+		c-0.33,0-0.59-0.28-0.59-0.62c0-0.34,0.26-0.62,0.59-0.62h1.53L4.04,10.02z M1.67,4.74c-0.23-0.24-0.23-0.63,0-0.87
+		c0.23-0.24,0.61-0.24,0.84,0l6.5,6.77c0.23,0.24,0.23,0.63,0,0.87c-0.23,0.24-0.61,0.24-0.84,0L1.67,4.74z"/>
+</g>
+</svg>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/icons/svg/dashboard.svg


+ 11 - 0
src/icons/svg/device-manage.svg

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M15.36,11.83V6.17h-0.64V1.5H0.96v6H0v7h4.16v-2H4.8V13c0,0.83,0.65,1.5,1.44,1.5h8.32c0.79,0,1.44-0.67,1.44-1.5v-1.17
+		H15.36L15.36,11.83z M3.2,13.5H0.96v-5H3.2V13.5z M5.44,11.5H4.16v-1h1.28V11.5L5.44,11.5z M5.44,9.5H4.16v-2H1.92v-5h11.84v3.67
+		H5.44V9.5z M14.4,7.17v4.67h-8V7.17H14.4z M15.04,13c0,0.28-0.22,0.5-0.48,0.5H6.24c-0.26,0-0.48-0.22-0.48-0.5v-0.17h9.28V13
+		L15.04,13z"/>
+</g>
+</svg>

+ 14 - 0
src/icons/svg/elect.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M3,0h10c1.1,0,2,0.9,2,2v12.61c0,0.6-0.5,1.1-1.1,1.1c-0.2,0-0.4-0.1-0.6-0.2c-1-0.6-2.3-0.6-3.3,0H9.9
+		c-1.1,0.6-2.4,0.7-3.5,0l-0.1-0.1c-1.1-0.6-2.4-0.6-3.5,0c-0.6,0.3-1.3,0.1-1.6-0.4c-0.1-0.2-0.2-0.4-0.2-0.6V2C1,0.9,1.9,0,3,0z
+		 M3,1C2.4,1,2,1.4,2,2v12.61c0,0.1,0.2,0.1,0.2,0.1c1.4-0.8,3.1-0.8,4.5,0l0.1,0.1c0.8,0.4,1.7,0.4,2.5,0h0.1
+		c1.4-0.8,3-0.8,4.4,0.1c0,0,0.1,0,0.1-0.1V2c0-0.6-0.4-1-1-1H3z M4.1,3.5H12c0.3,0,0.5,0.2,0.5,0.5c0,0.3-0.2,0.5-0.5,0.5H4.1
+		C3.8,4.5,3.6,4.3,3.6,4C3.6,3.7,3.8,3.5,4.1,3.5z M4.1,6.5H12c0.3,0,0.5,0.2,0.5,0.5s-0.2,0.5-0.5,0.5H4.1c-0.3,0-0.5-0.2-0.5-0.5
+		S3.8,6.5,4.1,6.5z M4.1,9.51H12c0.3,0,0.5,0.2,0.5,0.5c0,0.3-0.2,0.5-0.5,0.5H4.1c-0.3,0-0.5-0.2-0.5-0.5
+		C3.6,9.71,3.8,9.51,4.1,9.51z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/example.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>

+ 1 - 0
src/icons/svg/export.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1611107014793" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3443" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M438.272 57.6H183.744C114.176 57.6 57.6 115.072 57.6 185.6v652.8a127.168 127.168 0 0 0 126.08 128h656.576c69.632 0 126.144-57.408 126.144-128V575.36a48.192 48.192 0 0 0-41.6-47.872l-6.208-0.448a48.256 48.256 0 0 0-48.128 48.64V838.4l-0.32 5.056a30.272 30.272 0 0 1-29.888 25.664H183.744l-4.8-0.384a30.272 30.272 0 0 1-25.216-30.272V185.6l0.32-5.12c1.792-14.208 14.656-25.6 29.824-25.664H438.4a48.192 48.192 0 0 0 47.36-42.368l0.384-6.08A48.192 48.192 0 0 0 438.272 57.6z" fill="#ffffff" p-id="3444"></path><path d="M627.84 84.928l-2.368 5.76-1.856 7.296a48.448 48.448 0 0 0 26.688 51.648l113.92 52.608-9.024 2.112c-103.36 25.856-189.504 76.928-257.472 150.016a511.552 511.552 0 0 0-99.2 157.12l-7.36 19.712a429.44 429.44 0 0 0-24.768 138.816 51.392 51.392 0 0 0 14.08 35.84l5.12 4.736c9.216 7.04 19.456 10.624 30.208 10.688l7.168-0.576a49.728 49.728 0 0 0 28.352-14.784l4.48-5.504a51.904 51.904 0 0 0 9.536-30.72l0.128-6.592 0.576-11.648 1.216-14.208C485.504 467.2 627.648 323.84 829.76 293.888l12.48-1.728-77.312 168.32a48.128 48.128 0 0 0 3.072 46.08l3.648 4.928 4.928 5.12a49.792 49.792 0 0 0 32 12.672 48.768 48.768 0 0 0 44.096-28.16l106.88-232.64c4.544-10.048 6.848-20.736 6.848-32l-0.128-3.008a75.328 75.328 0 0 0-43.52-64.64L691.072 61.824a48.448 48.448 0 0 0-63.232 23.168z" fill="#ffffff" p-id="3445"></path></svg>

+ 1 - 0
src/icons/svg/eye-open.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>

+ 1 - 0
src/icons/svg/eye.svg

@@ -0,0 +1 @@
+<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/icons/svg/form.svg


+ 17 - 0
src/icons/svg/guard.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M15.52,14.53H0.48C0.22,14.53,0,14.75,0,15.01c0,0.27,0.22,0.48,0.48,0.48h15.04c0.26,0,0.48-0.22,0.48-0.48
+		C16,14.75,15.78,14.53,15.52,14.53L15.52,14.53z M5.01,6.34c0.06,0.08,0.14,0.13,0.25,0.13H6.6l-1.62,4.37
+		c-0.05,0.14,0,0.29,0.13,0.36c0.13,0.07,0.29,0.04,0.38-0.07l5.32-6.56c0.07-0.09,0.09-0.21,0.04-0.32
+		c-0.05-0.11-0.15-0.17-0.26-0.17H8.62l1.86-3.13c0.06-0.09,0.06-0.21,0-0.3c-0.06-0.1-0.15-0.15-0.26-0.15H7.38
+		c-0.12,0-0.23,0.07-0.27,0.19L4.98,6.06C4.94,6.15,4.95,6.25,5.01,6.34z M0.48,2.7H6l0.38-0.97h-5.9C0.22,1.73,0,1.95,0,2.21
+		C0,2.48,0.22,2.7,0.48,2.7z"/>
+	<path d="M9.82,2.7h5.7C15.78,2.7,16,2.48,16,2.21c0-0.27-0.22-0.48-0.48-0.48h-5.13L9.82,2.7z M0.48,6.97h3.78L4.65,6H0.48
+		C0.22,6,0,6.21,0,6.48C0,6.75,0.22,6.97,0.48,6.97z M15.52,6h-4.46l-0.78,0.97h5.25c0.26,0,0.48-0.22,0.48-0.49
+		C16,6.21,15.78,6,15.52,6z M0.48,11.23h3.79l0.36-0.97H0.48C0.22,10.26,0,10.48,0,10.75S0.22,11.23,0.48,11.23L0.48,11.23z
+		 M15.52,10.26H7.21l-0.78,0.97h9.1c0.26,0,0.48-0.22,0.48-0.48S15.78,10.26,15.52,10.26L15.52,10.26z"/>
+</g>
+</svg>

+ 17 - 0
src/icons/svg/home.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<style type="text/css">
+	.st0{}
+</style>
+<g>
+	<path class="st0" d="M15.94,7.82l-0.27,0.27c-0.08,0.08-0.19,0.08-0.27,0l-0.59-0.53v5.31c0,1.72-1.44,3.13-3.2,3.13h-1.13H9.46
+		h-2.5H5.95H5.21H4.39l0,0c-1.79,0.04-3.24-1.38-3.24-3.1V7.56L0.61,8.09c-0.08,0.08-0.2,0.08-0.27,0L0.06,7.82
+		c-0.08-0.08-0.08-0.19,0-0.27l7.69-7.53c0.04-0.04,0.16-0.04,0.23,0c0.08-0.04,0.2-0.04,0.27,0l7.69,7.53
+		C16.02,7.63,16.02,7.75,15.94,7.82L15.94,7.82z M6.38,14.85c0,0.15,0.04,0.27,0.04,0.38h3.51c0.04-0.11,0.04-0.27,0.04-0.38v-4.32
+		c0-0.88-0.7-1.57-1.6-1.57H7.98c-0.9,0-1.6,0.69-1.6,1.57V14.85L6.38,14.85z M13.99,6.79L7.98,0.91L1.97,6.79v6.11
+		c0,1.3,1.09,2.37,2.42,2.37h0.82h0.43C5.6,15.16,5.6,15.01,5.6,14.89v-4.36c0-1.3,1.09-2.37,2.42-2.37h0.39
+		c1.33,0,2.42,1.07,2.42,2.37v4.32c0,0.15,0,0.27-0.04,0.38h0.86c1.33,0,2.42-1.07,2.42-2.37V6.79H13.99L13.99,6.79z"/>
+</g>
+</svg>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/icons/svg/home1.svg


+ 1 - 0
src/icons/svg/link.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>

+ 28 - 0
src/icons/svg/log-manage.svg

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M14.99,12.56c-0.03-0.1-0.12-0.17-0.22-0.18l-1.29-0.18l-0.58-1.14c-0.09-0.18-0.4-0.18-0.49,0l-0.58,1.14l-1.29,0.18
+		c-0.1,0.01-0.19,0.08-0.22,0.18c-0.03,0.1-0.01,0.2,0.07,0.27l0.93,0.89l-0.22,1.26c-0.02,0.1,0.02,0.2,0.11,0.26
+		c0.08,0.06,0.2,0.07,0.29,0.02l1.16-0.59l1.16,0.59c0.04,0.02,0.08,0.03,0.13,0.03c0.06,0,0.11-0.02,0.16-0.05
+		c0.08-0.06,0.13-0.16,0.11-0.26l-0.22-1.26l0.93-0.89C14.99,12.76,15.02,12.65,14.99,12.56z M13.5,13.44
+		c-0.06,0.06-0.09,0.15-0.08,0.24l0.15,0.86l-0.79-0.41c-0.04-0.02-0.08-0.03-0.13-0.03c-0.04,0-0.09,0.01-0.13,0.03l-0.79,0.41
+		l0.15-0.86c0.02-0.09-0.01-0.17-0.08-0.24l-0.64-0.61l0.89-0.13c0.09-0.01,0.17-0.07,0.21-0.15l0.4-0.79l0.4,0.79
+		c0.04,0.08,0.12,0.13,0.21,0.15l0.89,0.13L13.5,13.44z"/>
+	<path d="M12.76,0H1.85C1.4,0,1,0.33,1,0.77v14.4C1,15.61,1.4,16,1.85,16h8.22c0.15,0,0.27-0.12,0.27-0.27
+		c0-0.15-0.12-0.27-0.27-0.27H1.85c-0.15,0-0.31-0.15-0.31-0.3V0.77c0-0.15,0.16-0.23,0.31-0.23h10.9c0.15,0,0.24,0.09,0.24,0.23
+		v9.34c0,0.15,0.12,0.27,0.27,0.27c0.15,0,0.27-0.12,0.27-0.27V0.76C13.54,0.32,13.21,0,12.76,0z"/>
+	<path d="M8.67,1.87H5.94c-0.15,0-0.27,0.12-0.27,0.27c0,0.15,0.12,0.27,0.27,0.27h2.73c0.15,0,0.27-0.12,0.27-0.27
+		C8.94,1.99,8.82,1.87,8.67,1.87z"/>
+	<path d="M11.12,3.73H3.49C3.34,3.73,3.22,3.85,3.22,4c0,0.15,0.12,0.27,0.27,0.27h7.64c0.15,0,0.27-0.12,0.27-0.27
+		C11.4,3.85,11.27,3.73,11.12,3.73z"/>
+	<path d="M11.12,5.6H3.49c-0.15,0-0.27,0.12-0.27,0.27s0.12,0.27,0.27,0.27h7.64c0.15,0,0.27-0.12,0.27-0.27S11.27,5.6,11.12,5.6z"
+		/>
+	<path d="M11.12,7.47H3.49c-0.15,0-0.27,0.12-0.27,0.27C3.22,7.88,3.34,8,3.49,8h7.64c0.15,0,0.27-0.12,0.27-0.27
+		C11.4,7.59,11.27,7.47,11.12,7.47z"/>
+	<path d="M11.12,9.33H3.49c-0.15,0-0.31,0.09-0.31,0.23v4c0,0.15,0.16,0.3,0.31,0.3h6c0.15,0,0.27-0.12,0.27-0.27
+		c0-0.15-0.12-0.27-0.27-0.27H3.73V9.87h7.09v1.57c0,0.15,0.12,0.27,0.27,0.27c0.15,0,0.27-0.12,0.27-0.27V9.57
+		C11.36,9.42,11.27,9.33,11.12,9.33z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/nested.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>

+ 13 - 0
src/icons/svg/organization.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M15.41,9.43h-1.82V8.09c0-0.33-0.26-0.59-0.59-0.59H8.59V6.51C9.96,6.23,10.99,5,10.99,3.53C10.99,1.86,9.65,0.5,8,0.5
+		c-1.65,0-2.99,1.36-2.99,3.03c0,1.47,1.04,2.7,2.41,2.98V7.5H2.99c-0.32,0-0.59,0.27-0.59,0.59v1.34H0.59C0.26,9.43,0,9.7,0,10.03
+		v4.88c0,0.33,0.26,0.59,0.59,0.59H5.4c0.32,0,0.59-0.27,0.59-0.59v-4.88c0-0.33-0.26-0.59-0.59-0.59H3.58V8.69h8.84v0.75H10.6
+		c-0.32,0-0.59,0.27-0.59,0.59v4.88c0,0.33,0.26,0.59,0.59,0.59h4.81c0.32,0,0.59-0.27,0.59-0.59v-4.88
+		C16,9.7,15.74,9.43,15.41,9.43z M4.81,10.62v3.69H1.17v-3.69H4.81z M6.18,3.53C6.18,2.52,7,1.69,8,1.69c1,0,1.82,0.83,1.82,1.85
+		C9.82,4.55,9,5.38,8,5.38C7,5.38,6.18,4.55,6.18,3.53z M14.83,14.31h-3.64v-3.69h3.64V14.31z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/orgnization-icon.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1610929356155" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1352" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M952 633.2h-89.8V493.6c0-17.6-14.4-32-32-32H554.5v-70.7h85.7c39.7 0 72-32.3 72-72v-240c0-39.7-32.3-72-72-72h-240c-39.7 0-72 32.3-72 72v240c0 39.7 32.3 72 72 72h90.3v70.7H194c-3.8 0-7.5 0.7-11 1.9-1 0.4-1.9 0.8-2.9 1.2-4.2 2-7.9 4.9-10.8 8.5-4.6 5.5-7.3 12.6-7.3 20.3v139.6H72c-39.7 0-72 32.3-72 72v240c0 39.7 32.3 72 72 72h240c39.7 0 72-32.3 72-72v-240c0-39.7-32.3-72-72-72h-86V525.6h290.4c2 0.4 4 0.6 6.1 0.6 2.1 0 4.1-0.2 6.1-0.6h269.5v107.6H712c-39.7 0-72 32.3-72 72v240c0 39.7 32.3 72 72 72h240c39.7 0 72-32.3 72-72v-240c0-39.7-32.3-72-72-72zM392.2 318.8v-240c0-4.4 3.6-8 8-8h240c4.4 0 8 3.6 8 8v240c0 4.4-3.6 8-8 8h-240c-4.4 0-8-3.6-8-8zM320 705.2v240c0 4.4-3.6 8-8 8H72c-4.4 0-8-3.6-8-8v-240c0-4.4 3.6-8 8-8h240c4.4 0 8 3.6 8 8z m640 240c0 4.4-3.6 8-8 8H712c-4.4 0-8-3.6-8-8v-240c0-4.4 3.6-8 8-8h240c4.4 0 8 3.6 8 8v240z"  p-id="1353"></path></svg>

+ 1 - 0
src/icons/svg/password.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z"/></svg>

+ 15 - 0
src/icons/svg/patrol-manage.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M13.5,0h-11c-1.1,0-2,0.9-2,2v12c0,1.1,0.9,2,2,2h11c1.1,0,2-0.9,2-2V2C15.5,0.9,14.61,0,13.5,0z M14.5,14
+		c0,0.55-0.45,1-1,1h-11c-0.55,0-1-0.45-1-1V4h13V14z M14.5,3h-13V2c0-0.55,0.45-1,1-1h11c0.55,0,1,0.45,1,1V3z M12,9
+		c0.83,0,1.5-0.67,1.5-1.5S12.83,6,12,6c-0.83,0-1.5,0.67-1.5,1.5S11.17,9,12,9z M11.5,7h1v1h-1V7z M12,13c0.83,0,1.5-0.67,1.5-1.5
+		c0-0.83-0.67-1.5-1.5-1.5c-0.83,0-1.5,0.67-1.5,1.5C10.5,12.33,11.17,13,12,13z M11.5,11h1v1h-1V11z M4,9c0.83,0,1.5-0.67,1.5-1.5
+		S4.83,6,4,6C3.17,6,2.5,6.67,2.5,7.5S3.17,9,4,9z M3.5,7h1v1h-1V7z M8,9c0.83,0,1.5-0.67,1.5-1.5S8.83,6,8,6
+		C7.17,6,6.5,6.67,6.5,7.5S7.17,9,8,9z M7.5,7h1v1h-1V7z M4,13c0.83,0,1.5-0.67,1.5-1.5C5.5,10.67,4.83,10,4,10
+		c-0.83,0-1.5,0.67-1.5,1.5C2.5,12.33,3.17,13,4,13z M3.5,11h1v1h-1V11z M8,13c0.83,0,1.5-0.67,1.5-1.5C9.5,10.67,8.83,10,8,10
+		c-0.83,0-1.5,0.67-1.5,1.5C6.5,12.33,7.17,13,8,13z M7.5,11h1v1h-1V11z"/>
+</g>
+</svg>

+ 13 - 0
src/icons/svg/patrol-plan.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M12.38,0H3.63C1.91,0,0.5,1.38,0.5,3.08v9.85C0.5,14.62,1.91,16,3.63,16h8.75c1.72,0,3.12-1.38,3.12-3.08V3.08
+		C15.5,1.38,14.09,0,12.38,0z M10.91,1.23v4.31l-1-0.92C9.72,4.43,9.5,4.37,9.25,4.37C9,4.37,8.78,4.46,8.59,4.65L7.69,5.51V1.23
+		H10.91z M1.75,12.92V3.08c0-1.02,0.84-1.85,1.87-1.85v13.54C2.59,14.77,1.75,13.94,1.75,12.92z M14.25,12.92
+		c0,1.02-0.84,1.85-1.88,1.85h-7.5V1.23h1.56v5.02c0,0.52,0.41,0.92,0.94,0.92c0.25,0,0.5-0.09,0.66-0.28l1.22-1.2l1.31,1.23
+		c0.19,0.15,0.41,0.25,0.66,0.25h0.03c0.25,0,0.47-0.09,0.66-0.28c0.16-0.18,0.25-0.4,0.25-0.65V1.23h0.22
+		c1.03,0,1.88,0.83,1.88,1.85V12.92L14.25,12.92z"/>
+</g>
+</svg>

+ 15 - 0
src/icons/svg/patrol-point.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M8,11.6c-0.17,0-0.33-0.07-0.44-0.2c-0.41-0.49-3.98-4.82-3.98-7.05C3.58,1.95,5.56,0,8,0c2.44,0,4.42,1.95,4.42,4.35
+		c0,2.23-3.58,6.56-3.98,7.05C8.33,11.53,8.17,11.6,8,11.6z M8,1.12c-1.81,0-3.29,1.45-3.29,3.23c0,1.37,2.08,4.28,3.29,5.8
+		c1.21-1.52,3.29-4.44,3.29-5.8C11.29,2.57,9.81,1.12,8,1.12z"/>
+	<path d="M8,6.54c-1.15,0-2.08-0.92-2.08-2.05c0-1.13,0.93-2.05,2.08-2.05c1.15,0,2.08,0.92,2.08,2.05C10.08,5.62,9.15,6.54,8,6.54z
+		 M8,3.56c-0.52,0-0.95,0.42-0.95,0.93S7.48,5.42,8,5.42c0.52,0,0.95-0.42,0.95-0.93S8.52,3.56,8,3.56z M14.3,16H2.83
+		c-0.31,0-0.57-0.25-0.57-0.56c0-0.31,0.25-0.56,0.57-0.56H14.3c0.31,0,0.57-0.25,0.57-0.56c0-0.31-0.25-0.56-0.57-0.56H1.7
+		c-0.94,0-1.7-0.75-1.7-1.68c0-0.95,0.76-1.7,1.7-1.7h1.64c0.31,0,0.57,0.25,0.57,0.56s-0.25,0.56-0.57,0.56H1.7
+		c-0.31,0-0.57,0.25-0.57,0.56c0,0.33,0.25,0.58,0.57,0.58H14.3c0.94,0,1.7,0.75,1.7,1.68C16,15.25,15.24,16,14.3,16L14.3,16z"/>
+</g>
+</svg>

+ 17 - 0
src/icons/svg/patrol-route.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M11.2,3.2C8.56,3.2,6.4,5.36,6.4,8c0,2.72,2.58,5.84,3.86,7.2H2.7c-1.04,0-1.9-0.8-1.9-1.8c0-0.98,0.88-1.8,1.9-1.8h0.96
+		c1.1,0,2-0.9,2-2s-0.9-2-2-2H1.6c-0.44,0-0.8-0.36-0.8-0.8C0.8,6.36,1.16,6,1.6,6h0.8c0.04,0,0.08,0,0.12-0.02h0.02
+		c0.04-0.02,0.08-0.04,0.1-0.06C2.74,5.84,4.8,4.18,4.8,2.4C4.8,1.08,3.72,0,2.4,0C1.08,0,0,1.08,0,2.4c0,1.1,0.78,2.14,1.4,2.82
+		C0.6,5.32,0,6,0,6.8c0,0.88,0.72,1.6,1.6,1.6h2.06c0.66,0,1.2,0.54,1.2,1.2c0,0.66-0.54,1.2-1.2,1.2H2.7c-1.48,0-2.7,1.16-2.7,2.6
+		C0,14.84,1.22,16,2.7,16h8.62c0.02,0,0.02,0,0.04-0.02c0.02,0,0.02-0.02,0.04-0.02c0.02,0,0.02-0.02,0.04-0.02
+		c0.02,0,0.02-0.02,0.04-0.02l0.02-0.02C11.66,15.72,16,11.54,16,8C16,5.36,13.84,3.2,11.2,3.2z M2.4,0.8C3.28,0.8,4,1.52,4,2.4
+		c0,1.08-1.1,2.2-1.6,2.66C1.9,4.6,0.8,3.48,0.8,2.4C0.8,1.52,1.52,0.8,2.4,0.8z M11.2,15.04c-0.94-0.98-4-4.34-4-7.04
+		c0-2.2,1.8-4,4-4s4,1.8,4,4C15.2,10.7,12.14,14.06,11.2,15.04L11.2,15.04z"/>
+	<path d="M11.2,6.2c-1,0-1.8,0.8-1.8,1.8c0,1,0.8,1.8,1.8,1.8S13,9,13,8C13,7,12.2,6.2,11.2,6.2z M11.2,9c-0.56,0-1-0.44-1-1
+		s0.44-1,1-1c0.56,0,1,0.44,1,1S11.76,9,11.2,9z"/>
+</g>
+</svg>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/icons/svg/per-manage-icon.svg


+ 49 - 0
src/icons/svg/per-manage.svg

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M4.63,9.3C4.41,9.07,4.11,8.95,3.8,8.95H3.05c-0.31,0-0.62,0.13-0.83,0.35C2,9.52,1.89,9.83,1.91,10.13l0.03,0.5v0
+		l0.08,1.17c0.03,0.47,0.3,0.89,0.72,1.11c0.21,0.11,0.44,0.17,0.68,0.17c0.23,0,0.46-0.06,0.68-0.17c0.42-0.23,0.69-0.64,0.72-1.11
+		l0.09-1.33l0.02-0.33C4.95,9.83,4.84,9.52,4.63,9.3z M2.56,10.09C2.55,9.96,2.6,9.83,2.69,9.73c0.09-0.1,0.22-0.15,0.36-0.15h0.51
+		L3.47,9.82c-0.05,0.06-0.27,0.34-0.9,0.44L2.56,10.09z M4.17,11.76c-0.02,0.25-0.16,0.48-0.39,0.6c-0.23,0.12-0.5,0.12-0.73,0
+		c-0.23-0.12-0.37-0.34-0.39-0.6L2.61,10.9c0.53-0.08,0.88-0.25,1.1-0.42c0.04,0.03,0.08,0.05,0.13,0.08
+		c0.09,0.05,0.22,0.09,0.4,0.14L4.17,11.76z M4.15,9.99C4.13,9.98,4.12,9.97,4.11,9.97l0.07-0.19c0.06,0.08,0.09,0.17,0.1,0.26
+		C4.2,10.01,4.16,9.99,4.15,9.99z"/>
+	<path d="M6.84,15.62l-0.12-0.67c-0.15-0.83-0.83-1.5-1.68-1.65c-0.13-0.02-0.26-0.04-0.39-0.04H4.27c-0.09,0-0.17,0.03-0.23,0.09
+		l-0.62,0.6l-0.62-0.6c-0.06-0.06-0.14-0.09-0.23-0.09H2.2c-0.13,0-0.26,0.01-0.39,0.04c-0.85,0.16-1.53,0.82-1.68,1.65l-0.12,0.67
+		c-0.02,0.09,0.01,0.19,0.07,0.26C0.14,15.96,0.23,16,0.33,16h6.19c0.1,0,0.19-0.04,0.25-0.11C6.83,15.81,6.85,15.72,6.84,15.62z
+		 M0.72,15.36l0.05-0.29c0.11-0.57,0.57-1.03,1.16-1.14c0.09-0.02,0.18-0.02,0.27-0.02h0.24l0.75,0.74c0.13,0.12,0.33,0.12,0.46,0
+		L4.4,13.9h0.24c0.09,0,0.18,0.01,0.27,0.02c0.59,0.11,1.05,0.57,1.16,1.14l0.05,0.29H0.72L0.72,15.36z"/>
+	<path d="M13.79,9.3c-0.21-0.22-0.52-0.35-0.83-0.35H12.2c-0.31,0-0.62,0.13-0.83,0.35c-0.21,0.22-0.33,0.53-0.31,0.83l0.03,0.5l0,0
+		l0.08,1.17c0.03,0.47,0.3,0.89,0.73,1.11c0.21,0.11,0.44,0.17,0.68,0.17c0.23,0,0.47-0.06,0.68-0.17c0.42-0.23,0.69-0.64,0.72-1.11
+		l0.09-1.33l0.02-0.33C14.11,9.83,14,9.52,13.79,9.3z M11.72,10.09c-0.01-0.13,0.04-0.26,0.13-0.36c0.09-0.1,0.22-0.15,0.36-0.15
+		h0.51l-0.09,0.24c-0.05,0.06-0.28,0.34-0.9,0.44L11.72,10.09z M13.33,11.76c-0.02,0.25-0.16,0.48-0.39,0.6
+		c-0.23,0.12-0.5,0.12-0.73,0c-0.23-0.12-0.37-0.34-0.39-0.6l-0.06-0.86c0.53-0.08,0.88-0.25,1.1-0.42
+		c0.04,0.03,0.08,0.05,0.13,0.08c0.09,0.05,0.22,0.09,0.4,0.14L13.33,11.76z M13.3,9.99c-0.01-0.01-0.03-0.01-0.04-0.02l0.07-0.19
+		c0.06,0.08,0.09,0.17,0.1,0.26C13.36,10.01,13.32,9.99,13.3,9.99z"/>
+	<path d="M15.99,15.62l-0.12-0.67c-0.15-0.83-0.83-1.5-1.68-1.65c-0.13-0.02-0.26-0.04-0.39-0.04h-0.37c-0.09,0-0.17,0.03-0.23,0.09
+		l-0.62,0.6l-0.62-0.6c-0.06-0.06-0.14-0.09-0.23-0.09h-0.37c-0.13,0-0.26,0.01-0.39,0.04c-0.85,0.16-1.53,0.82-1.68,1.65
+		l-0.12,0.67c-0.02,0.09,0.01,0.19,0.07,0.26C9.3,15.96,9.39,16,9.49,16h6.19c0.1,0,0.19-0.04,0.25-0.11
+		C15.99,15.81,16.01,15.72,15.99,15.62z M9.88,15.36l0.05-0.29c0.11-0.57,0.57-1.03,1.16-1.14c0.09-0.02,0.18-0.02,0.27-0.02h0.24
+		l0.75,0.74c0.13,0.12,0.33,0.12,0.46,0l0.75-0.74h0.24c0.09,0,0.18,0.01,0.27,0.02c0.59,0.11,1.05,0.57,1.16,1.14l0.05,0.29H9.88z"
+		/>
+	<path d="M9.21,0.35C8.99,0.13,8.69,0,8.37,0H7.63C7.31,0,7.01,0.13,6.79,0.35C6.58,0.58,6.47,0.88,6.49,1.19l0.03,0.5L6.6,2.85
+		c0.03,0.47,0.3,0.89,0.72,1.11C7.54,4.08,7.77,4.14,8,4.14c0.23,0,0.46-0.06,0.68-0.17C9.1,3.74,9.37,3.32,9.4,2.85l0.09-1.33
+		l0.02-0.33C9.53,0.88,9.42,0.58,9.21,0.35z M7.14,1.15C7.13,1.01,7.18,0.89,7.27,0.79c0.09-0.1,0.22-0.15,0.36-0.15h0.51L8.05,0.88
+		C8,0.94,7.77,1.21,7.15,1.31L7.14,1.15z M8.75,2.81c-0.02,0.25-0.16,0.48-0.39,0.6c-0.23,0.12-0.5,0.12-0.73,0
+		c-0.23-0.12-0.37-0.34-0.39-0.6L7.19,1.95C7.72,1.88,8.07,1.7,8.3,1.53c0.04,0.03,0.08,0.05,0.13,0.08
+		c0.09,0.05,0.22,0.09,0.4,0.14L8.75,2.81z M8.73,1.04C8.71,1.03,8.7,1.03,8.69,1.02l0.07-0.19c0.06,0.08,0.09,0.17,0.1,0.26
+		C8.78,1.07,8.74,1.05,8.73,1.04z"/>
+	<path d="M11.42,6.68l-0.12-0.67c-0.15-0.83-0.83-1.5-1.68-1.65C9.48,4.33,9.35,4.32,9.22,4.32H8.85c-0.09,0-0.17,0.03-0.23,0.09
+		L8,5.01l-0.62-0.6C7.32,4.35,7.24,4.32,7.15,4.32H6.78c-0.13,0-0.26,0.01-0.39,0.04C5.54,4.51,4.86,5.18,4.71,6.01L4.58,6.68
+		C4.57,6.77,4.59,6.87,4.66,6.94c0.06,0.07,0.15,0.11,0.25,0.11h6.19c0.1,0,0.19-0.04,0.25-0.11C11.41,6.87,11.43,6.77,11.42,6.68z
+		 M5.3,6.42l0.05-0.29c0.11-0.57,0.57-1.03,1.16-1.14C6.6,4.96,6.69,4.96,6.78,4.96h0.24l0.75,0.74c0.13,0.12,0.33,0.12,0.46,0
+		l0.75-0.74h0.24c0.09,0,0.18,0.01,0.27,0.02c0.59,0.11,1.05,0.57,1.16,1.14l0.05,0.29H5.3z"/>
+	<path d="M7.9,7.63c-0.18,0-0.33,0.14-0.33,0.32v0.1c0,0.18,0.15,0.32,0.33,0.32c0.18,0,0.33-0.14,0.33-0.32v-0.1
+		C8.23,7.78,8.08,7.63,7.9,7.63z"/>
+	<path d="M10.19,11.28l-1.96-1.11V8.98c0-0.18-0.15-0.32-0.33-0.32c-0.18,0-0.33,0.14-0.33,0.32v1.19l0,0l-1.96,1.11
+		c-0.16,0.09-0.21,0.28-0.12,0.44c0.06,0.1,0.17,0.16,0.28,0.16c0.06,0,0.11-0.01,0.16-0.04l1.96-1.11l1.96,1.11
+		c0.05,0.03,0.11,0.04,0.16,0.04c0.11,0,0.22-0.06,0.28-0.16C10.4,11.56,10.35,11.37,10.19,11.28z"/>
+</g>
+</svg>

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/icons/svg/security-icon.svg


+ 18 - 0
src/icons/svg/security.svg

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M13.84,1.63L8.62,0.09c-0.41-0.12-0.83-0.12-1.24,0L2.16,1.63C1.77,1.74,1.5,2.1,1.5,2.5v4.31c0,2,0.6,3.92,1.72,5.56
+		c1.1,1.6,2.63,2.83,4.43,3.56C7.77,15.98,7.88,16,8,16c0.12,0,0.23-0.02,0.35-0.07c1.8-0.73,3.33-1.96,4.43-3.56
+		c1.13-1.64,1.72-3.56,1.72-5.56V2.5C14.5,2.1,14.23,1.74,13.84,1.63z M13.77,6.81c0,1.85-0.55,3.63-1.6,5.15
+		c-1.02,1.48-2.44,2.62-4.1,3.3c-0.05,0.02-0.09,0.02-0.14,0c-1.66-0.68-3.08-1.82-4.1-3.3c-1.04-1.52-1.6-3.3-1.6-5.15V2.5
+		c0-0.08,0.05-0.15,0.13-0.17l5.22-1.54C7.72,0.75,7.86,0.73,8,0.73c0.14,0,0.28,0.02,0.41,0.06l5.22,1.54
+		c0.08,0.02,0.13,0.09,0.13,0.17V6.81L13.77,6.81z"/>
+	<path d="M12.05,3.24L8.16,2.09c-0.1-0.03-0.21-0.03-0.31,0L3.95,3.24C3.72,3.3,3.56,3.52,3.56,3.76v3.05
+		c0,1.61,0.49,3.16,1.41,4.47c0.72,1.02,1.68,1.86,2.77,2.43c0.08,0.04,0.17,0.06,0.25,0.06c0.09,0,0.17-0.02,0.25-0.06
+		c1.1-0.57,2.06-1.41,2.77-2.43c0.93-1.31,1.41-2.86,1.41-4.47V3.76C12.44,3.52,12.28,3.3,12.05,3.24z M11.71,6.81
+		c0,1.46-0.44,2.86-1.28,4.05C9.8,11.76,8.96,12.51,8,13.03c-0.96-0.52-1.8-1.26-2.43-2.16C4.73,9.68,4.29,8.27,4.29,6.81V3.9
+		L8,2.81l3.71,1.09V6.81z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/system-icon.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1610929455489" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1604" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M303.9232 864.8704l-45.3632 45.3632a51.2 51.2 0 0 1-72.3968 0l-72.3968-72.3968a51.2 51.2 0 0 1 0-72.3968l45.3632-45.3632A407.1424 407.1424 0 0 1 115.3024 614.4H51.2a51.2 51.2 0 0 1-51.2-51.2V460.8a51.2 51.2 0 0 1 51.2-51.2h64.1024c9.6768-37.5808 24.576-73.0624 43.8272-105.6768l-45.3632-45.3632a51.2 51.2 0 0 1 0-72.3968l72.3968-72.3968a51.2 51.2 0 0 1 72.3968 0l45.3632 45.3632A407.1424 407.1424 0 0 1 409.6 115.3024V51.2a51.2 51.2 0 0 1 51.2-51.2h102.4a51.2 51.2 0 0 1 51.2 51.2v64.1024c37.5808 9.6768 73.0624 24.576 105.6768 43.8272l45.3632-45.3632a51.2 51.2 0 0 1 72.3968 0l72.3968 72.3968a51.2 51.2 0 0 1 0 72.3968l-45.3632 45.3632c19.3024 32.6144 34.1504 68.096 43.8272 105.6768H972.8a51.2 51.2 0 0 1 51.2 51.2v102.4a51.2 51.2 0 0 1-51.2 51.2h-64.1024a407.1424 407.1424 0 0 1-43.8272 105.6768l45.3632 45.3632a51.2 51.2 0 0 1 0 72.3968l-72.3968 72.3968a51.2 51.2 0 0 1-72.3968 0l-45.3632-45.3632a407.1424 407.1424 0 0 1-105.6768 43.8272V972.8a51.2 51.2 0 0 1-51.2 51.2H460.8a51.2 51.2 0 0 1-51.2-51.2v-64.1024a407.1424 407.1424 0 0 1-105.6768-43.8272zM512 716.8a204.8 204.8 0 1 0 0-409.6 204.8 204.8 0 0 0 0 409.6z"  p-id="1605"></path></svg>

+ 40 - 0
src/icons/svg/system-manage.svg

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M15.29,6.45c-0.3-0.05-0.61-0.09-0.92-0.13c-0.04,0-0.07-0.03-0.08-0.06c-0.14-0.52-0.35-1.01-0.61-1.48
+		c-0.02-0.03-0.01-0.07,0.01-0.1c0.19-0.25,0.38-0.5,0.56-0.74c0.24-0.33,0.21-0.8-0.08-1.09l-1.01-1.01
+		c-0.29-0.29-0.76-0.33-1.09-0.08c-0.24,0.18-0.49,0.37-0.74,0.56c-0.03,0.02-0.07,0.03-0.1,0.01c-0.47-0.26-0.96-0.47-1.48-0.61
+		C9.7,1.7,9.68,1.67,9.67,1.63C9.63,1.32,9.59,1.01,9.55,0.71C9.48,0.31,9.13,0,8.72,0H7.28C6.87,0,6.52,0.31,6.45,0.71
+		c-0.05,0.3-0.09,0.61-0.13,0.92C6.32,1.67,6.3,1.7,6.26,1.71C5.75,1.85,5.25,2.06,4.78,2.32c-0.03,0.02-0.07,0.01-0.1-0.01
+		c-0.25-0.19-0.5-0.38-0.74-0.56c-0.33-0.24-0.8-0.21-1.09,0.08L1.84,2.85C1.55,3.14,1.51,3.61,1.76,3.94
+		c0.18,0.25,0.37,0.49,0.56,0.74c0.02,0.03,0.03,0.07,0.01,0.1C2.06,5.25,1.85,5.75,1.71,6.26C1.7,6.3,1.67,6.32,1.63,6.33
+		C1.32,6.37,1.01,6.41,0.71,6.45C0.31,6.52,0,6.87,0,7.28v1.43c0,0.41,0.31,0.77,0.71,0.83c0.3,0.05,0.61,0.09,0.92,0.13
+		c0.04,0,0.07,0.03,0.08,0.06c0.14,0.52,0.35,1.01,0.61,1.48c0.02,0.03,0.01,0.07-0.01,0.1c-0.19,0.25-0.38,0.5-0.56,0.74
+		c-0.24,0.33-0.21,0.8,0.08,1.09l1.01,1.01c0.29,0.29,0.76,0.33,1.09,0.08c0.24-0.18,0.49-0.37,0.74-0.56
+		c0.03-0.02,0.07-0.03,0.1-0.01c0.47,0.26,0.96,0.47,1.48,0.61c0.03,0.01,0.06,0.04,0.06,0.08c0.04,0.31,0.08,0.62,0.13,0.92
+		C6.52,15.69,6.87,16,7.28,16h1.43c0.41,0,0.77-0.31,0.83-0.71c0.04-0.3,0.09-0.61,0.13-0.92c0-0.04,0.03-0.07,0.06-0.08
+		c0.52-0.14,1.01-0.35,1.48-0.61c0.03-0.02,0.07-0.01,0.1,0.01c0.25,0.19,0.5,0.38,0.74,0.56c0.33,0.24,0.8,0.21,1.09-0.08
+		l1.01-1.01c0.29-0.29,0.33-0.76,0.08-1.09c-0.18-0.24-0.37-0.49-0.56-0.74c-0.02-0.03-0.03-0.07-0.01-0.1
+		c0.26-0.47,0.47-0.96,0.61-1.48c0.01-0.03,0.04-0.06,0.08-0.06c0.31-0.04,0.62-0.08,0.92-0.13C15.69,9.48,16,9.13,16,8.72V7.28
+		C16,6.87,15.69,6.52,15.29,6.45z M15.25,8.72c0,0.05-0.03,0.08-0.08,0.09c-0.3,0.04-0.6,0.09-0.9,0.13
+		c-0.34,0.04-0.61,0.28-0.7,0.61c-0.13,0.46-0.31,0.9-0.54,1.31c-0.17,0.29-0.14,0.66,0.07,0.93c0.19,0.24,0.37,0.49,0.55,0.73
+		c0.03,0.04,0.02,0.09-0.01,0.12l-1.01,1.01c-0.03,0.03-0.08,0.04-0.12,0.01c-0.24-0.18-0.49-0.36-0.73-0.55
+		c-0.27-0.21-0.63-0.23-0.93-0.07c-0.41,0.23-0.85,0.42-1.31,0.54c-0.32,0.09-0.56,0.36-0.61,0.7c-0.04,0.3-0.08,0.61-0.13,0.9
+		c-0.01,0.04-0.05,0.08-0.09,0.08H7.28c-0.05,0-0.08-0.03-0.09-0.08c-0.04-0.3-0.09-0.6-0.13-0.9c-0.04-0.34-0.28-0.61-0.61-0.7
+		c-0.46-0.13-0.9-0.31-1.31-0.54c-0.13-0.07-0.27-0.11-0.41-0.11c-0.18,0-0.36,0.06-0.51,0.18c-0.24,0.19-0.49,0.37-0.73,0.55
+		c-0.04,0.03-0.09,0.02-0.12-0.01l-1.01-1.01c-0.03-0.03-0.04-0.08-0.01-0.12c0.18-0.24,0.36-0.49,0.55-0.73
+		c0.21-0.27,0.23-0.63,0.07-0.93C2.74,10.44,2.55,10,2.43,9.54c-0.09-0.32-0.36-0.56-0.7-0.61c-0.3-0.04-0.61-0.08-0.9-0.13
+		C0.78,8.8,0.75,8.76,0.75,8.72V7.28c0-0.05,0.03-0.08,0.08-0.09c0.3-0.04,0.6-0.09,0.9-0.13c0.34-0.04,0.61-0.28,0.7-0.61
+		C2.55,6,2.74,5.56,2.97,5.15c0.17-0.29,0.14-0.66-0.07-0.93C2.72,3.98,2.53,3.74,2.36,3.5C2.33,3.46,2.33,3.41,2.37,3.38l1.01-1.01
+		C3.41,2.33,3.46,2.33,3.5,2.36c0.24,0.18,0.49,0.36,0.73,0.55c0.27,0.21,0.63,0.23,0.93,0.07C5.56,2.74,6,2.55,6.46,2.43
+		c0.32-0.09,0.56-0.36,0.61-0.7c0.04-0.3,0.08-0.61,0.13-0.9C7.2,0.78,7.24,0.75,7.28,0.75h1.43c0.05,0,0.08,0.03,0.09,0.08
+		c0.04,0.3,0.09,0.6,0.13,0.9c0.04,0.34,0.28,0.61,0.61,0.7c0.46,0.13,0.9,0.31,1.31,0.54c0.29,0.17,0.66,0.14,0.93-0.07
+		c0.24-0.19,0.49-0.37,0.73-0.55c0.04-0.03,0.09-0.02,0.12,0.01l1.01,1.01c0.03,0.03,0.04,0.08,0.01,0.12
+		c-0.18,0.24-0.36,0.49-0.55,0.73c-0.21,0.27-0.23,0.63-0.07,0.93c0.23,0.41,0.42,0.85,0.54,1.31c0.09,0.32,0.36,0.56,0.7,0.61
+		c0.3,0.04,0.61,0.08,0.9,0.13c0.04,0.01,0.08,0.05,0.08,0.09L15.25,8.72L15.25,8.72z"/>
+	<path d="M8,4.53C6.08,4.53,4.53,6.09,4.53,8S6.08,11.47,8,11.47c1.91,0,3.47-1.56,3.47-3.47S9.92,4.53,8,4.53z M8,10.73
+		C6.5,10.73,5.27,9.5,5.27,8S6.5,5.27,8,5.27c1.5,0,2.73,1.22,2.73,2.73S9.5,10.73,8,10.73z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/table.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/></svg>

+ 20 - 0
src/icons/svg/team.svg

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M3.88,8.2l1.16-0.33C5.22,7.8,5.37,7.66,5.41,7.44c0.04-0.22-0.07-0.4-0.25-0.51L4.1,6.35C3.56,6.02,3.19,5.44,3.19,4.79
+		c0-0.98,0.8-1.78,1.78-1.78c0.29,0,0.51-0.22,0.51-0.51C5.48,2.22,5.26,2,4.97,2C3.45,2,2.21,3.23,2.21,4.76
+		c0,0.98,0.54,1.92,1.41,2.39C1.49,7.84,0,9.83,0,12.04c0,0.22,0,0.44,0.04,0.69c0.04,0.25,0.25,0.44,0.51,0.44h0.07
+		c0.25-0.07,0.47-0.33,0.44-0.58c-0.04-0.18-0.04-0.36-0.04-0.54C1.02,10.27,2.18,8.67,3.88,8.2L3.88,8.2z M12.34,7.26
+		c0.87-0.51,1.41-1.41,1.41-2.39c0-1.52-1.23-2.76-2.76-2.76c-0.29,0-0.51,0.22-0.51,0.51s0.22,0.51,0.51,0.51
+		c0.98,0,1.78,0.8,1.78,1.78c0,0.65-0.36,1.23-0.91,1.56l-1.05,0.58c-0.18,0.11-0.29,0.29-0.25,0.51c0.04,0.22,0.18,0.36,0.36,0.43
+		l1.16,0.33c1.71,0.47,2.9,2.07,2.9,3.84c0,0.18,0,0.36-0.04,0.54c-0.04,0.29,0.15,0.51,0.44,0.58h0.07c0.25,0,0.47-0.18,0.51-0.44
+		C16,12.62,16,12.37,16,12.15C15.96,9.83,14.48,7.84,12.34,7.26z"/>
+	<path d="M8.05,3.27c1.05,0,1.85,0.8,1.85,1.85c0,0.69-0.33,1.31-0.94,1.63L8.02,7.26L7.15,6.75C6.57,6.42,6.2,5.77,6.2,5.12
+		C6.2,4.07,7,3.27,8.05,3.27 M8.05,8.42l1.16,0.33c1.81,0.51,3.08,2.18,3.08,4.06v0.11H3.81V12.8c0-1.89,1.27-3.55,3.08-4.06
+		L8.05,8.42 M8.05,2.18c-1.63,0-2.94,1.31-2.94,2.94c0,1.09,0.62,2.07,1.49,2.57c-2.21,0.62-3.88,2.68-3.88,5.11
+		c0,0.4,0.04,0.8,0.15,1.2h10.38c0.07-0.36,0.15-0.76,0.15-1.2c0-2.43-1.63-4.5-3.88-5.11c0.91-0.51,1.49-1.45,1.49-2.57
+		C10.99,3.49,9.69,2.18,8.05,2.18L8.05,2.18z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/tree-user.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1611017063399" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="941" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M593.066667 499.2C695.466667 465.066667 768 369.066667 768 256c0-140.8-115.2-256-256-256S256 115.2 256 256c0 113.066667 72.533333 209.066667 174.933333 243.2C249.6 535.466667 85.333333 689.066667 85.333333 874.666667c0 83.2 66.133333 149.333333 149.333334 149.333333h554.666666c83.2 0 149.333333-66.133333 149.333334-149.333333 0-185.6-164.266667-339.2-345.6-375.466667zM298.666667 256c0-117.333333 96-213.333333 213.333333-213.333333s213.333333 96 213.333333 213.333333-96 213.333333-213.333333 213.333333-213.333333-96-213.333333-213.333333z m490.666666 725.333333H234.666667c-59.733333 0-106.666667-46.933333-106.666667-106.666666 0-196.266667 202.666667-341.333333 384-341.333334s384 145.066667 384 341.333334c0 59.733333-46.933333 106.666667-106.666667 106.666666z" fill="#515151" p-id="942"></path></svg>

+ 1 - 0
src/icons/svg/tree.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z"/></svg>

+ 1 - 0
src/icons/svg/unit-info-icon.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1610929322669" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1226" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M945 912H81c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h80V176c0-35.346 28.654-64 64-64h320c35.346 0 64 28.654 64 64v160h192c35.346 0 64 28.654 64 64v448h80c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16zM353 272c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m0 192c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m0 192c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m160-384c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m0 192c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m0 192c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m256-192c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z m0 192c0-8.837-7.163-16-16-16h-64c-8.837 0-16 7.163-16 16v64c0 8.837 7.163 16 16 16h64c8.837 0 16-7.163 16-16v-64z"  p-id="1227"></path></svg>

+ 18 - 0
src/icons/svg/unit.svg

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M15.68,5.84h-8.4V1.32C7.29,1.14,7.14,1,6.97,1H0.32C0.14,1,0,1.14,0,1.32v13.36C0,14.86,0.14,15,0.32,15h15.36
+		c0.18,0,0.32-0.14,0.32-0.32V6.16C16,5.99,15.86,5.84,15.68,5.84z M6.65,14.36H0.64V1.64h6.01V14.36z M13.82,14.36H8.83V13.6H12
+		c0.18,0,0.32-0.14,0.32-0.32s-0.14-0.32-0.32-0.32H8.83v-0.71h4.98V14.36L13.82,14.36z M13.82,11.61H8.83V10.9h4.98V11.61
+		L13.82,11.61z M8.83,10.26V9.51h4.98v0.76H8.83z M15.36,14.36h-0.91V9.19c0-0.18-0.14-0.32-0.32-0.32H8.51
+		c-0.18,0-0.32,0.14-0.32,0.32v5.17H7.29V6.48h8.08V14.36z"/>
+	<path d="M5,8.77H2.29c-0.18,0-0.32,0.14-0.32,0.32v3.61c0,0.18,0.14,0.32,0.32,0.32H5c0.18,0,0.32-0.14,0.32-0.32V9.09
+		C5.32,8.91,5.17,8.77,5,8.77z M3.32,12.38H2.61V9.41h0.72V12.38z M4.68,12.38H3.96V9.41h0.72V12.38z"/>
+	<path d="M5,2.98H2.29c-0.18,0-0.32,0.14-0.32,0.32v3.61c0,0.18,0.14,0.32,0.32,0.32H5c0.18,0,0.32-0.14,0.32-0.32V3.3
+		C5.32,3.13,5.17,2.98,5,2.98z M3.32,6.59H2.61V3.62h0.72V6.59z M4.68,6.59H3.96V3.62h0.72V6.59z"/>
+	<path d="M13.1,12.96H13c-0.18,0-0.32,0.14-0.32,0.32S12.83,13.6,13,13.6h0.1c0.18,0,0.32-0.14,0.32-0.32S13.28,12.96,13.1,12.96z"
+		/>
+</g>
+</svg>

+ 15 - 0
src/icons/svg/user-manage.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
+<g>
+	<path d="M11.03,11.43H9.7v-0.5c1.74-0.43,3.03-2.01,3.03-3.89V5.52c0-2.63-2.12-4.76-4.73-4.76c-0.81,0-1.56,0.2-2.23,0.56
+		C5.47,0.55,4.72,0,3.84,0v1.14c0.5,0,0.91,0.4,0.94,0.89C3.85,2.91,3.27,4.15,3.27,5.52v1.52c0,1.88,1.29,3.46,3.03,3.89v0.5H4.97
+		c-2.19,0-3.97,1.79-3.97,4V16h14v-0.57C15,13.22,13.22,11.43,11.03,11.43z M8,1.9c1.59,0,2.95,1.05,3.42,2.5
+		c-0.57,0.36-1.22,0.55-1.9,0.55c-1.56,0-2.94-1.03-3.42-2.5C6.65,2.11,7.3,1.9,8,1.9z M4.41,5.52c0-0.85,0.29-1.64,0.79-2.26
+		C5.26,3.41,5.33,3.55,5.4,3.69c-0.18,0.76-0.52,1.48-1,2.09V5.52L4.41,5.52z M4.43,7.4c0.82-0.71,1.45-1.61,1.83-2.61
+		C7.11,5.6,8.27,6.1,9.51,6.1c0.73,0,1.44-0.17,2.08-0.48v1.44c0,1.58-1.27,2.86-2.84,2.86H7.24C5.8,9.9,4.6,8.81,4.43,7.4z
+		 M8.57,11.05V12c0,0.32-0.25,0.57-0.57,0.57c-0.31,0-0.57-0.26-0.57-0.57v-0.95H8.57z M2.19,14.86c0.26-1.3,1.41-2.29,2.78-2.29
+		h1.42c0.23,0.67,0.87,1.14,1.61,1.14c0.74,0,1.37-0.48,1.6-1.14h1.42c1.37,0,2.52,0.98,2.78,2.29H2.19L2.19,14.86z"/>
+</g>
+</svg>

+ 1 - 0
src/icons/svg/user.svg

@@ -0,0 +1 @@
+<svg width="130" height="130" xmlns="http://www.w3.org/2000/svg"><path d="M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z" stroke="#979797"/></svg>

+ 22 - 0
src/icons/svgo.yml

@@ -0,0 +1,22 @@
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+  # - name
+  #
+  # or:
+  # - name: false
+  # - name: true
+  #
+  # or:
+  # - name:
+  #     param1: 1
+  #     param2: 2
+
+- removeAttrs:
+    attrs:
+      - 'fill'
+      - 'fill-rule'

+ 46 - 0
src/layout/components/AppMain.vue

@@ -0,0 +1,46 @@
+<template>
+  <section class="app-main">
+    <transition name="fade-transform" mode="out-in">
+      <router-view :key="key" />
+    </transition>
+  </section>
+</template>
+
+<script>
+export default {
+  name: 'AppMain',
+  computed: {
+    key() {
+      return this.$route.path
+    }
+  }
+}
+</script>
+<style >
+.app-container{
+  background:#fff;
+  position: relative;
+}
+</style>
+<style scoped>
+.app-main {
+  /*50 = navbar  */
+  min-height: calc(100vh - 50px);
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+  background:#F4F4F4
+}
+.fixed-header+.app-main {
+  padding-top: 50px;
+}
+</style>
+
+<style lang="scss">
+// fix css style bug in open el-dialog
+.el-popup-parent--hidden {
+  .fixed-header {
+    padding-right: 15px;
+  }
+}
+</style>

+ 203 - 0
src/layout/components/Navbar.vue

@@ -0,0 +1,203 @@
+<template>
+  <div class="navbar">
+    <hamburger
+      :is-active="sidebar.opened"
+      class="hamburger-container"
+      @toggleClick="toggleSideBar"
+    />
+
+    <!-- <breadcrumb class="breadcrumb-container" /> -->
+
+    <div class="title-top">安防综合管理平台</div>
+
+    <div class="right-menu">
+      <el-dropdown class="avatar-container" trigger="click">
+        <div class="avatar-wrapper">
+          <img :src="avatar + '?imageView2/1/w/80/h/80'" class="user-avatar" />
+          <i class="el-icon-caret-bottom" />
+        </div>
+        <el-dropdown-menu slot="dropdown" class="user-dropdown">
+          <router-link to="/">
+            <el-dropdown-item> Home </el-dropdown-item>
+          </router-link>
+          <a
+            target="_blank"
+            href="https://github.com/PanJiaChen/vue-admin-template/"
+          >
+            <el-dropdown-item>Github</el-dropdown-item>
+          </a>
+          <a
+            target="_blank"
+            href="https://panjiachen.github.io/vue-element-admin-site/#/"
+          >
+            <el-dropdown-item>Docs</el-dropdown-item>
+          </a>
+          <el-dropdown-item divided @click.native="logout">
+            <span style="display: block">Log Out</span>
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    </div>
+
+    <div class="right-time date">{{ dateFormat(date)  }}</div>
+    <!-- <div class="right-time date">2020年9月22日18:04:17</div> -->
+  </div>
+</template>
+
+<script>
+import { mapGetters } from "vuex";
+import Breadcrumb from "@/components/Breadcrumb";
+import Hamburger from "@/components/Hamburger";
+
+export default {
+  data() {
+    return {
+      date: new Date(), //实时时间
+    };
+  },
+
+  filters: {},
+
+  components: {
+    Breadcrumb,
+    Hamburger,
+  },
+  computed: {
+    ...mapGetters(["sidebar", "avatar"]),
+  },
+  methods: {
+    toggleSideBar() {
+      this.$store.dispatch("app/toggleSideBar");
+    },
+    async logout() {
+      await this.$store.dispatch("user/logout");
+      this.$router.push(`/login?redirect=${this.$route.fullPath}`);
+    },
+
+    setZero(a) {
+      //设置小于10的数字在加0
+      return a < 10 ? "0" + a : a;
+    },
+
+  
+    dateFormat:function(time) {
+		var date=new Date(time);
+		var year=date.getFullYear();
+		/* 在日期格式中,月份是从0开始的,因此要加0
+		 * 使用三元表达式在小于10的前面加0,以达到格式统一  如 09:11:05
+		 * */
+		var month= date.getMonth()+1<10 ? "0"+(date.getMonth()+1) : date.getMonth()+1;
+		var day=date.getDate()<10 ? "0"+date.getDate() : date.getDate();
+		var hours=date.getHours()<10 ? "0"+date.getHours() : date.getHours();
+		var minutes=date.getMinutes()<10 ? "0"+date.getMinutes() : date.getMinutes();
+		var seconds=date.getSeconds()<10 ? "0"+date.getSeconds() : date.getSeconds();
+		// 拼接
+		return year+"年"+month+"月"+day+"日 "+hours+":"+minutes+":"+seconds;
+	},
+
+  },
+
+  mounted() {
+    var _this = this;
+    this.timer = setInterval(() => {
+      _this.date = new Date(); // 修改日期数据
+    }, 1000);
+  },
+
+  destroyed() {
+    if (this.timer) {
+      clearInterval(this.timer); // 在Vue实例销毁前,清除当前日期定时器
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.navbar {
+  height: 50px;
+  overflow: hidden;
+  position: relative;
+  background: #fff;
+  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
+
+  .hamburger-container {
+    line-height: 46px;
+    height: 100%;
+    float: left;
+    cursor: pointer;
+    transition: background 0.3s;
+    -webkit-tap-highlight-color: transparent;
+
+    &:hover {
+      background: rgba(0, 0, 0, 0.025);
+    }
+  }
+
+  // .breadcrumb-container {
+  //   float: left;
+  // }
+  .title-top {
+    line-height: 50px;
+    font-size: 24px;
+    width: 50%;
+    float: left;
+  }
+  .right-time {
+    float: right;
+    line-height: 50px;
+    margin-right: 50px;
+  }
+
+  .right-menu {
+    float: right;
+    height: 100%;
+    line-height: 50px;
+
+    &:focus {
+      outline: none;
+    }
+
+    .right-menu-item {
+      display: inline-block;
+      padding: 0 8px;
+      height: 100%;
+      font-size: 18px;
+      color: #5a5e66;
+      vertical-align: text-bottom;
+
+      &.hover-effect {
+        cursor: pointer;
+        transition: background 0.3s;
+
+        &:hover {
+          background: rgba(0, 0, 0, 0.025);
+        }
+      }
+    }
+
+    .avatar-container {
+      margin-right: 30px;
+
+      .avatar-wrapper {
+        margin-top: 5px;
+        position: relative;
+
+        .user-avatar {
+          cursor: pointer;
+          width: 40px;
+          height: 40px;
+          border-radius: 10px;
+        }
+
+        .el-icon-caret-bottom {
+          cursor: pointer;
+          position: absolute;
+          right: -20px;
+          top: 25px;
+          font-size: 12px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 26 - 0
src/layout/components/Sidebar/FixiOSBug.js

@@ -0,0 +1,26 @@
+export default {
+  computed: {
+    device() {
+      return this.$store.state.app.device
+    }
+  },
+  mounted() {
+    // In order to fix the click on menu on the ios device will trigger the mouseleave bug
+    // https://github.com/PanJiaChen/vue-element-admin/issues/1135
+    this.fixBugIniOS()
+  },
+  methods: {
+    fixBugIniOS() {
+      const $subMenu = this.$refs.subMenu
+      if ($subMenu) {
+        const handleMouseleave = $subMenu.handleMouseleave
+        $subMenu.handleMouseleave = (e) => {
+          if (this.device === 'mobile') {
+            return
+          }
+          handleMouseleave(e)
+        }
+      }
+    }
+  }
+}

+ 41 - 0
src/layout/components/Sidebar/Item.vue

@@ -0,0 +1,41 @@
+<script>
+export default {
+  name: 'MenuItem',
+  functional: true,
+  props: {
+    icon: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    }
+  },
+  render(h, context) {
+    const { icon, title } = context.props
+    const vnodes = []
+
+    if (icon) {
+      if (icon.includes('el-icon')) {
+        vnodes.push(<i class={[icon, 'sub-el-icon']} />)
+      } else {
+        vnodes.push(<svg-icon icon-class={icon}/>)
+      }
+    }
+
+    if (title) {
+      vnodes.push(<span slot='title'>{(title)}</span>)
+    }
+    return vnodes
+  }
+}
+</script>
+
+<style scoped>
+.sub-el-icon {
+  color: currentColor;
+  width: 1em;
+  height: 1em;
+}
+</style>

+ 43 - 0
src/layout/components/Sidebar/Link.vue

@@ -0,0 +1,43 @@
+<template>
+  <component :is="type" v-bind="linkProps(to)">
+    <slot />
+  </component>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  props: {
+    to: {
+      type: String,
+      required: true
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.to)
+    },
+    type() {
+      if (this.isExternal) {
+        return 'a'
+      }
+      return 'router-link'
+    }
+  },
+  methods: {
+    linkProps(to) {
+      if (this.isExternal) {
+        return {
+          href: to,
+          target: '_blank',
+          rel: 'noopener'
+        }
+      }
+      return {
+        to: to
+      }
+    }
+  }
+}
+</script>

+ 82 - 0
src/layout/components/Sidebar/Logo.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="sidebar-logo-container" :class="{'collapse':collapse}">
+    <transition name="sidebarLogoFade">
+      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+        <img v-if="logo" :src="logo" class="sidebar-logo">
+        <h1 v-else class="sidebar-title">{{ title }} </h1>
+      </router-link>
+      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
+        <img v-if="logo" :src="logo" class="sidebar-logo">
+        <h1 class="sidebar-title">{{ title }} </h1>
+      </router-link>
+    </transition>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'SidebarLogo',
+  props: {
+    collapse: {
+      type: Boolean,
+      required: true
+    }
+  },
+  data() {
+    return {
+      title: '',
+      logo: require('@/assets/logo.png')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.sidebarLogoFade-enter-active {
+  transition: opacity 1.5s;
+}
+
+.sidebarLogoFade-enter,
+.sidebarLogoFade-leave-to {
+  opacity: 0;
+}
+
+.sidebar-logo-container {
+  position: relative;
+  width: 100%;
+  height: 89px;
+  line-height: 89px;
+  background: #021233;
+  text-align: center;
+  overflow: hidden;
+
+  & .sidebar-logo-link {
+    height: 100%;
+    width: 100%;
+
+    & .sidebar-logo {
+      // width: 32px;
+      // height: 32px;
+      vertical-align: middle;
+      margin-right: 12px;
+    }
+
+    & .sidebar-title {
+      display: inline-block;
+      margin: 0;
+      color: #fff;
+      font-weight: 600;
+      line-height: 50px;
+      font-size: 14px;
+      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+      vertical-align: middle;
+    }
+  }
+
+  &.collapse {
+    .sidebar-logo {
+      margin-right: 0px;
+    }
+  }
+}
+</style>

+ 142 - 0
src/layout/components/Sidebar/SidebarItem.vue

@@ -0,0 +1,142 @@
+<template>
+
+  <div v-if="!item.hidden">
+
+    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
+      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
+        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
+          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
+        </el-menu-item>
+      </app-link>
+    </template>
+
+    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
+      <template slot="title">
+        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
+      </template>
+      <sidebar-item
+        v-for="child in item.children"
+        :key="child.path"
+        :is-nest="true"
+        :item="child"
+        :base-path="resolvePath(child.path)"
+        class="nest-menu"
+      />
+    </el-submenu>
+  </div>
+</template>
+
+<script>
+import path from 'path'
+import { isExternal } from '@/utils/validate'
+import Item from './Item'
+import AppLink from './Link'
+import FixiOSBug from './FixiOSBug'
+
+export default {
+  name: 'SidebarItem',
+  components: { Item, AppLink },
+  mixins: [FixiOSBug],
+  props: {
+    // route object
+    item: {
+      type: Object,
+      required: true
+    },
+    isNest: {
+      type: Boolean,
+      default: false
+    },
+    basePath: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
+    // TODO: refactor with render function
+    this.onlyOneChild = null
+    return {}
+  },
+  methods: {
+    hasOneShowingChild(children = [], parent) {
+      const showingChildren = children.filter(item => {
+        if (item.hidden) {
+          return false
+        } else {
+          // Temp set(will be used if only has one showing child)
+          this.onlyOneChild = item
+          return true
+        }
+      })
+
+      // When there is only one child router, the child router is displayed by default
+      if (showingChildren.length === 1) {
+        return true
+      }
+
+      // Show parent if there are no child router to display
+      if (showingChildren.length === 0) {
+        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
+        return true
+      }
+
+      return false
+    },
+    resolvePath(routePath) {
+      if (isExternal(routePath)) {
+        return routePath
+      }
+      if (isExternal(this.basePath)) {
+        return this.basePath
+      }
+      return path.resolve(this.basePath, routePath)
+    }
+  }
+}
+</script>
+
+
+<style lang="scss" scoped>
+  @import "~@/styles/mixin.scss";
+  @import "~@/styles/variables.scss";
+
+  // .app-wrapper {
+  //   @include clearfix;
+  //   position: relative;
+  //   height: 100%;
+  //   width: 100%;
+
+  //   &.mobile.openSidebar {
+  //     position: fixed;
+  //     top: 0;
+  //   }
+  // }
+
+  // .drawer-bg {
+  //   background: #000;
+  //   opacity: 0.3;
+  //   width: 100%;
+  //   top: 0;
+  //   height: 100%;
+  //   position: absolute;
+  //   z-index: 999;
+  // }
+
+  // .fixed-header {
+  //   position: fixed;
+  //   top: 0;
+  //   right: 0;
+  //   z-index: 9;
+  //   width: calc(100% - #{$sideBarWidth});
+  //   transition: width 0.28s;
+  // }
+
+  // .hideSidebar .fixed-header {
+  //   width: calc(100% - 54px)
+  // }
+
+  // .mobile .fixed-header {
+  //   width: 100%;
+  // }
+</style>

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

@@ -0,0 +1,58 @@
+<template>
+  <div :class="{'has-logo':showLogo}">
+    <logo v-if="showLogo" :collapse="isCollapse" />
+  
+    <el-scrollbar wrap-class="scrollbar-wrapper">
+      <el-menu
+        :default-active="activeMenu"
+        :collapse="isCollapse"
+        :background-color="variables.menuBg"
+        :text-color="variables.menuText"
+        :unique-opened="false"
+        :active-text-color="variables.menuActiveText"
+        :collapse-transition="false"
+        mode="vertical"
+      >
+        <sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
+      </el-menu>
+    </el-scrollbar>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Logo from './Logo'
+import SidebarItem from './SidebarItem'
+import variables from '@/styles/variables.scss'
+
+export default {
+  components: { SidebarItem, Logo },
+  computed: {
+    ...mapGetters([
+      'sidebar'
+    ]),
+    routes() {
+      return this.$router.options.routes
+    },
+    activeMenu() {
+      const route = this.$route
+      const { meta, path } = route
+      // if set path, the sidebar will highlight the path you set
+      if (meta.activeMenu) {
+        return meta.activeMenu
+      }
+      return path
+    },
+    showLogo() {
+      return this.$store.state.settings.sidebarLogo
+    },
+    variables() {
+      return variables
+    },
+    isCollapse() {
+      return !this.sidebar.opened
+    }
+  }
+}
+</script>
+

+ 3 - 0
src/layout/components/index.js

@@ -0,0 +1,3 @@
+export { default as Navbar } from './Navbar'
+export { default as Sidebar } from './Sidebar'
+export { default as AppMain } from './AppMain'

+ 94 - 0
src/layout/index.vue

@@ -0,0 +1,94 @@
+<template>
+  <div :class="classObj" class="app-wrapper">
+    
+    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
+    <sidebar class="sidebar-container" />
+    <div class="main-container">
+      <div :class="{'fixed-header':fixedHeader}">
+        <navbar />
+      </div>
+      <app-main />
+    </div>
+  </div>
+</template>
+
+<script>
+import { Navbar, Sidebar, AppMain } from './components'
+import ResizeMixin from './mixin/ResizeHandler'
+
+export default {
+  name: 'Layout',
+  components: {
+    Navbar,
+    Sidebar,
+    AppMain
+  },
+  mixins: [ResizeMixin],
+  computed: {
+    sidebar() {
+      return this.$store.state.app.sidebar
+    },
+    device() {
+      return this.$store.state.app.device
+    },
+    fixedHeader() {
+      return this.$store.state.settings.fixedHeader
+    },
+    classObj() {
+      return {
+        hideSidebar: !this.sidebar.opened,
+        openSidebar: this.sidebar.opened,
+        withoutAnimation: this.sidebar.withoutAnimation,
+        mobile: this.device === 'mobile'
+      }
+    }
+  },
+  methods: {
+    handleClickOutside() {
+      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "~@/styles/mixin.scss";
+  @import "~@/styles/variables.scss";
+
+  .app-wrapper {
+    @include clearfix;
+    position: relative;
+    height: 100%;
+    width: 100%;
+    &.mobile.openSidebar{
+      position: fixed;
+      top: 0;
+    }
+  }
+  .drawer-bg {
+    background: #000;
+    opacity: 0.3;
+    width: 100%;
+    top: 0;
+    height: 100%;
+    position: absolute;
+    z-index: 999;
+  }
+
+  .fixed-header {
+    position: fixed;
+    top: 0;
+    right: 0;
+    z-index: 9;
+    width: calc(100% - #{$sideBarWidth});
+    transition: width 0.28s;
+  }
+
+  .hideSidebar .fixed-header {
+    width: calc(100% - 54px)
+  }
+
+  .mobile .fixed-header {
+    width: 100%;
+  }
+</style>

+ 45 - 0
src/layout/mixin/ResizeHandler.js

@@ -0,0 +1,45 @@
+import store from '@/store'
+
+const { body } = document
+const WIDTH = 992 // refer to Bootstrap's responsive design
+
+export default {
+  watch: {
+    $route(route) {
+      if (this.device === 'mobile' && this.sidebar.opened) {
+        store.dispatch('app/closeSideBar', { withoutAnimation: false })
+      }
+    }
+  },
+  beforeMount() {
+    window.addEventListener('resize', this.$_resizeHandler)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.$_resizeHandler)
+  },
+  mounted() {
+    const isMobile = this.$_isMobile()
+    if (isMobile) {
+      store.dispatch('app/toggleDevice', 'mobile')
+      store.dispatch('app/closeSideBar', { withoutAnimation: true })
+    }
+  },
+  methods: {
+    // use $_ for mixins properties
+    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+    $_isMobile() {
+      const rect = body.getBoundingClientRect()
+      return rect.width - 1 < WIDTH
+    },
+    $_resizeHandler() {
+      if (!document.hidden) {
+        const isMobile = this.$_isMobile()
+        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
+
+        if (isMobile) {
+          store.dispatch('app/closeSideBar', { withoutAnimation: true })
+        }
+      }
+    }
+  }
+}

+ 43 - 0
src/main.js

@@ -0,0 +1,43 @@
+import Vue from 'vue'
+
+import 'normalize.css/normalize.css' // A modern alternative to CSS resets
+
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+import locale from 'element-ui/lib/locale/lang/en' // lang i18n
+
+import '@/styles/index.scss' // global css
+
+import App from './App'
+import store from './store'
+import router from './router'
+
+import '@/icons' // icon
+import '@/permission' // permission control
+
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online ! ! !
+ */
+if (process.env.NODE_ENV === 'production') {
+    const { mockXHR } = require('../mock')
+    mockXHR()
+}
+
+// set ElementUI lang to EN
+// Vue.use(ElementUI, { locale })
+// 如果想要中文版 element-ui,按如下方式声明
+Vue.use(ElementUI)
+
+Vue.config.productionTip = false
+
+new Vue({
+    el: '#app',
+    router,
+    store,
+    render: h => h(App)
+})

+ 64 - 0
src/permission.js

@@ -0,0 +1,64 @@
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress' // progress bar
+import 'nprogress/nprogress.css' // progress bar style
+import { getToken } from '@/utils/auth' // get token from cookie
+import getPageTitle from '@/utils/get-page-title'
+
+NProgress.configure({ showSpinner: false }) // NProgress Configuration
+
+const whiteList = ['/login'] // no redirect whitelist
+
+// router.beforeEach(async(to, from, next) => {
+//   // start progress bar
+//   NProgress.start()
+
+//   // set page title
+//   document.title = getPageTitle(to.meta.title)
+
+//   // determine whether the user has logged in
+//   const hasToken = getToken()
+
+//   if (hasToken) {
+//     if (to.path === '/login') {
+//       // if is logged in, redirect to the home page
+//       next({ path: '/' })
+//       NProgress.done()
+//     } else {
+//       const hasGetUserInfo = store.getters.name
+//       if (hasGetUserInfo) {
+//         next()
+//       } else {
+//         try {
+//           // get user info
+//           await store.dispatch('user/getInfo')
+
+//           next()
+//         } catch (error) {
+//           // remove token and go to login page to re-login
+//           await store.dispatch('user/resetToken')
+//           Message.error(error || 'Has Error')
+//           next(`/login?redirect=${to.path}`)
+//           NProgress.done()
+//         }
+//       }
+//     }
+//   } else {
+//     /* has no token*/
+
+//     if (whiteList.indexOf(to.path) !== -1) {
+//       // in the free login whitelist, go directly
+//       next()
+//     } else {
+//       // other pages that do not have permission to access are redirected to the login page.
+//       next(`/login?redirect=${to.path}`)
+//       NProgress.done()
+//     }
+//   }
+// })
+
+router.afterEach(() => {
+    // finish progress bar
+    NProgress.done()
+})

+ 262 - 0
src/router/index.js

@@ -0,0 +1,262 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '@/layout'
+
+/**
+ * Note: sub-menu only appear when route children.length >= 1
+ * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
+ *
+ * hidden: true                   if set true, item will not show in the sidebar(default is false)
+ * alwaysShow: true               if set true, will always show the root menu
+ *                                if not set alwaysShow, when item has more than one children route,
+ *                                it will becomes nested mode, otherwise not show the root menu
+ * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
+ * name:'router-name'             the name is used by <keep-alive> (must set!!!)
+ * meta : {
+    roles: ['admin','editor']    control the page roles (you can set multiple roles)
+    title: 'title'               the name show in sidebar and breadcrumb (recommend set)
+    icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
+    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
+    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
+  }
+ */
+
+/**
+ * constantRoutes
+ * a base page that does not have permission requirements
+ * all roles can be accessed
+ */
+export const constantRoutes = [{
+        path: '/login',
+        component: () =>
+            import ('@/views/login/index'),
+        hidden: true
+    },
+
+    {
+        path: '/404',
+        component: () =>
+            import ('@/views/404'),
+        hidden: true
+    },
+
+    {
+        path: '/',
+        component: Layout,
+        redirect: '/index',
+        children: [{
+            path: 'index',
+            name: 'index',
+            component: () =>
+                import ('@/views/index/index'),
+            meta: { title: '首页', icon: 'home' }
+        }]
+    },
+
+    {
+        path: '/system',
+        component: Layout,
+        redirect: '/system/per-manage',
+        name: 'Example',
+        meta: { title: '系统管理', icon: 'system-manage' },
+        children: [{
+                path: 'per-manage',
+                name: 'Table',
+                component: () =>
+                    import ('@/views/system/per-manage/index'),
+                meta: { title: '人员管理', icon: 'per-manage' }
+            },
+            {
+                path: 'organization',
+                name: 'Tree2',
+                component: () =>
+                    import ('@/views/system/organization/index'),
+                meta: { title: '组织机构', icon: 'organization' }
+            },
+            {
+                path: 'auth-manage',
+                name: 'Tree3',
+                component: () =>
+                    import ('@/views/system/auth-manage/index'),
+                meta: { title: '权限管理', icon: 'auth-manage' }
+            },
+            {
+                path: 'security',
+                name: 'Tree4',
+                component: () =>
+                    import ('@/views/system/security/index'),
+                meta: { title: '安全机制', icon: 'security' }
+            },
+            {
+                path: 'unit-info',
+                name: 'Tree5',
+                component: () =>
+                    import ('@/views/system/unit-info/index'),
+                meta: { title: '单位信息', icon: 'unit' }
+            }
+
+        ]
+    },
+
+    {
+        path: '/user',
+        component: Layout,
+        redirect: '/user/account-manage',
+        name: 'Nested2',
+        meta: {
+            title: '用户管理',
+            icon: 'user-manage'
+        },
+        children: [{
+                path: 'account-manage',
+                component: () =>
+                    import ('@/views/user/account-manage/index'), // Parent router-view
+                name: 'Menu122',
+                meta: { title: '账号管理', icon: 'account-manage' },
+
+            },
+            {
+                path: 'log-manage',
+                component: () =>
+                    import ('@/views/user/log-manage/index'),
+                name: 'Menu222',
+                meta: { title: '日志管理', icon: 'log-manage' }
+            }
+        ]
+    },
+
+
+    {
+        path: '/device',
+        component: Layout,
+        redirect: '/device/camera',
+        name: 'Nested22',
+        meta: {
+            title: '设备管理',
+            icon: 'device-manage'
+        },
+        children: [{
+                path: 'camera2',
+                component: () =>
+                    import ('@/views/device/camera/index'), // Parent router-view
+                name: 'Menu12',
+                meta: { title: '摄像头', icon: 'camera' },
+
+            },
+            {
+                path: 'guard',
+                component: () =>
+                    import ('@/views/device/guard/index'),
+                name: 'Menu22',
+                meta: { title: '周界防范', icon: 'guard' }
+            }
+        ]
+    },
+
+
+    {
+        path: '/patrol',
+        component: Layout,
+        redirect: '/patrol/patrol-point',
+        name: 'patrol-manage',
+        meta: {
+            title: '巡检管理',
+            icon: 'patrol-manage'
+        },
+        children: [{
+                path: 'patrol-point',
+                component: () =>
+                    import ('@/views/patrol/patrol-point/index'), // Parent router-view
+                name: 'Menu1',
+                meta: { title: '巡检点', icon: 'patrol-point' },
+
+            },
+            {
+                path: 'patrol-route',
+                component: () =>
+                    import ('@/views/patrol/patrol-route/index'),
+                name: 'Menu2',
+                meta: { title: '巡检路线', icon: 'patrol-route' }
+            },
+            {
+                path: 'team',
+                component: () =>
+                    import ('@/views/patrol/team/index'),
+                name: 'Menu3',
+                meta: { title: '班组人员', icon: 'team' }
+            },
+            {
+                path: 'elect-partol',
+                component: () =>
+                    import ('@/views/patrol/elect-partol/index'),
+                name: 'Menu4',
+                meta: { title: '电子巡更', icon: 'elect' }
+            },
+            {
+                path: 'partol-plan',
+                component: () =>
+                    import ('@/views/patrol/partol-plan/index'),
+                name: 'Menu5',
+                meta: { title: '巡检计划', icon: 'patrol-plan' }
+            }
+        ]
+    },
+    {
+        path: '/alarm',
+        component: Layout,
+        redirect: '/alarm/alarm-log',
+        name: 'Nested111',
+        meta: {
+            title: '告警中心',
+            icon: 'alarm'
+        },
+        children: [{
+                path: 'alarm-log',
+                component: () =>
+                    import ('@/views/alarm/alarm-log/index'), // Parent router-view
+                name: 'Menu13',
+                meta: { title: '告警记录', icon: 'alarm-log' },
+
+            },
+            {
+                path: 'alarm-task',
+                component: () =>
+                    import ('@/views/alarm/alarm-task/index'),
+                name: 'Menu23',
+                meta: { title: '任务中心', icon: 'alarm-task' }
+            },
+
+        ]
+    },
+
+
+
+
+
+
+
+
+
+    // 404 page must be placed at the end !!!
+    { path: '*', redirect: '/404', hidden: true }
+]
+
+const createRouter = () => new Router({
+    // mode: 'history', // require service support
+    scrollBehavior: () => ({ y: 0 }),
+    routes: constantRoutes
+})
+
+const router = createRouter()
+
+// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
+export function resetRouter() {
+    const newRouter = createRouter()
+    router.matcher = newRouter.matcher // reset router
+}
+
+export default router

+ 16 - 0
src/settings.js

@@ -0,0 +1,16 @@
+module.exports = {
+
+    title: '综合安防',
+
+    /**
+     * @type {boolean} true | false
+     * @description Whether fix the header
+     */
+    fixedHeader: false,
+
+    /**
+     * @type {boolean} true | false
+     * @description Whether show the logo in sidebar
+     */
+    sidebarLogo: true
+}

+ 8 - 0
src/store/getters.js

@@ -0,0 +1,8 @@
+const getters = {
+  sidebar: state => state.app.sidebar,
+  device: state => state.app.device,
+  token: state => state.user.token,
+  avatar: state => state.user.avatar,
+  name: state => state.user.name
+}
+export default getters

+ 19 - 0
src/store/index.js

@@ -0,0 +1,19 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import getters from './getters'
+import app from './modules/app'
+import settings from './modules/settings'
+import user from './modules/user'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  modules: {
+    app,
+    settings,
+    user
+  },
+  getters
+})
+
+export default store

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä