Kaynağa Gözat

add Admin source file

vbea 3 yıl önce
ebeveyn
işleme
7e7cccdd7a
100 değiştirilmiş dosya ile 2911 ekleme ve 0 silme
  1. 7 0
      Strides-Admin/.env.development
  2. 7 0
      Strides-Admin/.env.production
  3. 8 0
      Strides-Admin/.env.staging
  4. 9 0
      Strides-Admin/Makefile
  5. 51 0
      Strides-Admin/README.md
  6. 14 0
      Strides-Admin/babel.config.js
  7. 37 0
      Strides-Admin/document/errorTable.txt
  8. 9 0
      Strides-Admin/jsconfig.json
  9. 68 0
      Strides-Admin/package.json
  10. 5 0
      Strides-Admin/postcss.config.js
  11. BIN
      Strides-Admin/public/favicon.ico
  12. 16 0
      Strides-Admin/public/index.html
  13. 11 0
      Strides-Admin/src/App.vue
  14. 41 0
      Strides-Admin/src/api/article.js
  15. 8 0
      Strides-Admin/src/api/qiniu.js
  16. 17 0
      Strides-Admin/src/api/remote-search.js
  17. 38 0
      Strides-Admin/src/api/role.js
  18. 23 0
      Strides-Admin/src/api/user.js
  19. BIN
      Strides-Admin/src/assets/form-list-add.png
  20. BIN
      Strides-Admin/src/assets/form-list-sub.png
  21. BIN
      Strides-Admin/src/assets/ic-delete.png
  22. BIN
      Strides-Admin/src/assets/ic-update.png
  23. BIN
      Strides-Admin/src/assets/ic_cluster.png
  24. BIN
      Strides-Admin/src/assets/ic_cluster_un.png
  25. BIN
      Strides-Admin/src/assets/ic_marker.png
  26. BIN
      Strides-Admin/src/assets/ic_marker_un.png
  27. BIN
      Strides-Admin/src/assets/logo.png
  28. BIN
      Strides-Admin/src/assets/navigation_account.png
  29. BIN
      Strides-Admin/src/assets/navigation_logout.png
  30. BIN
      Strides-Admin/src/assets/navigation_message.png
  31. BIN
      Strides-Admin/src/assets/navigation_notification.png
  32. 94 0
      Strides-Admin/src/components/Breadcrumb/index.vue
  33. 78 0
      Strides-Admin/src/components/ErrorLog/index.vue
  34. 44 0
      Strides-Admin/src/components/Hamburger/index.vue
  35. 180 0
      Strides-Admin/src/components/HeaderSearch/index.vue
  36. 117 0
      Strides-Admin/src/components/Pagination.vue
  37. 145 0
      Strides-Admin/src/components/RightPanel/index.vue
  38. 60 0
      Strides-Admin/src/components/Screenfull/index.vue
  39. 57 0
      Strides-Admin/src/components/SizeSelect/index.vue
  40. 70 0
      Strides-Admin/src/components/SvgIcon/index.vue
  41. 75 0
      Strides-Admin/src/components/TableAction.vue
  42. 175 0
      Strides-Admin/src/components/ThemePicker/index.vue
  43. 49 0
      Strides-Admin/src/directive/clipboard/clipboard.js
  44. 13 0
      Strides-Admin/src/directive/clipboard/index.js
  45. 77 0
      Strides-Admin/src/directive/el-drag-dialog/drag.js
  46. 13 0
      Strides-Admin/src/directive/el-drag-dialog/index.js
  47. 41 0
      Strides-Admin/src/directive/el-table/adaptive.js
  48. 13 0
      Strides-Admin/src/directive/el-table/index.js
  49. 13 0
      Strides-Admin/src/directive/permission/index.js
  50. 31 0
      Strides-Admin/src/directive/permission/permission.js
  51. 91 0
      Strides-Admin/src/directive/sticky.js
  52. 13 0
      Strides-Admin/src/directive/waves/index.js
  53. 26 0
      Strides-Admin/src/directive/waves/waves.css
  54. 72 0
      Strides-Admin/src/directive/waves/waves.js
  55. 39 0
      Strides-Admin/src/http/api/charge.js
  56. 15 0
      Strides-Admin/src/http/api/chargingProfile.js
  57. 11 0
      Strides-Admin/src/http/api/dashboard.js
  58. 67 0
      Strides-Admin/src/http/api/driver.js
  59. 12 0
      Strides-Admin/src/http/api/error.js
  60. 9 0
      Strides-Admin/src/http/api/feedback.js
  61. 47 0
      Strides-Admin/src/http/api/fleetCompany.js
  62. 12 0
      Strides-Admin/src/http/api/limit.js
  63. 8 0
      Strides-Admin/src/http/api/map.js
  64. 69 0
      Strides-Admin/src/http/api/ocpp.js
  65. 39 0
      Strides-Admin/src/http/api/posDevices.js
  66. 28 0
      Strides-Admin/src/http/api/provider.js
  67. 21 0
      Strides-Admin/src/http/api/reports.js
  68. 21 0
      Strides-Admin/src/http/api/settings.js
  69. 53 0
      Strides-Admin/src/http/api/site.js
  70. 10 0
      Strides-Admin/src/http/api/transaction.js
  71. 5 0
      Strides-Admin/src/http/api/upload.js
  72. 7 0
      Strides-Admin/src/http/api/user.js
  73. 59 0
      Strides-Admin/src/http/api/userManagement.js
  74. 138 0
      Strides-Admin/src/http/http.js
  75. 9 0
      Strides-Admin/src/icons/index.js
  76. BIN
      Strides-Admin/src/icons/logo.png
  77. 1 0
      Strides-Admin/src/icons/svg/404.svg
  78. 1 0
      Strides-Admin/src/icons/svg/administrator-active.svg
  79. 35 0
      Strides-Admin/src/icons/svg/administrator.svg
  80. 1 0
      Strides-Admin/src/icons/svg/bug.svg
  81. 49 0
      Strides-Admin/src/icons/svg/charge-station-management-active.svg
  82. 49 0
      Strides-Admin/src/icons/svg/charge-station-management.svg
  83. 12 0
      Strides-Admin/src/icons/svg/charging-profiles-active.svg
  84. 65 0
      Strides-Admin/src/icons/svg/charging-profiles.svg
  85. 1 0
      Strides-Admin/src/icons/svg/chart.svg
  86. 1 0
      Strides-Admin/src/icons/svg/clipboard.svg
  87. 1 0
      Strides-Admin/src/icons/svg/component.svg
  88. 4 0
      Strides-Admin/src/icons/svg/credit-limit-active.svg
  89. 4 0
      Strides-Admin/src/icons/svg/credit-limit.svg
  90. 6 0
      Strides-Admin/src/icons/svg/dashboard-active.svg
  91. 73 0
      Strides-Admin/src/icons/svg/dashboard.svg
  92. 1 0
      Strides-Admin/src/icons/svg/documentation.svg
  93. 1 0
      Strides-Admin/src/icons/svg/drag.svg
  94. 1 0
      Strides-Admin/src/icons/svg/edit.svg
  95. 1 0
      Strides-Admin/src/icons/svg/education.svg
  96. 1 0
      Strides-Admin/src/icons/svg/email.svg
  97. 3 0
      Strides-Admin/src/icons/svg/error-table-active.svg
  98. 3 0
      Strides-Admin/src/icons/svg/error-table.svg
  99. 1 0
      Strides-Admin/src/icons/svg/example.svg
  100. 1 0
      Strides-Admin/src/icons/svg/excel.svg

+ 7 - 0
Strides-Admin/.env.development

@@ -0,0 +1,7 @@
+NODE_ENV = 'development'
+# just a flag
+ENV = 'development'
+
+# base api
+VUE_APP_BASE_API = 'http://161.117.183.142/'
+VUE_APP_API_PREFIX = 'steve/crmApi'

+ 7 - 0
Strides-Admin/.env.production

@@ -0,0 +1,7 @@
+NODE_ENV = 'production'
+# just a flag
+ENV = 'production'
+
+# base api
+VUE_APP_BASE_API = 'https://csms.evctechnology.com/'
+VUE_APP_API_PREFIX = 'juiceplus/crmApi'

+ 8 - 0
Strides-Admin/.env.staging

@@ -0,0 +1,8 @@
+NODE_ENV = 'production'
+
+# just a flag
+ENV = 'staging'
+
+# base api
+VUE_APP_BASE_API = 'http://161.117.183.142/'
+VUE_APP_API_PREFIX = 'steve/crmApi'

+ 9 - 0
Strides-Admin/Makefile

@@ -0,0 +1,9 @@
+.PHONY: dist build
+install:
+	@npm install
+
+dev: install
+	@npm run dev
+
+build:
+	@npm run build

+ 51 - 0
Strides-Admin/README.md

