liaoanqi пре 3 година
родитељ
комит
1c85f4c40d

+ 15 - 15
mall4uni/App.vue

@@ -8,22 +8,22 @@
 		onShow: function() {
 			// 判断浏览器环境
 			var ua = navigator.userAgent.toLowerCase();
-			if (ua.search(/MicroMessenger/i) > -1 && !uni.getStorageSync('appType')) {
-				// 微信环境
-				uni.setStorageSync('appType', 2)
-				http.mpAuthLogin()
-			}
-			const state = util.getUrlKey('state')
-			const code = util.getUrlKey('code')
-			if ((state == 'needCode' || state == 'unNeedCode') && code) {
-				let path = window.location.href
-				if (path.indexOf('code=') > 0 && path.indexOf('&state=unNeedCode') > -1) {
-					http.mpLogin(null, code)
-					path = path.substring(0, path.indexOf('code=') - 1)
-					history.replaceState({}, '', path)
-				}
+			// if (ua.search(/MicroMessenger/i) > -1 && !uni.getStorageSync('appType')) {
+			// 	// 微信环境
+			// 	uni.setStorageSync('appType', 2)
+			// 	http.mpAuthLogin()
+			// }
+			// const state = util.getUrlKey('state')
+			// const code = util.getUrlKey('code')
+			// if ((state == 'needCode' || state == 'unNeedCode') && code) {
+			// 	let path = window.location.href
+			// 	if (path.indexOf('code=') > 0 && path.indexOf('&state=unNeedCode') > -1) {
+			// 		http.mpLogin(null, code)
+			// 		path = path.substring(0, path.indexOf('code=') - 1)
+			// 		history.replaceState({}, '', path)
+			// 	}
 				http.getCartCount()
-			}
+			// }
 		},
 		globalData: {
 			// 定义全局请求队列

+ 5 - 2
mall4uni/package.json

@@ -14,7 +14,10 @@
   "author": "",
   "license": "ISC",
   "devDependencies": {
-    "uni-read-pages": "^1.0.5",
-    "query-string": "^6.13.1"
+    "query-string": "^6.13.1",
+    "uni-read-pages": "^1.0.5"
+  },
+  "dependencies": {
+    "crypto-js": "^4.1.1"
   }
 }

+ 23 - 28
mall4uni/pages/accountLogin/accountLogin.vue

@@ -33,6 +33,7 @@
 <script>
 	var http = require("../../utils/http");
 	var util = require('../../utils/util.js');
+	import { encrypt } from '../../utils/crypto.js'
 	import {
 		AppType
 	} from '../../utils/constant.js'
