fix 验证码添加点击验证,角色改为树形结构
This commit is contained in:
parent
17cb2a1d65
commit
ab1d7bee42
@ -29,6 +29,7 @@
|
|||||||
"pinia": "^2.0.34",
|
"pinia": "^2.0.34",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"qrcodejs2-fixes": "^0.0.2",
|
"qrcodejs2-fixes": "^0.0.2",
|
||||||
|
"qs": "^6.11.1",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"spark-md5": "^3.0.2",
|
"spark-md5": "^3.0.2",
|
||||||
@ -36,13 +37,12 @@
|
|||||||
"vue": "^3.2.47",
|
"vue": "^3.2.47",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-codemirror": "^6.1.1",
|
"vue-codemirror": "^6.1.1",
|
||||||
|
"vue-demi": "^0.13.11",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
"vue-simple-uploader": "^1.0.0-beta.5",
|
"vue-simple-uploader": "^1.0.0-beta.5",
|
||||||
"vue-ueditor-wrap": "^3.0.8",
|
"vue-ueditor-wrap": "^3.0.8"
|
||||||
"qs": "^6.11.1",
|
|
||||||
"vue-demi": "^0.13.11"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^18.15.11",
|
"@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,28 +33,50 @@ export function handleTree(data:any[], id:string, parentId:string, children:stri
|
|||||||
id = id || 'id'
|
id = id || 'id'
|
||||||
parentId = parentId || 'parentId'
|
parentId = parentId || 'parentId'
|
||||||
children = children || 'children'
|
children = children || 'children'
|
||||||
rootId = rootId || 0
|
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))
|
const cloneData = JSON.parse(JSON.stringify(data))
|
||||||
//循环所有项
|
rootIds.map((rItem:any)=>{
|
||||||
const treeData = cloneData.filter((father:any) => {
|
//循环所有项
|
||||||
let branchArr = cloneData.filter((child:any) => {
|
const td = cloneData.filter((father:any) => {
|
||||||
//返回每一项的子级数组
|
let branchArr = cloneData.filter((child:any) => {
|
||||||
return father[id] === child[parentId]
|
//返回每一项的子级数组
|
||||||
|
return father[id] === child[parentId]
|
||||||
|
});
|
||||||
|
branchArr.length > 0 ? father[children] = branchArr : '';
|
||||||
|
//返回第一层
|
||||||
|
switch (typeof father[parentId]){
|
||||||
|
case 'string':
|
||||||
|
if(father[parentId]===''&&rItem===0){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return father[parentId]===rItem.toString();
|
||||||
|
case 'number':
|
||||||
|
return father[parentId] === rItem;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
branchArr.length > 0 ? father[children] = branchArr : '';
|
if(td.length>0){
|
||||||
//返回第一层
|
treeData = [...treeData,...td]
|
||||||
switch (typeof father[parentId]){
|
|
||||||
case 'string':
|
|
||||||
if(father[parentId]===''&&rootId===0){
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return father[parentId]===rootId.toString();
|
|
||||||
case 'number':
|
|
||||||
return father[parentId] === rootId;
|
|
||||||
}
|
}
|
||||||
return false;
|
})
|
||||||
});
|
|
||||||
return treeData != '' ? treeData : data;
|
return treeData != '' ? treeData : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const service: AxiosInstance = axios.create({
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
paramsSerializer: {
|
paramsSerializer: {
|
||||||
serialize(params) {
|
serialize(params) {
|
||||||
return qs.stringify(params, { allowDots: true });
|
return qs.stringify(params, { allowDots: true,arrayFormat: 'brackets' });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,16 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item class="login-animation3" prop="verifyCode">
|
<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
|
<el-input
|
||||||
type="text"
|
type="text"
|
||||||
maxlength="4"
|
maxlength="4"
|
||||||
@ -48,8 +57,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1"></el-col>
|
<el-col :span="1" v-if="false"></el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8" v-if="false">
|
||||||
<div class="login-content-code">
|
<div class="login-content-code">
|
||||||
<img
|
<img
|
||||||
class="login-content-code-img"
|
class="login-content-code-img"
|
||||||
@ -57,7 +66,7 @@
|
|||||||
width="130"
|
width="130"
|
||||||
height="38"
|
height="38"
|
||||||
:src="captchaSrc"
|
:src="captchaSrc"
|
||||||
style="cursor: pointer"
|
style="cursor: pointer;display: none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -91,9 +100,11 @@ import { initBackEndControlRoutes } from '/@/router/backEnd';
|
|||||||
import { Session } from '/@/utils/storage';
|
import { Session } from '/@/utils/storage';
|
||||||
import { formatAxis } from '/@/utils/formatTime';
|
import { formatAxis } from '/@/utils/formatTime';
|
||||||
import { NextLoading } from '/@/utils/loading';
|
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({
|
export default defineComponent({
|
||||||
name: 'loginAccount',
|
name: 'loginAccount',
|
||||||
|
components: {GoCaptchaBtn},
|
||||||
setup() {
|
setup() {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const {proxy} = <any>getCurrentInstance();
|
const {proxy} = <any>getCurrentInstance();
|
||||||
@ -102,6 +113,7 @@ export default defineComponent({
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const loginForm = ref(null)
|
const loginForm = ref(null)
|
||||||
|
const checkCaptchaResult = ref('default')
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isShowPassword: false,
|
isShowPassword: false,
|
||||||
ruleForm: {
|
ruleForm: {
|
||||||
@ -117,7 +129,7 @@ export default defineComponent({
|
|||||||
password: [
|
password: [
|
||||||
{ required: true, trigger: "blur", message: "密码不能为空" }
|
{ required: true, trigger: "blur", message: "密码不能为空" }
|
||||||
],
|
],
|
||||||
verifyCode: [{ required: true, trigger: "blur", message: "验证码不能为空" }]
|
verifyCode: [{ required: true, trigger: "blur", message: "请先进行人机验证" }]
|
||||||
},
|
},
|
||||||
loading: {
|
loading: {
|
||||||
signIn: false,
|
signIn: false,
|
||||||
@ -128,10 +140,11 @@ export default defineComponent({
|
|||||||
getCaptcha();
|
getCaptcha();
|
||||||
});
|
});
|
||||||
const getCaptcha = () => {
|
const getCaptcha = () => {
|
||||||
captcha().then((res:any)=>{
|
// 验证码V1版
|
||||||
state.captchaSrc = res.data.img
|
// captcha().then((res:any)=>{
|
||||||
state.ruleForm.verifyKey = res.data.key
|
// state.captchaSrc = res.data.img
|
||||||
})
|
// state.ruleForm.verifyKey = res.data.key
|
||||||
|
// })
|
||||||
};
|
};
|
||||||
// 时间获取
|
// 时间获取
|
||||||
const currentTime = computed(() => {
|
const currentTime = computed(() => {
|
||||||
@ -173,7 +186,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}).catch(()=>{
|
}).catch(()=>{
|
||||||
state.loading.signIn = false;
|
state.loading.signIn = false;
|
||||||
getCaptcha();
|
state.ruleForm.verifyKey = ''
|
||||||
|
state.ruleForm.verifyCode = ''
|
||||||
|
checkCaptchaResult.value = 'default'
|
||||||
|
// 验证码V1版
|
||||||
|
//getCaptcha();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -200,9 +217,17 @@ export default defineComponent({
|
|||||||
// 添加 loading,防止第一次进入界面时出现短暂空白
|
// 添加 loading,防止第一次进入界面时出现短暂空白
|
||||||
NextLoading.start();
|
NextLoading.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleVerifyCodeConfirm = (data:{key:string,dots:string})=>{
|
||||||
|
state.ruleForm.verifyCode = data.dots
|
||||||
|
state.ruleForm.verifyKey = data.key
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onSignIn,
|
onSignIn,
|
||||||
getCaptcha,
|
getCaptcha,
|
||||||
|
checkCaptchaResult,
|
||||||
|
handleVerifyCodeConfirm,
|
||||||
loginForm,
|
loginForm,
|
||||||
...toRefs(state),
|
...toRefs(state),
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,23 @@
|
|||||||
<el-dialog :title="(formData.id===0?'添加':'修改')+'角色'" v-model="isShowDialog" width="769px">
|
<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-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px">
|
||||||
<el-row :gutter="35">
|
<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-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
<el-form-item label="角色名称" prop="name">
|
<el-form-item label="角色名称" prop="name">
|
||||||
<el-input v-model="formData.name" placeholder="请输入角色名称" clearable></el-input>
|
<el-input v-model="formData.name" placeholder="请输入角色名称" clearable></el-input>
|
||||||
@ -72,6 +89,7 @@ interface MenuDataTree {
|
|||||||
}
|
}
|
||||||
interface DialogRow {
|
interface DialogRow {
|
||||||
id:number;
|
id:number;
|
||||||
|
pid:number;
|
||||||
name: string;
|
name: string;
|
||||||
status: number;
|
status: number;
|
||||||
listOrder: number;
|
listOrder: number;
|
||||||
@ -96,6 +114,12 @@ interface RoleState {
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'systemEditRole',
|
name: 'systemEditRole',
|
||||||
|
props:{
|
||||||
|
roleData:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
}
|
||||||
|
},
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {proxy} = getCurrentInstance() as any;
|
const {proxy} = getCurrentInstance() as any;
|
||||||
const formRef = ref<HTMLElement | null>(null);
|
const formRef = ref<HTMLElement | null>(null);
|
||||||
@ -105,6 +129,7 @@ export default defineComponent({
|
|||||||
isShowDialog: false,
|
isShowDialog: false,
|
||||||
formData: {
|
formData: {
|
||||||
id:0,
|
id:0,
|
||||||
|
pid:0,
|
||||||
name: '',
|
name: '',
|
||||||
status: 1,
|
status: 1,
|
||||||
listOrder: 0,
|
listOrder: 0,
|
||||||
@ -198,6 +223,7 @@ export default defineComponent({
|
|||||||
state.menuNodeAll = false;
|
state.menuNodeAll = false;
|
||||||
state.formData = {
|
state.formData = {
|
||||||
id:0,
|
id:0,
|
||||||
|
pid:0,
|
||||||
name: '',
|
name: '',
|
||||||
status: 1,
|
status: 1,
|
||||||
listOrder: 0,
|
listOrder: 0,
|
||||||
|
@ -28,8 +28,10 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="tableData.data" style="width: 100%">
|
<el-table :data="tableData.data" style="width: 100%"
|
||||||
<el-table-column type="index" label="序号" width="60" />
|
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="name" label="角色名称" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column prop="listOrder" 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">
|
<el-table-column prop="userCnt" label="用户数量" align="center">
|
||||||
@ -54,15 +56,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</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>
|
</el-card>
|
||||||
<EditRole ref="editRoleRef" @getRoleList="roleList"/>
|
<EditRole ref="editRoleRef" @getRoleList="roleList" :roleData="tableData.data"/>
|
||||||
<DataScope ref="dataScopeRef" @getRoleList="roleList"/>
|
<DataScope ref="dataScopeRef" @getRoleList="roleList"/>
|
||||||
|
|
||||||
<el-dialog :title="selectRow.name+'-用户列表'" v-model="isShowDialog" width="70vw">
|
<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 {
|
interface TableData {
|
||||||
id:number;
|
id:number;
|
||||||
|
pid:number;
|
||||||
status: number;
|
status: number;
|
||||||
listOrder: number;
|
listOrder: number;
|
||||||
name: string;
|
name: string;
|
||||||
@ -151,6 +147,7 @@ export default defineComponent({
|
|||||||
list.map((item:TableData)=>{
|
list.map((item:TableData)=>{
|
||||||
data.push({
|
data.push({
|
||||||
id:item.id,
|
id:item.id,
|
||||||
|
pid:item.pid,
|
||||||
status: item.status,
|
status: item.status,
|
||||||
listOrder: item.listOrder,
|
listOrder: item.listOrder,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
@ -160,8 +157,7 @@ export default defineComponent({
|
|||||||
createdAt: item.createdAt,
|
createdAt: item.createdAt,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
state.tableData.data = data;
|
state.tableData.data = proxy.handleTree(data??[], "id","pid","children",true);
|
||||||
state.tableData.total = res.data.total;
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
// 打开角色用户列表
|
// 打开角色用户列表
|
||||||
|
@ -20,15 +20,19 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
<el-form-item label="关联角色" prop="roleIds">
|
<el-form-item label="关联角色" prop="roleIds">
|
||||||
<el-select v-model="ruleForm.roleIds" placeholder="请选择" clearable class="w100" multiple>
|
<el-cascader
|
||||||
<el-option
|
:options="roleList"
|
||||||
v-for="role in roleList"
|
:props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name',multiple: true }"
|
||||||
:key="'role-'+role.id"
|
placeholder="请选择角色"
|
||||||
:label="role.name"
|
clearable
|
||||||
:value="role.id"
|
class="w100"
|
||||||
:disabled="role.disabled">
|
v-model="ruleForm.roleIds"
|
||||||
</el-option>
|
>
|
||||||
</el-select>
|
<template #default="{ node, data }">
|
||||||
|
<span>{{ data.name }}</span>
|
||||||
|
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||||
|
</template>
|
||||||
|
</el-cascader>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||||
@ -116,7 +120,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<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 {getParams, addUser, editUser, getEditUser} from "/@/api/system/user";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
|
|
||||||
@ -134,6 +138,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(prop,{emit}) {
|
setup(prop,{emit}) {
|
||||||
|
const {proxy} = getCurrentInstance() as any;
|
||||||
const roleList = ref([]);
|
const roleList = ref([]);
|
||||||
const postList = ref([]);
|
const postList = ref([]);
|
||||||
const formRef = ref<HTMLElement | null>(null);
|
const formRef = ref<HTMLElement | null>(null);
|
||||||
@ -253,7 +258,7 @@ export default defineComponent({
|
|||||||
item.disabled = true
|
item.disabled = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
roleList.value = roles
|
roleList.value = proxy.handleTree(roles??[], "id","pid","children",true);
|
||||||
postList.value = res.data.posts??[];
|
postList.value = res.data.posts??[];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user