管理、商家添加登录图片验证

master
mabo 2021-06-03 14:35:19 +08:00
parent 65cb7787a6
commit 33ec809e73
19 changed files with 528 additions and 44 deletions

View File

@ -6,7 +6,7 @@
#### 在组件上添加v-if来判断组件显隐 #### 在组件上添加v-if来判断组件显隐
#### verifyType 验证格式[ 'LOGIN' ,'REGISTER' ]等,详情看接口文档 #### verifyType 验证格式[ 'LOGIN' ,'REGISTER' ]
#### @change方法 获取回调,参数为对象 {status:false,distance:100} status 为回调状态distance为移动距离 #### @change方法 获取回调,参数为对象 {status:false,distance:100} status 为回调状态distance为移动距离

View File

@ -26,7 +26,3 @@ export function postVerifyImg (params) {
headers: {uuid: storage.getItem('uuid')} headers: {uuid: storage.getItem('uuid')}
}); });
} }
export function mouseup () {
console.log(111);
}

View File

@ -47,7 +47,8 @@
"vuex": "^3.4.0", "vuex": "^3.4.0",
"wangeditor": "^4.5.3", "wangeditor": "^4.5.3",
"xlsx": "^0.16.2", "xlsx": "^0.16.2",
"xss": "^1.0.7" "xss": "^1.0.7",
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^4.4.4", "@vue/cli-plugin-babel": "^4.4.4",

View File

@ -5,6 +5,7 @@
</template> </template>
<script> <script>
import {v4 as uuidv4} from 'uuid';
import {getCategoryTree} from '@/api/goods.js' import {getCategoryTree} from '@/api/goods.js'
export default { export default {
updated() { updated() {
@ -15,7 +16,14 @@ export default {
} }
}) })
} }
},
mounted() {
let uuid = this.getStore('uuid');
if (!uuid) {
uuid = uuidv4();
this.setStore('uuid', uuid);
} }
},
}; };
</script> </script>

View File