@@ -156,24 +157,18 @@
 					})
 					// #ifdef H5 || APP-PLUS
 					var params = {
-						url: "/webLogin",
+						url: "/login",
 						method: "post",
 						data: {
-							"principal": this.principal,
-							"credentials": this.credentials
+							"userName": this.principal,
+							"passWord": encrypt(this.credentials)
 						},
 						callBack: res => {
-							console.log("login",res)
-							// var loginResult = '';
-							// uni.setStorageSync("loginResult",res);
-							// uni.setStorageSync('token', 'bearer' + res.access_token);
-							// return
 							http.loginSuccess(res, () => {
 								uni.showToast({
 									title: "登录成功",
 									icon: 'none',
 									complete: () => {
-										// this.$Router.pushTab('/pages/index/index')
 										setTimeout(() => {
 											wx.switchTab({
 											url: '/pages/index/index'
@@ -188,25 +183,25 @@
 					http.request(params)
 					// #endif
 					// #ifdef MP-WEIXIN
-					wx.login({
-						success: (res) => {
-							var params = {
-								url: "/login",
-								method: "post",
-								data: {
-									appType: 1,
-									credentials: this.credentials,
-									loginType: 0,
-									principal: this.principal + ':' + res.code
-								},
-								callBack: result => {
-									http.loginSuccess(result)
-									this.$Router.pushTab('/pages/index/index')
-								},
-							}
-							http.request(params)
-						},
-					})
+					// wx.login({
+					// 	success: (res) => {
+					// 		var params = {
+					// 			url: "/login",
+					// 			method: "post",
+					// 			data: {
+					// 				appType: 1,
+					// 				credentials: this.credentials,
+					// 				loginType: 0,
+					// 				principal: this.principal + ':' + res.code
+					// 			},
+					// 			callBack: result => {
+					// 				http.loginSuccess(result)
+					// 				this.$Router.pushTab('/pages/index/index')
+					// 			},
+					// 		}
+					// 		http.request(params)
+					// 	},
+					// })
 					// #endif
 				}
 			},

+ 3 - 3
mall4uni/pages/register/register.vue

@@ -39,6 +39,7 @@
 	// pages/register/register.js
 	var http = require("../../utils/http");
 	var util = require("../../utils/util.js");
+	import { encrypt } from '../../utils/crypto.js'
 
 	export default {
 		data() {
@@ -143,11 +144,10 @@
 						data: {
 							// appType: 1,
 							// 应用类型 1小程序 2微信公众号 3 PC 4 H5
-							userMail: this.principal,
-							password: this.credentials,
+							userName: this.principal,
+							passWord: encrypt(this.credentials),
 						},
 						callBack: res => {
-							console.log("1111",res)
 							uni.hideLoading();
 							uni.showToast({
 								title: "注册成功,请登录",

+ 3 - 3
mall4uni/pages/user/user.vue

@@ -323,8 +323,8 @@
 			logout: function() {
 				// 请求退出登陆接口
 				http.request({
-					url: '/p/user/logout',
-					method: 'GET',
+					url: '/logOut',
+					method: 'post',
 					callBack: res => {
 						util.removeTabBadge()
 
@@ -336,7 +336,7 @@
 							title: "退出成功",
 							icon: "none"
 						})
-						
+
 						this.setData({
 							orderAmount: ''
 						});

+ 11 - 0
mall4uni/utils/crypto.js

@@ -0,0 +1,11 @@
+import CryptoJS from 'crypto-js'
+// 加密
+const keyStr = '-mall4j-password' // 解密用的key
+export function encrypt (word) {
+  const time = Date.now()
+
+  const key = CryptoJS.enc.Utf8.parse(keyStr)
+  const srcs = CryptoJS.enc.Utf8.parse(time + word) // 加密方式: 时间戳 + 密文
+  const encrypted = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7})
+  return encrypted.toString()
+}

+ 69 - 37
mall4uni/utils/http.js

@@ -19,9 +19,9 @@ function request(params, isGetTonken) {
 		params.data = params.data + '';
 	}
 	var needToken = false
-	if (params.url.indexOf("/p/") == 0 || params.url.indexOf("/user/registerOrBindUser") == 0) {
-		needToken = true
-	}
+	// if (params.url.indexOf("/p/") == 0 || params.url.indexOf("/user/registerOrBindUser") == 0) {
+	// 	needToken = true
+	// }
 
   wx.request({
     // url: config.domain + params.url,
@@ -31,7 +31,7 @@ function request(params, isGetTonken) {
     header: {
       // 'content-type': params.method == "GET" ? 'application/x-www-form-urlencoded' : 'application/json;charset=utf-8',
       // 'Authorization': params.login ? undefined : uni.getStorageSync('token')
-			'Authorization': !needToken ? undefined : uni.getStorageSync('token') || uni.getStorageSync('tempToken'),
+			'Authorization': uni.getStorageSync('token') ,
     },
     method: params.method == undefined ? "POST" : params.method,
     dataType: 'json',
@@ -247,24 +247,24 @@ var getToken = function (fn) {
  * @param {Object} fn		登录成功后的回调
  */
 function loginSuccess (result, fn) {
-	if (!result.enabled) {
-		uni.showModal({
-			showCancel: false,
-			title: "提示",
-			content: "您已被禁用,不能购买,请联系客服",
-			cancelText: "取消",
-			confirmText: "确定",
-			success: function (res) {
-        if (res.confirm) {
-					wx.switchTab({
-						url: '/pages/index/index'
-					});
-        }
-			}
-		})
-		wx.setStorageSync('token', '');
-		return
-	}
+	// if (!result.enabled) {
+	// 	uni.showModal({
+	// 		showCancel: false,
+	// 		title: "提示",
+	// 		content: "您已被禁用,不能购买,请联系客服",
+	// 		cancelText: "取消",
+	// 		confirmText: "确定",
+	// 		success: function (res) {
+  //       if (res.confirm) {
+	// 				wx.switchTab({
+	// 					url: '/pages/index/index'
+	// 				});
+  //       }
+	// 		}
+	// 	})
+	// 	wx.setStorageSync('token', '');
+	// 	return
+	// }
 
 	// 保存登陆信息
 	wx.setStorageSync('loginResult', result)
@@ -273,21 +273,53 @@ function loginSuccess (result, fn) {
 	// 没有获取到用户昵称,说明服务器没有保存用户的昵称,也就是用户授权的信息并没有传到服务器
 	// if (!result.pic) {
 	// 	updateUserInfo();
-	// }
-
-	wx.setStorageSync('token', 'bearer' + result.access_token); //把token存入缓存,请求接口数据时要用
-
-	if (result.userId) {
-		wx.setStorageSync('hadBindUser', true);
-		getCartCount()
-	} else {
-		wx.setStorageSync('hadBindUser', false);
-	}
-	// var globalData = getApp().globalData;
-	// globalData.isLanding = false;
-	// while (globalData.requestQueue.length) {
-	// 	request(globalData.requestQueue.pop());
-	// }
+	// }  
+	const expiresTimeStamp = result.expiresIn * 1000 / 2 + new Date().getTime()
+  // 缓存token的过期时间
+  uni.setStorageSync('expiresTimeStamp', expiresTimeStamp)
+
+	wx.setStorageSync('token', result.accessToken); //把token存入缓存,请求接口数据时要用
+
+  // const routeUrlAfterLogin = uni.getStorageSync('routeUrlAfterLogin')
+  // const pages = getCurrentPages()
+  // if (pages.length === 1) {
+  //   uni.reLaunch({
+  //     url: routeUrlAfterLogin
+  //   })
+  //   uni.removeStorageSync('routeUrlAfterLogin')
+  //   return
+  // }
+  // const prevPage = pages[pages.length - 2]
+  // if (!prevPage) {
+	// 	wx.switchTab({
+	// 		url: '/pages/index/index'
+	// 	});
+  //   return
+  // }
+  // // 判断上一页面是否为tabbar页面 (首页和分类页无需登录接口)
+  // const isTabbar = prevPage.route === 'pages/user/user' || prevPage.route === 'pages/basket/basket'
+  // if (isTabbar) {
+	// 	wx.switchTab({
+	// 		url: '/' + prevPage.route
+	// 	});
+  // } else {
+  //   // 非tabbar页面
+  //   let backDelata = 0
+  //   pages.forEach((page, index) => {
+  //     if (page.$page.fullPath === routeUrlAfterLogin) {
+  //       backDelata = pages.length - index - 1
+  //     }
+  //   })
+  //   if (backDelata) {
+  //     uni.navigateBack({
+  //       delta: backDelata
+  //     })
+  //   } else {
+	// 		wx.switchTab({
+	// 			url: '/pages/index/index'
+	// 		});
+  //   }
+  // }
 
 	if (fn) {
 		fn()

BIN
mall4v/src/assets/img/default-verify-error.jpg


Разлика између датотеке није приказан због своје велике величине
+ 413 - 0
mall4v/src/components/verifition/Verify.vue


+ 268 - 0
mall4v/src/components/verifition/Verify/VerifyPoints.vue

@@ -0,0 +1,268 @@
+<template>
+  <div
+    style="position: relative"
+  >
+    <div class="verify-img-out">
+      <div
+        class="verify-img-panel"
+        :style="{'width': setSize.imgWidth,
+                 'height': setSize.imgHeight,
+                 'background-size' : setSize.imgWidth + ' '+ setSize.imgHeight,
+                 'margin-bottom': vSpace + 'px'}"
+      >
+        <div v-show="showRefresh" class="verify-refresh" style="z-index:3" @click="refresh">
+          <i class="iconfont icon-refresh" />
+        </div>
+        <img
+          ref="canvas"
+          :src="pointBackImgBase?('data:image/png;base64,'+pointBackImgBase):defaultImg"
+          alt=""
+          style="width:100%;height:100%;display:block"
+          @click="bindingClick?canvasClick($event):undefined"
+        >
+
+        <div
+          v-for="(tempPoint, index) in tempPoints"
+          :key="index"
+          class="point-area"
+          :style="{
+            'background-color':'#1abd6c',
+            color:'#fff',
+            'z-index':9999,
+            width:'20px',
+            height:'20px',
+            'text-align':'center',
+            'line-height':'20px',
+            'border-radius': '50%',
+            position:'absolute',
+            top:parseInt(tempPoint.y-10) + 'px',
+            left:parseInt(tempPoint.x-10) + 'px'
+          }"
+        >
+          {{ index + 1 }}
+        </div>
+      </div>
+    </div>
+    <!-- 'height': this.barSize.height, -->
+    <div
+      class="verify-bar-area"
+      :style="{'width': setSize.imgWidth,
+               'color': this.barAreaColor,
+               'border-color': this.barAreaBorderColor,
+               'line-height':this.barSize.height}"
+    >
+      <span class="verify-msg">{{ text }}</span>
+    </div>
+  </div>
+</template>
+<script type="text/babel">
+/**
+     * VerifyPoints
+     * @description 点选
+     * */
+import { resetSize, _code_chars, _code_color1, _code_color2 } from './../utils/util'
+import { aesEncrypt } from './../utils/ase'
+import { reqGet, reqCheck } from './../api/index'
+
+export default {
+  name: 'VerifyPoints',
+  props: {
+    // 弹出式pop,固定fixed
+    mode: {
+      type: String,
+      default: 'fixed'
+    },
+    captchaType: {
+      type: String,
+    },
+    // 间隔
+    vSpace: {
+      type: Number,
+      default: 5
+    },
+    imgSize: {
+      type: Object,
+      default() {
+        return {
+          width: '310px',
+          height: '155px'
+        }
+      }
+    },
+    barSize: {
+      type: Object,
+      default() {
+        return {
+          width: '310px',
+          height: '40px'
+        }
+      }
+    },
+    defaultImg: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      secretKey: '', // 后端返回的ase加密秘钥
+      checkNum: 3, // 默认需要点击的字数
+      fontPos: [], // 选中的坐标信息
+      checkPosArr: [], // 用户点击的坐标
+      num: 1, // 点击的记数
+      pointBackImgBase: '', // 后端获取到的背景图片
+      poinTextList: [], // 后端返回的点击字体顺序
+      backToken: '', // 后端返回的token值
+      setSize: {
+        imgHeight: 0,
+        imgWidth: 0,
+        barHeight: 0,
+        barWidth: 0
+      },
+      tempPoints: [],
+      text: '',
+      barAreaColor: undefined,
+      barAreaBorderColor: undefined,
+      showRefresh: true,
+      bindingClick: true
+    }
+  },
+  computed: {
+    resetSize() {
+      return resetSize
+    }
+  },
+  watch: {
+    // type变化则全面刷新
+    type: {
+      immediate: true,
+      handler() {
+        this.init()
+      }
+    }
+  },
+  mounted() {
+    // 禁止拖拽
+    this.$el.onselectstart = function() {
+      return false
+    }
+  },
+  methods: {
+    init() {
+      // 加载页面
+      this.fontPos.splice(0, this.fontPos.length)
+      this.checkPosArr.splice(0, this.checkPosArr.length)
+      this.num = 1
+      this.getPictrue()
+      this.$nextTick(() => {
+        this.setSize = this.resetSize(this)	// 重新设置宽度高度
+        this.$parent.$emit('ready', this)
+      })
+    },
+    canvasClick(e) {
+      this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e))
+      if (this.num == this.checkNum) {
+        this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e))
+        // 按比例转换坐标值
+        this.checkPosArr = this.pointTransfrom(this.checkPosArr, this.setSize)
+        // 等创建坐标执行完
+        setTimeout(() => {
+          // var flag = this.comparePos(this.fontPos, this.checkPosArr);
+          // 发送后端请求
+          var captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify(this.checkPosArr), this.secretKey) : this.backToken + '---' + JSON.stringify(this.checkPosArr)
+          const data = {
+            captchaType: this.captchaType,
+            'pointJson': this.secretKey ? aesEncrypt(JSON.stringify(this.checkPosArr), this.secretKey) : JSON.stringify(this.checkPosArr),
+            'token': this.backToken
+          }
+          reqCheck(data).then(res => {
+            if (res.repCode == '0000') {
+              this.barAreaColor = '#4cae4c'
+              this.barAreaBorderColor = '#5cb85c'
+              this.text = '验证成功'
+              this.bindingClick = false
+              if (this.mode == 'pop') {
+                setTimeout(() => {
+                  this.$parent.clickShow = false
+                  this.refresh()
+                }, 1500)
+              }
+              this.$parent.$emit('success', { captchaVerification })
+            } else {
+              this.$parent.$emit('error', this)
+              this.barAreaColor = '#d9534f'
+              this.barAreaBorderColor = '#d9534f'
+              this.text = '验证失败'
+              setTimeout(() => {
+                this.refresh()
+              }, 700)
+            }
+          })
+        }, 400)
+      }
+      if (this.num < this.checkNum) {
+        this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e))
+      }
+    },
+
+    // 获取坐标
+    getMousePos: function(obj, e) {
+      var x = e.offsetX
+      var y = e.offsetY
+      return { x, y }
+    },
+    // 创建坐标点
+    createPoint: function(pos) {
+      this.tempPoints.push(Object.assign({}, pos))
+      return ++this.num
+    },
+    refresh: function() {
+      this.tempPoints.splice(0, this.tempPoints.length)
+      this.barAreaColor = '#000'
+      this.barAreaBorderColor = '#ddd'
+      this.bindingClick = true
+      this.fontPos.splice(0, this.fontPos.length)
+      this.checkPosArr.splice(0, this.checkPosArr.length)
+      this.num = 1
+      this.getPictrue()
+      this.text = '验证失败'
+      this.showRefresh = true
+    },
+
+    // 请求背景图片和验证图片
+    getPictrue() {
+      const data = {
+        captchaType: this.captchaType,
+        clientUid: localStorage.getItem('point'),
+        ts: Date.now(), // 现在的时间戳
+      }
+      reqGet(data).then(res => {
+        if (res.repCode == '0000') {
+          this.pointBackImgBase = res.repData.originalImageBase64
+          this.backToken = res.repData.token
+          this.secretKey = res.repData.secretKey
+          this.poinTextList = res.repData.wordList
+          this.text = '请依次点击【' + this.poinTextList.join(',') + '】'
+        } else {
+          this.text = res.repMsg
+        }
+
+        // 判断接口请求次数是否失效
+        if (res.repCode == '6201') {
+          this.pointBackImgBase = null
+        }
+      })
+    },
+    // 坐标转换函数
+    pointTransfrom(pointArr, imgSize) {
+      var newPointArr = pointArr.map(p => {
+        const x = Math.round(310 * p.x / parseInt(imgSize.imgWidth))
+        const y = Math.round(155 * p.y / parseInt(imgSize.imgHeight))
+        return { x, y }
+      })
+      // console.log(newPointArr,"newPointArr");
+      return newPointArr
+    }
+  },
+}
+</script>

+ 378 - 0
mall4v/src/components/verifition/Verify/VerifySlide.vue

@@ -0,0 +1,378 @@
+<template>
+  <div style="position: relative;">
+    <div
+      v-if="type === '2'"
+      class="verify-img-out"
+      :style="{height: (parseInt(setSize.imgHeight) + vSpace) + 'px'}"
+    >
+      <div
+        class="verify-img-panel"
+        :style="{width: setSize.imgWidth,
+                 height: setSize.imgHeight,}"
+      >
+        <img :src="backImgBase?('data:image/png;base64,'+backImgBase):defaultImg" alt="" style="width:100%;height:100%;display:block">
+        <div v-show="showRefresh" class="verify-refresh" @click="refresh"><i class="iconfont icon-refresh" />
+        </div>
+        <transition name="tips">
+          <span v-if="tipWords" class="verify-tips" :class="passFlag ?'suc-bg':'err-bg'">{{ tipWords }}</span>
+        </transition>
+      </div>
+    </div>
+    <!-- 公共部分 -->
+    <div
+      class="verify-bar-area"
+      :style="{width: setSize.imgWidth,
+               height: barSize.height,
+               'line-height':barSize.height}"
+    >
+      <span class="verify-msg" v-text="text" />
+      <div
+        class="verify-left-bar"
+        :style="{width: (leftBarWidth!==undefined)?leftBarWidth: barSize.height, height: barSize.height, 'border-color': leftBarBorderColor, transaction: transitionWidth}"
+      >
+        <span class="verify-msg" v-text="finishText" />
+        <div
+          class="verify-move-block"
+          :style="{width: barSize.height, height: barSize.height, 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}"
+          @touchstart="start"
+          @mousedown="start"
+        >
+          <i
+            :class="['verify-icon iconfont', iconClass]"
+            :style="{color: iconColor}"
+          />
+          <div
+            v-if="type === '2'"
+            class="verify-sub-block"
+            :style="{'width':Math.floor(parseInt(setSize.imgWidth)*47/310)+ 'px',
+                     'height': setSize.imgHeight,
+                     'top':'-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
+                     'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
+            }"
+          >
+            <img :src="'data:image/png;base64,'+blockBackImgBase" alt="" style="width:100%;height:100%;display:block">
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script type="text/babel">
+/**
+     * VerifySlide
+     * @description 滑块
+     * */
+import { aesEncrypt } from './../utils/ase'
+import { resetSize } from './../utils/util'
+import { reqGet, reqCheck } from './../api/index'
+
+//  "captchaType":"blockPuzzle",
+export default {
+  name: 'VerifySlide',
+  props: {
+    captchaType: {
+      type: String,
+    },
+    type: {
+      type: String,
+      default: '1'
+    },
+    // 弹出式pop,固定fixed
+    mode: {
+      type: String,
+      default: 'fixed'
+    },
+    vSpace: {
+      type: Number,
+      default: 5
+    },
+    explain: {
+      type: String,
+      default: '向右滑动完成验证'
+    },
+    imgSize: {
+      type: Object,
+      default() {
+        return {
+          width: '310px',
+          height: '155px'
+        }
+      }
+    },
+    blockSize: {
+      type: Object,
+      default() {
+        return {
+          width: '50px',
+          height: '50px'
+        }
+      }
+    },
+    barSize: {
+      type: Object,
+      default() {
+        return {
+          width: '310px',
+          height: '40px'
+        }
+      }
+    },
+    defaultImg: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      secretKey: '', // 后端返回的加密秘钥 字段
+      passFlag: '', // 是否通过的标识
+      backImgBase: '', // 验证码背景图片
+      blockBackImgBase: '', // 验证滑块的背景图片
+      backToken: '', // 后端返回的唯一token值
+      startMoveTime: '', // 移动开始的时间
+      endMovetime: '', // 移动结束的时间
+      tipsBackColor: '', // 提示词的背景颜色
+      tipWords: '',
+      text: '',
+      finishText: '',
+      setSize: {
+        imgHeight: 0,
+        imgWidth: 0,
+        barHeight: 0,
+        barWidth: 0
+      },
+      top: 0,
+      left: 0,
+      moveBlockLeft: undefined,
+      leftBarWidth: undefined,
+      // 移动中样式
+      moveBlockBackgroundColor: undefined,
+      leftBarBorderColor: '#ddd',
+      iconColor: undefined,
+      iconClass: 'icon-right',
+      status: false, // 鼠标状态
+      isEnd: false,		// 是够验证完成
+      showRefresh: true,
+      transitionLeft: '',
+      transitionWidth: ''
+    }
+  },
+  computed: {
+    barArea() {
+      return this.$el.querySelector('.verify-bar-area')
+    },
+    resetSize() {
+      return resetSize
+    }
+  },
+  watch: {
+    // type变化则全面刷新
+    type: {
+      immediate: true,
+      handler() {
+        this.init()
+      }
+    }
+  },
+  mounted() {
+    // 禁止拖拽
+    this.$el.onselectstart = function() {
+      return false
+    }
+    console.log(this.defaultImg)
+  },
+  methods: {
+    init() {
+      this.text = this.explain
+      this.getPictrue()
+      this.$nextTick(() => {
+        const setSize = this.resetSize(this)	// 重新设置宽度高度
+        for (const key in setSize) {
+          this.$set(this.setSize, key, setSize[key])
+        }
+        this.$parent.$emit('ready', this)
+      })
+
+      var _this = this
+
+      window.removeEventListener('touchmove', function(e) {
+        _this.move(e)
+      })
+      window.removeEventListener('mousemove', function(e) {
+        _this.move(e)
+      })
+
+      // 鼠标松开
+      window.removeEventListener('touchend', function() {
+        _this.end()
+      })
+      window.removeEventListener('mouseup', function() {
+        _this.end()
+      })
+
+      window.addEventListener('touchmove', function(e) {
+        _this.move(e)
+      })
+      window.addEventListener('mousemove', function(e) {
+        _this.move(e)
+      })
+
+      // 鼠标松开
+      window.addEventListener('touchend', function() {
+        _this.end()
+      })
+      window.addEventListener('mouseup', function() {
+        _this.end()
+      })
+    },
+
+    // 鼠标按下
+    start: function(e) {
+      e = e || window.event
+      if (!e.touches) { // 兼容PC端
+        var x = e.clientX
+      } else { // 兼容移动端
+        var x = e.touches[0].pageX
+      }
+      this.startLeft = Math.floor(x - this.barArea.getBoundingClientRect().left)
+      this.startMoveTime = +new Date() // 开始滑动的时间
+      if (this.isEnd == false) {
+        this.text = ''
+        this.moveBlockBackgroundColor = '#337ab7'
+        this.leftBarBorderColor = '#337AB7'
+        this.iconColor = '#fff'
+        e.stopPropagation()
+        this.status = true
+      }
+    },
+    // 鼠标移动
+    move: function(e) {
+      e = e || window.event
+      if (this.status && this.isEnd == false) {
+        if (!e.touches) { // 兼容PC端
+          var x = e.clientX
+        } else { // 兼容移动端
+          var x = e.touches[0].pageX
+        }
+        var bar_area_left = this.barArea.getBoundingClientRect().left
+        var move_block_left = x - bar_area_left // 小方块相对于父元素的left值
+        if (move_block_left >= this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2) {
+          move_block_left = this.barArea.offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2
+        }
+        if (move_block_left <= 0) {
+          move_block_left = parseInt(parseInt(this.blockSize.width) / 2)
+        }
+        // 拖动后小方块的left值
+        this.moveBlockLeft = (move_block_left - this.startLeft) + 'px'
+        this.leftBarWidth = (move_block_left - this.startLeft) + 'px'
+      }
+    },
+
+    // 鼠标松开
+    end: function() {
+      this.endMovetime = +new Date()
+      var _this = this
+      // 判断是否重合
+      if (this.status && this.isEnd == false) {
+        var moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''))
+        moveLeftDistance = moveLeftDistance * 310 / parseInt(this.setSize.imgWidth)
+        const data = {
+          captchaType: this.captchaType,
+          'pointJson': this.secretKey ? aesEncrypt(JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey) : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
+          'token': this.backToken
+        }
+        reqCheck(data).then(res => {
+          res = res.data
+          if (res.repCode == '0000') {
+            this.moveBlockBackgroundColor = '#5cb85c'
+            this.leftBarBorderColor = '#5cb85c'
+            this.iconColor = '#fff'
+            this.iconClass = 'icon-check'
+            this.showRefresh = false
+            this.isEnd = true
+            if (this.mode == 'pop') {
+              setTimeout(() => {
+                this.$parent.clickShow = false
+                this.refresh()
+              }, 1500)
+            }
+            this.passFlag = true
+            this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`
+            var captchaVerification = this.secretKey ? aesEncrypt(this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey) : this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 })
+            setTimeout(() => {
+              this.tipWords = ''
+              this.$parent.closeBox()
+              this.$parent.$emit('success', { captchaVerification })
+            }, 1000)
+          } else {
+            this.moveBlockBackgroundColor = '#d9534f'
+            this.leftBarBorderColor = '#d9534f'
+            this.iconColor = '#fff'
+            this.iconClass = 'icon-close'
+            this.passFlag = false
+            setTimeout(function() {
+              _this.refresh()
+            }, 1000)
+            this.$parent.$emit('error', this)
+            this.tipWords = '验证失败'
+            setTimeout(() => {
+              this.tipWords = ''
+            }, 1000)
+          }
+        })
+        this.status = false
+      }
+    },
+
+    refresh: function() {
+      this.showRefresh = true
+      this.finishText = ''
+
+      this.transitionLeft = 'left .3s'
+      this.moveBlockLeft = 0
+
+      this.leftBarWidth = undefined
+      this.transitionWidth = 'width .3s'
+
+      this.leftBarBorderColor = '#ddd'
+      this.moveBlockBackgroundColor = '#fff'
+      this.iconColor = '#000'
+      this.iconClass = 'icon-right'
+      this.isEnd = false
+
+      this.getPictrue()
+      setTimeout(() => {
+        this.transitionWidth = ''
+        this.transitionLeft = ''
+        this.text = this.explain
+      }, 300)
+    },
+
+    // 请求背景图片和验证图片
+    getPictrue() {
+      const data = {
+        captchaType: this.captchaType,
+        clientUid: localStorage.getItem('slider'),
+        ts: Date.now(), // 现在的时间戳
+      }
+      reqGet(data).then(res => {
+        if (res.data.repCode == '0000') {
+          this.backImgBase = res.data.repData.originalImageBase64
+          this.blockBackImgBase = res.data.repData.jigsawImageBase64
+          this.backToken = res.data.repData.token
+          this.secretKey = res.data.repData.secretKey
+        } else {
+          this.tipWords = res.data.repMsg
+        }
+
+        // 判断接口请求次数是否失效
+        if (res.data.repCode == '6201') {
+          this.backImgBase = null
+          this.blockBackImgBase = null
+        }
+      })
+    },
+  },
+}
+</script>
+

+ 24 - 0
mall4v/src/components/verifition/api/index.js

@@ -0,0 +1,24 @@
+/**
+ * 此处可直接引用自己项目封装好的 axios 配合后端联调
+ */
+
+import httpRequest from '@/utils/httpRequest'
+
+// 获取验证图片  以及token
+export function reqGet (data) {
+  return httpRequest({
+    url: httpRequest.adornUrl('/captcha/get'),
+    method: 'post',
+    data
+  })
+}
+
+// 滑动或者点选验证
+export function reqCheck (data) {
+  return httpRequest({
+    url: httpRequest.adornUrl('/captcha/check'),
+    method: 'post',
+    data
+  })
+}
+

+ 11 - 0
mall4v/src/components/verifition/utils/ase.js

@@ -0,0 +1,11 @@
+import CryptoJS from 'crypto-js'
+/**
+ * @word 要加密的内容
+ * @keyWord String  服务器随机返回的关键字
+ *  */
+export function aesEncrypt(word, keyWord = 'XwKsGlMcdPMEhR1B') {
+  var key = CryptoJS.enc.Utf8.parse(keyWord)
+  var srcs = CryptoJS.enc.Utf8.parse(word)
+  var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 })
+  return encrypted.toString()
+}

+ 36 - 0
mall4v/src/components/verifition/utils/util.js

@@ -0,0 +1,36 @@
+export function resetSize(vm) {
+  var img_width, img_height, bar_width, bar_height	// 图片的宽度、高度,移动条的宽度、高度
+
+  var parentWidth = vm.$el.parentNode.offsetWidth || window.offsetWidth
+  var parentHeight = vm.$el.parentNode.offsetHeight || window.offsetHeight
+
+  if (vm.imgSize.width.indexOf('%') != -1) {
+    img_width = parseInt(this.imgSize.width) / 100 * parentWidth + 'px'
+  } else {
+    img_width = this.imgSize.width
+  }
+
+  if (vm.imgSize.height.indexOf('%') != -1) {
+    img_height = parseInt(this.imgSize.height) / 100 * parentHeight + 'px'
+  } else {
+    img_height = this.imgSize.height
+  }
+
+  if (vm.barSize.width.indexOf('%') != -1) {
+    bar_width = parseInt(this.barSize.width) / 100 * parentWidth + 'px'
+  } else {
+    bar_width = this.barSize.width
+  }
+
+  if (vm.barSize.height.indexOf('%') != -1) {
+    bar_height = parseInt(this.barSize.height) / 100 * parentHeight + 'px'
+  } else {
+    bar_height = this.barSize.height
+  }
+
+  return { imgWidth: img_width, imgHeight: img_height, barWidth: bar_width, barHeight: bar_height }
+}
+
+export const _code_chars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
+export const _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0']
+export const _code_color2 = ['#FF0033', '#006699', '#993366', '#FF9900', '#66CC66', '#FF33CC']

+ 11 - 0
mall4v/src/utils/crypto.js

@@ -0,0 +1,11 @@
+import CryptoJS from 'crypto-js'
+// 加密
+const keyStr = '-mall4j-password' // 解密用的key
+export function encrypt(word){ 
+  const time = Date.now();
+
+  const key  = CryptoJS.enc.Utf8.parse(keyStr);
+  const srcs = CryptoJS.enc.Utf8.parse(time + word); // 加密方式: 时间戳 + 密文
+  const encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
+  return encrypted.toString();
+}

+ 1 - 1
mall4v/src/utils/index.js

@@ -20,7 +20,7 @@ export function isAuth (key) {
   if (authorities.length) {
     for (const i in authorities) {
       const element = authorities[i]
-      if (element.authority === key) {
+      if (element === key) {
         return true
       }
     }

+ 66 - 17
mall4v/src/views/common/login.vue

@@ -22,7 +22,7 @@
                       type="password"
                       placeholder="密码"></el-input>
           </el-form-item>
-          <el-form-item prop="captcha">
+          <!-- <el-form-item prop="captcha">
             <el-row :gutter="20">
               <el-col :span="14">
                 <el-input v-model="dataForm.captcha"
@@ -36,7 +36,7 @@
                      alt="">
               </el-col>
             </el-row>
-          </el-form-item>
+          </el-form-item> -->
           <el-form-item>
             <div class="item-btn"><input type="button"
                      value="登录"
@@ -47,12 +47,23 @@
 
       <div class="bottom">Copyright © 2019 广州市蓝海创新科技有限公司</div>
     </div>
+    <Verify
+      ref="verify"
+      :captcha-type="'blockPuzzle'"
+      :img-size="{width:'400px',height:'200px'}"
+      @success="login"
+    />
   </div>
 </template>
 
 <script>
 import { getUUID } from '@/utils'
+import Verify from '@/components/verifition/Verify'
+import { encrypt } from '@/utils/crypto'
 export default {
+  components: {
+    Verify
+  },
   data () {
     return {
       dataForm: {
@@ -75,32 +86,70 @@ export default {
       captchaPath: ''
     }
   },
+  beforeDestroy () {
+    document.removeEventListener('keyup', this.handerKeyup)
+  },
   created () {
     this.getCaptcha()
+
+    document.addEventListener('keyup', this.handerKeyup)
   },
   methods: {
+    handerKeyup (e) {
+      var keycode = document.all ? event.keyCode : e.which
+      if (keycode === 13) {
+        this.dataFormSubmit()
+      }
+    },
     // 提交表单
     dataFormSubmit () {
       this.$refs['dataForm'].validate((valid) => {
         if (valid) {
-          this.$http({
-            url: this.$http.adornUrl('/login?grant_type=admin'),
-            method: 'post',
-            data: this.$http.adornData({
-              'principal': this.dataForm.userName,
-              'credentials': this.dataForm.password,
-              'sessionUUID': this.dataForm.uuid,
-              'imageCode': this.dataForm.captcha
-            })
-          }).then(({ data }) => {
-            this.$cookie.set('Authorization', 'bearer' + data.access_token)
-            this.$router.replace({ name: 'home' })
-          }).catch(() => {
-            this.getCaptcha()
-          })
+          this.$refs.verify.show()
         }
       })
     },
+    login (verifyResult) {
+      if (this.isSubmit) {
+        return
+      }
+      this.isSubmit = true
+      this.$http({
+        url: this.$http.adornUrl('/adminLogin'),
+        method: 'post',
+        data: this.$http.adornData({
+          'userName': this.dataForm.userName,
+          'passWord': encrypt(this.dataForm.password),
+          'captchaVerification': verifyResult.captchaVerification
+        })
+      }).then(({ data }) => {
+        this.$cookie.set('Authorization', data.accessToken)
+        this.$router.replace({ name: 'home' })
+      }).catch(() => {
+        this.isSubmit = false
+      })
+    },
+    // dataFormSubmit () {
+    //   this.$refs['dataForm'].validate((valid) => {
+    //     if (valid) {
+    //       this.$http({
+    //         url: this.$http.adornUrl('/login?grant_type=admin'),
+    //         method: 'post',
+    //         data: this.$http.adornData({
+    //           'principal': this.dataForm.userName,
+    //           'credentials': this.dataForm.password,
+    //           'sessionUUID': this.dataForm.uuid,
+    //           'imageCode': this.dataForm.captcha
+    //         })
+    //       }).then(({ data }) => {
+    //         this.$cookie.set('Authorization', 'bearer' + data.access_token)
+    //         this.$router.replace({ name: 'home' })
+    //       }).catch(() => {
+    //         this.getCaptcha()
+    //       })
+    //     }
+    //   })
+    // },
     // 获取验证码
     getCaptcha () {
       this.dataForm.uuid = getUUID()

+ 1 - 1
mall4v/src/views/main-navbar.vue

@@ -79,7 +79,7 @@
           type: 'warning'
         }).then(() => {
           this.$http({
-            url: this.$http.adornUrl('/sys/logout'),
+            url: this.$http.adornUrl('/logOut'),
             method: 'post',
             data: this.$http.adornData()
           }).then(({data}) => {

+ 2 - 1
mall4v/src/views/modules/sys/user-add-or-update.vue

@@ -41,6 +41,7 @@
 <script>
   import { isEmail, isMobile } from '@/utils/validate'
   import { Debounce } from '@/utils/debounce'
+  import { encrypt } from '@/utils/crypto'
   export default {
     data () {
       var validatePassword = (rule, value, callback) => {
@@ -149,7 +150,7 @@
               data: this.$http.adornData({
                 'userId': this.dataForm.id || undefined,
                 'username': this.dataForm.userName,
-                'password': this.dataForm.password,
+                'password': encrypt(this.dataForm.password),
                 'email': this.dataForm.email,
                 'mobile': this.dataForm.mobile,
                 'status': this.dataForm.status,

Неке датотеке нису приказане због велике количине промена