Browse Source

添加登录验证码

achao 2 years ago
parent
commit
bc6b7d6f0a

+ 30 - 0
src/global/directive.js

@@ -1,3 +1,32 @@
+// bind 只调用一次,指令第一次绑定到元素时候调用,用这个钩子可以定义一个绑定时执行一次的初始化动作。
+// inserted:被绑定的元素插入父节点的时候调用(父节点存在即可调用,不必存在document中)
+// update: 被绑定与元素所在模板更新时调用,而且无论绑定值是否有变化,通过比较更新前后的绑定值,忽略不必要的模板更新
+// componentUpdate :被绑定的元素所在模板完成一次更新更新周期的时候调用
+// unbind: 只调用一次,指令月元素解绑的时候调用
+// demo
+// Vue.directive("hello",{
+//   bind:function(el,bingind,vnode){
+//     el.style["color"] = bingind.value;
+//     console.log("1-bind");
+// },
+// inserted:function(){
+//     console.log("2-insert");
+// },
+// update:function(){
+//     console.log("3-update");
+// },
+// componentUpdated:function(){
+//     console.log('4 - componentUpdated');
+// },
+// unbind:function(){
+//     console.log('5 - unbind');
+// }
+// })
+// 输入框只允许输入数字  v-number-input.float
+
+/**
+ * 拖动
+ */
 const drag = {
   install(Vue, options = {}) {
     Vue.directive('drag', {
@@ -151,6 +180,7 @@ const loadmore = {
   }
 }
 const permission = (el, binding, vnode) => {
+  debugger
   const roles = vnode.context.$store.getters.roles;
   if (!roles) {
     return;

+ 2 - 1
src/global/index.js

@@ -1,7 +1,8 @@
-import './prototypes'
+// import './prototypes'
 import directive from './directive'
 import Vue from 'vue'
 // import filters from '@/global/filters';
+debugger
 Object.values(directive).forEach(value => Vue.use(value))
 // const install = () => {
 

+ 4 - 1
src/main.js

@@ -21,6 +21,7 @@ import 'quill/dist/quill.core.css'
 import 'quill/dist/quill.snow.css'
 import 'quill/dist/quill.bubble.css'
 Vue.use(VueQuillEditor)
+import './global/index'
 /**
  * If you don't want to use mock-server
  * you want to use MockJs for mock api
@@ -35,7 +36,9 @@ Vue.use(VueQuillEditor)
 // }
 
 // set ElementUI lang to EN
-Vue.use(ElementUI, { locale })
+Vue.use(ElementUI, {
+  locale
+})
 // 如果想要中文版 element-ui,按如下方式声明
 // Vue.use(ElementUI)
 

+ 2 - 1
src/store/modules/permission.js

@@ -130,8 +130,9 @@ const actions = {
       getRoule().then(response => {
         const roles = []
         handleRoles(response.data, roles, '')
-        // console.log(roles)
+        console.log("roles", roles)
         const accessedRoutes = filterAsyncRoutes(constantRoutes, roles)
+
         commit('user/SET_ROLES', roles, {
           root: true
         })

+ 36 - 22
src/views/driverManagement/identityExamine.vue

@@ -9,7 +9,8 @@
           </el-col>
           <el-col :span="10">
             <div class="screen">
-              <el-input class='find' placeholder="可按司机姓名、账号、身份证号查找" @keyup.enter.native="find" v-model="searchkeyWord" clearable @change="find"></el-input>
+              <el-input class='find' placeholder="可按司机姓名、账号、身份证号查找" @keyup.enter.native="find" v-model="searchkeyWord"
+                clearable @change="find"></el-input>
               <el-button class="search" @click="find"><img width="16" height="16" style="margin-left: -8px"
                   src="../../../public/img/sousuo.png" /></el-button><span
                 class="count_css">共{{ deptBudgetTotal }}条</span>
@@ -51,7 +52,8 @@
           </el-col>
         </el-row>
       </div>
-      <el-table :data="tableData" style="width: 98%; margin: 0 auto; border-radius: 10px" height="55.8vh" border highlight-current-row>
+      <el-table :data="tableData" style="width: 98%; margin: 0 auto; border-radius: 10px" height="55.8vh" border
+        highlight-current-row>
         <el-table-column prop="driverName" label="司机姓名" min-width="130"></el-table-column>
         <el-table-column prop="driverPhone" label="账号" min-width="110"></el-table-column>
         <el-table-column prop="numberCard" label="身份证号" min-width="165"></el-table-column>
@@ -94,7 +96,8 @@
         </el-table-column>
         <el-table-column label="车辆">
           <template slot-scope="scope">
-            <span @click="carLook(scope.row)" class="btn_css">查看</span>
+            <span @click="carLook(scope.row)" class="btn_css"
+              v-hasPermission="`changyuntong.changyuntongquanxian.audit.chakan`">查看</span>
           </template>
         </el-table-column>
         <el-table-column prop="payee" label="账户">
@@ -165,7 +168,8 @@
       style="text-align: center; margin-top: 10px" :page-size="deptCircularPage.pageSize"
       layout="total, sizes, prev, pager, next, jumper" :total="deptBudgetTotal">
     </el-pagination>
-    <el-dialog :close-on-click-modal='false' title="车辆信息" :visible.sync="carInfo" width="500px" :before-close="carClose">
+    <el-dialog :close-on-click-modal='false' title="车辆信息" :visible.sync="carInfo" width="500px"
+      :before-close="carClose">
       <!-- <span v-if="carSee.length == 0">暂无车辆</span> -->
       <span class="tips">注:车辆信息不在本页面审核,仅供查看</span>
       <div class="car_css" v-for="(item, index) in carSee" :key="index">
@@ -185,7 +189,8 @@
         <div class="carborder_css"></div>
       </div>
     </el-dialog>
-    <el-dialog :close-on-click-modal='false' title="账户信息" :visible.sync="userInfo" width="500px" :before-close="userClose">
+    <el-dialog :close-on-click-modal='false' title="账户信息" :visible.sync="userInfo" width="500px"
+      :before-close="userClose">
       <div class="user" v-for="(item, index) in paySee" :key="index">
         <div class="name_css">{{ item.payeeName }}</div>
         <div class="id_css">{{ item.bankCard }}</div>
@@ -196,7 +201,8 @@
       <div v-if="paySee.length == 0">暂无账户信息</div>
     </el-dialog>
     <!-- 账单 -->
-    <el-dialog :close-on-click-modal='false' title="账单" :visible.sync="billShow" width="500px" :before-close="billClose">
+    <el-dialog :close-on-click-modal='false' title="账单" :visible.sync="billShow" width="500px"
+      :before-close="billClose">
       <div style="height: 450px" class="bill_css">
         <div class="user" v-for="(item, index) in billInfo" :key="index">
           <div class="flex">
@@ -211,7 +217,8 @@
         <div v-show="billInfo.length == 0">暂无账单信息</div>
       </div>
     </el-dialog>
-    <el-dialog :close-on-click-modal='false' title="附件" :visible.sync="fujianInfo" width="830px" :before-close="fujianClose">
+    <el-dialog :close-on-click-modal='false' title="附件" :visible.sync="fujianInfo" width="830px"
+      :before-close="fujianClose">
       <div class="file">
         <div class="fujian_css">
           <div class="fujian_item" :class="count == 1 ? 'file_btn' : ''" @click="btnChange(1)">
@@ -237,10 +244,12 @@
           </div> -->
         </div>
         <div class="file_tips">
-          <span v-if="count == 1">有效期:{{file.cardValidityDate}} </span><span v-if="count == 2"> 准驾车型:{{file.quasiDrivingVehicle}} </span> <span v-if="count == 2"> 发证机关:{{file.lssuingAuthority}} </span> <span v-if="count == 4"> 从业资格证号:{{file.qualificationCertificateNumber}}</span>
+          <span v-if="count == 1">有效期:{{file.cardValidityDate}} </span><span v-if="count == 2">
+            准驾车型:{{file.quasiDrivingVehicle}} </span> <span v-if="count == 2"> 发证机关:{{file.lssuingAuthority}} </span>
+          <span v-if="count == 4"> 从业资格证号:{{file.qualificationCertificateNumber}}</span>
         </div>
         <div class="file_img">
-          <img :src="img[index]" class="img_css" @click="enlarge(img[index])"/>
+          <img :src="img[index]" class="img_css" @click="enlarge(img[index])" />
         </div>
         <div class="btn">
           <el-button style="margin-right: 120px" @click="index = 0"
@@ -250,7 +259,8 @@
         </div>
       </div>
     </el-dialog>
-    <el-dialog :close-on-click-modal='false' title="驳回认证" :visible.sync="rejectInfo" width="400px" :before-close="rejectClose">
+    <el-dialog :close-on-click-modal='false' title="驳回认证" :visible.sync="rejectInfo" width="400px"
+      :before-close="rejectClose">
       <div>
         <div><span class="sign">*</span>选择驳回原因</div>
         <div class="form_css">
@@ -274,7 +284,8 @@
       </div>
     </el-dialog>
     <!-- //消息 -->
-    <el-dialog title="发送信息" :close-on-click-modal='false' :visible.sync="sendInfo" width="400px" :before-close="sendInfoClose">
+    <el-dialog title="发送信息" :close-on-click-modal='false' :visible.sync="sendInfo" width="400px"
+      :before-close="sendInfoClose">
       <div class="Info_css">
         <div class="Info_title">标题</div>
         <div class="Info_item">
@@ -352,14 +363,14 @@
     },
     methods: {
       closeImgViewer() {
-         this.srcList = []
+        this.srcList = []
         this.imgsVisible = false;
       },
       enlarge(url) {
         this.imgsVisible = true;
         this.srcList.push(url)
       },
-            editNumber(item) {
+      editNumber(item) {
         //   // item.iconShow = false
         //   this.$set(item,"iconShow",false)
         for (let i = 0; i < this.tableData.length; i++) {
@@ -378,7 +389,7 @@
           type: "warning",
         }).then(() => {
           this.listLoading = true;
-          val.advancePayment = val.advancePayment/100
+          val.advancePayment = val.advancePayment / 100
           editInfo(val)
             .then((response) => {
               if (response.code == 200) {
@@ -424,8 +435,8 @@
             this.tableData = response.data.records;
             for (let i = 0; i < this.tableData.length; i++) {
               this.tableData[i].iconShow = true;
-              if(this.tableData[i].advancePayment){
-                this.tableData[i].advancePayment*=100
+              if (this.tableData[i].advancePayment) {
+                this.tableData[i].advancePayment *= 100
               }
             }
             this.deptBudgetTotal = response.data.total;
@@ -739,7 +750,7 @@
         background: #2f53eb;
         border-radius: 0px 2px 2px 0px;
         border: 1px solid #DCDFE6;
-        margin-left:-1px;
+        margin-left: -1px;
       }
 
       .count_css {
@@ -937,9 +948,10 @@
         background-color: #cfdbfe;
       }
     }
-    .file_tips{
-        margin: 10px auto;
-       width: 50%;
+
+    .file_tips {
+      margin: 10px auto;
+      width: 50%;
     }
 
     .file_img {
@@ -974,9 +986,11 @@
   ::v-deep .input_css .el-input__inner {
     height: 30px;
   }
-  .find::v-deep input.el-input__inner{
-    border-radius:0;
+
+  .find::v-deep input.el-input__inner {
+    border-radius: 0;
   }
+
   // .tupian{
   //   width: 100%;
   //   height: 100%;

+ 117 - 12
src/views/login/index.vue

@@ -24,7 +24,20 @@
           <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
         </span>
       </el-form-item>
-
+      <el-form-item prop="code">
+        <el-row :span="24" style="display: flex;align-items: center;">
+          <el-col :span="12">
+            <el-input v-model="loginForm.code" auto-complete="off" placeholder="请输入验证码" size=""
+              @keyup.enter.native="submitForm('loginForm')"></el-input>
+          </el-col>
+          <el-col :span="12" style="display: flex;justify-content: flex-end;">
+            <div class="login-code" @click="refreshCode">
+              <!--验证码组件-->
+              <s-identify :identifyCode="identifyCode"></s-identify>
+            </div>
+          </el-col>
+        </el-row>
+      </el-form-item>
       <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;"
         @click.native.prevent="handleLogin">进入</el-button>
 
@@ -38,11 +51,15 @@
 
 <script>
   import {
-    validUsername
+    validUsername,
+    isLoginName
   } from '@/utils/validate'
-
+  import SIdentify from './sidentify'
   export default {
     name: 'Login',
+    components: {
+      SIdentify
+    },
     data() {
       const validateUsername = (rule, value, callback) => {
         if (!validUsername(value)) {
@@ -58,19 +75,63 @@
           callback()
         }
       }
+      const validateCode = (rule, value, callback) => {
+        if (this.identifyCode !== value) {
+          this.loginForm.code = ''
+          this.refreshCode()
+          callback(new Error('请输入正确的验证码'))
+        } else {
+          callback()
+        }
+      }
       return {
-        loginForm: {},
+        isDebugLogin: false,
+        loginForm: {
+          username: '',
+          password: '',
+          code: ''
+        },
+        identifyCodes: '1234567890',
+        identifyCode: '',
         loginRules: {
           username: [{
-            required: true,
-            trigger: 'blur',
-            validator: validateUsername
-          }],
+              required: true,
+              trigger: 'blur',
+              message: '请输入用户名'
+            },
+            {
+              min: 1,
+              max: 200,
+              message: '长度在1-200字符之间',
+              trigger: 'blur'
+            },
+            {
+              validator: isLoginName,
+              trigger: 'blur'
+            }
+          ],
           password: [{
-            required: true,
-            trigger: 'blur',
-            validator: validatePassword
-          }]
+              required: true,
+              message: '请输入密码',
+              trigger: 'blur'
+            },
+            {
+              min: 1,
+              max: 100,
+              message: '长度在1-100字符之间',
+              trigger: 'blur'
+            }
+          ],
+          code: [{
+              required: true,
+              message: '请输入验证码',
+              trigger: 'blur'
+            },
+            {
+              validator: validateCode,
+              trigger: 'blur'
+            }
+          ]
         },
         loading: false,
         passwordType: 'password',
@@ -83,9 +144,32 @@
           this.redirect = route.query && route.query.redirect
         },
         immediate: true
+      },
+      isDebugLogin(v) {
+        if (v) {
+          this.loginForm.password = '123'
+          this.refreshCode()
+        }
+      },
+      identifyCode(v) {
+        this.isDebugLogin && (this.loginForm.code = v)
       }
     },
     methods: {
+      randomNum(min, max) {
+        return Math.floor(Math.random() * (max - min) + min)
+      },
+      refreshCode() {
+        this.identifyCode = ''
+        this.makeCode(this.identifyCodes, 4)
+      },
+      makeCode(o, l) {
+        for (let i = 0; i < l; i++) {
+          this.identifyCode += this.identifyCodes[
+            this.randomNum(0, this.identifyCodes.length)
+          ]
+        }
+      },
       showPwd() {
         if (this.passwordType === 'password') {
           this.passwordType = ''
@@ -118,6 +202,9 @@
           }
         })
       }
+    },
+    created() {
+      this.refreshCode()
     }
   }
 </script>
@@ -231,4 +318,22 @@
       user-select: none;
     }
   }
+
+  .login-code {
+    cursor: pointer;
+    margin-right: 5px;
+
+    .login-code-img {
+      width: 100px;
+      height: 38px;
+      background-color: #eee;
+      border: 1px solid #f0f0f0;
+      color: #333;
+      font-size: 18px;
+      font-weight: bold;
+      letter-spacing: 2px;
+      text-indent: 2px;
+      text-align: center;
+    }
+  }
 </style>

+ 142 - 0
src/views/login/sidentify.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="s-canvas">
+    <canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
+  </div>
+</template>
+<script>
+  export default {
+    name: 'SIdentify',
+    props: {
+      identifyCode: {
+        type: String,
+        default: '1234'
+      },
+      fontSizeMin: {
+        type: Number,
+        default: 24
+      },
+      fontSizeMax: {
+        type: Number,
+        default: 36
+      },
+      backgroundColorMin: {
+        type: Number,
+        default: 180
+      },
+      backgroundColorMax: {
+        type: Number,
+        default: 240
+      },
+      colorMin: {
+        type: Number,
+        default: 50
+      },
+      colorMax: {
+        type: Number,
+        default: 160
+      },
+      lineColorMin: {
+        type: Number,
+        default: 40
+      },
+      lineColorMax: {
+        type: Number,
+        default: 180
+      },
+      dotColorMin: {
+        type: Number,
+        default: 0
+      },
+      dotColorMax: {
+        type: Number,
+        default: 255
+      },
+      contentWidth: {
+        type: Number,
+        default: 112
+      },
+      contentHeight: {
+        type: Number,
+        default: 38
+      }
+    },
+    methods: {
+      // 生成一个随机数
+      randomNum(min, max) {
+        return Math.floor(Math.random() * (max - min) + min)
+      },
+      // 生成一个随机的颜色
+      randomColor(min, max) {
+        let r = this.randomNum(min, max)
+        let g = this.randomNum(min, max)
+        let b = this.randomNum(min, max)
+        return 'rgb(' + r + ',' + g + ',' + b + ')'
+      },
+      drawPic() {
+        let canvas = document.getElementById('s-canvas')
+        let ctx = canvas.getContext('2d')
+        ctx.textBaseline = 'bottom'
+        // 绘制背景
+        ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax)
+        ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
+        // 绘制文字
+        for (let i = 0; i < this.identifyCode.length; i++) {
+          this.drawText(ctx, this.identifyCode[i], i)
+        }
+        // this.drawLine(ctx)
+        this.drawDot(ctx)
+      },
+      drawText(ctx, txt, i) {
+        ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
+        ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei'
+        let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))
+        let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
+        var deg = this.randomNum(-45, 45)
+        // 修改坐标原点和旋转角度
+        ctx.translate(x, y)
+        ctx.rotate(deg * Math.PI / 180)
+        ctx.fillText(txt, 0, 0)
+        // 恢复坐标原点和旋转角度
+        ctx.rotate(-deg * Math.PI / 180)
+        ctx.translate(-x, -y)
+      },
+      drawLine(ctx) {
+        // 绘制干扰线
+        for (let i = 0; i < 8; i++) {
+          ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
+          ctx.beginPath()
+          ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
+          ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
+          ctx.stroke()
+        }
+      },
+      drawDot(ctx) {
+        // 绘制干扰点
+        for (let i = 0; i < 100; i++) {
+          ctx.fillStyle = this.randomColor(0, 255)
+          ctx.beginPath()
+          ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
+          ctx.fill()
+        }
+      }
+    },
+    watch: {
+      identifyCode() {
+        this.drawPic()
+      }
+    },
+    mounted() {
+      this.drawPic()
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  .s-canvas {
+    height: 38px;
+
+    canvas {
+      margin-top: 1px;
+      margin-left: 8px;
+    }
+  }
+</style>

+ 1 - 0
src/views/permissionSetting/permissionSetting.vue

@@ -300,6 +300,7 @@
 
       },
       setInfo(val) {
+        debugger
         this.showRoleRan(val)
       },
       // 保存权限范围