@ -1,4 +1,4 @@
import {commonUrl, getRequest} from '@/libs/axios'; import {commonUrl, getRequest, getRequestWithNoToken, postRequestWithNoToken} from '@/libs/axios';
// 通过id获取子地区 // 通过id获取子地区
export const getChildRegion = (id) => { export const getChildRegion = (id) => {
@ -6,6 +6,16 @@ export const getChildRegion = (id) => {
}; };
// 点地图获取地址信息 // 点地图获取地址信息
export const getRegion = (parpams) => { export const getRegion = (params) => {
return getRequest(`${commonUrl}/common/region/region`, parpams); return getRequest(`${commonUrl}/common/region/region`, params);
};
// 获取拼图验证
export const getVerifyImg = (verificationEnums) => {
return getRequestWithNoToken(`${commonUrl}/common/slider/${verificationEnums}`);
};
// 拼图验证
export const postVerifyImg = (params) => {
return postRequestWithNoToken(`${commonUrl}/common/slider/${params.verificationEnums}`, params);
}; };

View File

@ -24,6 +24,8 @@ service.interceptors.request.use(
...config.params ...config.params
} }
} }
const uuid = getStore('uuid');
config.headers['uuid'] = uuid;
return config; return config;
}, },
err => { err => {

View File

@ -5,7 +5,7 @@ export const loginRouter = {
path: "/login", path: "/login",
name: "login", name: "login",
meta: { meta: {
title: "登录 - lili " title: "登录 - lili运营后台"
}, },
component: () => import("@/views/login.vue") component: () => import("@/views/login.vue")
}; };

View File

@ -22,6 +22,13 @@
</Row> </Row>
</Row> </Row>
<!-- 拼图验证码 -->
<verify
ref="verify"
class="verify-con"
verifyType="LOGIN"
@change="verifyChange"
></verify>
<div v-if="socialLogining"> <div v-if="socialLogining">
<RectLoading /> <RectLoading />
</div> </div>
@ -41,6 +48,7 @@ import LangSwitch from "@/views/main-components/lang-switch";
import RectLoading from "@/views/my-components/lili/rect-loading"; import RectLoading from "@/views/my-components/lili/rect-loading";
import CountDownButton from "@/views/my-components/lili/count-down-button"; import CountDownButton from "@/views/my-components/lili/count-down-button";
import util from "@/libs/util.js"; import util from "@/libs/util.js";
import verify from '@/views/my-components/verify';
export default { export default {
components: { components: {
@ -49,6 +57,7 @@ export default {
LangSwitch, LangSwitch,
Header, Header,
Footer, Footer,
verify
}, },
data() { data() {
return { return {
@ -79,7 +88,7 @@ export default {
}, },
methods: { methods: {
mounted() {}, mounted() {},
afterLogin(res) { afterLogin(res) { //
let accessToken = res.result.accessToken; let accessToken = res.result.accessToken;
let refreshToken = res.result.refreshToken; let refreshToken = res.result.refreshToken;
this.setStore("accessToken", accessToken); this.setStore("accessToken", accessToken);
@ -100,9 +109,16 @@ export default {
} }
}); });
}, },
submitLogin() { submitLogin() { //
this.$refs.usernameLoginForm.validate((valid) => { this.$refs.usernameLoginForm.validate((valid) => {
if (valid) { if (valid) {
this.$refs.verify.show = true;
}
});
},
verifyChange (con) { //
if (!con.status) return;
this.loading = true; this.loading = true;
login({ login({
username: this.form.username, username: this.form.username,
@ -113,10 +129,8 @@ export default {
} else { } else {
this.loading = false; this.loading = false;
} }
}); }).catch(()=>{this.loading = false});
} }
});
},
}, },
}; };
</script> </script>
@ -140,7 +154,12 @@ export default {
position: relative; position: relative;
zoom: 1; zoom: 1;
} }
.verify-con{
position: absolute;
top: 90px;
z-index: 10;
left: 20px;
}
.form { .form {
padding-top: 1vh; padding-top: 1vh;

View File

@ -0,0 +1,14 @@
### 滑动拼图验证
### 在页面中引入 .vue文件
#### 参数
#### 在组件上添加v-if来判断组件显隐
#### verifyType 验证格式[ 'LOGIN' ,'REGISTER' ]
#### @change方法 获取回调,参数为对象 {status:false,distance:100} status 为回调状态distance为移动距离
#### <Verify class="verify-content" verifyType='LOGIN' @change="verifyChange"></Verify>

View File

@ -0,0 +1,185 @@
<template>
<div class="verify-content" v-if="show" @mousemove="mouseMove" @mouseup="mouseUp">
<div class="imgBox" :style="{width:data.originalWidth+'px',height:data.originalHeight + 'px'}">
<img :src="data.backImage" style="width:100%;height:100%" alt="">
<img class="slider" :src="data.slidingImage" :style="{left:distance+'px',top:data.randomY+'px'}" :width="data.sliderWidth" :height="data.sliderHeight" alt="">
<Icon type="md-refresh" class="refresh" @click="refresh" />
</div>
<div class="handle" :style="{width:data.originalWidth+'px'}">
<span class="bgcolor" :style="{width:distance + 'px',background:bgColor}"></span>
<span class="swiper" :style="{left:distance + 'px'}" @mousedown="mouseDown">
<Icon type="md-arrow-round-forward" />
</span>
<span class="text">{{verifyText}}</span>
</div>
</div>
</template>
<script>
import { getVerifyImg, postVerifyImg } from './verify.js';
export default {
props: {
verifyType: {
defalut: 'LOGIN',
type: String
}
},
data () {
return {
show: false, //
type: 'LOGIN', //
data: { //
backImage: '',
slidingImage: '',
originalHeight: 150,
originalWidth: 300,
sliderWidth: 60,
sliderHeight: 60
},
distance: 0, //
flag: false, //
downX: 0, //
bgColor: 'aqua', //
verifyText: '拖动滑块解锁' //
};
},
methods: {
mouseDown (e) {
this.downX = e.clientX;
this.flag = true;
},
mouseMove (e) {
if (this.flag) {
let offset = e.clientX - this.downX;
if (offset > this.data.originalWidth - 43) {
this.distance = this.data.originalWidth - 43;
} else if (offset < 0) {
this.distance = 0;
} else {
this.distance = offset;
}
}
},
mouseUp () {
if (!this.flag) return false;
this.flag = false;
let params = {
verificationEnums: this.type,
xPos: this.distance
};
postVerifyImg(params).then(res => {
if (res.result) {
this.bgColor = 'green';
this.verifyText = '解锁成功';
this.$emit('change', { status: true, distance: this.distance });
} else {
this.bgColor = 'red';
this.verifyText = '解锁失败';
let that = this;
setTimeout(() => {
that.refresh();
}, 1000);
this.$emit('change', { status: false, distance: this.distance });
}
});
},
refresh () {
this.flag = false;
this.downX = 0;
this.distance = 0;
this.bgColor = 'aqua';
this.verifyText = '拖动滑块解锁';
this.getImg();
},
getImg () {
getVerifyImg(this.type).then(res => {
this.data = res.result;
});
}
},
created () {
this.getImg();
},
watch: {
verifyType: {
immediate: true,
handler: function (v) {
this.type = v;
this.refresh();
}
},
show (v) {
if (v) this.refresh();
}
}
};
</script>
<style lang="scss" scoped>
.verify-content{
padding: 10px;
background: #fff;
border: 1px solid #eee;
border-radius: 5px;
box-shadow: 1px 1px 3px #999;
}
.imgBox {
width: 300px;
height: 150px;
position: relative;
overflow: hidden;
.slider {
position: absolute;
cursor: pointer;
}
.refresh {
position: absolute;
right: 5px;
top: 5px;
font-size: 20px;
color: #fff;
cursor: pointer;
}
}
.handle {
border: 1px solid rgb(134, 134, 134);
margin-top: 5px;
height: 42px;
background: #ddd;
position: relative;
.bgcolor {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
opacity: 0.5;
background: aqua;
}
.swiper {
position: absolute;
width: 40px;
height: 40px;
background-color: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
.ivu-icon {
font-size: 20px;
}
}
.text {
display: inline-block;
width: inherit;
text-align: center;
line-height: 42px;
font-size: 14px;
user-select: none;
}
}
</style>

View File

@ -0,0 +1,13 @@
import {commonUrl, getRequestWithNoToken, postRequestWithNoToken} from '@/libs/axios';
// 获取拼图验证
export const getVerifyImg = (verificationEnums) => {
return getRequestWithNoToken(`${commonUrl}/common/slider/${verificationEnums}`);
};
// 拼图验证
export const postVerifyImg = (params) => {
return postRequestWithNoToken(`${commonUrl}/common/slider/${params.verificationEnums}`, params);
};

View File

@ -44,7 +44,8 @@
"vuex": "^3.4.0", "vuex": "^3.4.0",
"wangeditor": "^4.6.13", "wangeditor": "^4.6.13",
"xlsx": "^0.16.2", "xlsx": "^0.16.2",
"xss": "^1.0.7" "xss": "^1.0.7",
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^4.4.4", "@vue/cli-plugin-babel": "^4.4.4",

View File

@ -5,13 +5,15 @@
</template> </template>
<script> <script>
import {v4 as uuidv4} from 'uuid';
export default { export default {
data() { mounted() {
return {}; let uuid = this.getStore('uuid');
if (!uuid) {
uuid = uuidv4();
this.setStore('uuid', uuid);
}
}, },
mounted() {},
beforeDestroy() {},
methods: {}
}; };
</script> </script>

View File

@ -24,6 +24,8 @@ service.interceptors.request.use(
...config.params ...config.params
} }
} }
const uuid = getStore('uuid');
config.headers['uuid'] = uuid;
return config; return config;
}, },
err => { err => {

View File

@ -5,7 +5,7 @@ export const loginRouter = {
path: "/login", path: "/login",
name: "login", name: "login",
meta: { meta: {
title: "登录 - lili " title: "登录 - lili商家后台 "
}, },
component: () => import("@/views/login.vue") component: () => import("@/views/login.vue")
}; };

View File

@ -55,6 +55,13 @@
</Row> </Row>
<Footer /> <Footer />
<!-- 拼图验证码 -->
<verify
ref="verify"
class="verify-con"
verifyType="LOGIN"
@change="verifyChange"
></verify>
</Col> </Col>
<!-- <LangSwitch /> --> <!-- <LangSwitch /> -->
</Row> </Row>
@ -72,11 +79,13 @@ import Header from "@/views/main-components/header";
import Footer from "@/views/main-components/footer"; import Footer from "@/views/main-components/footer";
import LangSwitch from "@/views/main-components/lang-switch"; import LangSwitch from "@/views/main-components/lang-switch";
import util from "@/libs/util.js"; import util from "@/libs/util.js";
import verify from '@/views/my-components/verify';
export default { export default {
components: { components: {
LangSwitch, LangSwitch,
Header, Header,
Footer, Footer,
verify
}, },
data() { data() {
return { return {
@ -154,10 +163,16 @@ export default {
} }
}); });
}, },
submitLogin() { submitLogin() { //
//
this.$refs.usernameLoginForm.validate((valid) => { this.$refs.usernameLoginForm.validate((valid) => {
if (valid) { if (valid) {
this.$refs.verify.show = true;
}
})
},
verifyChange (con) { //
if (!con.status) return;
this.loading = true; this.loading = true;
login({ login({
username: this.form.username, username: this.form.username,
@ -169,8 +184,6 @@ export default {
} }
}).catch(()=>{this.loading = false}) }).catch(()=>{this.loading = false})
} }
})
},
} }
}; };
</script> </script>
@ -203,6 +216,12 @@ export default {
display: flex; display: flex;
flex-direction: column !important; flex-direction: column !important;
} }
.verify-con{
position: absolute;
top: 126px;
z-index: 10;
left: 20px;
}
.form { .form {
padding-top: 1vh; padding-top: 1vh;

View File

@ -0,0 +1,14 @@
### 滑动拼图验证
### 在页面中引入 .vue文件
#### 参数
#### 在组件上添加v-if来判断组件显隐
#### verifyType 验证格式[ 'LOGIN' ,'REGISTER' ]
#### @change方法 获取回调,参数为对象 {status:false,distance:100} status 为回调状态distance为移动距离
#### <Verify class="verify-content" verifyType='LOGIN' @change="verifyChange"></Verify>

View File

@ -0,0 +1,185 @@
<template>
<div class="verify-content" v-if="show" @mousemove="mouseMove" @mouseup="mouseUp">
<div class="imgBox" :style="{width:data.originalWidth+'px',height:data.originalHeight + 'px'}">
<img :src="data.backImage" style="width:100%;height:100%" alt="">
<img class="slider" :src="data.slidingImage" :style="{left:distance+'px',top:data.randomY+'px'}" :width="data.sliderWidth" :height="data.sliderHeight" alt="">
<Icon type="md-refresh" class="refresh" @click="refresh" />
</div>
<div class="handle" :style="{width:data.originalWidth+'px'}">
<span class="bgcolor" :style="{width:distance + 'px',background:bgColor}"></span>
<span class="swiper" :style="{left:distance + 'px'}" @mousedown="mouseDown">
<Icon type="md-arrow-round-forward" />
</span>
<span class="text">{{verifyText}}</span>
</div>
</div>
</template>
<script>
import { getVerifyImg, postVerifyImg } from './verify.js';
export default {
props: {
verifyType: {
defalut: 'LOGIN',
type: String
}
},
data () {
return {
show: false, //
type: 'LOGIN', //
data: { //
backImage: '',
slidingImage: '',
originalHeight: 150,
originalWidth: 300,
sliderWidth: 60,
sliderHeight: 60
},
distance: 0, //
flag: false, //
downX: 0, //
bgColor: 'aqua', //
verifyText: '拖动滑块解锁' //
};
},
methods: {
mouseDown (e) {
this.downX = e.clientX;
this.flag = true;
},
mouseMove (e) {
if (this.flag) {
let offset = e.clientX - this.downX;
if (offset > this.data.originalWidth - 43) {
this.distance = this.data.originalWidth - 43;
} else if (offset < 0) {
this.distance = 0;
} else {
this.distance = offset;
}
}
},
mouseUp () {
if (!this.flag) return false;
this.flag = false;
let params = {
verificationEnums: this.type,
xPos: this.distance
};
postVerifyImg(params).then(res => {
if (res.result) {
this.bgColor = 'green';
this.verifyText = '解锁成功';
this.$emit('change', { status: true, distance: this.distance });
} else {
this.bgColor = 'red';
this.verifyText = '解锁失败';
let that = this;
setTimeout(() => {
that.refresh();
}, 1000);
this.$emit('change', { status: false, distance: this.distance });
}
});
},
refresh () {
this.flag = false;
this.downX = 0;
this.distance = 0;
this.bgColor = 'aqua';
this.verifyText = '拖动滑块解锁';
this.getImg();
},
getImg () {
getVerifyImg(this.type).then(res => {
this.data = res.result;
});
}
},
created () {
this.getImg();
},
watch: {
verifyType: {
immediate: true,
handler: function (v) {
this.type = v;
this.refresh();
}
},
show (v) {
if (v) this.refresh();
}
}
};
</script>
<style lang="scss" scoped>
.verify-content{
padding: 10px;
background: #fff;
border: 1px solid #eee;
border-radius: 5px;
box-shadow: 1px 1px 3px #999;
}
.imgBox {
width: 300px;
height: 150px;
position: relative;
overflow: hidden;
.slider {
position: absolute;
cursor: pointer;
}
.refresh {
position: absolute;
right: 5px;
top: 5px;
font-size: 20px;
color: #fff;
cursor: pointer;
}
}
.handle {
border: 1px solid rgb(134, 134, 134);
margin-top: 5px;
height: 42px;
background: #ddd;
position: relative;
.bgcolor {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
opacity: 0.5;
background: aqua;
}
.swiper {
position: absolute;
width: 40px;
height: 40px;
background-color: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
.ivu-icon {
font-size: 20px;
}
}
.text {
display: inline-block;
width: inherit;
text-align: center;
line-height: 42px;
font-size: 14px;
user-select: none;
}
}
</style>

View File

@ -0,0 +1,13 @@
import {commonUrl, getRequestWithNoToken, postRequestWithNoToken} from '@/libs/axios';
// 获取拼图验证
export const getVerifyImg = (verificationEnums) => {
return getRequestWithNoToken(`${commonUrl}/common/slider/${verificationEnums}`);
};
// 拼图验证
export const postVerifyImg = (params) => {
return postRequestWithNoToken(`${commonUrl}/common/slider/${params.verificationEnums}`, params);
};