vbea преди 3 години
родител
ревизия
471e68579a

+ 1 - 0
Strides-Admin/package.json

@@ -26,6 +26,7 @@
     "js-cookie": "^2.2.0",
     "nprogress": "^0.2.0",
     "path-to-regexp": "^6.2.0",
+	"particles.js": "^2.0.0",
     "qrcodejs2": "^0.0.2",
     "screenfull": "^4.2.0",
     "script-loader": "^0.7.2",

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


+ 5 - 2
Strides-Admin/src/layout/components/Navbar.vue

@@ -108,8 +108,11 @@ export default {
           type: 'warning',
         },
       ).then(async () => {
-        await this.$store.dispatch('user/logout')
-        this.$router.push(`/login`)
+        const path = this.$router.currentRoute.fullPath
+        //console.log('lougout+path', path);
+        this.$store.dispatch("user/logout").then(res => {
+          this.$router.push({ path: "/login?redirect=" + path});
+        })
       })
     },
     onClickMessageButton() {

+ 1 - 1
Strides-Admin/src/router/index.js

@@ -36,7 +36,7 @@ const constantRoutes = [
   },
   {
     path: '/login',
-    component: () => import('@/views/login/index'),
+    component: () => import('@/views/login/login'),
     meta: {
       title: 'Login'
     },

+ 110 - 0
Strides-Admin/src/views/login/animate.json

@@ -0,0 +1,110 @@
+{
+  "particles": {
+    "number": {
+      "value": 40,
+      "density": {
+        "enable": true,
+        "value_area": 800
+      }
+    },
+    "color": {
+      "value": "#ffffff"
+    },
+    "shape": {
+      "type": "circle",
+      "stroke": {
+        "width": 0,
+        "color": "#000000"
+      },
+      "polygon": {
+        "nb_sides": 5
+      },
+      "image": {
+        "src": "img/github.svg",
+        "width": 100,
+        "height": 100
+      }
+    },
+    "opacity": {
+      "value": 0.7,
+      "random": false,
+      "anim": {
+        "enable": false,
+        "speed": 1,
+        "opacity_min": 0.1,
+        "sync": false
+      }
+    },
+    "size": {
+      "value": 3,
+      "random": true,
+      "anim": {
+        "enable": false,
+        "speed": 40,
+        "size_min": 0.1,
+        "sync": false
+      }
+    },
+    "line_linked": {
+      "enable": true,
+      "distance": 150,
+      "color": "#ffffff",
+      "opacity": 0.6,
+      "width": 1
+    },
+    "move": {
+      "enable": true,
+      "speed": 6,
+      "direction": "none",
+      "random": false,
+      "straight": false,
+      "out_mode": "out",
+      "bounce": false,
+      "attract": {
+        "enable": false,
+        "rotateX": 600,
+        "rotateY": 1200
+      }
+    }
+  },
+  "interactivity": {
+    "detect_on": "canvas",
+    "events": {
+      "onhover": {
+        "enable": true,
+        "mode": "grab"
+      },
+      "onclick": {
+        "enable": true,
+        "mode": "push"
+      },
+      "resize": true
+    },
+    "modes": {
+      "grab": {
+        "distance": 200,
+        "line_linked": {
+          "opacity": 1
+        }
+      },
+      "bubble": {
+        "distance": 400,
+        "size": 40,
+        "duration": 2,
+        "opacity": 8,
+        "speed": 3
+      },
+      "repulse": {
+        "distance": 200,
+        "duration": 0.4
+      },
+      "push": {
+        "particles_nb": 4
+      },
+      "remove": {
+        "particles_nb": 2
+      }
+    }
+  },
+  "retina_detect": false
+}

+ 382 - 0
Strides-Admin/src/views/login/login.vue

@@ -0,0 +1,382 @@
+<template>
+  <div class="login-container" id="particles-js">
+    <div class="bg-logo"></div>
+    <el-form
+      ref="loginForm"
+      :model="loginForm"
+      :rules="loginRules"
+      class="login-form"
+      autocomplete="on"
+      label-position="left">
+
+      <div class="title-container">
+        <!-- <h3 class="title">{{appName}}</h3> -->
+        <img class="csms-logo" src="../../icons/logo.png"/>
+        <p class="title">CSMS LOGIN</p>
+      </div>
+
+      <el-form-item prop="username">
+        <div class="form-login-input">
+          <span class="svg-container">
+            <svg-icon icon-class="user" />
+          </span>
+          <el-input
+            ref="username"
+            v-model="loginForm.username"
+            name="username"
+            type="text"
+            tabindex="1"
+            autocomplete="on"
+            clearable
+            maxlength="50"
+            @focus="() => focusFiled.username = true"
+            @blur="() => focusFiled.username = false"/>
+          <label :class='isNameValid ? "focus" : ""'>Username</label>
+        </div>
+      </el-form-item>
+      <el-form-item prop="password">
+        <div class="form-login-input">
+          <span class="svg-container">
+            <svg-icon icon-class="password" />
+          </span>
+          <el-input
+            ref="password"
+            v-model="loginForm.password"
+            :type="passwordType"
+            name="password"
+            tabindex="2"
+            autocomplete="on"
+            clearable
+            maxlength="20"
+            @keyup.enter.native="handleLogin"
+            @focus="() => focusFiled.password = true"
+            @blur="() => focusFiled.password = false"
+          />
+          <span class="show-pwd" @click="showPwd">
+            <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
+          </span>
+          <label :class='isPsdValid ? "focus" : ""'>Password</label>
+        </div>
+      </el-form-item>
+
+      <el-button
+        :loading="loading"
+        type="primary"
+        class="login-button"
+        @click.native.prevent="handleLogin">
+        Login
+      </el-button>
+    </el-form>
+    <div class="copyinfo">©{{copyYear}}&nbsp; {{company}}</div>
+  </div>
+</template>
+
+<script>
+import { validUsername } from '@/utils/validate'
+import VueRouter from 'vue-router'
+import { Message } from 'element-ui'
+import settings from '../../settings.js'
+import {getUserName} from '../../utils/auth.js'
+import particles from 'particles.js'
+import animateJson from './animate.json'
+const { isNavigationFailure, NavigationFailureType } = VueRouter
+
+export default {
+  name: 'Login',
+  data() {
+    const validatePassword = (rule, value, callback) => {
+      if (value.length < 6) {
+        callback(new Error('The password can not be less than 6 digits'))
+      } else {
+        callback()
+      }
+    }
+    return {
+      year: 2023,
+      appName: settings.title,
+      company: settings.company,
+      loginForm: {
+        username: '',
+        password: ''
+      },
+      loginRules: {
+        username: [{
+          required: true,
+          trigger: 'blur',
+          message: "Please type username"
+        }],
+        password: [{
+          required: true,
+          trigger: 'blur',
+          message: "Please type password"
+          //validator: validatePassword
+        }]
+      },
+      passwordType: 'password',
+      loading: false,
+      redirect: undefined,
+      otherQuery: {},
+      focusFiled: {
+        username: false,
+        password: false
+      }
+    }
+  },
+  watch: {
+    $route: {
+      handler: function(route) {
+        const query = route.query
+        if (query) {
+          this.redirect = query.redirect
+          this.otherQuery = this.getOtherQuery(query)
+        }
+      },
+      immediate: true
+    }
+  },
+  computed: {
+    copyYear() {
+      const year = new Date().getFullYear();
+      if (year > this.year) {
+        return this.year + "-" + year;
+      } else {
+        return this.year;
+      }
+    },
+    isNameValid() {
+      return (this.loginForm.username !== "" || this.focusFiled.username)
+    },
+    isPsdValid() {
+      return (this.loginForm.password !== "" || this.focusFiled.password)
+    }
+  },
+  created() {
+    // window.addEventListener('storage', this.afterQRScan)
+    const user = getUserName()
+    if (user) {
+      this.loginForm.username = user;
+    }
+    console.log(animateJson);
+    //
+  },
+  beforeMount() {
+    this.$nextTick(() => {
+      const sss = document.getElementById("particles-js");
+      console.log(sss);
+      particlesJS('particles-js', animateJson);
+    })
+  },
+  mounted() {
+    if (this.loginForm.username === '') {
+      this.$refs.username.focus()
+    } else if (this.loginForm.password === '') {
+      this.$refs.password.focus()
+    }
+  },
+  destroyed() {
+    // window.removeEventListener('storage', this.afterQRScan)
+  },
+  methods: {
+    showPwd() {
+      if (this.passwordType === 'password') {
+        this.passwordType = ''
+      } else {
+        this.passwordType = 'password'
+      }
+      this.$nextTick(() => {
+        this.$refs.password.focus()
+      })
+    },
+    handleLogin() {
+      this.$refs.loginForm.validate(valid => {
+        if (valid) {
+          this.loading = true
+          this.$store.dispatch('user/login', this.loginForm).then((response) => {
+            let path = this.redirect || '/'
+            if (response.data.roleName === "MCST") {
+              path = '/site-management'
+            } else if (response.data.resources.length > 0) {
+              let validPath = false;
+              for (let _route of response.data.resources) {
+                if (path.indexOf(_route.resourcePath) >= 0) {
+                  validPath = true;
+                  break
+                }
+              }
+              if (!validPath) {
+                path =  response.data.resources[0].resourcePath;
+              }
+            }
+            this.$router.push({
+              path: path,
+              query: this.otherQuery,
+            }).catch((failure) => {
+              if (!isNavigationFailure(failure, NavigationFailureType.redirected)) {
+                throw failure
+              }
+            })
+            this.loading = false
+          }).catch((error) => {
+            Message.error(error.message)
+            this.loading = false
+          });
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    getOtherQuery(query) {
+      return Object.keys(query).reduce((acc, cur) => {
+        if (cur !== 'redirect') {
+          acc[cur] = query[cur]
+        }
+        return acc
+      }, {})
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+/* reset element-ui css */
+.login-container {
+  width: 100%;
+  display: flex;
+  overflow: hidden;
+  min-height: 100%;
+  user-select: none;
+  align-items: center;
+  justify-content: center;
+  background: linear-gradient(0deg, #333333 0%, #A1A1A1 100%);
+  
+  .login-form {
+    width: 100%;
+    z-index: 2;
+    margin: 0 auto;
+    max-width: 420px;
+    overflow: hidden;
+    background: #fff;
+    position: relative;
+    border-radius: 3px;
+    padding: 30px 40px 50px;
+    box-shadow: 1px 1px 5px 3px rgba(0,0,0,.2);
+  }
+  .title-container {
+    text-align: center;
+    position: relative;
+    padding: 20px 0 0;
+  
+    .title {
+      font-size: 18px;
+      color: #333;
+      margin: 20px 0;
+      text-align: center;
+      font-weight: bold;
+    }
+    .csms-logo {
+      max-width: 200px;
+    }
+  }
+  
+  .form-login-input {
+    width: 100%;
+    display: flex;
+    padding: 0 10px;
+    margin-top: 20px;
+    position: relative;
+    align-items: center;
+    border-bottom: 1px solid #999;
+    label {
+      top: 0;
+      left: 0;
+      color: #aaa;
+      font-size: 14px;
+      position:absolute;
+      padding-top: 7px;
+      padding-left: 45px;
+      font-weight: normal;
+      pointer-events: none;
+      transition: all 0.3s;
+    }
+    label.focus {
+    	top: -30px;
+    	color: #333;
+    	font-size: 15px;
+      font-weight: bold;
+      padding-left: 5px;
+    }
+    .svg-container {
+      width: 30px;
+      color: #333;
+      font-size: 16px;
+      padding: 6px 6px 6px 5px;
+    }
+    .el-input {
+      flex: 1;
+      height: 42px;
+    
+      &::v-deep input {
+        color: #333;
+        height: 42px;
+        border: none;
+        font-size: 14px;
+        padding: 0 5px;
+        border-radius: 0px;
+        -webkit-appearance: none;
+        background: transparent;
+      }
+    }
+  }
+  
+  .show-pwd {
+    color: #999;
+    cursor: pointer;
+    font-size: 16px;
+    user-select: none;
+  }
+  
+  .login-button {
+    width:100%;
+    color: #fff;
+    padding: 15px;
+    margin-top: 40px;
+    margin-bottom: 30px;
+    font-weight: bold;
+  }
+  
+  .copyinfo {
+    left: 0;
+    right: 0;
+    bottom: 10px;
+    color: #e0e0e0;
+    font-size: 12px;
+    user-select: none;
+    text-align: center;
+    position: absolute;
+    transform: scale(.8);
+  }
+  
+  .bg-logo {
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 1;
+    opacity: .3;
+    position: fixed;
+    filter: blur(30px);
+    pointer-events: none;
+    background-size: contain;
+    background-position: center;
+    background-repeat: no-repeat;
+    background-image: url(../../assets/logo.png);
+  }
+}
+</style>
+<style>
+  .particles-js-canvas-el {
+    z-index: 1;
+    position: fixed;
+  }
+</style>