fix 验证码添加点击验证,角色改为树形结构
This commit is contained in:
parent
17cb2a1d65
commit
ab1d7bee42
@ -29,6 +29,7 @@
|
||||
"pinia": "^2.0.34",
|
||||
"print-js": "^1.6.0",
|
||||
"qrcodejs2-fixes": "^0.0.2",
|
||||
"qs": "^6.11.1",
|
||||
"screenfull": "^6.0.2",
|
||||
"sortablejs": "^1.15.0",
|
||||
"spark-md5": "^3.0.2",
|
||||
@ -36,13 +37,12 @@
|
||||
"vue": "^3.2.47",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-demi": "^0.13.11",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-simple-uploader": "^1.0.0-beta.5",
|
||||
"vue-ueditor-wrap": "^3.0.8",
|
||||
"qs": "^6.11.1",
|
||||
"vue-demi": "^0.13.11"
|
||||
"vue-ueditor-wrap": "^3.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.15.11",
|
||||
|
@ -22,6 +22,27 @@ export function captcha(){
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码V2
|
||||
*/
|
||||
export function captchaV2(){
|
||||
return request({
|
||||
url:"/api/v1/pub/captcha/v2",
|
||||
method:"get"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查v2验证码
|
||||
*/
|
||||
export function checkCaptchaV2(data: { dots: string, key: string }){
|
||||
return request({
|
||||
url:"/api/v1/pub/captcha/v2Check",
|
||||
data:data,
|
||||
method:"post"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
|
378
src/components/goCaptcha/GoCaptcha.vue
Normal file
378
src/components/goCaptcha/GoCaptcha.vue
Normal file
@ -0,0 +1,378 @@
|
||||
<template>
|
||||
<div class="wg-cap-wrap">
|
||||
<div class="wg-cap-wrap__header">
|
||||
<span>请在下图<em>依次</em>点击:</span>
|
||||
<img class="wg-cap-wrap__thumb" v-if="thumbBase64Code" :src="thumbBase64Code" alt=" ">
|
||||
</div>
|
||||
<div class="wg-cap-wrap__body" :style="style">
|
||||
<img class="wg-cap-wrap__picture" v-if="imageBase64Code" :src="imageBase64Code" alt=" " @click="handleClickPos($event)">
|
||||
<img class="wg-cap-wrap__loading" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBzdHlsZT0ibWFyZ2luOiBhdXRvOyBiYWNrZ3JvdW5kOiByZ2JhKDI0MSwgMjQyLCAyNDMsIDApOyBkaXNwbGF5OiBibG9jazsgc2hhcGUtcmVuZGVyaW5nOiBhdXRvOyIgd2lkdGg9IjY0cHgiIGhlaWdodD0iNjRweCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4KICA8Y2lyY2xlIGN4PSI1MCIgY3k9IjM2LjgxMDEiIHI9IjEzIiBmaWxsPSIjM2U3Y2ZmIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImN5IiBkdXI9IjFzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgY2FsY01vZGU9InNwbGluZSIga2V5U3BsaW5lcz0iMC40NSAwIDAuOSAwLjU1OzAgMC40NSAwLjU1IDAuOSIga2V5VGltZXM9IjA7MC41OzEiIHZhbHVlcz0iMjM7Nzc7MjMiPjwvYW5pbWF0ZT4KICA8L2NpcmNsZT4KPC9zdmc+" alt="正在加载中...">
|
||||
<template v-for="(dot, key) in dots" :key="key">
|
||||
<div class="wg-cap-wrap__dot" :style="`top: ${dot.y}px; left:${dot.x}px;`">
|
||||
<span>{{ dot.index }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="wg-cap-wrap__footer">
|
||||
<div class="wg-cap-wrap__ico">
|
||||
<img @click="handleCloseEvent"
|
||||
src="data:image/svg+xml;base64,PHN2ZyB0PSIxNjI2NjE0NDM5NDIzIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9Ijg2NzUiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNNTEyIDIzLjI3MjcyN2MyNjkuOTE3MDkxIDAgNDg4LjcyNzI3MyAyMTguODEwMTgyIDQ4OC43MjcyNzMgNDg4LjcyNzI3M2E0ODYuNjMyNzI3IDQ4Ni42MzI3MjcgMCAwIDEtODQuOTQ1NDU1IDI3NS40MDk0NTUgNDYuNTQ1NDU1IDQ2LjU0NTQ1NSAwIDAgMS03Ni44NDY1NDUtNTIuNTI2NTQ2QTM5My41NDE4MTggMzkzLjU0MTgxOCAwIDAgMCA5MDcuNjM2MzY0IDUxMmMwLTIxOC41MDc2MzYtMTc3LjEyODcyNy0zOTUuNjM2MzY0LTM5NS42MzYzNjQtMzk1LjYzNjM2NFMxMTYuMzYzNjM2IDI5My40OTIzNjQgMTE2LjM2MzYzNiA1MTJzMTc3LjEyODcyNyAzOTUuNjM2MzY0IDM5NS42MzYzNjQgMzk1LjYzNjM2NGEzOTUuMTcwOTA5IDM5NS4xNzA5MDkgMCAwIDAgMTI1LjQ0LTIwLjI5MzgxOSA0Ni41NDU0NTUgNDYuNTQ1NDU1IDAgMCAxIDI5LjQ4NjU0NSA4OC4yOTY3MjhBNDg4LjI2MTgxOCA0ODguMjYxODE4IDAgMCAxIDUxMiAxMDAwLjcyNzI3M0MyNDIuMDgyOTA5IDEwMDAuNzI3MjczIDIzLjI3MjcyNyA3ODEuOTE3MDkxIDIzLjI3MjcyNyA1MTJTMjQyLjA4MjkwOSAyMy4yNzI3MjcgNTEyIDIzLjI3MjcyN3ogbS0xMTUuMiAzMDcuNzEyTDUxMiA0NDYuMTM4MTgybDExNS4yLTExNS4yYTQ2LjU0NTQ1NSA0Ni41NDU0NTUgMCAxIDEgNjUuODE1MjczIDY1Ljg2MTgxOEw1NzcuODYxODE4IDUxMmwxMTUuMiAxMTUuMmE0Ni41NDU0NTUgNDYuNTQ1NDU1IDAgMSAxLTY1Ljg2MTgxOCA2NS44MTUyNzNMNTEyIDU3Ny44NjE4MThsLTExNS4yIDExNS4yYTQ2LjU0NTQ1NSA0Ni41NDU0NTUgMCAxIDEtNjUuODE1MjczLTY1Ljg2MTgxOEw0NDYuMTM4MTgyIDUxMmwtMTE1LjItMTE1LjJhNDYuNTQ1NDU1IDQ2LjU0NTQ1NSAwIDEgMSA2NS44NjE4MTgtNjUuODE1MjczeiIgcC1pZD0iODY3NiIgZmlsbD0iIzcwNzA3MCI+PC9wYXRoPjwvc3ZnPg=="
|
||||
alt="关闭">
|
||||
<img @click="handleRefreshEvent"
|
||||
src="data:image/svg+xml;base64,PHN2ZyB0PSIxNjI2NjE0NDk5NjM4IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEzNjAiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNMTg3LjQ1NiA0MjUuMDI0YTMzNiAzMzYgMCAwIDAgMzY4LjM4NCA0MjAuMjI0IDQ4IDQ4IDAgMCAxIDEyLjU0NCA5NS4xNjggNDMyIDQzMiAwIDAgMS00NzMuNjY0LTU0MC4xNmwtNTcuMjgtMTUuMzZhMTIuOCAxMi44IDAgMCAxLTYuMjcyLTIwLjkyOGwxNTkuMTY4LTE3OS40NTZhMTIuOCAxMi44IDAgMCAxIDIyLjE0NCA1Ljg4OGw0OC4wNjQgMjM1LjA3MmExMi44IDEyLjggMCAwIDEtMTUuODA4IDE0LjkxMmwtNTcuMjgtMTUuMzZ6TTgzNi40OCA1OTkuMDRhMzM2IDMzNiAwIDAgMC0zNjguMzg0LTQyMC4yMjQgNDggNDggMCAxIDEtMTIuNTQ0LTk1LjE2OCA0MzIgNDMyIDAgMCAxIDQ3My42NjQgNTQwLjE2bDU3LjI4IDE1LjM2YTEyLjggMTIuOCAwIDAgMSA2LjI3MiAyMC45MjhsLTE1OS4xNjggMTc5LjQ1NmExMi44IDEyLjggMCAwIDEtMjIuMTQ0LTUuODg4bC00OC4wNjQtMjM1LjA3MmExMi44IDEyLjggMCAwIDEgMTUuODA4LTE0LjkxMmw1Ny4yOCAxNS4zNnoiIGZpbGw9IiM3MDcwNzAiIHAtaWQ9IjEzNjEiPjwvcGF0aD48L3N2Zz4="
|
||||
alt="刷新">
|
||||
</div>
|
||||
<div class="wg-cap-wrap__btn">
|
||||
<button @click="handleConfirmEvent">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GoCaptcha',
|
||||
props: {
|
||||
value: Boolean,
|
||||
width: {
|
||||
type: String,
|
||||
default: '300px'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '240px'
|
||||
},
|
||||
calcPosType: {
|
||||
type: String,
|
||||
default: 'dom',
|
||||
validator: value => ['dom', 'screen'].includes(value)
|
||||
},
|
||||
maxDot: {
|
||||
type: Number,
|
||||
default: 5
|
||||
// validator: value => value > 10
|
||||
},
|
||||
imageBase64: String,
|
||||
thumbBase64: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dots: [],
|
||||
imageBase64Code: '',
|
||||
thumbBase64Code: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.dots = []
|
||||
this.imageBase64Code = ''
|
||||
this.thumbBase64Code = ''
|
||||
},
|
||||
imageBase64(val) {
|
||||
this.dots = []
|
||||
this.imageBase64Code = val
|
||||
},
|
||||
thumbBase64(val) {
|
||||
this.dots = []
|
||||
this.thumbBase64Code = val
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
return `width:${this.width}; height:${this.height};`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Description: 处理关闭事件
|
||||
*/
|
||||
handleCloseEvent() {
|
||||
this.$emit('close')
|
||||
this.dots = []
|
||||
this.imageBase64Code = ''
|
||||
this.thumbBase64Code = ''
|
||||
},
|
||||
/**
|
||||
* @Description: 处理刷新事件
|
||||
*/
|
||||
handleRefreshEvent() {
|
||||
this.dots = []
|
||||
this.$emit('refresh')
|
||||
},
|
||||
/**
|
||||
* @Description: 处理确认事件
|
||||
*/
|
||||
handleConfirmEvent() {
|
||||
this.$emit('confirm', this.dots)
|
||||
},
|
||||
/**
|
||||
* @Description: 处理dot
|
||||
* @param ev
|
||||
*/
|
||||
handleClickPos(ev) {
|
||||
if (this.dots.length >= this.maxDot) {
|
||||
return
|
||||
}
|
||||
const e = ev || window.event
|
||||
e.preventDefault()
|
||||
const dom = e.currentTarget
|
||||
|
||||
const {domX, domY} = this.getDomXY(dom)
|
||||
// ===============================================
|
||||
// @notice 如 getDomXY 不准确可尝试使用 calcLocationLeft 或 calcLocationTop
|
||||
// const domX = this.calcLocationLeft(dom)
|
||||
// const domY = this.calcLocationTop(dom)
|
||||
// ===============================================
|
||||
|
||||
let mouseX = (navigator.appName === 'Netscape') ? e.pageX : e.x + document.body.offsetTop
|
||||
let mouseY = (navigator.appName === 'Netscape') ? e.pageY : e.y + document.body.offsetTop
|
||||
|
||||
if (this.calcPosType === 'screen') {
|
||||
mouseX = (navigator.appName === 'Netscape') ? e.clientX : e.x
|
||||
mouseY = (navigator.appName === 'Netscape') ? e.clientY : e.y
|
||||
}
|
||||
|
||||
// 计算点击的相对位置
|
||||
const xPos = mouseX - domX
|
||||
const yPos = mouseY - domY
|
||||
|
||||
// 转整形
|
||||
const xp = parseInt(xPos.toString())
|
||||
const yp = parseInt(yPos.toString())
|
||||
|
||||
// 减去点的一半
|
||||
this.dots.push({
|
||||
x: xp - 11,
|
||||
y: yp - 11,
|
||||
index: this.dots.length + 1
|
||||
})
|
||||
return false
|
||||
},
|
||||
/**
|
||||
* @Description: 找到元素的屏幕位置
|
||||
* @param el
|
||||
*/
|
||||
calcLocationLeft(el) {
|
||||
let tmp = el.offsetLeft
|
||||
let val = el.offsetParent
|
||||
while (val != null) {
|
||||
tmp += val.offsetLeft
|
||||
val = val.offsetParent
|
||||
}
|
||||
return tmp
|
||||
},
|
||||
/**
|
||||
* @Description: 找到元素的屏幕位置
|
||||
* @param el
|
||||
*/
|
||||
calcLocationTop(el) {
|
||||
let tmp = el.offsetTop
|
||||
let val = el.offsetParent
|
||||
while (val != null) {
|
||||
tmp += val.offsetTop
|
||||
val = val.offsetParent
|
||||
}
|
||||
return tmp
|
||||
},
|
||||
/**
|
||||
* @Description: 找到元素的屏幕位置
|
||||
* @param dom
|
||||
*/
|
||||
getDomXY(dom){
|
||||
let x = 0
|
||||
let y = 0
|
||||
if (dom.getBoundingClientRect) {
|
||||
let box = dom.getBoundingClientRect();
|
||||
let D = document.documentElement;
|
||||
x = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft;
|
||||
y = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop
|
||||
}
|
||||
else{
|
||||
while (dom !== document.body) {
|
||||
x += dom.offsetLeft
|
||||
y += dom.offsetTop
|
||||
dom = dom.offsetParent
|
||||
}
|
||||
}
|
||||
return {
|
||||
domX: x,
|
||||
domY: y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wg-cap-wrap{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.wg-cap-wrap__header{
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
|
||||
display:-webkit-box;
|
||||
display:-webkit-flex;
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-webkit-box-align:center;
|
||||
-webkit-align-items:center;
|
||||
-ms-flex-align:center;
|
||||
align-items: center;
|
||||
}
|
||||
.wg-cap-wrap__header span{
|
||||
padding-right: 5px;
|
||||
}
|
||||
.wg-cap-wrap__header span em{
|
||||
padding: 0 3px;
|
||||
font-weight: bold;
|
||||
color: #3e7cff;
|
||||
font-style: normal;
|
||||
}
|
||||
.wg-cap-wrap__header .wg-cap-wrap__image{
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
.wg-cap-wrap__header .wg-cap-wrap__thumb{
|
||||
min-width: 150px;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
max-height: 100%;
|
||||
}
|
||||
.wg-cap-wrap__header .wg-cap-wrap__thumb.wg-cap-wrap__hidden{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wg-cap-wrap__body{
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
background: #34383e;
|
||||
margin: auto;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wg-cap-wrap__body .wg-cap-wrap__picture{
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
|
||||
/*height: 100%;*/
|
||||
/*max-width: 100%;*/
|
||||
/*max-height: 100%;*/
|
||||
/*object-fit: cover;*/
|
||||
/*text-align: center;*/
|
||||
}
|
||||
.wg-cap-wrap__body .wg-cap-wrap__picture.wg-cap-wrap__hidden{
|
||||
display: none;
|
||||
}
|
||||
.wg-cap-wrap__body .wg-cap-wrap__loading{
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
margin-left: -34px;
|
||||
margin-top: -34px;
|
||||
line-height: 68px;
|
||||
text-align: center;
|
||||
}
|
||||
.wg-cap-wrap__body .wg-cap-wrap__dot{
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
color: #cedffe;
|
||||
background: #3e7cff;
|
||||
border: 2px solid #f7f9fb;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
-webkit-border-radius: 22px;
|
||||
-moz-border-radius: 22px;
|
||||
border-radius: 22px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.wg-cap-wrap__footer {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
color: #34383e;
|
||||
display:-webkit-box;
|
||||
display:-webkit-flex;
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-webkit-box-align:center;
|
||||
-webkit-align-items:center;
|
||||
-ms-flex-align:center;
|
||||
align-items: center;
|
||||
padding-top: 15px;
|
||||
}
|
||||
.wg-cap-wrap__footer .wg-cap-wrap__ico{
|
||||
flex: 1;
|
||||
}
|
||||
.wg-cap-wrap__footer .wg-cap-wrap__ico img{
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: #34383e;
|
||||
margin: 0 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.wg-cap-wrap__footer .wg-cap-wrap__btn{
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
}
|
||||
.wg-cap-wrap__footer .wg-cap-wrap__btn button{
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
letter-spacing: 2px;
|
||||
text-align: center;
|
||||
padding: 9px 15px;
|
||||
font-size: 15px;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background-color: #409eff;
|
||||
border: 1px solid #409eff;
|
||||
-webkit-appearance: none;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
transition: .1s;
|
||||
font-weight: 500;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
.wg-cap-wrap__footer .wg-cap-wrap__btn button:hover {
|
||||
background: #66b1ff;
|
||||
border-color: #66b1ff;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
334
src/components/goCaptcha/GoCaptchaBtn.vue
Normal file
334
src/components/goCaptcha/GoCaptchaBtn.vue
Normal file
@ -0,0 +1,334 @@
|
||||
<template>
|
||||
<div class="wg-cap-btn" :style="style">
|
||||
<div class="wg-cap-btn__inner" :class="activeClass">
|
||||
<!-- wg-cap-active__default wg-cap-active__error wg-cap-active__over wg-cap-active__success -->
|
||||
<el-popover
|
||||
:visible="popoverVisible"
|
||||
placement="top"
|
||||
width="330px"
|
||||
@hide="handleCloseEvent"
|
||||
trigger="click">
|
||||
<go-captcha
|
||||
v-model="popoverVisible"
|
||||
width="300px"
|
||||
height="240px"
|
||||
:max-dot="maxDot"
|
||||
:image-base64="captchaData.captBase64"
|
||||
:thumb-base64="captchaData.captThumbBase64"
|
||||
@close="handleCloseEvent"
|
||||
@refresh="handleRefreshEvent"
|
||||
@confirm="handleConfirmEvent"
|
||||
/>
|
||||
<template v-slot:reference>
|
||||
<div @click="handleBtnEvent" class="wg-cap-state__default" v-if="captStatus==='default'">
|
||||
<!-- 初始状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico wg-cap-btn__verify">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSLlm77lsYJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDIwMCAyMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDIwMCAyMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojM0U3Q0ZGO30KCS5zdDF7ZmlsbDojRkZGRkZGO30KPC9zdHlsZT4KPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iMTAwIiBjeT0iMTAwIiByPSI5Ni4zIi8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xNDAuOCw2NC40bC0zOS42LTExLjloLTIuNEw1OS4yLDY0LjRjLTEuNiwwLjgtMi44LDIuNC0yLjgsNHYyNC4xYzAsMjUuMywxNS44LDQ1LjksNDIuMyw1NC42CgljMC40LDAsMC44LDAuNCwxLjIsMC40YzAuNCwwLDAuOCwwLDEuMi0wLjRjMjYuNS04LjcsNDIuMy0yOC45LDQyLjMtNTQuNlY2OC4zQzE0My41LDY2LjgsMTQyLjMsNjUuMiwxNDAuOCw2NC40eiIvPgo8L3N2Zz4K">
|
||||
</div>
|
||||
<span class="wg-cap-btn__text">点击按键进行人机验证</span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="()=>false" class="wg-cap-state__check" v-if="captStatus==='check'">
|
||||
<!-- 验证状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PHN2ZyB0PSIxNjI3MDU1NTg2NTk0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEyMTEiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNMTIwLjI1OTQ1NiA1MTIuMDAxMDIzbS0xMTcuOTIzNzYgMGExMTUuMjM4IDExNS4yMzggMCAxIDAgMjM1Ljg0NzUxOSAwIDExNS4yMzggMTE1LjIzOCAwIDEgMC0yMzUuODQ3NTE5IDBaIiBwLWlkPSIxMjEyIiBmaWxsPSIjZmZhMDAwIj48L3BhdGg+PHBhdGggZD0iTTUxMS45OTk0ODggNTEyLjAwMTAyM20tMTE3LjkyMTcxMyAwYTExNS4yMzYgMTE1LjIzNiAwIDEgMCAyMzUuODQzNDI2IDAgMTE1LjIzNiAxMTUuMjM2IDAgMSAwLTIzNS44NDM0MjYgMFoiIHAtaWQ9IjEyMTMiIGZpbGw9IiNmZmEwMDAiPjwvcGF0aD48cGF0aCBkPSJNOTAzLjczOTUyMSA1MTIuMDAxMDIzbS0xMTcuOTIzNzYgMGExMTUuMjM4IDExNS4yMzggMCAxIDAgMjM1Ljg0NzUxOSAwIDExNS4yMzggMTE1LjIzOCAwIDEgMC0yMzUuODQ3NTE5IDBaIiBwLWlkPSIxMjE0IiBmaWxsPSIjZmZhMDAwIj48L3BhdGg+PC9zdmc+"
|
||||
alt="">
|
||||
</div>
|
||||
<span class="wg-cap-btn__text">正在进行人机验证...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="handleBtnEvent" class="wg-cap-state__error" v-if="captStatus==='error'">
|
||||
<!-- 验证失败状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0VENDYzMDt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xODQsMjYuNkwxMDIuNCwyLjFoLTQuOUwxNiwyNi42Yy0zLjMsMS42LTUuNyw0LjktNS43LDguMnY0OS44YzAsNTIuMiwzMi42LDk0LjcsODcuMywxMTIuNgoJYzAuOCwwLDEuNiwwLjgsMi40LDAuOHMxLjYsMCwyLjQtMC44YzU0LjctMTgsODcuMy01OS42LDg3LjMtMTEyLjZWMzQuN0MxODkuOCwzMS41LDE4Ny4zLDI4LjIsMTg0LDI2LjZ6IE0xMzQuNSwxMjMuMQoJYzMuMSwzLjEsMy4xLDguMiwwLDExLjNjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zcy00LjEtMC44LTUuNy0yLjNMMTAwLDExMS4zbC0yMy4xLDIzLjFjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zCgljLTIsMC00LjEtMC44LTUuNy0yLjNjLTMuMS0zLjEtMy4xLTguMiwwLTExLjNMODguNywxMDBMNjUuNSw3Ni45Yy0zLjEtMy4xLTMuMS04LjIsMC0xMS4zYzMuMS0zLjEsOC4yLTMuMSwxMS4zLDBMMTAwLDg4LjcKCWwyMy4xLTIzLjFjMy4xLTMuMSw4LjItMy4xLDExLjMsMGMzLjEsMy4xLDMuMSw4LjIsMCwxMS4zTDExMS4zLDEwMEwxMzQuNSwxMjMuMXoiLz4KPC9zdmc+Cg=="
|
||||
alt="失败">
|
||||
</div>
|
||||
<span>人机验证失败 <em>点击重试</em></span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="handleBtnEvent" class="wg-cap-state__over" v-if="captStatus==='over'">
|
||||
<!-- 验证次数过多状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0VENDYzMDt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xODQsMjYuNkwxMDIuNCwyLjFoLTQuOUwxNiwyNi42Yy0zLjMsMS42LTUuNyw0LjktNS43LDguMnY0OS44YzAsNTIuMiwzMi42LDk0LjcsODcuMywxMTIuNgoJYzAuOCwwLDEuNiwwLjgsMi40LDAuOHMxLjYsMCwyLjQtMC44YzU0LjctMTgsODcuMy01OS42LDg3LjMtMTEyLjZWMzQuN0MxODkuOCwzMS41LDE4Ny4zLDI4LjIsMTg0LDI2LjZ6IE0xMzQuNSwxMjMuMQoJYzMuMSwzLjEsMy4xLDguMiwwLDExLjNjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zcy00LjEtMC44LTUuNy0yLjNMMTAwLDExMS4zbC0yMy4xLDIzLjFjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zCgljLTIsMC00LjEtMC44LTUuNy0yLjNjLTMuMS0zLjEtMy4xLTguMiwwLTExLjNMODguNywxMDBMNjUuNSw3Ni45Yy0zLjEtMy4xLTMuMS04LjIsMC0xMS4zYzMuMS0zLjEsOC4yLTMuMSwxMS4zLDBMMTAwLDg4LjcKCWwyMy4xLTIzLjFjMy4xLTMuMSw4LjItMy4xLDExLjMsMGMzLjEsMy4xLDMuMSw4LjIsMCwxMS4zTDExMS4zLDEwMEwxMzQuNSwxMjMuMXoiLz4KPC9zdmc+Cg=="
|
||||
alt="失败">
|
||||
</div>
|
||||
<span>点击次数过多 <em>点击重试</em></span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="()=>false" class="wg-cap-state__success" v-if="captStatus==='success'">
|
||||
<!-- 验证成功状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzVFQUEyRjt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xODMuMywyNy4yTDEwMi40LDIuOWgtNC45TDE2LjcsMjcuMkMxMy40LDI4LjgsMTEsMzIsMTEsMzUuM3Y0OS40YzAsNTEuOCwzMi40LDkzLjksODYuNiwxMTEuNwoJYzAuOCwwLDEuNiwwLjgsMi40LDAuOGMwLjgsMCwxLjYsMCwyLjQtMC44YzU0LjItMTcuOCw4Ni42LTU5LjEsODYuNi0xMTEuN1YzNS4zQzE4OSwzMiwxODYuNiwyOC44LDE4My4zLDI3LjJ6IE0xNDYuMSw4MS40CglsLTQ4LjUsNDguNWMtMS42LDEuNi0zLjIsMi40LTUuNywyLjRjLTIuNCwwLTQtMC44LTUuNy0yLjRMNjIsMTA1LjdjLTMuMi0zLjItMy4yLTguMSwwLTExLjNjMy4yLTMuMiw4LjEtMy4yLDExLjMsMGwxOC42LDE4LjYKCWw0Mi45LTQyLjljMy4yLTMuMiw4LjEtMy4yLDExLjMsMEMxNDkuNCw3My4zLDE0OS40LDc4LjIsMTQ2LjEsODEuNEwxNDYuMSw4MS40eiIvPgo8L3N2Zz4K"
|
||||
alt="成功">
|
||||
</div>
|
||||
<span>人机验证已通过</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GoCaptcha from './GoCaptcha.vue'
|
||||
import {captchaV2, checkCaptchaV2} from "/@/api/login";
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
export default {
|
||||
name: 'GoCaptchaBtn',
|
||||
components: {GoCaptcha},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
validator: value => ['default', 'check', 'error', 'over', 'success'].indexOf(value) > -1
|
||||
},
|
||||
width: String,
|
||||
height: String,
|
||||
maxDot: {
|
||||
type: Number,
|
||||
default: 5
|
||||
}
|
||||
},
|
||||
emits:['update:modelValue','handleConfirm'],
|
||||
data() {
|
||||
return {
|
||||
popoverVisible: false,
|
||||
captStatus: 'default',
|
||||
captchaData: {
|
||||
captBase64: '',
|
||||
captThumbBase64: '',
|
||||
captKey: '',
|
||||
captStatus: 'default',
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
popoverVisible(val) {
|
||||
if (val) {
|
||||
this.captStatus = 'check'
|
||||
}else if(this.captStatus!=='success'){
|
||||
this.captStatus = 'default'
|
||||
}
|
||||
},
|
||||
modelValue(val) {
|
||||
window.console.log(val)
|
||||
if (this.captStatus !== 'check') {
|
||||
this.captStatus = val
|
||||
}
|
||||
if (val === 'over' || val === 'success') {
|
||||
setTimeout(() => {
|
||||
this.popoverVisible = false
|
||||
}, 0)
|
||||
}
|
||||
},
|
||||
captStatus(val) {
|
||||
if (val !== 'check' && this.value !== val) {
|
||||
this.$emit('update:modelValue', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
return `width:${this.width}; height:${this.height};`
|
||||
},
|
||||
activeClass() {
|
||||
let activeClass = this.captStatus
|
||||
return `wg-cap-active__${activeClass}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleBtnEvent() {
|
||||
this.popoverVisible = false
|
||||
setTimeout(() => {
|
||||
this.popoverVisible = true
|
||||
this.handleRefreshEvent()
|
||||
}, 200)
|
||||
},
|
||||
handleRefreshEvent() {
|
||||
this.captStatus = 'check'
|
||||
this.captchaData.captBase64 = ''
|
||||
this.captchaData.captThumbBase64 = ''
|
||||
this.captchaData.captKey = ''
|
||||
captchaV2().then(res=>{
|
||||
if(res.code === 0) {
|
||||
this.captchaData.captBase64 = res.data['img'] || ''
|
||||
this.captchaData.captThumbBase64 = res.data['thumb'] || ''
|
||||
this.captchaData.captKey = res.data['key'] || ''
|
||||
}
|
||||
})
|
||||
},
|
||||
handleConfirmEvent(dots) {
|
||||
if (dots.length <= 0) {
|
||||
ElMessage.error('请进行人机验证再操作')
|
||||
return
|
||||
}
|
||||
const str = btoa(encodeURIComponent(JSON.stringify(dots)))
|
||||
checkCaptchaV2({key:this.captchaData.captKey,dots:str}).then(res=>{
|
||||
if(res.code === 0) {
|
||||
ElMessage.success('人机验证成功')
|
||||
this.captStatus='success'
|
||||
this.popoverVisible = false
|
||||
this.$emit('handleConfirm',{key:this.captchaData.captKey,dots:str})
|
||||
}
|
||||
}).catch(err=>{
|
||||
window.console.log(err)
|
||||
this.captStatus='error'
|
||||
})
|
||||
|
||||
},
|
||||
handleCloseEvent() {
|
||||
this.popoverVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.wg-cap-btn {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner{
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
position: relative;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__default,.wg-cap-btn .wg-cap-state__check, .wg-cap-btn .wg-cap-state__error, .wg-cap-btn .wg-cap-state__success, .wg-cap-btn .wg-cap-state__over{
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__default{
|
||||
color: #3e7cff;
|
||||
border: 1px solid #50a1ff;
|
||||
background: #ecf5ff;
|
||||
box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
|
||||
-webkit-box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
|
||||
-moz-box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__check{
|
||||
cursor: default;
|
||||
color: #ffa000;
|
||||
background: #fdf6ec;
|
||||
border: 1px solid #ffbe09;
|
||||
pointer-events: none;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__error{
|
||||
color: #ed4630;
|
||||
background: #fef0f0;
|
||||
border: 1px solid #ff5a34;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__over{
|
||||
color: #ed4630;
|
||||
background: #fef0f0;
|
||||
border: 1px solid #ff5a34;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__success{
|
||||
color: #5eaa2f;
|
||||
background: #f0f9eb;
|
||||
border: 1px solid #8bc640;
|
||||
pointer-events: none;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-active__default .wg-cap-state__default, .wg-cap-btn .wg-cap-active__error .wg-cap-state__error,.wg-cap-btn .wg-cap-active__over .wg-cap-state__over ,.wg-cap-btn .wg-cap-active__success .wg-cap-state__success,.wg-cap-btn .wg-cap-active__check .wg-cap-state__check {
|
||||
visibility: visible;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__inner{
|
||||
display:-webkit-box;
|
||||
display:-webkit-flex;
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-webkit-box-align:center;
|
||||
-webkit-align-items:center;
|
||||
-ms-flex-align:center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__inner em{
|
||||
padding-left: 5px;
|
||||
color: #3e7cff;
|
||||
font-style: normal;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__ico{
|
||||
position: relative;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 12px;
|
||||
font-size: 14px;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
flex: 0;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__ico img{
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
float: left;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
@keyframes ripple {
|
||||
0% { opacity: 0; }
|
||||
5% { opacity: 0.05; }
|
||||
20% { opacity: 0.35; }
|
||||
65% { opacity: 0.01; }
|
||||
100% {
|
||||
transform: scaleX(2) scaleY(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes ripple {
|
||||
0% { opacity: 0; }
|
||||
5% { opacity: 0.05; }
|
||||
20% { opacity: 0.35; }
|
||||
65% { opacity: 0.01; }
|
||||
100% {
|
||||
transform: scaleX(2) scaleY(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__verify::after {
|
||||
background: #409eff;
|
||||
-webkit-border-radius: 50px;
|
||||
-moz-border-radius: 50px;
|
||||
border-radius: 50px;
|
||||
content: "";
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9;
|
||||
|
||||
animation: ripple 1.3s infinite;
|
||||
-moz-animation: ripple 1.3s infinite;
|
||||
-webkit-animation: ripple 1.3s infinite;
|
||||
animation-delay: 2s;
|
||||
-moz-animation-delay: 2s;
|
||||
-webkit-animation-delay: 2s;
|
||||
}
|
||||
|
||||
.wg-cap-tip{
|
||||
padding: 50px 20px 100px;
|
||||
font-size: 13px;
|
||||
color: #76839b;
|
||||
text-align: center;
|
||||
line-height: 180%;
|
||||
width: 100%;
|
||||
max-width: 680px;
|
||||
}
|
||||
</style>
|
331
src/components/goCaptcha/GoCaptchaBtnDialog.vue
Normal file
331
src/components/goCaptcha/GoCaptchaBtnDialog.vue
Normal file
@ -0,0 +1,331 @@
|
||||
<template>
|
||||
<div class="wg-cap-btn" :style="style">
|
||||
<div class="wg-cap-btn__inner" :class="activeClass">
|
||||
<!-- wg-cap-active__default wg-cap-active__error wg-cap-active__over wg-cap-active__success -->
|
||||
<template>
|
||||
<div @click="handleBtnEvent" class="wg-cap-state__default">
|
||||
<!-- 初始状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico wg-cap-btn__verify">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSLlm77lsYJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDIwMCAyMDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDIwMCAyMDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojM0U3Q0ZGO30KCS5zdDF7ZmlsbDojRkZGRkZGO30KPC9zdHlsZT4KPGNpcmNsZSBjbGFzcz0ic3QwIiBjeD0iMTAwIiBjeT0iMTAwIiByPSI5Ni4zIi8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xNDAuOCw2NC40bC0zOS42LTExLjloLTIuNEw1OS4yLDY0LjRjLTEuNiwwLjgtMi44LDIuNC0yLjgsNHYyNC4xYzAsMjUuMywxNS44LDQ1LjksNDIuMyw1NC42CgljMC40LDAsMC44LDAuNCwxLjIsMC40YzAuNCwwLDAuOCwwLDEuMi0wLjRjMjYuNS04LjcsNDIuMy0yOC45LDQyLjMtNTQuNlY2OC4zQzE0My41LDY2LjgsMTQyLjMsNjUuMiwxNDAuOCw2NC40eiIvPgo8L3N2Zz4K">
|
||||
</div>
|
||||
<span class="wg-cap-btn__text">点击按键进行人机验证</span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="()=>false" class="wg-cap-state__check">
|
||||
<!-- 验证状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PHN2ZyB0PSIxNjI3MDU1NTg2NTk0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjEyMTEiIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj48cGF0aCBkPSJNMTIwLjI1OTQ1NiA1MTIuMDAxMDIzbS0xMTcuOTIzNzYgMGExMTUuMjM4IDExNS4yMzggMCAxIDAgMjM1Ljg0NzUxOSAwIDExNS4yMzggMTE1LjIzOCAwIDEgMC0yMzUuODQ3NTE5IDBaIiBwLWlkPSIxMjEyIiBmaWxsPSIjZmZhMDAwIj48L3BhdGg+PHBhdGggZD0iTTUxMS45OTk0ODggNTEyLjAwMTAyM20tMTE3LjkyMTcxMyAwYTExNS4yMzYgMTE1LjIzNiAwIDEgMCAyMzUuODQzNDI2IDAgMTE1LjIzNiAxMTUuMjM2IDAgMSAwLTIzNS44NDM0MjYgMFoiIHAtaWQ9IjEyMTMiIGZpbGw9IiNmZmEwMDAiPjwvcGF0aD48cGF0aCBkPSJNOTAzLjczOTUyMSA1MTIuMDAxMDIzbS0xMTcuOTIzNzYgMGExMTUuMjM4IDExNS4yMzggMCAxIDAgMjM1Ljg0NzUxOSAwIDExNS4yMzggMTE1LjIzOCAwIDEgMC0yMzUuODQ3NTE5IDBaIiBwLWlkPSIxMjE0IiBmaWxsPSIjZmZhMDAwIj48L3BhdGg+PC9zdmc+"
|
||||
alt="">
|
||||
</div>
|
||||
<span class="wg-cap-btn__text">正在进行人机验证...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="handleBtnEvent" class="wg-cap-state__error">
|
||||
<!-- 验证失败状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0VENDYzMDt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xODQsMjYuNkwxMDIuNCwyLjFoLTQuOUwxNiwyNi42Yy0zLjMsMS42LTUuNyw0LjktNS43LDguMnY0OS44YzAsNTIuMiwzMi42LDk0LjcsODcuMywxMTIuNgoJYzAuOCwwLDEuNiwwLjgsMi40LDAuOHMxLjYsMCwyLjQtMC44YzU0LjctMTgsODcuMy01OS42LDg3LjMtMTEyLjZWMzQuN0MxODkuOCwzMS41LDE4Ny4zLDI4LjIsMTg0LDI2LjZ6IE0xMzQuNSwxMjMuMQoJYzMuMSwzLjEsMy4xLDguMiwwLDExLjNjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zcy00LjEtMC44LTUuNy0yLjNMMTAwLDExMS4zbC0yMy4xLDIzLjFjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zCgljLTIsMC00LjEtMC44LTUuNy0yLjNjLTMuMS0zLjEtMy4xLTguMiwwLTExLjNMODguNywxMDBMNjUuNSw3Ni45Yy0zLjEtMy4xLTMuMS04LjIsMC0xMS4zYzMuMS0zLjEsOC4yLTMuMSwxMS4zLDBMMTAwLDg4LjcKCWwyMy4xLTIzLjFjMy4xLTMuMSw4LjItMy4xLDExLjMsMGMzLjEsMy4xLDMuMSw4LjIsMCwxMS4zTDExMS4zLDEwMEwxMzQuNSwxMjMuMXoiLz4KPC9zdmc+Cg=="
|
||||
alt="失败">
|
||||
</div>
|
||||
<span>人机验证失败 <em>点击重试</em></span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="handleBtnEvent" class="wg-cap-state__over">
|
||||
<!-- 验证次数过多状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0VENDYzMDt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xODQsMjYuNkwxMDIuNCwyLjFoLTQuOUwxNiwyNi42Yy0zLjMsMS42LTUuNyw0LjktNS43LDguMnY0OS44YzAsNTIuMiwzMi42LDk0LjcsODcuMywxMTIuNgoJYzAuOCwwLDEuNiwwLjgsMi40LDAuOHMxLjYsMCwyLjQtMC44YzU0LjctMTgsODcuMy01OS42LDg3LjMtMTEyLjZWMzQuN0MxODkuOCwzMS41LDE4Ny4zLDI4LjIsMTg0LDI2LjZ6IE0xMzQuNSwxMjMuMQoJYzMuMSwzLjEsMy4xLDguMiwwLDExLjNjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zcy00LjEtMC44LTUuNy0yLjNMMTAwLDExMS4zbC0yMy4xLDIzLjFjLTEuNiwxLjYtMy42LDIuMy01LjcsMi4zCgljLTIsMC00LjEtMC44LTUuNy0yLjNjLTMuMS0zLjEtMy4xLTguMiwwLTExLjNMODguNywxMDBMNjUuNSw3Ni45Yy0zLjEtMy4xLTMuMS04LjIsMC0xMS4zYzMuMS0zLjEsOC4yLTMuMSwxMS4zLDBMMTAwLDg4LjcKCWwyMy4xLTIzLjFjMy4xLTMuMSw4LjItMy4xLDExLjMsMGMzLjEsMy4xLDMuMSw4LjIsMCwxMS4zTDExMS4zLDEwMEwxMzQuNSwxMjMuMXoiLz4KPC9zdmc+Cg=="
|
||||
alt="失败">
|
||||
</div>
|
||||
<span>点击次数过多 <em>点击重试</em></span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click="()=>false" class="wg-cap-state__success">
|
||||
<!-- 验证成功状态 -->
|
||||
<div class="wg-cap-state__inner">
|
||||
<div class="wg-cap-btn__ico">
|
||||
<img
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAyMDAgMjAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMDAgMjAwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzVFQUEyRjt9Cjwvc3R5bGU+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xODMuMywyNy4yTDEwMi40LDIuOWgtNC45TDE2LjcsMjcuMkMxMy40LDI4LjgsMTEsMzIsMTEsMzUuM3Y0OS40YzAsNTEuOCwzMi40LDkzLjksODYuNiwxMTEuNwoJYzAuOCwwLDEuNiwwLjgsMi40LDAuOGMwLjgsMCwxLjYsMCwyLjQtMC44YzU0LjItMTcuOCw4Ni42LTU5LjEsODYuNi0xMTEuN1YzNS4zQzE4OSwzMiwxODYuNiwyOC44LDE4My4zLDI3LjJ6IE0xNDYuMSw4MS40CglsLTQ4LjUsNDguNWMtMS42LDEuNi0zLjIsMi40LTUuNywyLjRjLTIuNCwwLTQtMC44LTUuNy0yLjRMNjIsMTA1LjdjLTMuMi0zLjItMy4yLTguMSwwLTExLjNjMy4yLTMuMiw4LjEtMy4yLDExLjMsMGwxOC42LDE4LjYKCWw0Mi45LTQyLjljMy4yLTMuMiw4LjEtMy4yLDExLjMsMEMxNDkuNCw3My4zLDE0OS40LDc4LjIsMTQ2LjEsODEuNEwxNDYuMSw4MS40eiIvPgo8L3N2Zz4K"
|
||||
alt="成功">
|
||||
</div>
|
||||
<span>人机验证已通过</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="popoverVisible"
|
||||
:close-on-click-modal="false"
|
||||
append-to-body
|
||||
:center="true"
|
||||
title="人机校验"
|
||||
:show-close="false"
|
||||
z-index="999999"
|
||||
width="360px"
|
||||
>
|
||||
<go-captcha
|
||||
v-model="popoverVisible"
|
||||
width="300px"
|
||||
height="240px"
|
||||
:max-dot="maxDot"
|
||||
:image-base64="imageBase64"
|
||||
:thumb-base64="thumbBase64"
|
||||
@close="handleCloseEvent"
|
||||
@refresh="handleRefreshEvent"
|
||||
@confirm="handleConfirmEvent"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GoCaptcha from './GoCaptcha.vue'
|
||||
export default {
|
||||
name: 'GoCaptchaBtnDialog',
|
||||
components: {GoCaptcha},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
validator: value => ['default', 'check', 'error', 'over', 'success'].indexOf(value) > -1
|
||||
},
|
||||
width: String,
|
||||
height: String,
|
||||
maxDot: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
imageBase64: String,
|
||||
thumbBase64: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
popoverVisible: false,
|
||||
captStatus: 'default'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
popoverVisible(val) {
|
||||
if (val) {
|
||||
this.captStatus = 'check'
|
||||
this.$emit('refresh')
|
||||
} else if (this.captStatus === 'check') {
|
||||
this.captStatus = this.value
|
||||
}
|
||||
},
|
||||
value(val) {
|
||||
if (this.captStatus !== 'check') {
|
||||
this.captStatus = val
|
||||
}
|
||||
if (val === 'over' || val === 'success') {
|
||||
setTimeout(() => {
|
||||
this.popoverVisible = false
|
||||
}, 0)
|
||||
}
|
||||
},
|
||||
captStatus(val) {
|
||||
if (val !== 'check' && this.value !== val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
return `width:${this.width}; height:${this.height};`
|
||||
},
|
||||
activeClass() {
|
||||
let activeClass = this.captStatus
|
||||
return `wg-cap-active__${activeClass}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleBtnEvent() {
|
||||
setTimeout(() => {
|
||||
this.popoverVisible = true
|
||||
}, 0)
|
||||
},
|
||||
handleRefreshEvent() {
|
||||
this.captStatus = 'check'
|
||||
this.$emit('refresh')
|
||||
},
|
||||
handleConfirmEvent(data) {
|
||||
this.$emit('confirm', data)
|
||||
},
|
||||
handleCloseEvent() {
|
||||
this.popoverVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wg-cap-btn {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner{
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
position: relative;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__default,.wg-cap-btn .wg-cap-state__check, .wg-cap-btn .wg-cap-state__error, .wg-cap-btn .wg-cap-state__success, .wg-cap-btn .wg-cap-state__over{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
font-size: 13px;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
transition: .1s;
|
||||
font-weight: 500;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
display:-webkit-box;
|
||||
display:-webkit-flex;
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-webkit-box-align:center;
|
||||
-webkit-align-items:center;
|
||||
-ms-flex-align:center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
|
||||
visibility: hidden;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__default{
|
||||
color: #3e7cff;
|
||||
border: 1px solid #50a1ff;
|
||||
background: #ecf5ff;
|
||||
box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
|
||||
-webkit-box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
|
||||
-moz-box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__check{
|
||||
cursor: default;
|
||||
color: #ffa000;
|
||||
background: #fdf6ec;
|
||||
border: 1px solid #ffbe09;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__error{
|
||||
color: #ed4630;
|
||||
background: #fef0f0;
|
||||
border: 1px solid #ff5a34;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__over{
|
||||
color: #ed4630;
|
||||
background: #fef0f0;
|
||||
border: 1px solid #ff5a34;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__success{
|
||||
color: #5eaa2f;
|
||||
background: #f0f9eb;
|
||||
border: 1px solid #8bc640
|
||||
}
|
||||
.wg-cap-btn .wg-cap-active__default .wg-cap-state__default, .wg-cap-btn .wg-cap-active__error .wg-cap-state__error,.wg-cap-btn .wg-cap-active__over .wg-cap-state__over ,.wg-cap-btn .wg-cap-active__success .wg-cap-state__success,.wg-cap-btn .wg-cap-active__check .wg-cap-state__check {
|
||||
visibility: visible;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__inner{
|
||||
display:-webkit-box;
|
||||
display:-webkit-flex;
|
||||
display:-ms-flexbox;
|
||||
display:flex;
|
||||
-webkit-box-align:center;
|
||||
-webkit-align-items:center;
|
||||
-ms-flex-align:center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-state__inner em{
|
||||
padding-left: 5px;
|
||||
color: #3e7cff;
|
||||
font-style: normal;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__ico{
|
||||
position: relative;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 12px;
|
||||
font-size: 14px;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
flex: 0;
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__ico img{
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
float: left;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
@keyframes ripple {
|
||||
0% { opacity: 0; }
|
||||
5% { opacity: 0.05; }
|
||||
20% { opacity: 0.35; }
|
||||
65% { opacity: 0.01; }
|
||||
100% {
|
||||
transform: scaleX(2) scaleY(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes ripple {
|
||||
0% { opacity: 0; }
|
||||
5% { opacity: 0.05; }
|
||||
20% { opacity: 0.35; }
|
||||
65% { opacity: 0.01; }
|
||||
100% {
|
||||
transform: scaleX(2) scaleY(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__verify::after {
|
||||
background: #409eff;
|
||||
-webkit-border-radius: 50px;
|
||||
-moz-border-radius: 50px;
|
||||
border-radius: 50px;
|
||||
content: "";
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9;
|
||||
|
||||
animation: ripple 1.3s infinite;
|
||||
-moz-animation: ripple 1.3s infinite;
|
||||
-webkit-animation: ripple 1.3s infinite;
|
||||
animation-delay: 2s;
|
||||
-moz-animation-delay: 2s;
|
||||
-webkit-animation-delay: 2s;
|
||||
}
|
||||
|
||||
.wg-cap-tip{
|
||||
padding: 50px 20px 100px;
|
||||
font-size: 13px;
|
||||
color: #76839b;
|
||||
text-align: center;
|
||||
line-height: 180%;
|
||||
width: 100%;
|
||||
max-width: 680px;
|
||||
}
|
||||
</style>
|
@ -33,11 +33,29 @@ export function handleTree(data:any[], id:string, parentId:string, children:stri
|
||||
id = id || 'id'
|
||||
parentId = parentId || 'parentId'
|
||||
children = children || 'children'
|
||||
let rootIds:any = []
|
||||
if(typeof rootId === 'boolean' && rootId){
|
||||
//自动获取rootId
|
||||
let idSet:any = {}
|
||||
data.map((item:any)=>{
|
||||
idSet[item[id]] = true
|
||||
})
|
||||
data.map((item:any)=>{
|
||||
if(!idSet[item[parentId]]){
|
||||
rootIds.push(item[parentId])
|
||||
}
|
||||
})
|
||||
}else{
|
||||
rootId = rootId || 0
|
||||
rootIds = [rootId]
|
||||
}
|
||||
rootIds = [...new Set(rootIds)]
|
||||
let treeData:any = []
|
||||
//对源数据深度克隆
|
||||
const cloneData = JSON.parse(JSON.stringify(data))
|
||||
rootIds.map((rItem:any)=>{
|
||||
//循环所有项
|
||||
const treeData = cloneData.filter((father:any) => {
|
||||
const td = cloneData.filter((father:any) => {
|
||||
let branchArr = cloneData.filter((child:any) => {
|
||||
//返回每一项的子级数组
|
||||
return father[id] === child[parentId]
|
||||
@ -46,15 +64,19 @@ export function handleTree(data:any[], id:string, parentId:string, children:stri
|
||||
//返回第一层
|
||||
switch (typeof father[parentId]){
|
||||
case 'string':
|
||||
if(father[parentId]===''&&rootId===0){
|
||||
if(father[parentId]===''&&rItem===0){
|
||||
return true
|
||||
}
|
||||
return father[parentId]===rootId.toString();
|
||||
return father[parentId]===rItem.toString();
|
||||
case 'number':
|
||||
return father[parentId] === rootId;
|
||||
return father[parentId] === rItem;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if(td.length>0){
|
||||
treeData = [...treeData,...td]
|
||||
}
|
||||
})
|
||||
return treeData != '' ? treeData : data;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ const service: AxiosInstance = axios.create({
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
paramsSerializer: {
|
||||
serialize(params) {
|
||||
return qs.stringify(params, { allowDots: true });
|
||||
return qs.stringify(params, { allowDots: true,arrayFormat: 'brackets' });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -33,7 +33,16 @@
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item class="login-animation3" prop="verifyCode">
|
||||
<el-col :span="15">
|
||||
<el-col :span="24">
|
||||
<GoCaptchaBtn
|
||||
class="go-captcha-btn"
|
||||
v-model="checkCaptchaResult"
|
||||
width="100%"
|
||||
height="50px"
|
||||
@handleConfirm="handleVerifyCodeConfirm"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="15" v-if="false">
|
||||
<el-input
|
||||
type="text"
|
||||
maxlength="4"
|
||||
@ -48,8 +57,8 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="1"></el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :span="1" v-if="false"></el-col>
|
||||
<el-col :span="8" v-if="false">
|
||||
<div class="login-content-code">
|
||||
<img
|
||||
class="login-content-code-img"
|
||||
@ -57,7 +66,7 @@
|
||||
width="130"
|
||||
height="38"
|
||||
:src="captchaSrc"
|
||||
style="cursor: pointer"
|
||||
style="cursor: pointer;display: none"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -91,9 +100,11 @@ import { initBackEndControlRoutes } from '/@/router/backEnd';
|
||||
import { Session } from '/@/utils/storage';
|
||||
import { formatAxis } from '/@/utils/formatTime';
|
||||
import { NextLoading } from '/@/utils/loading';
|
||||
import {login,captcha} from "/@/api/login";
|
||||
import {login} from "/@/api/login";
|
||||
import GoCaptchaBtn from "/@/components/goCaptcha/GoCaptchaBtn.vue";
|
||||
export default defineComponent({
|
||||
name: 'loginAccount',
|
||||
components: {GoCaptchaBtn},
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const {proxy} = <any>getCurrentInstance();
|
||||
@ -102,6 +113,7 @@ export default defineComponent({
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const loginForm = ref(null)
|
||||
const checkCaptchaResult = ref('default')
|
||||
const state = reactive({
|
||||
isShowPassword: false,
|
||||
ruleForm: {
|
||||
@ -117,7 +129,7 @@ export default defineComponent({
|
||||
password: [
|
||||
{ required: true, trigger: "blur", message: "密码不能为空" }
|
||||
],
|
||||
verifyCode: [{ required: true, trigger: "blur", message: "验证码不能为空" }]
|
||||
verifyCode: [{ required: true, trigger: "blur", message: "请先进行人机验证" }]
|
||||
},
|
||||
loading: {
|
||||
signIn: false,
|
||||
@ -128,10 +140,11 @@ export default defineComponent({
|
||||
getCaptcha();
|
||||
});
|
||||
const getCaptcha = () => {
|
||||
captcha().then((res:any)=>{
|
||||
state.captchaSrc = res.data.img
|
||||
state.ruleForm.verifyKey = res.data.key
|
||||
})
|
||||
// 验证码V1版
|
||||
// captcha().then((res:any)=>{
|
||||
// state.captchaSrc = res.data.img
|
||||
// state.ruleForm.verifyKey = res.data.key
|
||||
// })
|
||||
};
|
||||
// 时间获取
|
||||
const currentTime = computed(() => {
|
||||
@ -173,7 +186,11 @@ export default defineComponent({
|
||||
}
|
||||
}).catch(()=>{
|
||||
state.loading.signIn = false;
|
||||
getCaptcha();
|
||||
state.ruleForm.verifyKey = ''
|
||||
state.ruleForm.verifyCode = ''
|
||||
checkCaptchaResult.value = 'default'
|
||||
// 验证码V1版
|
||||
//getCaptcha();
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -200,9 +217,17 @@ export default defineComponent({
|
||||
// 添加 loading,防止第一次进入界面时出现短暂空白
|
||||
NextLoading.start();
|
||||
};
|
||||
|
||||
const handleVerifyCodeConfirm = (data:{key:string,dots:string})=>{
|
||||
state.ruleForm.verifyCode = data.dots
|
||||
state.ruleForm.verifyKey = data.key
|
||||
}
|
||||
|
||||
return {
|
||||
onSignIn,
|
||||
getCaptcha,
|
||||
checkCaptchaResult,
|
||||
handleVerifyCodeConfirm,
|
||||
loginForm,
|
||||
...toRefs(state),
|
||||
};
|
||||
|
@ -3,6 +3,23 @@
|
||||
<el-dialog :title="(formData.id===0?'添加':'修改')+'角色'" v-model="isShowDialog" width="769px">
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px">
|
||||
<el-row :gutter="35">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
||||
<el-form-item label="上级角色">
|
||||
<el-cascader
|
||||
:options="roleData"
|
||||
:props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name' }"
|
||||
placeholder="请选择上级"
|
||||
clearable
|
||||
class="w100"
|
||||
v-model="formData.pid"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span>{{ data.name }}</span>
|
||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||
</template>
|
||||
</el-cascader>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="角色名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入角色名称" clearable></el-input>
|
||||
@ -72,6 +89,7 @@ interface MenuDataTree {
|
||||
}
|
||||
interface DialogRow {
|
||||
id:number;
|
||||
pid:number;
|
||||
name: string;
|
||||
status: number;
|
||||
listOrder: number;
|
||||
@ -96,6 +114,12 @@ interface RoleState {
|
||||
|
||||
export default defineComponent({
|
||||
name: 'systemEditRole',
|
||||
props:{
|
||||
roleData:{
|
||||
type:Array,
|
||||
default:()=>[]
|
||||
}
|
||||
},
|
||||
setup(props,{emit}) {
|
||||
const {proxy} = getCurrentInstance() as any;
|
||||
const formRef = ref<HTMLElement | null>(null);
|
||||
@ -105,6 +129,7 @@ export default defineComponent({
|
||||
isShowDialog: false,
|
||||
formData: {
|
||||
id:0,
|
||||
pid:0,
|
||||
name: '',
|
||||
status: 1,
|
||||
listOrder: 0,
|
||||
@ -198,6 +223,7 @@ export default defineComponent({
|
||||
state.menuNodeAll = false;
|
||||
state.formData = {
|
||||
id:0,
|
||||
pid:0,
|
||||
name: '',
|
||||
status: 1,
|
||||
listOrder: 0,
|
||||
|
@ -28,8 +28,10 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table :data="tableData.data" style="width: 100%">
|
||||
<el-table-column type="index" label="序号" width="60" />
|
||||
<el-table :data="tableData.data" style="width: 100%"
|
||||
row-key="id"
|
||||
default-expand-all
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }">
|
||||
<el-table-column prop="name" label="角色名称" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="listOrder" label="排序" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="userCnt" label="用户数量" align="center">
|
||||
@ -54,15 +56,8 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="tableData.total>0"
|
||||
:total="tableData.total"
|
||||
v-model:page="tableData.param.pageNum"
|
||||
v-model:limit="tableData.param.pageSize"
|
||||
@pagination="roleList"
|
||||
/>
|
||||
</el-card>
|
||||
<EditRole ref="editRoleRef" @getRoleList="roleList"/>
|
||||
<EditRole ref="editRoleRef" @getRoleList="roleList" :roleData="tableData.data"/>
|
||||
<DataScope ref="dataScopeRef" @getRoleList="roleList"/>
|
||||
|
||||
<el-dialog :title="selectRow.name+'-用户列表'" v-model="isShowDialog" width="70vw">
|
||||
@ -83,6 +78,7 @@ import UserList from '/@/views/system/user/component/userList.vue';
|
||||
// 定义接口来定义对象的类型
|
||||
interface TableData {
|
||||
id:number;
|
||||
pid:number;
|
||||
status: number;
|
||||
listOrder: number;
|
||||
name: string;
|
||||
@ -151,6 +147,7 @@ export default defineComponent({
|
||||
list.map((item:TableData)=>{
|
||||
data.push({
|
||||
id:item.id,
|
||||
pid:item.pid,
|
||||
status: item.status,
|
||||
listOrder: item.listOrder,
|
||||
name: item.name,
|
||||
@ -160,8 +157,7 @@ export default defineComponent({
|
||||
createdAt: item.createdAt,
|
||||
});
|
||||
})
|
||||
state.tableData.data = data;
|
||||
state.tableData.total = res.data.total;
|
||||
state.tableData.data = proxy.handleTree(data??[], "id","pid","children",true);
|
||||
})
|
||||
};
|
||||
// 打开角色用户列表
|
||||
|
@ -20,15 +20,19 @@
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="关联角色" prop="roleIds">
|
||||
<el-select v-model="ruleForm.roleIds" placeholder="请选择" clearable class="w100" multiple>
|
||||
<el-option
|
||||
v-for="role in roleList"
|
||||
:key="'role-'+role.id"
|
||||
:label="role.name"
|
||||
:value="role.id"
|
||||
:disabled="role.disabled">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-cascader
|
||||
:options="roleList"
|
||||
:props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name',multiple: true }"
|
||||
placeholder="请选择角色"
|
||||
clearable
|
||||
class="w100"
|
||||
v-model="ruleForm.roleIds"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span>{{ data.name }}</span>
|
||||
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||
</template>
|
||||
</el-cascader>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
@ -116,7 +120,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { reactive, toRefs, onMounted, defineComponent,ref,unref } from 'vue';
|
||||
import {reactive, toRefs, onMounted, defineComponent, ref, unref, getCurrentInstance} from 'vue';
|
||||
import {getParams, addUser, editUser, getEditUser} from "/@/api/system/user";
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
@ -134,6 +138,7 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(prop,{emit}) {
|
||||
const {proxy} = getCurrentInstance() as any;
|
||||
const roleList = ref([]);
|
||||
const postList = ref([]);
|
||||
const formRef = ref<HTMLElement | null>(null);
|
||||
@ -253,7 +258,7 @@ export default defineComponent({
|
||||
item.disabled = true
|
||||
}
|
||||
})
|
||||
roleList.value = roles
|
||||
roleList.value = proxy.handleTree(roles??[], "id","pid","children",true);
|
||||
postList.value = res.data.posts??[];
|
||||
});
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user