@@ -0,0 +1,51 @@
+# Juice Plus Admin
+
+## Environment
+
+`Node >= 6`
+
+## Start
+
+``` bash
+yarn install
+#or
+npm install
+```
+
+## Develop
+
+``` bash
+# serve with hot reload at localhost:8010
+npm run dev
+#or
+yarn dev
+```
+
+## Build
+
+debug
+
+``` bash
+npm run build:stage
+#or
+yarn build:stage
+```
+
+release
+
+``` bash
+npm run build:prod
+#or
+yarn build:prod
+```
+
+
+## Document
+
+[Vue.js](https://cn.vuejs.org/v2/guide/)  
+[Element UI](https://cloud.tencent.com/developer/doc/1270)  
+[Vue Router](https://router.vuejs.org/zh/guide/)  
+[Vuex](https://vuex.vuejs.org/zh/guide/)  
+[Echarts](https://echarts.apache.org/zh/tutorial.html)  
+[Axios](http://www.axios-js.com/zh-cn/docs/)  
+[vue-element-admin](https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/)

+ 14 - 0
Strides-Admin/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']
+    }
+  }
+}

+ 37 - 0
Strides-Admin/document/errorTable.txt

@@ -0,0 +1,37 @@
+分页获取充电桩异常信息:
+api url:
+http://161.117.183.142/steve/crmApi/error/table/pages
+
+type:
+POST
+
+header:
+accessToken
+
+params:
+{
+    "pageSize": 10,
+    "pageNo": 1,
+    "pageVo": {
+        "criteria": ""
+    }
+}
+
+return:
+{
+    "code": 2000,
+    "success": true,
+    "msg": "Succeed.",
+    "data": [
+        {
+            "siteName": "Marina Country Club",
+            "chargeBoxId": "MCC-0001",
+            "status": "Faulted",
+            "errorCode": "OtherError",
+            "vendorErrorCode": "4024",
+            "statusTimestamp": "2021-11-23 11:06",
+            "connectorId": 0
+        }
+    ],
+    "total": 87
+}

+ 9 - 0
Strides-Admin/jsconfig.json

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

+ 68 - 0
Strides-Admin/package.json

@@ -0,0 +1,68 @@
+{
+  "name": "strides-admin",
+  "version": "0.0.1",
+  "description": "A Vue.js project",
+  "author": "vbe",
+  "private": true,
+  "scripts": {
+    "dev": "vue-cli-service serve",
+    "build:prod": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "dev-bak": "webpack-dev-server --inline --hot --env.dev",
+    "build": "rimraf dist && webpack -p --progress --hide-modules"
+  },
+  "dependencies": {
+    "@googlemaps/js-api-loader": "^1.12.1",
+    "@googlemaps/markerclustererplus": "^1.2.0",
+    "axios": "^0.21.1",
+    "babel-preset-es2015": "^6.24.1",
+    "core-js": "^3.14.0",
+    "echarts": "4.2.1",
+    "element-resize-detector": "^1.2.3",
+    "element-ui": "^2.15.2",
+    "fuse.js": "^3.4.4",
+    "js-base64": "^3.6.1",
+    "js-cookie": "^2.2.0",
+    "nprogress": "^0.2.0",
+    "path-to-regexp": "^6.2.0",
+    "screenfull": "^4.2.0",
+    "script-loader": "^0.7.2",
+    "vue": "^2.6.14",
+    "vue-router": "^3.5.1",
+    "vuex": "^3.6.2"
+  },
+  "engines": {
+    "node": ">=6"
+  },
+  "devDependencies": {
+    "@types/blueimp-md5": "^2.18.0",
+    "@types/echarts": "^4.9.9",
+    "@types/google.maps": "^3.45.4",
+    "@vue/cli-plugin-babel": "^4.5.13",
+    "@vue/cli-service": "^4.5.13",
+    "autoprefixer": "^6.6.0",
+    "babel-core": "^6.24.1",
+    "babel-loader": "^6.4.0",
+    "babel-plugin-dynamic-import-node": "^2.3.3",
+    "chalk": "^4.1.1",
+    "connect": "^3.7.0",
+    "css-loader": "^0.27.0",
+    "file-loader": "^0.10.1",
+    "html-webpack-plugin": "^2.24.1",
+    "mini-css-extract-plugin": "^2.1.0",
+    "postcss-loader": "^1.3.3",
+    "rimraf": "^2.5.4",
+    "sass": "^1.35.0",
+    "sass-loader": "^10.1.1",
+    "script-ext-html-webpack-plugin": "^2.1.5",
+    "serve-static": "^1.14.1",
+    "style-loader": "^0.13.2",
+    "svg-sprite-loader": "^4.1.3",
+    "svgo": "^1.2.0",
+    "url-loader": "^0.5.8",
+    "vue-loader": "^13.3.0",
+    "vue-template-compiler": "^2.6.14",
+    "webpack": "^2.4.1",
+    "webpack-dev-server": "^2.4.2"
+  }
+}

+ 5 - 0
Strides-Admin/postcss.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  plugins: [
+    require('autoprefixer')()
+  ]
+}

BIN
Strides-Admin/public/favicon.ico


+ 16 - 0
Strides-Admin/public/index.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<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>Juice Plus Admin</title>
+</head>
+
+<body>
+  <div id="app"></div>
+</body>
+
+</html>

+ 11 - 0
Strides-Admin/src/App.vue

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

+ 41 - 0
Strides-Admin/src/api/article.js

@@ -0,0 +1,41 @@
+import request from '@/utils/request'
+
+export function fetchList(query) {
+  return request({
+    url: '/vue-element-admin/article/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchArticle(id) {
+  return request({
+    url: '/vue-element-admin/article/detail',
+    method: 'get',
+    params: { id }
+  })
+}
+
+export function fetchPv(pv) {
+  return request({
+    url: '/vue-element-admin/article/pv',
+    method: 'get',
+    params: { pv }
+  })
+}
+
+export function createArticle(data) {
+  return request({
+    url: '/vue-element-admin/article/create',
+    method: 'post',
+    data
+  })
+}
+
+export function updateArticle(data) {
+  return request({
+    url: '/vue-element-admin/article/update',
+    method: 'post',
+    data
+  })
+}

+ 8 - 0
Strides-Admin/src/api/qiniu.js

@@ -0,0 +1,8 @@
+import request from '@/utils/request'
+
+export function getToken() {
+  return request({
+    url: '/qiniu/upload/token', // 假地址 自行替换
+    method: 'get'
+  })
+}

+ 17 - 0
Strides-Admin/src/api/remote-search.js

@@ -0,0 +1,17 @@
+import request from '@/utils/request'
+
+export function searchUser(name) {
+  return request({
+    url: '/vue-element-admin/search/user',
+    method: 'get',
+    params: { name }
+  })
+}
+
+export function transactionList(query) {
+  return request({
+    url: '/vue-element-admin/transaction/list',
+    method: 'get',
+    params: query
+  })
+}

+ 38 - 0
Strides-Admin/src/api/role.js

@@ -0,0 +1,38 @@
+import request from '@/utils/request'
+
+export function getRoutes() {
+  return request({
+    url: '/vue-element-admin/routes',
+    method: 'get'
+  })
+}
+
+export function getRoles() {
+  return request({
+    url: '/vue-element-admin/roles',
+    method: 'get'
+  })
+}
+
+export function addRole(data) {
+  return request({
+    url: '/vue-element-admin/role',
+    method: 'post',
+    data
+  })
+}
+
+export function updateRole(id, data) {
+  return request({
+    url: `/vue-element-admin/role/${id}`,
+    method: 'put',
+    data
+  })
+}
+
+export function deleteRole(id) {
+  return request({
+    url: `/vue-element-admin/role/${id}`,
+    method: 'delete'
+  })
+}

+ 23 - 0
Strides-Admin/src/api/user.js

@@ -0,0 +1,23 @@
+import request from '@/utils/request'
+
+const MODULE_NAME = "/user/"
+
+function getUserUrl(params) {
+  return MODULE_NAME + params.function
+}
+
+export function login(data) {
+  return request({
+    url: getUserUrl({ function: 'login' }),
+    method: 'post',
+    data
+  })
+}
+
+export function getInfo(token) {
+  return request({
+    url: '/vue-element-admin/user/info',
+    method: 'get',
+    params: { token }
+  })
+}

BIN
Strides-Admin/src/assets/form-list-add.png


BIN
Strides-Admin/src/assets/form-list-sub.png


BIN
Strides-Admin/src/assets/ic-delete.png


BIN
Strides-Admin/src/assets/ic-update.png


BIN
Strides-Admin/src/assets/ic_cluster.png


BIN
Strides-Admin/src/assets/ic_cluster_un.png


BIN
Strides-Admin/src/assets/ic_marker.png


BIN
Strides-Admin/src/assets/ic_marker_un.png


BIN
Strides-Admin/src/assets/logo.png


BIN
Strides-Admin/src/assets/navigation_account.png


BIN
Strides-Admin/src/assets/navigation_logout.png


BIN
Strides-Admin/src/assets/navigation_message.png


BIN
Strides-Admin/src/assets/navigation_notification.png


+ 94 - 0
Strides-Admin/src/components/Breadcrumb/index.vue

@@ -0,0 +1,94 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator-class="el-icon-arrow-right">
+    <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 }}
+          <template v-if="item.meta.subTitle">{{ item.meta.subTitle }}</template>
+        </span>
+        <a v-else @click.prevent="handleLink(item)">
+          {{ item.meta.title }}
+        </a>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+import { compile } from 'path-to-regexp'
+import VueRouter from 'vue-router'
+const { isNavigationFailure, NavigationFailureType } = VueRouter
+
+export default {
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route(route) {
+      // if you go to the redirect page, do not update the breadcrumbs
+      if (route.path.startsWith('/redirect/')) {
+        console.log('#####################################################')
+        return
+      }
+      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)
+
+      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+    },
+    pathCompile(path) {
+      // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
+      const { params } = this.$route
+      var toPath = compile(path)
+      return toPath(params)
+    },
+    handleLink(item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect).catch((failure) => {
+          if (!isNavigationFailure(failure, NavigationFailureType.duplicated)) {
+            //throw failure
+          }
+        })
+      } else {
+        this.$router.push(this.pathCompile(path)).catch((failure) => {
+          if (!isNavigationFailure(failure, NavigationFailureType.duplicated)) {
+            //throw failure
+          }
+        })
+
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../styles/variables.scss';
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: $navigationBarHeight;
+  margin-left: 8px;
+
+  .no-redirect {
+    color: #333333;
+    cursor: text;
+  }
+}
+</style>
+<style>
+  .el-breadcrumb__separator {
+    color: #555 !important;
+    font-weight: bold !important;
+  }
+</style>

+ 78 - 0
Strides-Admin/src/components/ErrorLog/index.vue

@@ -0,0 +1,78 @@
+<template>
+  <div v-if="errorLogs.length>0">
+    <el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
+      <el-button style="padding: 8px 10px;" size="small" type="danger">
+        <svg-icon icon-class="bug" />
+      </el-button>
+    </el-badge>
+
+    <el-dialog :visible.sync="dialogTableVisible" width="80%" append-to-body>
+      <div slot="title">
+        <span style="padding-right: 10px;">Error Log</span>
+        <el-button size="mini" type="primary" icon="el-icon-delete" @click="clearAll">Clear All</el-button>
+      </div>
+      <el-table :data="errorLogs" border>
+        <el-table-column label="Message">
+          <template slot-scope="{row}">
+            <div>
+              <span class="message-title">Msg:</span>
+              <el-tag type="danger">
+                {{ row.err.message }}
+              </el-tag>
+            </div>
+            <br>
+            <div>
+              <span class="message-title" style="padding-right: 10px;">Info: </span>
+              <el-tag type="warning">
+                {{ row.vm.$vnode.tag }} error in {{ row.info }}
+              </el-tag>
+            </div>
+            <br>
+            <div>
+              <span class="message-title" style="padding-right: 16px;">Url: </span>
+              <el-tag type="success">
+                {{ row.url }}
+              </el-tag>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="Stack">
+          <template slot-scope="scope">
+            {{ scope.row.err.stack }}
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ErrorLog',
+  data() {
+    return {
+      dialogTableVisible: false
+    }
+  },
+  computed: {
+    errorLogs() {
+      return this.$store.getters.errorLogs
+    }
+  },
+  methods: {
+    clearAll() {
+      this.dialogTableVisible = false
+      this.$store.dispatch('errorLog/clearErrorLog')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.message-title {
+  font-size: 16px;
+  color: #333;
+  font-weight: bold;
+  padding-right: 8px;
+}
+</style>

+ 44 - 0
Strides-Admin/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>

+ 180 - 0
Strides-Admin/src/components/HeaderSearch/index.vue

@@ -0,0 +1,180 @@
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+    <el-select
+      ref="headerSearchSelect"
+      v-model="search"
+      :remote-method="querySearch"
+      filterable
+      default-first-option
+      remote
+      placeholder="Search"
+      class="header-search-select"
+      @change="change"
+    >
+      <el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
+    </el-select>
+  </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js'
+import path from 'path'
+
+export default {
+  name: 'HeaderSearch',
+  data() {
+    return {
+      search: '',
+      options: [],
+      searchPool: [],
+      show: false,
+      fuse: undefined
+    }
+  },
+  computed: {
+    routes() {
+      return this.$store.getters.permission_routes
+    }
+  },
+  watch: {
+    routes() {
+      this.searchPool = this.generateRoutes(this.routes)
+    },
+    searchPool(list) {
+      this.initFuse(list)
+    },
+    show(value) {
+      if (value) {
+        document.body.addEventListener('click', this.close)
+      } else {
+        document.body.removeEventListener('click', this.close)
+      }
+    }
+  },
+  mounted() {
+    this.searchPool = this.generateRoutes(this.routes)
+  },
+  methods: {
+    click() {
+      this.show = !this.show
+      if (this.show) {
+        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+      }
+    },
+    close() {
+      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+      this.options = []
+      this.show = false
+    },
+    change(val) {
+      this.$router.push(val.path)
+      this.search = ''
+      this.options = []
+      this.$nextTick(() => {
+        this.show = false
+      })
+    },
+    initFuse(list) {
+      this.fuse = new Fuse(list, {
+        shouldSort: true,
+        threshold: 0.4,
+        location: 0,
+        distance: 100,
+        maxPatternLength: 32,
+        minMatchCharLength: 1,
+        keys: [{
+          name: 'title',
+          weight: 0.7
+        }, {
+          name: 'path',
+          weight: 0.3
+        }]
+      })
+    },
+    // Filter out the routes that can be displayed in the sidebar
+    // And generate the internationalized title
+    generateRoutes(routes, basePath = '/', prefixTitle = []) {
+      let res = []
+
+      for (const router of routes) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: path.resolve(basePath, router.path),
+          title: [...prefixTitle]
+        }
+
+        if (router.meta && router.meta.title) {
+          data.title = [...data.title, router.meta.title]
+
+          if (router.redirect !== 'noRedirect') {
+            // only push the routes with title
+            // special case: need to exclude parent router without redirect
+            res.push(data)
+          }
+        }
+
+        // recursive child routes
+        if (router.children) {
+          const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+          if (tempRoutes.length >= 1) {
+            res = [...res, ...tempRoutes]
+          }
+        }
+      }
+      return res
+    },
+    querySearch(query) {
+      if (query !== '') {
+        this.options = this.fuse.search(query)
+      } else {
+        this.options = []
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+  font-size: 0 !important;
+
+  .search-icon {
+    cursor: pointer;
+    font-size: 18px;
+    vertical-align: middle;
+  }
+
+  .header-search-select {
+    font-size: 18px;
+    transition: width 0.2s;
+    width: 0;
+    overflow: hidden;
+    background: transparent;
+    border-radius: 0;
+    display: inline-block;
+    vertical-align: middle;
+
+    ::v-deep .el-input__inner {
+      border-radius: 0;
+      border: 0;
+      padding-left: 0;
+      padding-right: 0;
+      box-shadow: none !important;
+      border-bottom: 1px solid #d9d9d9;
+      vertical-align: middle;
+    }
+  }
+
+  &.show {
+    .header-search-select {
+      width: 210px;
+      margin-left: 10px;
+    }
+  }
+}
+</style>

+ 117 - 0
Strides-Admin/src/components/Pagination.vue

@@ -0,0 +1,117 @@
+<template>
+  <div :class="{'hidden':hidden}" class="pagination-container">
+    <el-pagination
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :page-sizes="pageSizes"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+  name: 'Pagination',
+  props: {
+    total: {
+      required: true,
+      type: Number
+    },
+    page: {
+      type: Number,
+      default: 1
+    },
+    limit: {
+      type: Number,
+      default: 20
+    },
+    pageSizes: {
+      type: Array,
+      default() {
+        return [10, 20, 30, 50]
+      }
+    },
+    layout: {
+      type: String,
+      default: 'total, prev, pager, next, sizes'//, jumper'
+    },
+    background: {
+      type: Boolean,
+      default: true
+    },
+    autoScroll: {
+      type: Boolean,
+      default: true
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    currentPage: {
+      get() {
+        return this.page
+      },
+      set(val) {
+        this.$emit('update:page', val)
+      }
+    },
+    pageSize: {
+      get() {
+        return this.limit
+      },
+      set(val) {
+        this.$emit('update:limit', val)
+      }
+    }
+  },
+  methods: {
+    handleSizeChange(pageSize) {
+      this.$emit('pagination', { page: this.currentPage, limit: pageSize})
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    },
+    handleCurrentChange(page) {
+      this.$emit('pagination', { page, limit: this.pageSize })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped="scoped">
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+.pagination-container >>> .el-pagination.is-background .el-pager li:not(.disabled) {
+  color: #333;
+  border: 1px solid #eee;
+  background-color: white;
+}
+.pagination-container >>> .el-pagination.is-background .el-pager li:not(.disabled).active {
+  background-color: #001489;
+}
+.pagination-container >>> .btn-prev,
+.pagination-container >>> .btn-next {
+  border: 1px solid #eee;
+  background-color: white;
+}
+.pagination-container >>> .el-pagination__total {
+  color: #333;
+}
+</style>

+ 145 - 0
Strides-Admin/src/components/RightPanel/index.vue

@@ -0,0 +1,145 @@
+<template>
+  <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
+    <div class="rightPanel-background" />
+    <div class="rightPanel">
+      <div class="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
+        <i :class="show?'el-icon-close':'el-icon-setting'" />
+      </div>
+      <div class="rightPanel-items">
+        <slot />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { addClass, removeClass } from '@/utils'
+
+export default {
+  name: 'RightPanel',
+  props: {
+    clickNotClose: {
+      default: false,
+      type: Boolean
+    },
+    buttonTop: {
+      default: 250,
+      type: Number
+    }
+  },
+  data() {
+    return {
+      show: false
+    }
+  },
+  computed: {
+    theme() {
+      return this.$store.state.settings.theme
+    }
+  },
+  watch: {
+    show(value) {
+      if (value && !this.clickNotClose) {
+        this.addEventClick()
+      }
+      if (value) {
+        addClass(document.body, 'showRightPanel')
+      } else {
+        removeClass(document.body, 'showRightPanel')
+      }
+    }
+  },
+  mounted() {
+    this.insertToBody()
+  },
+  beforeDestroy() {
+    const elx = this.$refs.rightPanel
+    elx.remove()
+  },
+  methods: {
+    addEventClick() {
+      window.addEventListener('click', this.closeSidebar)
+    },
+    closeSidebar(evt) {
+      const parent = evt.target.closest('.rightPanel')
+      if (!parent) {
+        this.show = false
+        window.removeEventListener('click', this.closeSidebar)
+      }
+    },
+    insertToBody() {
+      const elx = this.$refs.rightPanel
+      const body = document.querySelector('body')
+      body.insertBefore(elx, body.firstChild)
+    }
+  }
+}
+</script>
+
+<style>
+.showRightPanel {
+  overflow: hidden;
+  position: relative;
+  width: calc(100% - 15px);
+}
+</style>
+
+<style lang="scss" scoped>
+.rightPanel-background {
+  position: fixed;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+  background: rgba(0, 0, 0, .2);
+  z-index: -1;
+}
+
+.rightPanel {
+  width: 100%;
+  max-width: 260px;
+  height: 100vh;
+  position: fixed;
+  top: 0;
+  right: 0;
+  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+  transition: all .25s cubic-bezier(.7, .3, .1, 1);
+  transform: translate(100%);
+  background: #fff;
+  z-index: 40000;
+}
+
+.show {
+  transition: all .3s cubic-bezier(.7, .3, .1, 1);
+
+  .rightPanel-background {
+    z-index: 20000;
+    opacity: 1;
+    width: 100%;
+    height: 100%;
+  }
+
+  .rightPanel {
+    transform: translate(0);
+  }
+}
+
+.handle-button {
+  width: 48px;
+  height: 48px;
+  position: absolute;
+  left: -48px;
+  text-align: center;
+  font-size: 24px;
+  border-radius: 6px 0 0 6px !important;
+  z-index: 0;
+  pointer-events: auto;
+  cursor: pointer;
+  color: #fff;
+  line-height: 48px;
+  i {
+    font-size: 24px;
+    line-height: 48px;
+  }
+}
+</style>

+ 60 - 0
Strides-Admin/src/components/Screenfull/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <div>
+    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'Screenfull',
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  mounted() {
+    this.init()
+  },
+  beforeDestroy() {
+    this.destroy()
+  },
+  methods: {
+    click() {
+      if (!screenfull.enabled) {
+        this.$message({
+          message: 'you browser can not work',
+          type: 'warning'
+        })
+        return false
+      }
+      screenfull.toggle()
+    },
+    change() {
+      this.isFullscreen = screenfull.isFullscreen
+    },
+    init() {
+      if (screenfull.enabled) {
+        screenfull.on('change', this.change)
+      }
+    },
+    destroy() {
+      if (screenfull.enabled) {
+        screenfull.off('change', this.change)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>

+ 57 - 0
Strides-Admin/src/components/SizeSelect/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <el-dropdown trigger="click" @command="handleSetSize">
+    <div>
+      <svg-icon class-name="size-icon" icon-class="size" />
+    </div>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+        {{
+          item.label }}
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      sizeOptions: [
+        { label: 'Default', value: 'default' },
+        { label: 'Medium', value: 'medium' },
+        { label: 'Small', value: 'small' },
+        { label: 'Mini', value: 'mini' }
+      ]
+    }
+  },
+  computed: {
+    size() {
+      return this.$store.getters.size
+    }
+  },
+  methods: {
+    handleSetSize(size) {
+      this.$ELEMENT.size = size
+      this.$store.dispatch('app/setSize', size)
+      this.refreshView()
+      this.$message({
+        message: 'Switch Size Success',
+        type: 'success'
+      })
+    },
+    refreshView() {
+      // In order to make the cached page re-rendered
+      this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+      const { fullPath } = this.$route
+
+      this.$nextTick(() => {
+        this.$router.replace({
+          path: '/redirect' + fullPath
+        })
+      })
+    }
+  }
+
+}
+</script>

+ 70 - 0
Strides-Admin/src/components/SvgIcon/index.vue

@@ -0,0 +1,70 @@
+<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>

+ 75 - 0
Strides-Admin/src/components/TableAction.vue

@@ -0,0 +1,75 @@
+<template>
+  <div class="table-actions">
+    <div class="table-action action-edit" @click="handleEdit()" v-if="showEdit">
+      <img src="../assets/ic-update.png"/>
+      <span>Edit</span>
+     </div>
+    <div class="table-action action-delete" @click="handleDelete()" v-if="showDel">
+      <img src="../assets/ic-delete.png" />
+      <span>Delete</span>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'TableAction',
+    props: {
+      showDel: {
+        type: Boolean,
+        default: true
+      },
+      showEdit: {
+        type: Boolean,
+        default: true
+      }
+    },
+    methods: {
+      handleEdit() {
+        this.$emit('edit');
+      },
+      handleDelete() {
+        this.$emit('delete');
+      }
+    }
+  }
+</script>
+
+<style lang="scss">
+  .table-actions {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+  .table-action {
+    padding: 0 14px;
+    font-size: 14px;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    position: relative;
+    & span {
+      white-space: nowrap;
+    }
+    & + .table-action::before {
+      left: 0;
+      height: 14px;
+      content: " ";
+      position: absolute;
+      border-left: 1px solid #999;
+    }
+  }
+  .action-edit {
+    color: #3179E4;
+    img {
+      width: 15px;
+      margin-right: 5px;
+    }
+  }
+  .action-delete {
+    color: #ED3F3F;
+    img {
+      width: 20px;
+    }
+  }
+</style>

+ 175 - 0
Strides-Admin/src/components/ThemePicker/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+  />
+</template>
+
+<script>
+const version = require('element-ui/package.json').version // element-ui version from node_modules
+const ORIGINAL_THEME = '#409EFF' // default color
+
+export default {
+  data() {
+    return {
+      chalk: '', // content of theme-chalk css
+      theme: ''
+    }
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme
+    }
+  },
+  watch: {
+    defaultTheme: {
+      handler: function(val, oldVal) {
+        this.theme = val
+      },
+      immediate: true
+    },
+    async theme(val) {
+      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
+      if (typeof val !== 'string') return
+      const themeCluster = this.getThemeCluster(val.replace('#', ''))
+      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+      console.log(themeCluster, originalCluster)
+
+      const $message = this.$message({
+        message: '  Compiling the theme',
+        customClass: 'theme-message',
+        type: 'success',
+        duration: 0,
+        iconClass: 'el-icon-loading'
+      })
+
+      const getHandler = (variable, id) => {
+        return () => {
+          const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+          const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+          let styleTag = document.getElementById(id)
+          if (!styleTag) {
+            styleTag = document.createElement('style')
+            styleTag.setAttribute('id', id)
+            document.head.appendChild(styleTag)
+          }
+          styleTag.innerText = newStyle
+        }
+      }
+
+      if (!this.chalk) {
+        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+        await this.getCSSString(url, 'chalk')
+      }
+
+      const chalkHandler = getHandler('chalk', 'chalk-style')
+
+      chalkHandler()
+
+      const styles = [].slice.call(document.querySelectorAll('style'))
+        .filter(style => {
+          const text = style.innerText
+          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+        })
+      styles.forEach(style => {
+        const { innerText } = style
+        if (typeof innerText !== 'string') return
+        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+      })
+
+      this.$emit('change', val)
+
+      $message.close()
+    }
+  },
+
+  methods: {
+    updateStyle(style, oldCluster, newCluster) {
+      let newStyle = style
+      oldCluster.forEach((color, index) => {
+        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+      })
+      return newStyle
+    },
+
+    getCSSString(url, variable) {
+      return new Promise(resolve => {
+        const xhr = new XMLHttpRequest()
+        xhr.onreadystatechange = () => {
+          if (xhr.readyState === 4 && xhr.status === 200) {
+            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+            resolve()
+          }
+        }
+        xhr.open('GET', url)
+        xhr.send()
+      })
+    },
+
+    getThemeCluster(theme) {
+      const tintColor = (color, tint) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        if (tint === 0) { // when primary color is in its rgb space
+          return [red, green, blue].join(',')
+        } else {
+          red += Math.round(tint * (255 - red))
+          green += Math.round(tint * (255 - green))
+          blue += Math.round(tint * (255 - blue))
+
+          red = red.toString(16)
+          green = green.toString(16)
+          blue = blue.toString(16)
+
+          return `#${red}${green}${blue}`
+        }
+      }
+
+      const shadeColor = (color, shade) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        red = Math.round((1 - shade) * red)
+        green = Math.round((1 - shade) * green)
+        blue = Math.round((1 - shade) * blue)
+
+        red = red.toString(16)
+        green = green.toString(16)
+        blue = blue.toString(16)
+
+        return `#${red}${green}${blue}`
+      }
+
+      const clusters = [theme]
+      for (let i = 0; i <= 9; i++) {
+        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+      }
+      clusters.push(shadeColor(theme, 0.1))
+      return clusters
+    }
+  }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>

+ 49 - 0
Strides-Admin/src/directive/clipboard/clipboard.js

@@ -0,0 +1,49 @@
+// Inspired by https://github.com/Inndy/vue-clipboard2
+const Clipboard = require('clipboard')
+if (!Clipboard) {
+  throw new Error('you should npm install `clipboard` --save at first ')
+}
+
+export default {
+  bind(el, binding) {
+    if (binding.arg === 'success') {
+      el._v_clipboard_success = binding.value
+    } else if (binding.arg === 'error') {
+      el._v_clipboard_error = binding.value
+    } else {
+      const clipboard = new Clipboard(el, {
+        text() { return binding.value },
+        action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+      })
+      clipboard.on('success', e => {
+        const callback = el._v_clipboard_success
+        callback && callback(e) // eslint-disable-line
+      })
+      clipboard.on('error', e => {
+        const callback = el._v_clipboard_error
+        callback && callback(e) // eslint-disable-line
+      })
+      el._v_clipboard = clipboard
+    }
+  },
+  update(el, binding) {
+    if (binding.arg === 'success') {
+      el._v_clipboard_success = binding.value
+    } else if (binding.arg === 'error') {
+      el._v_clipboard_error = binding.value
+    } else {
+      el._v_clipboard.text = function() { return binding.value }
+      el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+    }
+  },
+  unbind(el, binding) {
+    if (binding.arg === 'success') {
+      delete el._v_clipboard_success
+    } else if (binding.arg === 'error') {
+      delete el._v_clipboard_error
+    } else {
+      el._v_clipboard.destroy()
+      delete el._v_clipboard
+    }
+  }
+}

+ 13 - 0
Strides-Admin/src/directive/clipboard/index.js

@@ -0,0 +1,13 @@
+import Clipboard from './clipboard'
+
+const install = function(Vue) {
+  Vue.directive('Clipboard', Clipboard)
+}
+
+if (window.Vue) {
+  window.clipboard = Clipboard
+  Vue.use(install); // eslint-disable-line
+}
+
+Clipboard.install = install
+export default Clipboard

+ 77 - 0
Strides-Admin/src/directive/el-drag-dialog/drag.js

@@ -0,0 +1,77 @@
+export default {
+  bind(el, binding, vnode) {
+    const dialogHeaderEl = el.querySelector('.el-dialog__header')
+    const dragDom = el.querySelector('.el-dialog')
+    dialogHeaderEl.style.cssText += ';cursor:move;'
+    dragDom.style.cssText += ';top:0px;'
+
+    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
+    const getStyle = (function() {
+      if (window.document.currentStyle) {
+        return (dom, attr) => dom.currentStyle[attr]
+      } else {
+        return (dom, attr) => getComputedStyle(dom, false)[attr]
+      }
+    })()
+
+    dialogHeaderEl.onmousedown = (e) => {
+      // 鼠标按下,计算当前元素距离可视区的距离
+      const disX = e.clientX - dialogHeaderEl.offsetLeft
+      const disY = e.clientY - dialogHeaderEl.offsetTop
+
+      const dragDomWidth = dragDom.offsetWidth
+      const dragDomHeight = dragDom.offsetHeight
+
+      const screenWidth = document.body.clientWidth
+      const screenHeight = document.body.clientHeight
+
+      const minDragDomLeft = dragDom.offsetLeft
+      const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
+
+      const minDragDomTop = dragDom.offsetTop
+      const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight
+
+      // 获取到的值带px 正则匹配替换
+      let styL = getStyle(dragDom, 'left')
+      let styT = getStyle(dragDom, 'top')
+
+      if (styL.includes('%')) {
+        styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
+        styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
+      } else {
+        styL = +styL.replace(/\px/g, '')
+        styT = +styT.replace(/\px/g, '')
+      }
+
+      document.onmousemove = function(e) {
+        // 通过事件委托,计算移动的距离
+        let left = e.clientX - disX
+        let top = e.clientY - disY
+
+        // 边界处理
+        if (-(left) > minDragDomLeft) {
+          left = -minDragDomLeft
+        } else if (left > maxDragDomLeft) {
+          left = maxDragDomLeft
+        }
+
+        if (-(top) > minDragDomTop) {
+          top = -minDragDomTop
+        } else if (top > maxDragDomTop) {
+          top = maxDragDomTop
+        }
+
+        // 移动当前元素
+        dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
+
+        // emit onDrag event
+        vnode.child.$emit('dragDialog')
+      }
+
+      document.onmouseup = function(e) {
+        document.onmousemove = null
+        document.onmouseup = null
+      }
+    }
+  }
+}

+ 13 - 0
Strides-Admin/src/directive/el-drag-dialog/index.js

@@ -0,0 +1,13 @@
+import drag from './drag'
+
+const install = function(Vue) {
+  Vue.directive('el-drag-dialog', drag)
+}
+
+if (window.Vue) {
+  window['el-drag-dialog'] = drag
+  Vue.use(install); // eslint-disable-line
+}
+
+drag.install = install
+export default drag

+ 41 - 0
Strides-Admin/src/directive/el-table/adaptive.js

@@ -0,0 +1,41 @@
+import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event'
+
+/**
+ * How to use
+ * <el-table height="100px" v-el-height-adaptive-table="{bottomOffset: 30}">...</el-table>
+ * el-table height is must be set
+ * bottomOffset: 30(default)   // The height of the table from the bottom of the page.
+ */
+
+const doResize = (el, binding, vnode) => {
+  const { componentInstance: $table } = vnode
+
+  const { value } = binding
+
+  if (!$table.height) {
+    throw new Error(`el-$table must set the height. Such as height='100px'`)
+  }
+  const bottomOffset = (value && value.bottomOffset) || 30
+
+  if (!$table) return
+
+  const height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset
+  $table.layout.setHeight(height)
+  $table.doLayout()
+}
+
+export default {
+  bind(el, binding, vnode) {
+    el.resizeListener = () => {
+      doResize(el, binding, vnode)
+    }
+    // parameter 1 is must be "Element" type
+    addResizeListener(window.document.body, el.resizeListener)
+  },
+  inserted(el, binding, vnode) {
+    doResize(el, binding, vnode)
+  },
+  unbind(el) {
+    removeResizeListener(window.document.body, el.resizeListener)
+  }
+}

+ 13 - 0
Strides-Admin/src/directive/el-table/index.js

@@ -0,0 +1,13 @@
+import adaptive from './adaptive'
+
+const install = function(Vue) {
+  Vue.directive('el-height-adaptive-table', adaptive)
+}
+
+if (window.Vue) {
+  window['el-height-adaptive-table'] = adaptive
+  Vue.use(install); // eslint-disable-line
+}
+
+adaptive.install = install
+export default adaptive

+ 13 - 0
Strides-Admin/src/directive/permission/index.js

@@ -0,0 +1,13 @@
+import permission from './permission'
+
+const install = function(Vue) {
+  Vue.directive('permission', permission)
+}
+
+if (window.Vue) {
+  window['permission'] = permission
+  Vue.use(install); // eslint-disable-line
+}
+
+permission.install = install
+export default permission

+ 31 - 0
Strides-Admin/src/directive/permission/permission.js

@@ -0,0 +1,31 @@
+import store from '@/store'
+
+function checkPermission(el, binding) {
+  const { value } = binding
+  const roles = store.getters && store.getters.roles
+
+  if (value && value instanceof Array) {
+    if (value.length > 0) {
+      const permissionRoles = value
+
+      const hasPermission = roles.some(role => {
+        return permissionRoles.includes(role)
+      })
+
+      if (!hasPermission) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    }
+  } else {
+    throw new Error(`need roles! Like v-permission="['admin','editor']"`)
+  }
+}
+
+export default {
+  inserted(el, binding) {
+    checkPermission(el, binding)
+  },
+  update(el, binding) {
+    checkPermission(el, binding)
+  }
+}

+ 91 - 0
Strides-Admin/src/directive/sticky.js

@@ -0,0 +1,91 @@
+const vueSticky = {}
+let listenAction
+vueSticky.install = Vue => {
+  Vue.directive('sticky', {
+    inserted(el, binding) {
+      const params = binding.value || {}
+      const stickyTop = params.stickyTop || 0
+      const zIndex = params.zIndex || 1000
+      const elStyle = el.style
+
+      elStyle.position = '-webkit-sticky'
+      elStyle.position = 'sticky'
+      // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
+      // if (~elStyle.position.indexOf('sticky')) {
+      //     elStyle.top = `${stickyTop}px`;
+      //     elStyle.zIndex = zIndex;
+      //     return
+      // }
+      const elHeight = el.getBoundingClientRect().height
+      const elWidth = el.getBoundingClientRect().width
+      elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
+
+      const parentElm = el.parentNode || document.documentElement
+      const placeholder = document.createElement('div')
+      placeholder.style.display = 'none'
+      placeholder.style.width = `${elWidth}px`
+      placeholder.style.height = `${elHeight}px`
+      parentElm.insertBefore(placeholder, el)
+
+      let active = false
+
+      const getScroll = (target, top) => {
+        const prop = top ? 'pageYOffset' : 'pageXOffset'
+        const method = top ? 'scrollTop' : 'scrollLeft'
+        let ret = target[prop]
+        if (typeof ret !== 'number') {
+          ret = window.document.documentElement[method]
+        }
+        return ret
+      }
+
+      const sticky = () => {
+        if (active) {
+          return
+        }
+        if (!elStyle.height) {
+          elStyle.height = `${el.offsetHeight}px`
+        }
+
+        elStyle.position = 'fixed'
+        elStyle.width = `${elWidth}px`
+        placeholder.style.display = 'inline-block'
+        active = true
+      }
+
+      const reset = () => {
+        if (!active) {
+          return
+        }
+
+        elStyle.position = ''
+        placeholder.style.display = 'none'
+        active = false
+      }
+
+      const check = () => {
+        const scrollTop = getScroll(window, true)
+        const offsetTop = el.getBoundingClientRect().top
+        if (offsetTop < stickyTop) {
+          sticky()
+        } else {
+          if (scrollTop < elHeight + stickyTop) {
+            reset()
+          }
+        }
+      }
+      listenAction = () => {
+        check()
+      }
+
+      window.addEventListener('scroll', listenAction)
+    },
+
+    unbind() {
+      window.removeEventListener('scroll', listenAction)
+    }
+  })
+}
+
+export default vueSticky
+

+ 13 - 0
Strides-Admin/src/directive/waves/index.js

@@ -0,0 +1,13 @@
+import waves from './waves'
+
+const install = function(Vue) {
+  Vue.directive('waves', waves)
+}
+
+if (window.Vue) {
+  window.waves = waves
+  Vue.use(install); // eslint-disable-line
+}
+
+waves.install = install
+export default waves

+ 26 - 0
Strides-Admin/src/directive/waves/waves.css

@@ -0,0 +1,26 @@
+.waves-ripple {
+    position: absolute;
+    border-radius: 100%;
+    background-color: rgba(0, 0, 0, 0.15);
+    background-clip: padding-box;
+    pointer-events: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    -webkit-transform: scale(0);
+    -ms-transform: scale(0);
+    transform: scale(0);
+    opacity: 1;
+}
+
+.waves-ripple.z-active {
+    opacity: 0;
+    -webkit-transform: scale(2);
+    -ms-transform: scale(2);
+    transform: scale(2);
+    -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
+}

+ 72 - 0
Strides-Admin/src/directive/waves/waves.js

@@ -0,0 +1,72 @@
+import './waves.css'
+
+const context = '@@wavesContext'
+
+function handleClick(el, binding) {
+  function handle(e) {
+    const customOpts = Object.assign({}, binding.value)
+    const opts = Object.assign({
+      ele: el, // 波纹作用元素
+      type: 'hit', // hit 点击位置扩散 center中心点扩展
+      color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
+    },
+    customOpts
+    )
+    const target = opts.ele
+    if (target) {
+      target.style.position = 'relative'
+      target.style.overflow = 'hidden'
+      const rect = target.getBoundingClientRect()
+      let ripple = target.querySelector('.waves-ripple')
+      if (!ripple) {
+        ripple = document.createElement('span')
+        ripple.className = 'waves-ripple'
+        ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
+        target.appendChild(ripple)
+      } else {
+        ripple.className = 'waves-ripple'
+      }
+      switch (opts.type) {
+        case 'center':
+          ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
+          ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
+          break
+        default:
+          ripple.style.top =
+            (e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
+              document.body.scrollTop) + 'px'
+          ripple.style.left =
+            (e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
+              document.body.scrollLeft) + 'px'
+      }
+      ripple.style.backgroundColor = opts.color
+      ripple.className = 'waves-ripple z-active'
+      return false
+    }
+  }
+
+  if (!el[context]) {
+    el[context] = {
+      removeHandle: handle
+    }
+  } else {
+    el[context].removeHandle = handle
+  }
+
+  return handle
+}
+
+export default {
+  bind(el, binding) {
+    el.addEventListener('click', handleClick(el, binding), false)
+  },
+  update(el, binding) {
+    el.removeEventListener('click', el[context].removeHandle, false)
+    el.addEventListener('click', handleClick(el, binding), false)
+  },
+  unbind(el) {
+    el.removeEventListener('click', el[context].removeHandle, false)
+    el[context] = null
+    delete el[context]
+  }
+}

+ 39 - 0
Strides-Admin/src/http/api/charge.js

@@ -0,0 +1,39 @@
+import {get, post} from '../http'
+
+const charge = {
+  getStationPages: (params) => {
+    return post('station/getStationPages', params)
+  },
+  addStation: (params) => {
+    return post('station/addStation', params)
+  },
+  getStationInfo: (params) => {
+    return get('station/getStationInfo', params)
+  },
+  updateStation: (params) => {
+    return post('station/updateStation', params)
+  },
+  deleteStation: (params) => {
+    return get('station/delStation', params)
+  },
+  getUnknownStationPages: (params) => {
+    return post('station/getUnknownStationPages', params)
+  },
+  getConnectorList: (params) => {
+    return post('station/getConnectorStatusPages', params)
+  },
+  getAllStationList: (params) => {
+    return get('station/getAllStationList', params)
+  },
+  getStatusList: () => {
+    return get('station/getStatusList')
+  },
+  getHeartbeatPeriodList: () => {
+    return get('station/getHeartbeatPeriodList')
+  },
+  getRegistrationStatusList: () => {
+    return get('station/getRegistrationStatusList')
+  }
+}
+
+export default charge;

+ 15 - 0
Strides-Admin/src/http/api/chargingProfile.js

@@ -0,0 +1,15 @@
+import {get, post} from '../http'
+
+const profile = {
+  addChargingProfile: (params) => post('chargingProfile/addChargingProfile', params),
+  delChargingProfile: (params) => get('chargingProfile/delChargingProfile', {chargingProfilePk: params}),
+  getPurposeOptionList: () => get('chargingProfile/getChargingProfilePurposeList'),
+  getKindOptionList: () => get('chargingProfile/getChargingProfileKindList'),
+  getRecurrencyKindList: () => get('chargingProfile/getRecurrencyKindList'),
+  getChargingRateUnitList: () => get('chargingProfile/getChargingRateUnitList'),
+  getChargingProfileById: (params) => get('chargingProfile/getChargingProfile', {chargingProfilePk: params}),
+  getChargingProfilePages: (params) => post('chargingProfile/getChargingProfilePages', params),
+  updateChargingProfile: (params) => post('chargingProfile/updateChargingProfile', params)
+}
+
+export default profile;

+ 11 - 0
Strides-Admin/src/http/api/dashboard.js

@@ -0,0 +1,11 @@
+import {get, post} from '../http'
+
+const dashboard = {
+  getProviderList: () => get('dashboard/getProviderList'),
+  getHourlyUtilization: (providerPk) => get('dashboard/getHourlyUtilization', {providerPk}),
+  getCardSection: (providerPk) => get('dashboard/getCardSection', {providerPk}),
+  getRangeTab: () => get('dashboard/getBottomTab'),
+  getBarChart: (params) => get('dashboard/getBottomChart', params)
+}
+
+export default dashboard

+ 67 - 0
Strides-Admin/src/http/api/driver.js

@@ -0,0 +1,67 @@
+import { get, post } from '../http'
+
+// {
+//   "pageSize": 10,
+//   "pageNo": 1,
+//   "pageVo": {
+//     "criteria": "test"
+//   }
+// }
+export function fetchDriverPages(data) {
+  return post('driver/getDriverPages', data)
+}
+
+// userPk
+export function fetchDriverDetail(params) {
+  return get('driver/getDriverDetail', params)
+}
+
+// {
+//   "fleetCompanyId": 1,
+//   "nickName": "nickName",
+//   "email": "email@qq.com",
+//   "pdvLicence": "132321321321323",
+//   "phone": 13122222222,
+//   "pdvLicencePictures": [
+//     "/juicePicture/userProfile/906c9fe4bae144bf8f2b85b4dff6b336.jpg",
+//     "/juicePicture/userProfile/906c9fe4bae144bf8f2b85b4dff6b336.jpg"
+//   ]
+// }
+export function addDriver(data) {
+  return post('driver/addDriver', data)
+}
+
+// {
+//   "userPk": 109,
+//   "fleetCompanyId": 1,
+//   "nickName": "nickName1",
+//   "email": "email@qq.com",
+//   "pdvLicence": "132321321321323",
+//   "phone": 13122222222,
+//   "pdvLicencePictures": [
+//     "/juicePicture/userProfile/906c9fe4bae144bf8f2b85b4dff6b336.jpg",
+//     "/juicePicture/userProfile/906c9fe4bae144bf8f2b85b4dff6b336.jpg"
+//   ]
+// }
+export function updateDriver(data) {
+  return post('driver/updateDriver', data)
+}
+
+// userPk
+export function deleteDriver(params) {
+  return get('driver/delDriver', params)
+}
+
+// userPk
+export function approveDriver(params) {
+  return get('driver/approveDriver', params)
+}
+
+// userPk
+export function rejectDriver(params) {
+  return get('driver/rejectDriver', params)
+}
+
+export function fetchFleetCompanyOptions() {
+  return get('siteManagement/getFleetCompanyList')
+}

+ 12 - 0
Strides-Admin/src/http/api/error.js

@@ -0,0 +1,12 @@
+import { get, post } from '../http'
+
+// {
+//   "pageSize": 10,
+//   "pageNo": 1,
+//   "pageVo": {
+//     "criteria": "test"
+//   }
+// }
+export function fetchErrorPages(data) {
+  return post('error/table/pages', data)
+}

+ 9 - 0
Strides-Admin/src/http/api/feedback.js

@@ -0,0 +1,9 @@
+import {get, post} from '../http'
+
+const feedback = {
+  getFeedbackPages: (params) => post('feedback/getFeedbackPages', params),
+  deleteFeedback: (id) => get('feedback/delFeedback', {feedbackPk: id}),
+  readFeedback: (id) => get('feedback/readFeedback', {feedbackPk: id})
+}
+
+export default feedback;

+ 47 - 0
Strides-Admin/src/http/api/fleetCompany.js

@@ -0,0 +1,47 @@
+import { get, post } from '../http'
+
+// {
+//   "pageSize": 10,
+//   "pageNo": 1,
+//   "pageVo": {
+//     "criteria": ""
+//   }
+// }
+export function fetchFleetCompanyPages(data) {
+  return post('fleetCompany/getFleetCompanyPages', data)
+}
+
+// {
+//   "fleetCompanyName": "fleetCompanyName123",
+//   "fleetCompanyType": "Private",
+//   "contactPerson": "contactPerson",
+//   "contactNumber": "8008208820"
+// }
+export function addFleetCompany(data) {
+  return post('fleetCompany/addFleetCompany', data)
+}
+
+// {
+//   "fleetCompanyId": 2,
+//   "fleetCompanyName": "fleetCompanyName",
+//   "fleetCompanyType": "Private",
+//   "contactPerson": "contactPerson",
+//   "contactNumber": "8008208820"
+// }
+export function updateFleetCompany(data) {
+  return post('fleetCompany/updateFleetCompany', data)
+}
+
+// fleetCompanyId
+export function fetchFleetCompanyDetail(params) {
+  return get('fleetCompany/getFleetCompany', params)
+}
+
+// fleetCompanyId
+export function deleteFleetCompany(params) {
+  return get('fleetCompany/delFleetCompany', params)
+}
+
+export function fetchFleetCompanyType() {
+  return get('fleetCompany/getFleetCompanyType')
+}

+ 12 - 0
Strides-Admin/src/http/api/limit.js

@@ -0,0 +1,12 @@
+import {get, post} from '../http'
+
+const limit = {
+  getLimitStatus: () => get('creditLimit/status'),
+  getCreditLimitPages: (params) => post('creditLimit/pages', params),
+  addCreditLimit: (params) => post('creditLimit/add', params),
+  viewCreditLimit: (id) => get('creditLimit/detail', {creditLimitId: id}),
+  updateCreditLimit: (params) => post('creditLimit/update', params),
+  deleteCreditLimit: (id) => get('creditLimit/delete', {creditLimitId: id}),
+}
+
+export default limit;

+ 8 - 0
Strides-Admin/src/http/api/map.js

@@ -0,0 +1,8 @@
+const { get } = require("../http");
+
+const map = {
+  getConnectorStatusCount: () => get('dashboard/getConnectorStatusCount'),
+  getSiteInfoList: (siteName) => get('dashboard/getSiteInfoList', { siteName }),
+}
+
+export default map

+ 69 - 0
Strides-Admin/src/http/api/ocpp.js

@@ -0,0 +1,69 @@
+import {get, post} from '../http'
+
+const ocpp = {
+  getOperationList: () => [
+    {
+      "name": "Change Availability",
+      "value": "CA",
+      "api": "ocppOperations/changeAvailability"
+    },
+    {
+      "name": "Change Configuration",
+      "value": "CC",
+      "api": "ocppOperations/changeConfiguration"
+    },
+    {
+      "name": "Remote Start Transaction",
+      "value": "RSTART",
+      "api": "ocppOperations/remoteStartTransaction"
+    },
+    {
+      "name": "Remote Stop Transaction",
+      "value": "RSTOP",
+      "singleStation": true,
+      "api": "ocppOperations/remoteStopTransaction"
+    },
+    {
+      "name": "Reset",
+      "value": "RS",
+      "api": "ocppOperations/reset"
+    },
+    {
+      "name": "Unlock Connector",
+      "value": "UC",
+      "singleStation": true,
+      "api": "ocppOperations/unlockConnector"
+    },
+    {
+      "name": "Get Configuration",
+      "value": "GC",
+      "api": "ocppOperations/getConfiguration"
+    },
+    {
+      "name": "Clear Charging Profile",
+      "value": "CCP",
+      "singleStation": true,
+      "api": "ocppOperations/clearChargingProfile"
+    },
+    {
+      "name": "Set Charging Profile",
+      "value": "SCP",
+      "singleStation": true,
+      "api": "ocppOperations/setChargingProfile"
+    }
+  ],
+  getKeyTypeList: () => get('ocppOperations/getKeyTypeList'),
+  getActiveIdTags: (params) => get('ocppOperations/getActiveIdTags', params),
+  getResetTypeList: () => get('ocppOperations/getResetTypeList'),
+  getStationPages: (params) => post('ocppOperations/getChargePointsPages', params),
+  getConfigurationKeyList: () => get('ocppOperations/getConfigurationKeyList'),
+  getAvailabilityTypeList: () => get('ocppOperations/getAvailabilityTypeList'),
+  getChargingProfileList: () => get('ocppOperations/getChargingProfileList'),
+  getClearChargingProfileFilterType: () => get('ocppOperations/getClearChargingProfileFilterType'),
+  getConnectorIds: (param) => get('ocppOperations/getConnectorsByStationId', {stationId: param}),
+  getActiveConnectorIds: (param) => get('ocppOperations/getActiveTransactionIdsByStationId', {stationId: param}),
+  getTaskInfo: (id) => get('ocppOperations/getTaskInfo', {taskId: id}),
+  sendPerform: (api, params) => post(api, params),
+}
+
+export default ocpp;

+ 39 - 0
Strides-Admin/src/http/api/posDevices.js

@@ -0,0 +1,39 @@
+import {get, post} from '../http'
+
+const posDevices = {
+  getDevicePages: (params) => {
+    return post('pos/getPosDevicePages', params)
+  },
+  getSiteList: () => {
+    return get('pos/getSites')
+  },
+  /**
+   * 获取指定站点的充电桩列表
+   * @param {Object} params sitePk
+   */
+  getStationBySite: (params) => {
+    return get('pos/getStations', params)
+  },
+  /**
+   * 获取设备信息 
+   * @param {Object} params deviceId
+   */
+  getPosDevice(params) {
+    return get('pos/getPosDevice', params)
+  },
+  addPosDevice: (params) => {
+    return post('pos/addPosDevice', params)
+  },
+  editPosDevice: (params) => {
+    return post('pos/updatePosDevice', params)
+  },
+  /**
+   * 删除设备信息 
+   * @param {Object} params deviceId
+   */
+  deletePosDevice(params) {
+    return get('pos/delPosDevice', params)
+  }
+}
+
+export default posDevices;

+ 28 - 0
Strides-Admin/src/http/api/provider.js

@@ -0,0 +1,28 @@
+import {get, post} from '../http'
+import {uploadImage} from './upload'
+
+const provider = {
+  addServiceProvider: (params) => {
+    return post('serviceProvider/addServiceProvider', params)
+  },
+  getServiceProviderPages: (params) => {
+    return post('serviceProvider/getServiceProviderPages', params)
+  },
+  updateServiceProvider: (params) => {
+    return post('serviceProvider/updateServiceProvider', params)
+  },
+  getServiceProviderInfo: (params) => {
+    return get('serviceProvider/getServiceProviderInfo', params)
+  },
+  deleteProviderInfo: (params) => {
+    return get('serviceProvider/delServiceProviderInfo', params)
+  },
+  getAllServiceProvider: (params) => {
+    return get('serviceProvider/getAllServiceProviderList', params)
+  },
+  uploadLogo: (data) => {
+    return uploadImage(data, "SERVICE_LOGO")
+  }
+}
+
+export default provider;

+ 21 - 0
Strides-Admin/src/http/api/reports.js

@@ -0,0 +1,21 @@
+import { get, post, download } from '../http'
+
+const reports = {
+  getReportTypeList() {
+    return get('reports/getReportTypeList')
+  },
+  getMonthList() {
+    return get('reports/getMonthStrList')
+  },
+  getReportsPages(params) {
+    return post('reports/getReportsPages', params)
+  },
+  downloadFile(params) {
+    return download('reports/downloadReportFile', params)
+  },
+  generateMonthlyExcel(params) {
+    return post('reports/reGenerateMonthlyExcel', params)
+  }
+}
+
+export default reports

+ 21 - 0
Strides-Admin/src/http/api/settings.js

@@ -0,0 +1,21 @@
+import {get, post} from '../http'
+
+const settings = {
+  getFeatures: () => {
+    return get('administratorSettings/getFeatures')
+  },
+  getSettings: () => {
+    return get('administratorSettings/getSettings')
+  },
+  updateSettings: (params) => {
+    return post('administratorSettings/updateSettings', params)
+  },
+  testMail: (params) => {
+    return post('administratorSettings/testMail', params)
+  },
+  getCountryList: () => {
+    return get('base/getCountries')
+  }
+}
+
+export default settings

+ 53 - 0
Strides-Admin/src/http/api/site.js

@@ -0,0 +1,53 @@
+import {get, post} from '../http'
+
+const MODULE_NAME = 'siteManagement'
+
+const site = {
+  getAllSiteList: (params) => {
+    return get('siteManagement/getAllSiteList', params)
+  },
+  getRateTypeList: () => {
+    return get(`${MODULE_NAME}/getRateTypeList`)
+  },
+  getChargeTypeList: () => {
+    return get(`${MODULE_NAME}/getChargeTypeList`)
+  },
+  getSiteTypeList: () => {
+    return get(`${MODULE_NAME}/getSiteTypeList`)
+  },
+  addSite: (data) => {
+    return post(`${MODULE_NAME}/addSite`, data)
+  },
+  getSiteList: (data) => {
+    return post(`${MODULE_NAME}/getSitePages`, data)
+  },
+  updateSite: (data) => {
+    return post(`${MODULE_NAME}/updateSite`, data)
+  },
+  getSiteInfo: (data) => {
+    return get(`${MODULE_NAME}/getSiteInfo`, data)
+  },
+  deleteChargeRate: (params) => {
+    return get(`${MODULE_NAME}/delChargeRate`, params)
+  },
+  deleteWhitelistUser: (params) => {
+    return get(`${MODULE_NAME}/delWhitelistUser`, params)
+  },
+  deleteWhitelistFleet: (params) => {
+    return get(`${MODULE_NAME}/delFleetWhitelist`, params)
+  },
+  getCountryList: () => {
+    return get(`${MODULE_NAME}/getCountryList`)
+  },
+  deleteSite: (params) => {
+    return get(`${MODULE_NAME}/delSite`, params)
+  },
+  getChargingProfiles() {
+    return get(MODULE_NAME+ '/getChargingProfiles')
+  },
+  deleteChargingProfile(id) {
+    return get(MODULE_NAME+ '/delSiteChargingProfile', {siteChargingProfileId: id})
+  }
+}
+
+export default site;

+ 10 - 0
Strides-Admin/src/http/api/transaction.js

@@ -0,0 +1,10 @@
+import {get, post, download} from '../http'
+
+const transaction = {
+  getTransactionFilters: () => get('transaction/getTransactionFilters'),
+  getTransactionPages: (params) => post('transaction/getTransactionPages', params),
+  getTransactionDetail: (chargingPk) => get('transaction/getTransactionDetail', {transactionPk: chargingPk}),
+  downloadInvoice: (chargingPk) => download('transaction/downloadInvoice', {transactionPk: chargingPk})
+}
+
+export default transaction;

+ 5 - 0
Strides-Admin/src/http/api/upload.js

@@ -0,0 +1,5 @@
+import {upload} from '../http'
+
+export function uploadImage(form, type) {
+  return upload('picture/upload', form, {photoSubDir: type})
+}

+ 7 - 0
Strides-Admin/src/http/api/user.js

@@ -0,0 +1,7 @@
+import {get, post} from '../http'
+
+const MODULE_NAME = "user/"
+
+export function login(data) {
+  return post(`${MODULE_NAME}/login`, data)
+}

+ 59 - 0
Strides-Admin/src/http/api/userManagement.js

@@ -0,0 +1,59 @@
+import { get, post } from "../http";
+
+const moduleName = 'devicesUser'
+
+const functionUris = {
+  userList: "/getDevicesUserPages",
+  addUser: "/addDevicesUser",
+  updateUser: "/updateDevicesUser",
+  getUser: "/getDevicesUser",
+  deleteUser: "/delDevicesUser",
+}
+
+export function fetchList(
+  query = {
+    limit: 10,
+    page: 1,
+    criteria: '',
+  }
+) {
+  const { limit = 10, page = 1, criteria = '' } = query;
+  return post(`${moduleName}${functionUris.userList}`, {
+    pageVo: { criteria },
+    pageSize: limit,
+    pageNo: page,
+  }).then((response) => {
+    const { data, ...other } = response;
+    const copyData = [];
+    data.forEach(user => {
+      const { userPk, ...other } = user;
+      copyData.push({ userId: userPk, ...other });
+    });
+    return { ...other, data: copyData }
+  })
+}
+
+export function addUser(params) {
+  return post(`${moduleName}${functionUris.addUser}`, params)
+}
+
+export function updateUser(data) {
+  return post(`${moduleName}${functionUris.updateUser}`, data)
+}
+
+export function getUser(userId) {
+  return get(
+    `${moduleName}${functionUris.getUser}`,
+    {userPk: userId},
+  )
+}
+
+export function deleteUser(userId) {
+  return get(`${moduleName}${functionUris.deleteUser}`, {
+    userPk: userId,
+  })
+}
+
+export function deleteUserVehicle(vehiclePk) {
+  return get(`${moduleName}/delUserVehicle`, { vehiclePk })
+}

+ 138 - 0
Strides-Admin/src/http/http.js

@@ -0,0 +1,138 @@
+import axios from 'axios'
+import store from '@/store'
+import router from '@/router'
+import { getToken } from '@/utils/auth'
+
+export const baseURL = process.env.VUE_APP_BASE_API
+console.log('---CONFIG---', process.env)
+// 设置接口响应时间
+axios.defaults.timeout = 50000
+axios.defaults.baseURL = baseURL + process.env.VUE_APP_API_PREFIX
+// request interceptor
+axios.interceptors.request.use(
+  config => {
+    // do something before request is sent
+
+    if (store.getters.token) {
+      // let each request carry token
+      // ['X-Token'] is a custom headers key
+      // please modify it according to the actual situation
+      config.headers['accessToken'] = getToken()
+    }
+    console.log("======= request config ========= ", config)
+    return config
+  },
+  error => {
+    // do something with request error
+    console.log(error) // for debug
+    return Promise.reject(error)
+  }
+)
+
+// response interceptor
+axios.interceptors.response.use(res => {
+  console.log("========== response =========> ", res)
+  if (res.data instanceof Blob) {
+    return res
+  }
+  if (res.data.success) {
+    return res;
+  } else {
+    if (res.data.code == "402") { //Token过期,需要登录
+      const path = router.currentRoute.fullPath
+      //console.log('lougout+path', path);
+      store.dispatch("user/logout").then(res => {
+        router.push({ path: "/login?redirect=" + path});
+      })
+    }
+    if (res.data.msg) {
+      return Promise.reject(res.data.msg)
+    } else {
+      return Promise.reject(new Error(res.msg || 'Error'))
+    }
+  }
+}, error => {
+    console.log('http-err', error) // for debug
+    return Promise.reject(error)
+  }
+)
+
+/**
+ * get 请求方法
+ * @param url
+ * @param params
+ * @returns {Promise}
+ */
+export function get(url, params = {}) {
+  return new Promise((resolve, reject) => {
+    axios.get(url, {
+      params: params
+    }).then(response => {
+      resolve(response.data)
+    }, err => {
+      reject(err)
+    }).catch(err => {
+      reject(err)
+    })
+  })
+}
+
+/**
+ * post 请求方法
+ * @param url
+ * @param data
+ * @returns {Promise}
+ */
+export function post(url, data = {}) {
+  return new Promise((resolve, reject) => {
+    axios.post(url, data)
+    .then(response => {
+      resolve(response.data)
+    }, err => {
+      reject(err)
+    }).catch(err => {
+      reject(err)
+    })
+  })
+}
+
+export function upload(url, data, header = {}) {
+  return new Promise((resolve, reject) => {
+    axios.post(url, data, {
+      headers: {
+        'Accept': 'application/json',
+        'Content-Type': 'multipart/form-data',
+        ...header
+      }
+    }).then(response => {
+      resolve(response.data);
+    }, err => {
+      reject(err);
+    }).catch(err => {
+      reject(err);
+    });
+  })
+}
+
+/**
+ * put 文件流下载封装
+ * @param url
+ * @param data
+ * @returns {Promise}
+ */
+export function download(url, data = {}) {
+  return new Promise((resolve, reject) => {
+    axios({
+      method: 'post',
+      url: url,
+      data: data,
+      responseType: 'blob'
+    }).then(response => {
+        resolve(response.data)
+      },
+      err => {
+        reject(err)
+      }
+    )
+  })
+}

+ 9 - 0
Strides-Admin/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)

BIN
Strides-Admin/src/icons/logo.png


+ 1 - 0
Strides-Admin/src/icons/svg/404.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
Strides-Admin/src/icons/svg/administrator-active.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 35 - 0
Strides-Admin/src/icons/svg/administrator.svg


+ 1 - 0
Strides-Admin/src/icons/svg/bug.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>

+ 49 - 0
Strides-Admin/src/icons/svg/charge-station-management-active.svg

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="20"
+   height="20"
+   viewBox="0 0 20 20"
+   fill="none"
+   version="1.1"
+   id="svg23"
+   sodipodi:docname="charge-station-management-active.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs27" />
+  <sodipodi:namedview
+     id="namedview25"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="13.841615"
+     inkscape:cx="-12.895894"
+     inkscape:cy="2.8537132"
+     inkscape:window-width="1920"
+     inkscape:window-height="1001"
+     inkscape:window-x="-9"
+     inkscape:window-y="41"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg23" />
+  <path
+     d="M18.7175 5.22218C18.1473 4.74391 17.1804 3.94373 16.8953 3.64941C16.7249 3.48999 16.3545 3.41028 16.0989 3.64941C15.8433 3.88855 15.958 4.21046 16.1284 4.36988C16.384 4.60902 16.9543 5.06276 17.2689 5.4092C16.9838 5.72804 16.5577 5.67592 16.2726 5.97024C16.2431 5.99784 16.2431 6.04995 16.2431 6.07755V6.42399C16.2431 6.4761 16.3283 6.5037 16.3578 6.5037C16.643 6.5037 17.8687 6.28909 18.1538 6.28909C18.239 6.28909 18.1538 7.06168 18.1538 7.06168V16.0139C18.1538 16.4922 17.6131 16.4124 17.3279 16.4124C16.702 16.4124 16.502 16.1181 16.502 15.6399V8.63444C16.502 7.99369 16.502 7.86186 16.076 7.86186H13.9981V3.17115C13.9981 2.53039 13.4278 2 12.7461 2H3.60224C2.91727 2 2.35028 2.53345 2.35028 3.17115V18.1753H1.45556C1.19992 18.1753 1 18.3623 1 18.6014C1 18.816 1.19992 19 1.45556 19H14.788C15.0436 19 15.2435 18.813 15.2435 18.5739C15.2435 18.3347 15.0436 18.1477 14.788 18.1477H14.0178V8.60685H15.2697C15.6401 8.60685 15.6958 9.00541 15.6958 9.00541V15.6123C15.6958 17.3445 17.1772 17.1574 17.3476 17.1574C17.577 17.1574 18.9994 17.4518 18.9994 15.7196V5.70352C19.0027 5.70352 19.0027 5.48891 18.7175 5.22218ZM3.39249 18.1753V3.19874C3.39249 2.98413 3.59241 2.80018 3.81855 2.80018H12.5364C12.7658 2.80018 12.9625 2.9872 12.9625 3.19874V18.1753H3.39249Z"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.3"
+     id="path19"
+     style="stroke:#0bd373;stroke-opacity:0.89999998;fill:#0bd373;fill-opacity:0.89999998;stroke-width:0.3;stroke-miterlimit:4;stroke-dasharray:none" />
+  <path
+     d="M9.19665 9L5.87486 13.684H7.88603L6.95419 17L10.1285 12.2593H8.2648L9.19665 9ZM10.5642 5H5.43575C5.20112 5 5 5.19228 5 5.40977V5.81954C5 6.04019 5.20447 6.22931 5.43575 6.22931H10.5642C10.7989 6.22931 11 6.03704 11 5.81954V5.40977C10.9732 5.19228 10.7989 5 10.5642 5Z"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.3"
+     id="path21"
+     style="stroke:#0bd373;stroke-opacity:0.89803922;fill:#0bd373;fill-opacity:0.89803922" />
+</svg>

+ 49 - 0
Strides-Admin/src/icons/svg/charge-station-management.svg

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="20"
+   height="20"
+   viewBox="0 0 20 20"
+   fill="none"
+   version="1.1"
+   id="svg1036"
+   sodipodi:docname="charge-station-management.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs1040" />
+  <sodipodi:namedview
+     id="namedview1038"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="40.6"
+     inkscape:cx="9.9876847"
+     inkscape:cy="9.9876847"
+     inkscape:window-width="1920"
+     inkscape:window-height="1001"
+     inkscape:window-x="-9"
+     inkscape:window-y="41"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg1036" />
+  <path
+     d="M18.7175 5.22218C18.1473 4.74391 17.1804 3.94373 16.8953 3.64941C16.7249 3.48999 16.3545 3.41028 16.0989 3.64941C15.8433 3.88855 15.958 4.21046 16.1284 4.36988C16.384 4.60902 16.9543 5.06276 17.2689 5.4092C16.9838 5.72804 16.5577 5.67592 16.2726 5.97024C16.2431 5.99784 16.2431 6.04995 16.2431 6.07755V6.42399C16.2431 6.4761 16.3283 6.5037 16.3578 6.5037C16.643 6.5037 17.8687 6.28909 18.1538 6.28909C18.239 6.28909 18.1538 7.06168 18.1538 7.06168V16.0139C18.1538 16.4922 17.6131 16.4124 17.3279 16.4124C16.702 16.4124 16.502 16.1181 16.502 15.6399V8.63444C16.502 7.99369 16.502 7.86186 16.076 7.86186H13.9981V3.17115C13.9981 2.53039 13.4278 2 12.7461 2H3.60224C2.91727 2 2.35028 2.53345 2.35028 3.17115V18.1753H1.45556C1.19992 18.1753 1 18.3623 1 18.6014C1 18.816 1.19992 19 1.45556 19H14.788C15.0436 19 15.2435 18.813 15.2435 18.5739C15.2435 18.3347 15.0436 18.1477 14.788 18.1477H14.0178V8.60685H15.2697C15.6401 8.60685 15.6958 9.00541 15.6958 9.00541V15.6123C15.6958 17.3445 17.1772 17.1574 17.3476 17.1574C17.577 17.1574 18.9994 17.4518 18.9994 15.7196V5.70352C19.0027 5.70352 19.0027 5.48891 18.7175 5.22218ZM3.39249 18.1753V3.19874C3.39249 2.98413 3.59241 2.80018 3.81855 2.80018H12.5364C12.7658 2.80018 12.9625 2.9872 12.9625 3.19874V18.1753H3.39249Z"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.3"
+     id="path1032"
+     style="fill:#0bd373;fill-opacity:0.89803922;stroke:#0bd373;stroke-opacity:0.89803922" />
+  <path
+     d="M9.19665 9L5.87486 13.684H7.88603L6.95419 17L10.1285 12.2593H8.2648L9.19665 9ZM10.5642 5H5.43575C5.20112 5 5 5.19228 5 5.40977V5.81954C5 6.04019 5.20447 6.22931 5.43575 6.22931H10.5642C10.7989 6.22931 11 6.03704 11 5.81954V5.40977C10.9732 5.19228 10.7989 5 10.5642 5Z"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.3"
+     id="path1034"
+     style="stroke:#0bd373;stroke-opacity:0.89803922;fill:#0bd373;fill-opacity:0.89803922" />
+</svg>

+ 12 - 0
Strides-Admin/src/icons/svg/charging-profiles-active.svg

@@ -0,0 +1,12 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0)">
+<path d="M0 14.875V5.125C0 4.625 0.5 4.125 1 4.125H16.375C16.875 4.125 17.375 4.625 17.375 5.125V14.875C17.375 15.375 16.875 15.875 16.375 15.875H1C0.37502 15.875 0 15.375 0 14.875ZM16.75 5.125C16.75 5.00002 16.625 4.75 16.375 4.75H1.00002C0.875039 4.75 0.62502 4.875 0.62502 5.125V14.875C0.62502 15 0.75002 15.25 1.00002 15.25H16.375C16.5 15.25 16.75 15.125 16.75 14.875V5.125Z" fill="#666666" stroke="#666666" stroke-width="0.4"/>
+<path d="M6.00002 5.5L9.37502 14.5H2C1.62502 14.5 1.37502 14.25 1.375 13.875V6.125C1.375 5.75002 1.625 5.50002 2 5.5H5.99998H6.00002Z" fill="#666666"/>
+<path d="M13.875 11.125L10.5 10.25V12L5.5 8.87502L9 9.875V7.875L13.875 11.125ZM19.5 8.5V11.5C19.5 11.625 19.375 11.875 19.125 11.875H18.5C18.375 11.875 18.125 11.75 18.125 11.5V8.5C18.125 8.37502 18.25 8.125 18.5 8.125H19.125C19.375 8.125 19.5 8.25 19.5 8.5Z" fill="#666666"/>
+</g>
+<defs>
+<clipPath id="clip0">
+<rect width="20" height="20" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 65 - 0
Strides-Admin/src/icons/svg/charging-profiles.svg

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="20"
+   height="20"
+   viewBox="0 0 20 20"
+   fill="none"
+   version="1.1"
+   id="svg1206"
+   sodipodi:docname="charging-profiles.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <sodipodi:namedview
+     id="namedview1208"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="40.6"
+     inkscape:cx="9.9630542"
+     inkscape:cy="9.9630542"
+     inkscape:window-width="1920"
+     inkscape:window-height="1001"
+     inkscape:window-x="-9"
+     inkscape:window-y="41"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g1199" />
+  <g
+     clip-path="url(#clip0)"
+     id="g1199">
+    <path
+       d="M0 14.875V5.125C0 4.625 0.5 4.125 1 4.125H16.375C16.875 4.125 17.375 4.625 17.375 5.125V14.875C17.375 15.375 16.875 15.875 16.375 15.875H1C0.37502 15.875 0 15.375 0 14.875ZM16.75 5.125C16.75 5.00002 16.625 4.75 16.375 4.75H1.00002C0.875039 4.75 0.62502 4.875 0.62502 5.125V14.875C0.62502 15 0.75002 15.25 1.00002 15.25H16.375C16.5 15.25 16.75 15.125 16.75 14.875V5.125Z"
+       fill="#666666"
+       stroke="#666666"
+       stroke-width="0.4"
+       id="path1193"
+       style="fill:#0bd373;fill-opacity:0.89803922;stroke:#0bd373;stroke-opacity:0.89803922" />
+    <path
+       d="M6.00002 5.5L9.37502 14.5H2C1.62502 14.5 1.37502 14.25 1.375 13.875V6.125C1.375 5.75002 1.625 5.50002 2 5.5H5.99998H6.00002Z"
+       fill="#666666"
+       id="path1195"
+       style="fill:#0bd373;fill-opacity:0.89803922" />
+    <path
+       d="M13.875 11.125L10.5 10.25V12L5.5 8.87502L9 9.875V7.875L13.875 11.125ZM19.5 8.5V11.5C19.5 11.625 19.375 11.875 19.125 11.875H18.5C18.375 11.875 18.125 11.75 18.125 11.5V8.5C18.125 8.37502 18.25 8.125 18.5 8.125H19.125C19.375 8.125 19.5 8.25 19.5 8.5Z"
+       fill="#666666"
+       id="path1197"
+       style="fill:#0bd373;fill-opacity:0.89803922" />
+  </g>
+  <defs
+     id="defs1204">
+    <clipPath
+       id="clip0">
+      <rect
+         width="20"
+         height="20"
+         fill="white"
+         id="rect1201" />
+    </clipPath>
+  </defs>
+</svg>

+ 1 - 0
Strides-Admin/src/icons/svg/chart.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>

+ 1 - 0
Strides-Admin/src/icons/svg/clipboard.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.857 118.857h64V73.143H89.143c-1.902 0-3.52-.668-4.855-2.002-1.335-1.335-2.002-2.954-2.002-4.855V36.57H54.857v82.286zM73.143 16v-4.571a2.2 2.2 0 0 0-.677-1.61 2.198 2.198 0 0 0-1.609-.676H20.571c-.621 0-1.158.225-1.609.676a2.198 2.198 0 0 0-.676 1.61V16a2.2 2.2 0 0 0 .676 1.61c.451.45.988.676 1.61.676h50.285c.622 0 1.158-.226 1.61-.677.45-.45.676-.987.676-1.609zm18.286 48h21.357L91.43 42.642V64zM128 73.143v48c0 1.902-.667 3.52-2.002 4.855-1.335 1.335-2.953 2.002-4.855 2.002H52.57c-1.901 0-3.52-.667-4.854-2.002-1.335-1.335-2.003-2.953-2.003-4.855v-11.429H6.857c-1.902 0-3.52-.667-4.855-2.002C.667 106.377 0 104.759 0 102.857v-96c0-1.902.667-3.52 2.002-4.855C3.337.667 4.955 0 6.857 0h77.714c1.902 0 3.52.667 4.855 2.002 1.335 1.335 2.003 2.953 2.003 4.855V30.29c1 .622 1.856 1.29 2.569 2.003l29.147 29.147c1.335 1.335 2.478 3.145 3.429 5.43.95 2.287 1.426 4.383 1.426 6.291v-.018z"/></svg>

+ 1 - 0
Strides-Admin/src/icons/svg/component.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h54.857v54.857H0V0zm0 73.143h54.857V128H0V73.143zm73.143 0H128V128H73.143V73.143zm27.428-18.286C115.72 54.857 128 42.577 128 27.43 128 12.28 115.72 0 100.571 0 85.423 0 73.143 12.28 73.143 27.429c0 15.148 12.28 27.428 27.428 27.428z"/></svg>

+ 4 - 0
Strides-Admin/src/icons/svg/credit-limit-active.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M18.7486 9.99668C18.7486 5.16699 14.8334 1.25195 10.0039 1.25195C5.1742 1.25195 1.25916 5.16699 1.25916 9.99668C1.25916 14.8264 5.1742 18.7414 10.0039 18.7414C14.8336 18.7414 18.7486 14.8262 18.7486 9.99668ZM2.96155 9.99746C2.96155 5.89238 5.89866 2.95508 10.0039 2.95508C14.109 2.95508 17.0463 5.89238 17.0463 9.99746C17.0463 14.1025 14.109 17.0398 10.0039 17.0398C5.89885 17.0398 2.96155 14.1025 2.96155 9.99746Z" fill="#666666"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.294 9.15231L14.3817 9.98102C13.2477 11.0121 11.9475 11.0121 10.3262 9.93121C8.31233 8.58766 6.46213 8.58766 4.93069 9.98102C4.82463 10.0896 4.76135 10.233 4.75256 10.3845C4.75256 13.2955 7.11233 15.6552 10.0233 15.6552C12.9342 15.6552 15.294 13.2955 15.294 10.3845V9.15231ZM6.38733 10.9042C7.38655 10.1072 8.30471 10.307 9.71038 11.2441C11.1469 12.2011 12.178 12.3101 13.3658 11.756C12.8635 13.5609 11.4567 14.1574 9.59397 13.9572C7.73127 13.7572 6.49495 12.7745 6.38733 10.9042Z" fill="#666666"/>
+</svg>

+ 4 - 0
Strides-Admin/src/icons/svg/credit-limit.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M18.7486 9.99668C18.7486 5.16699 14.8334 1.25195 10.0039 1.25195C5.1742 1.25195 1.25916 5.16699 1.25916 9.99668C1.25916 14.8264 5.1742 18.7414 10.0039 18.7414C14.8336 18.7414 18.7486 14.8262 18.7486 9.99668ZM2.96155 9.99746C2.96155 5.89238 5.89866 2.95508 10.0039 2.95508C14.109 2.95508 17.0463 5.89238 17.0463 9.99746C17.0463 14.1025 14.109 17.0398 10.0039 17.0398C5.89885 17.0398 2.96155 14.1025 2.96155 9.99746Z" fill="#0bd373"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.294 9.15231L14.3817 9.98102C13.2477 11.0121 11.9475 11.0121 10.3262 9.93121C8.31233 8.58766 6.46213 8.58766 4.93069 9.98102C4.82463 10.0896 4.76135 10.233 4.75256 10.3845C4.75256 13.2955 7.11233 15.6552 10.0233 15.6552C12.9342 15.6552 15.294 13.2955 15.294 10.3845V9.15231ZM6.38733 10.9042C7.38655 10.1072 8.30471 10.307 9.71038 11.2441C11.1469 12.2011 12.178 12.3101 13.3658 11.756C12.8635 13.5609 11.4567 14.1574 9.59397 13.9572C7.73127 13.7572 6.49495 12.7745 6.38733 10.9042Z" fill="#0bd373"/>
+</svg>

+ 6 - 0
Strides-Admin/src/icons/svg/dashboard-active.svg

@@ -0,0 +1,6 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M16.3823 1.90002H2.70318C1.75953 1.90002 1 2.68001 1 3.62196L1.00597 3.63901V13.87L1 13.853C0.999991 14.0759 1.04415 14.2967 1.12993 14.5024C1.21571 14.7082 1.34141 14.895 1.49977 15.0519C1.65813 15.2088 1.84601 15.3328 2.05256 15.4168C2.25911 15.5007 2.48024 15.5428 2.70318 15.5408H7.83148C8.06095 15.5437 8.28017 15.6363 8.4422 15.7988C8.60423 15.9613 8.6962 16.1808 8.69841 16.4103V16.4018C8.69841 16.8732 8.30373 17.2465 7.83148 17.2465H5.26733C4.79593 17.2465 4.42511 17.6446 4.42511 18.116V18.1075C4.42511 18.5781 4.79593 18.5589 5.26733 18.5589H13.8148C14.287 18.5589 14.6809 18.5866 14.6809 18.116V18.1075C14.6786 17.879 14.5865 17.6605 14.4244 17.4994C14.2623 17.3383 14.0433 17.2474 13.8148 17.2465H11.2506C11.14 17.2484 11.0301 17.228 10.9274 17.1867C10.8248 17.1454 10.7314 17.084 10.6528 17.0061C10.5743 16.9282 10.5121 16.8353 10.47 16.733C10.4279 16.6307 10.4066 16.521 10.4076 16.4103V16.4018C10.4076 15.9312 10.7784 15.5408 11.2506 15.5408H16.3823L16.3874 15.5579C17.3302 15.5579 18.1 14.8128 18.1 13.8726V3.6356C18.0987 3.18126 17.918 2.74583 17.5973 2.424C17.2766 2.10218 16.8418 1.91999 16.3874 1.91707L16.3823 1.90002ZM16.8188 13.4285C16.8188 13.8991 16.4361 14.281 15.9638 14.281H3.12897C3.12897 14.281 2.68537 14.1915 2.52505 14.0317C2.36473 13.8719 2.27442 13.6549 2.27397 13.4285V4.01085C2.27397 3.5403 2.65672 3.15841 3.12897 3.15841H15.9638C16.4361 3.15841 16.8188 3.5403 16.8188 4.01085V13.4285Z" fill="#666666"/>
+<rect x="6" y="9" width="1" height="3" rx="0.5" fill="#666666" stroke="#666666" stroke-width="0.5"/>
+<rect x="9" y="8" width="1" height="4" rx="0.5" fill="#666666" stroke="#666666" stroke-width="0.5"/>
+<rect x="12" y="6" width="1" height="6" rx="0.5" fill="#666666" stroke="#666666" stroke-width="0.5"/>
+</svg>

+ 73 - 0
Strides-Admin/src/icons/svg/dashboard.svg

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="20"
+   height="20"
+   viewBox="0 0 20 20"
+   fill="none"
+   version="1.1"
+   id="svg872"
+   sodipodi:docname="dashboard.svg"
+   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs876" />
+  <sodipodi:namedview
+     id="namedview874"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="39.15"
+     inkscape:cx="10"
+     inkscape:cy="9.9489144"
+     inkscape:window-width="1920"
+     inkscape:window-height="1001"
+     inkscape:window-x="-9"
+     inkscape:window-y="41"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg872" />
+  <path
+     d="M16.3823 1.90002H2.70318C1.75953 1.90002 1 2.68001 1 3.62196L1.00597 3.63901V13.87L1 13.853C0.999991 14.0759 1.04415 14.2967 1.12993 14.5024C1.21571 14.7082 1.34141 14.895 1.49977 15.0519C1.65813 15.2088 1.84601 15.3328 2.05256 15.4168C2.25911 15.5007 2.48024 15.5428 2.70318 15.5408H7.83148C8.06095 15.5437 8.28017 15.6363 8.4422 15.7988C8.60423 15.9613 8.6962 16.1808 8.69841 16.4103V16.4018C8.69841 16.8732 8.30373 17.2465 7.83148 17.2465H5.26733C4.79593 17.2465 4.42511 17.6446 4.42511 18.116V18.1075C4.42511 18.5781 4.79593 18.5589 5.26733 18.5589H13.8148C14.287 18.5589 14.6809 18.5866 14.6809 18.116V18.1075C14.6786 17.879 14.5865 17.6605 14.4244 17.4994C14.2623 17.3383 14.0433 17.2474 13.8148 17.2465H11.2506C11.14 17.2484 11.0301 17.228 10.9274 17.1867C10.8248 17.1454 10.7314 17.084 10.6528 17.0061C10.5743 16.9282 10.5121 16.8353 10.47 16.733C10.4279 16.6307 10.4066 16.521 10.4076 16.4103V16.4018C10.4076 15.9312 10.7784 15.5408 11.2506 15.5408H16.3823L16.3874 15.5579C17.3302 15.5579 18.1 14.8128 18.1 13.8726V3.6356C18.0987 3.18126 17.918 2.74583 17.5973 2.424C17.2766 2.10218 16.8418 1.91999 16.3874 1.91707L16.3823 1.90002ZM16.8188 13.4285C16.8188 13.8991 16.4361 14.281 15.9638 14.281H3.12897C3.12897 14.281 2.68537 14.1915 2.52505 14.0317C2.36473 13.8719 2.27442 13.6549 2.27397 13.4285V4.01085C2.27397 3.5403 2.65672 3.15841 3.12897 3.15841H15.9638C16.4361 3.15841 16.8188 3.5403 16.8188 4.01085V13.4285Z"
+     fill="#666666"
+     id="path864"
+     style="fill:#0bd373;fill-opacity:0.89803922" />
+  <rect
+     x="6"
+     y="9"
+     height="3"
+     rx="0.5"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.5"
+     id="rect866"
+     width="1.0015748"
+     style="fill:#0bd373;fill-opacity:0.89803922;stroke:#0bd373;stroke-opacity:0.89803922" />
+  <rect
+     x="9"
+     y="8"
+     width="1"
+     height="4"
+     rx="0.5"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.5"
+     id="rect868"
+     style="fill:#0bd373;fill-opacity:0.89803922;stroke:#0bd373;stroke-opacity:0.89803922" />
+  <rect
+     x="12"
+     y="6"
+     width="1"
+     height="6"
+     rx="0.5"
+     fill="#666666"
+     stroke="#666666"
+     stroke-width="0.5"
+     id="rect870"
+     style="fill:#0bd373;fill-opacity:0.89803922;stroke:#0bd373;stroke-opacity:0.89803922" />
+</svg>

+ 1 - 0
Strides-Admin/src/icons/svg/documentation.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>

+ 1 - 0
Strides-Admin/src/icons/svg/drag.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M73.137 29.08h-9.209 29.7L63.886.093 34.373 29.08h20.49v27.035H27.238v17.948h27.625v27.133h18.274V74.063h27.41V56.115h-27.41V29.08zm-9.245 98.827l27.518-26.711H36.59l27.302 26.71zM.042 64.982l27.196 27.029V38.167L.042 64.982zm100.505-26.815V92.01l27.41-27.029-27.41-26.815z"/></svg>

+ 1 - 0
Strides-Admin/src/icons/svg/edit.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M106.133 67.2a4.797 4.797 0 0 0-4.8 4.8c0 .187.014.36.027.533h-.027V118.4H9.6V26.667h50.133c2.654 0 4.8-2.147 4.8-4.8 0-2.654-2.146-4.8-4.8-4.8H9.6a9.594 9.594 0 0 0-9.6 9.6V118.4c0 5.307 4.293 9.6 9.6 9.6h91.733c5.307 0 9.6-4.293 9.6-9.6V72.533h-.026c.013-.173.026-.346.026-.533 0-2.653-2.146-4.8-4.8-4.8z"/><path d="M125.16 13.373L114.587 2.8c-3.747-3.747-9.854-3.72-13.6.027l-52.96 52.96a4.264 4.264 0 0 0-.907 1.36L33.813 88.533c-.746 1.76-.226 3.534.907 4.68 1.133 1.147 2.92 1.667 4.693.92l31.4-13.293c.507-.213.96-.52 1.36-.907l52.96-52.96c3.747-3.746 3.774-9.853.027-13.6zM66.107 72.4l-18.32 7.76 7.76-18.32L92.72 24.667l10.56 10.56L66.107 72.4zm52.226-52.227l-8.266 8.267-10.56-10.56 8.266-8.267.027-.026 10.56 10.56-.027.026z"/></svg>

+ 1 - 0
Strides-Admin/src/icons/svg/education.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M88.883 119.565c-7.284 0-19.434 2.495-21.333 8.25v.127c-4.232.13-5.222 0-7.108 0-1.895-5.76-14.045-8.256-21.333-8.256H0V0h42.523c9.179 0 17.109 5.47 21.47 13.551C68.352 5.475 76.295 0 85.478 0H128v119.57l-39.113-.005h-.004zM60.442 24.763c0-9.651-8.978-16.507-17.777-16.507H7.108V111.43H39.11c7.054-.14 18.177.082 21.333 6.12v-4.628c-.134-5.722-.004-13.522 0-13.832V27.413l.004-2.655-.004.005zm60.442-16.517h-35.55c-8.802 0-17.78 6.856-17.78 16.493v74.259c.004.32.138 8.115 0 13.813v4.627c3.155-6.022 14.279-6.26 21.333-6.114h32V8.25l-.003-.005z"/></svg>

+ 1 - 0
Strides-Admin/src/icons/svg/email.svg

@@ -0,0 +1 @@
+<svg width="128" height="96" xmlns="http://www.w3.org/2000/svg"><path d="M64.125 56.975L120.188.912A12.476 12.476 0 0 0 115.5 0h-103c-1.588 0-3.113.3-4.513.838l56.138 56.137z"/><path d="M64.125 68.287l-62.3-62.3A12.42 12.42 0 0 0 0 12.5v71C0 90.4 5.6 96 12.5 96h103c6.9 0 12.5-5.6 12.5-12.5v-71a12.47 12.47 0 0 0-1.737-6.35L64.125 68.287z"/></svg>

+ 3 - 0
Strides-Admin/src/icons/svg/error-table-active.svg

@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.14286 9.42857V5.14286H6.85714V9.42857H5.14286ZM5.14286 4.28571V2.57143H6.85714V4.28571H5.14286ZM6 10.7143C8.59971 10.7143 10.7143 8.59971 10.7143 6C10.7143 3.40029 8.59971 1.28571 6 1.28571C4.75011 1.28708 3.55181 1.78419 2.668 2.668C1.78419 3.55181 1.28708 4.75011 1.28571 6C1.28571 8.59971 3.40029 10.7143 6 10.7143ZM6 0C7.5913 0 9.11742 0.632141 10.2426 1.75736C11.3679 2.88258 12 4.4087 12 6C12 7.5913 11.3679 9.11742 10.2426 10.2426C9.11742 11.3679 7.5913 12 6 12C4.4087 12 2.88258 11.3679 1.75736 10.2426C0.632141 9.11742 0 7.5913 0 6C0 4.4087 0.632141 2.88258 1.75736 1.75736C2.88258 0.632141 4.4087 0 6 0V0Z" fill="#666666"/>
+</svg>

+ 3 - 0
Strides-Admin/src/icons/svg/error-table.svg

@@ -0,0 +1,3 @@
+<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.14286 9.42857V5.14286H6.85714V9.42857H5.14286ZM5.14286 4.28571V2.57143H6.85714V4.28571H5.14286ZM6 10.7143C8.59971 10.7143 10.7143 8.59971 10.7143 6C10.7143 3.40029 8.59971 1.28571 6 1.28571C4.75011 1.28708 3.55181 1.78419 2.668 2.668C1.78419 3.55181 1.28708 4.75011 1.28571 6C1.28571 8.59971 3.40029 10.7143 6 10.7143ZM6 0C7.5913 0 9.11742 0.632141 10.2426 1.75736C11.3679 2.88258 12 4.4087 12 6C12 7.5913 11.3679 9.11742 10.2426 10.2426C9.11742 11.3679 7.5913 12 6 12C4.4087 12 2.88258 11.3679 1.75736 10.2426C0.632141 9.11742 0 7.5913 0 6C0 4.4087 0.632141 2.88258 1.75736 1.75736C2.88258 0.632141 4.4087 0 6 0V0Z" fill="#0bd373"/>
+</svg>

+ 1 - 0
Strides-Admin/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
Strides-Admin/src/icons/svg/excel.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.208 16.576v8.384h38.72v5.376h-38.72v8.704h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.512h38.72v5.376h-38.72v11.136H128v-94.72H78.208zM0 114.368L72.128 128V0L0 13.632v100.736z"/><path d="M28.672 82.56h-11.2l14.784-23.488-14.08-22.592h11.52l8.192 14.976 8.448-14.976h11.136l-14.08 22.208L58.368 82.56H46.656l-8.768-15.68z"/></svg>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor