mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-12-26 18:15:57 +08:00
增加移动端登录页面
This commit is contained in:
@@ -1,130 +1,138 @@
|
||||
<template>
|
||||
<el-container class="captcha-box">
|
||||
<el-dialog
|
||||
v-model="show"
|
||||
:close-on-click-modal="true"
|
||||
:show-close="false"
|
||||
style="width: 360px;"
|
||||
>
|
||||
<el-dialog v-model="show" :close-on-click-modal="true" :show-close="isMobileInternal" style="width: 360px; --el-dialog-padding-primary: 5px 15px 15px 15px">
|
||||
<template #title>
|
||||
<div class="text-center p-3" style="color: var(--el-text-color-primary)" v-if="isMobileInternal">
|
||||
<span>人机验证</span>
|
||||
</div>
|
||||
</template>
|
||||
<slide-captcha
|
||||
v-if="isMobile()"
|
||||
:bg-img="bgImg"
|
||||
:bk-img="bkImg"
|
||||
:result="result"
|
||||
@refresh="getSlideCaptcha"
|
||||
@confirm="handleSlideConfirm"
|
||||
@hide="show = false"/>
|
||||
v-if="isMobileInternal"
|
||||
:bg-img="bgImg"
|
||||
:bk-img="bkImg"
|
||||
:result="result"
|
||||
@refresh="getSlideCaptcha"
|
||||
@confirm="handleSlideConfirm"
|
||||
@hide="show = false"
|
||||
/>
|
||||
|
||||
<captcha-plus
|
||||
v-else
|
||||
:max-dot="maxDot"
|
||||
:image-base64="imageBase64"
|
||||
:thumb-base64="thumbBase64"
|
||||
width="300"
|
||||
@close="show = false"
|
||||
@refresh="handleRequestCaptCode"
|
||||
@confirm="handleConfirm"
|
||||
v-else
|
||||
:max-dot="maxDot"
|
||||
:image-base64="imageBase64"
|
||||
:thumb-base64="thumbBase64"
|
||||
width="300"
|
||||
@close="show = false"
|
||||
@refresh="handleRequestCaptCode"
|
||||
@confirm="handleConfirm"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import lodash from 'lodash'
|
||||
import {validateEmail, validateMobile} from "@/utils/validate";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import { ref } from "vue";
|
||||
import lodash from "lodash";
|
||||
import { validateEmail, validateMobile } from "@/utils/validate";
|
||||
import { httpGet, httpPost } from "@/utils/http";
|
||||
import CaptchaPlus from "@/components/CaptchaPlus.vue";
|
||||
import SlideCaptcha from "@/components/SlideCaptcha.vue";
|
||||
import {isMobile} from "@/utils/libs";
|
||||
import {showMessageError, showMessageOK} from "@/utils/dialog";
|
||||
import { isMobile } from "@/utils/libs";
|
||||
import { showMessageError, showMessageOK } from "@/utils/dialog";
|
||||
|
||||
const show = ref(false)
|
||||
const maxDot = ref(5)
|
||||
const imageBase64 = ref('')
|
||||
const thumbBase64 = ref('')
|
||||
const captKey = ref('')
|
||||
const dots = ref(null)
|
||||
const show = ref(false);
|
||||
const maxDot = ref(5);
|
||||
const imageBase64 = ref("");
|
||||
const thumbBase64 = ref("");
|
||||
const captKey = ref("");
|
||||
const dots = ref(null);
|
||||
const isMobileInternal = isMobile();
|
||||
|
||||
const emits = defineEmits(['success']);
|
||||
const emits = defineEmits(["success"]);
|
||||
const handleRequestCaptCode = () => {
|
||||
|
||||
httpGet('/api/captcha/get').then(res => {
|
||||
const data = res.data
|
||||
imageBase64.value = data.image
|
||||
thumbBase64.value = data.thumb
|
||||
captKey.value = data.key
|
||||
}).catch(e => {
|
||||
showMessageError('获取人机验证数据失败:' + e.message)
|
||||
})
|
||||
}
|
||||
httpGet("/api/captcha/get")
|
||||
.then((res) => {
|
||||
const data = res.data;
|
||||
imageBase64.value = data.image;
|
||||
thumbBase64.value = data.thumb;
|
||||
captKey.value = data.key;
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessageError("获取人机验证数据失败:" + e.message);
|
||||
});
|
||||
};
|
||||
|
||||
const handleConfirm = (dts) => {
|
||||
if (lodash.size(dts) <= 0) {
|
||||
return showMessageError('请进行人机验证再操作')
|
||||
return showMessageError("请进行人机验证再操作");
|
||||
}
|
||||
|
||||
let dotArr = []
|
||||
let dotArr = [];
|
||||
lodash.forEach(dts, (dot) => {
|
||||
dotArr.push(dot.x, dot.y)
|
||||
})
|
||||
dots.value = dotArr.join(',')
|
||||
httpPost('/api/captcha/check', {
|
||||
dotArr.push(dot.x, dot.y);
|
||||
});
|
||||
dots.value = dotArr.join(",");
|
||||
httpPost("/api/captcha/check", {
|
||||
dots: dots.value,
|
||||
key: captKey.value
|
||||
}).then(() => {
|
||||
// ElMessage.success('人机验证成功')
|
||||
show.value = false
|
||||
emits('success', {key:captKey.value, dots:dots.value})
|
||||
}).catch(() => {
|
||||
showMessageError('人机验证失败')
|
||||
handleRequestCaptCode()
|
||||
key: captKey.value,
|
||||
})
|
||||
}
|
||||
.then(() => {
|
||||
// ElMessage.success('人机验证成功')
|
||||
show.value = false;
|
||||
emits("success", { key: captKey.value, dots: dots.value });
|
||||
})
|
||||
.catch(() => {
|
||||
showMessageError("人机验证失败");
|
||||
handleRequestCaptCode();
|
||||
});
|
||||
};
|
||||
|
||||
const loadCaptcha = () => {
|
||||
show.value = true
|
||||
show.value = true;
|
||||
// 手机用滑动验证码
|
||||
if (isMobile()) {
|
||||
getSlideCaptcha()
|
||||
getSlideCaptcha();
|
||||
} else {
|
||||
handleRequestCaptCode()
|
||||
handleRequestCaptCode();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 滑动验证码
|
||||
const bgImg = ref('')
|
||||
const bkImg = ref('')
|
||||
const result = ref(0)
|
||||
const bgImg = ref("");
|
||||
const bkImg = ref("");
|
||||
const result = ref(0);
|
||||
|
||||
const getSlideCaptcha = () => {
|
||||
result.value = 0
|
||||
httpGet("/api/captcha/slide/get").then(res => {
|
||||
bkImg.value = res.data.bkImg
|
||||
bgImg.value = res.data.bgImg
|
||||
captKey.value = res.data.key
|
||||
}).catch(e => {
|
||||
showMessageError('获取人机验证数据失败:' + e.message)
|
||||
})
|
||||
}
|
||||
result.value = 0;
|
||||
httpGet("/api/captcha/slide/get")
|
||||
.then((res) => {
|
||||
bkImg.value = res.data.bkImg;
|
||||
bgImg.value = res.data.bgImg;
|
||||
captKey.value = res.data.key;
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessageError("获取人机验证数据失败:" + e.message);
|
||||
});
|
||||
};
|
||||
|
||||
const handleSlideConfirm = (x) => {
|
||||
httpPost("/api/captcha/slide/check", {
|
||||
key: captKey.value,
|
||||
x: x
|
||||
}).then(() => {
|
||||
result.value = 1
|
||||
show.value = false
|
||||
emits('success',{key:captKey.value, x:x})
|
||||
}).catch(() => {
|
||||
result.value = 2
|
||||
x: x,
|
||||
})
|
||||
}
|
||||
.then(() => {
|
||||
result.value = 1;
|
||||
show.value = false;
|
||||
emits("success", { key: captKey.value, x: x });
|
||||
})
|
||||
.catch(() => {
|
||||
result.value = 2;
|
||||
});
|
||||
};
|
||||
|
||||
// 导出方法以便父组件调用
|
||||
defineExpose({
|
||||
loadCaptcha
|
||||
loadCaptcha,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -137,8 +145,9 @@ defineExpose({
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding 0
|
||||
padding-bottom: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,90 +1,93 @@
|
||||
<template>
|
||||
|
||||
<div class="wg-cap-wrap" :style="{width: width}">
|
||||
<div class="wg-cap-wrap" :style="{ width: width }">
|
||||
<div class="wg-cap-wrap__header">
|
||||
<span>请在下图<em>依次</em>点击:</span>
|
||||
<img class="wg-cap-wrap__thumb" v-if="thumbBase64Code" :src="thumbBase64Code" alt=" ">
|
||||
<img class="wg-cap-wrap__thumb" v-if="thumbBase64Code" :src="thumbBase64Code" alt=" " />
|
||||
</div>
|
||||
<div class="wg-cap-wrap__body">
|
||||
<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="正在加载中...">
|
||||
<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="正在加载中..."
|
||||
/>
|
||||
<div v-for="(dot, key) in dots" :key="key" class="wg-cap-wrap__dot" :style="`top: ${dot.y}px; left:${dot.x}px;`">
|
||||
<span>{{ dot.index }}</span>
|
||||
</div>
|
||||
</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 class="wg-cap-wrap__ico flex">
|
||||
<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">
|
||||
<el-button type="primary" @click="handleConfirmEvent">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CaptchaPlus',
|
||||
name: "CaptchaPlus",
|
||||
mounted() {
|
||||
this.$emit('refresh')
|
||||
this.$emit("refresh");
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
width: {
|
||||
type: String,
|
||||
default: '300px'
|
||||
default: "300px",
|
||||
},
|
||||
calcPosType: {
|
||||
type: String,
|
||||
default: 'dom',
|
||||
validator: value => ['dom', 'screen'].includes(value)
|
||||
default: "dom",
|
||||
validator: (value) => ["dom", "screen"].includes(value),
|
||||
},
|
||||
maxDot: {
|
||||
type: Number,
|
||||
default: 5
|
||||
default: 5,
|
||||
// validator: value => value > 10
|
||||
},
|
||||
imageBase64: String,
|
||||
thumbBase64: String
|
||||
thumbBase64: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dots: [],
|
||||
imageBase64Code: '',
|
||||
thumbBase64Code: ''
|
||||
}
|
||||
imageBase64Code: "",
|
||||
thumbBase64Code: "",
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.dots = []
|
||||
this.imageBase64Code = ''
|
||||
this.thumbBase64Code = ''
|
||||
this.dots = [];
|
||||
this.imageBase64Code = "";
|
||||
this.thumbBase64Code = "";
|
||||
},
|
||||
imageBase64(val) {
|
||||
this.dots = []
|
||||
this.imageBase64Code = val
|
||||
this.dots = [];
|
||||
this.imageBase64Code = val;
|
||||
},
|
||||
thumbBase64(val) {
|
||||
this.dots = []
|
||||
this.thumbBase64Code = val
|
||||
}
|
||||
this.dots = [];
|
||||
this.thumbBase64Code = val;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @Description: 处理关闭事件
|
||||
*/
|
||||
handleCloseEvent() {
|
||||
this.$emit('close')
|
||||
this.$emit("close");
|
||||
// this.dots = []
|
||||
// this.imageBase64Code = ''
|
||||
// this.thumbBase64Code = ''
|
||||
@@ -93,14 +96,14 @@ export default {
|
||||
* @Description: 处理刷新事件
|
||||
*/
|
||||
handleRefreshEvent() {
|
||||
this.dots = []
|
||||
this.$emit('refresh')
|
||||
this.dots = [];
|
||||
this.$emit("refresh");
|
||||
},
|
||||
/**
|
||||
* @Description: 处理确认事件
|
||||
*/
|
||||
handleConfirmEvent() {
|
||||
this.$emit('confirm', this.dots)
|
||||
this.$emit("confirm", this.dots);
|
||||
},
|
||||
/**
|
||||
* @Description: 处理dot
|
||||
@@ -108,102 +111,102 @@ export default {
|
||||
*/
|
||||
handleClickPos(ev) {
|
||||
if (this.dots.length >= this.maxDot) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const e = ev || window.event
|
||||
e.preventDefault()
|
||||
const dom = e.currentTarget
|
||||
const e = ev || window.event;
|
||||
e.preventDefault();
|
||||
const dom = e.currentTarget;
|
||||
|
||||
const {domX, domY} = this.getDomXY(dom)
|
||||
const { domX, domY } = this.getDomXY(dom);
|
||||
// ===============================================
|
||||
// @notice 如 getDomXY 不准确可尝试使用 calcLocationLeft 或 calcLocationTop
|
||||
// const domX = this.calcLocationLeft(dom)
|
||||
// const domY = this.calcLocationTop(dom)
|
||||
// ===============================================
|
||||
let mouseX = (navigator.vendor === 'Netscape') ? e.pageX : e.x + document.body.offsetTop
|
||||
let mouseY = (navigator.vendor === 'Netscape') ? e.pageY : e.y + document.body.offsetTop
|
||||
let mouseX = navigator.vendor === "Netscape" ? e.pageX : e.x + document.body.offsetTop;
|
||||
let mouseY = navigator.vendor === "Netscape" ? e.pageY : e.y + document.body.offsetTop;
|
||||
// 兼容移动触摸事件
|
||||
if (e.touches && e.touches.length > 0) {
|
||||
mouseX = e.touches[0].clientX
|
||||
mouseY = e.touches[0].clientY
|
||||
mouseX = e.touches[0].clientX;
|
||||
mouseY = e.touches[0].clientY;
|
||||
} else {
|
||||
mouseX = e.clientX
|
||||
mouseY = e.clientY
|
||||
mouseX = e.clientX;
|
||||
mouseY = e.clientY;
|
||||
}
|
||||
|
||||
// 计算点击的相对位置
|
||||
const xPos = mouseX - domX
|
||||
const yPos = mouseY - domY
|
||||
const xPos = mouseX - domX;
|
||||
const yPos = mouseY - domY;
|
||||
|
||||
// 转整形
|
||||
const xp = parseInt(xPos.toString())
|
||||
const yp = parseInt(yPos.toString())
|
||||
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
|
||||
index: this.dots.length + 1,
|
||||
});
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* @Description: 找到元素的屏幕位置
|
||||
* @param el
|
||||
*/
|
||||
calcLocationLeft(el) {
|
||||
let tmp = el.offsetLeft
|
||||
let val = el.offsetParent
|
||||
let tmp = el.offsetLeft;
|
||||
let val = el.offsetParent;
|
||||
while (val != null) {
|
||||
tmp += val.offsetLeft
|
||||
val = val.offsetParent
|
||||
tmp += val.offsetLeft;
|
||||
val = val.offsetParent;
|
||||
}
|
||||
return tmp
|
||||
return tmp;
|
||||
},
|
||||
/**
|
||||
* @Description: 找到元素的屏幕位置
|
||||
* @param el
|
||||
*/
|
||||
calcLocationTop(el) {
|
||||
let tmp = el.offsetTop
|
||||
let val = el.offsetParent
|
||||
let tmp = el.offsetTop;
|
||||
let val = el.offsetParent;
|
||||
while (val != null) {
|
||||
tmp += val.offsetTop
|
||||
val = val.offsetParent
|
||||
tmp += val.offsetTop;
|
||||
val = val.offsetParent;
|
||||
}
|
||||
return tmp
|
||||
return tmp;
|
||||
},
|
||||
/**
|
||||
* @Description: 找到元素的屏幕位置
|
||||
* @param dom
|
||||
*/
|
||||
getDomXY(dom) {
|
||||
let x = 0
|
||||
let y = 0
|
||||
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
|
||||
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
|
||||
x += dom.offsetLeft;
|
||||
y += dom.offsetTop;
|
||||
dom = dom.offsetParent;
|
||||
}
|
||||
}
|
||||
return {
|
||||
domX: x,
|
||||
domY: y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
domY: y,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
.wg-cap-wrap {
|
||||
background: #ffffff;
|
||||
background: var(--el-bg-color);
|
||||
|
||||
-webkit-border-radius: 10px;
|
||||
-moz-border-radius: 10px;
|
||||
@@ -219,14 +222,7 @@ export default {
|
||||
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;
|
||||
|
||||
span {
|
||||
|
||||
@@ -1,32 +1,9 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="login-dialog"
|
||||
v-model="showDialog"
|
||||
:close-on-click-modal="true"
|
||||
:show-close="false"
|
||||
:before-close="close"
|
||||
>
|
||||
<template #header="{ titleId, titleClass }">
|
||||
<div class="header">
|
||||
<div class="title" v-if="login">用户登录-</div>
|
||||
<div class="title" v-else>用户注册</div>
|
||||
<div class="close-icon">
|
||||
<el-icon @click="close">
|
||||
<Close />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="login-dialog w-full p-8">
|
||||
<div class="login-box" v-if="login">
|
||||
<el-form :model="data" label-width="120px" class="form">
|
||||
<el-form :model="data" class="form">
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="账号"
|
||||
size="large"
|
||||
v-model="data.username"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="账号" size="large" v-model="data.username" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Iphone />
|
||||
@@ -36,14 +13,7 @@
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="请输入密码(8-16位)"
|
||||
maxlength="16"
|
||||
size="large"
|
||||
v-model="data.password"
|
||||
show-password
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="请输入密码(8-16位)" maxlength="16" size="large" v-model="data.password" show-password autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Lock />
|
||||
@@ -54,67 +24,42 @@
|
||||
|
||||
<el-row class="btn-row" :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-button
|
||||
class="login-btn"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="submitLogin"
|
||||
>登录</el-button
|
||||
>
|
||||
<el-button class="login-btn" type="primary" size="large" @click="submitLogin">登 录</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<div class="reg">
|
||||
还没有账号?
|
||||
<el-button
|
||||
type="primary"
|
||||
class="forget"
|
||||
size="small"
|
||||
@click="login = false"
|
||||
>注册</el-button
|
||||
>
|
||||
<div class="w-full">
|
||||
<div class="text flex justify-center items-center pt-3 text-sm">
|
||||
还没有账号?
|
||||
<el-button size="small" @click="login = false">注册</el-button>
|
||||
|
||||
<el-button
|
||||
type="info"
|
||||
class="forget"
|
||||
size="small"
|
||||
@click="showResetPass = true"
|
||||
>忘记密码?</el-button
|
||||
>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<div class="c-login" v-if="wechatLoginURL !== ''">
|
||||
<div class="text">其他登录方式:</div>
|
||||
<div class="login-type">
|
||||
<a
|
||||
class="wechat-login"
|
||||
:href="wechatLoginURL"
|
||||
@click="setRoute(router.currentRoute.value.path)"
|
||||
><i class="iconfont icon-wechat"></i
|
||||
></a>
|
||||
<el-button type="info" class="forget" size="small" @click="showResetPass = true">忘记密码?</el-button>
|
||||
</div>
|
||||
<div v-if="wechatLoginURL !== ''">
|
||||
<el-divider>
|
||||
<div class="text-center">其他登录方式</div>
|
||||
</el-divider>
|
||||
<div class="c-login flex justify-center">
|
||||
<!-- <div class="login-type mr-2">
|
||||
<a class="wechat-login" :href="wechatLoginURL" @click="setRoute(router.currentRoute.value.path)"><i class="iconfont icon-wechat"></i></a>
|
||||
</div> -->
|
||||
<div class="p-2 w-full">
|
||||
<el-button type="success" class="w-full" size="large" :href="wechatLoginURL" @click="setRoute(router.currentRoute.value.path)"
|
||||
><i class="iconfont icon-wechat mr-2"></i> 微信登录
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="register-box" v-else>
|
||||
<div class="register-box w-full" v-else>
|
||||
<el-form :model="data" class="form" v-if="enableRegister">
|
||||
<el-tabs v-model="activeName" class="demo-tabs">
|
||||
<el-tab-pane label="手机注册" name="mobile" v-if="enableMobile">
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="手机号码"
|
||||
size="large"
|
||||
v-model="data.mobile"
|
||||
maxlength="11"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="手机号码" size="large" v-model="data.mobile" maxlength="11" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Iphone />
|
||||
@@ -125,13 +70,7 @@
|
||||
<div class="block">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-input
|
||||
placeholder="验证码"
|
||||
size="large"
|
||||
maxlength="30"
|
||||
v-model="data.code"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="验证码" size="large" maxlength="30" v-model="data.code" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Checked />
|
||||
@@ -140,23 +79,14 @@
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<send-msg
|
||||
size="large"
|
||||
:receiver="data.mobile"
|
||||
type="mobile"
|
||||
/>
|
||||
<send-msg size="large" :receiver="data.mobile" type="mobile" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="邮箱注册" name="email" v-if="enableEmail">
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="邮箱地址"
|
||||
size="large"
|
||||
v-model="data.email"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="邮箱地址" size="large" v-model="data.email" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Message />
|
||||
@@ -167,13 +97,7 @@
|
||||
<div class="block">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-input
|
||||
placeholder="验证码"
|
||||
size="large"
|
||||
maxlength="30"
|
||||
v-model="data.code"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="验证码" size="large" maxlength="30" v-model="data.code" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Checked />
|
||||
@@ -189,12 +113,7 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="用户名注册" name="username" v-if="enableUser">
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="用户名"
|
||||
size="large"
|
||||
v-model="data.username"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="用户名" size="large" v-model="data.username" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Iphone />
|
||||
@@ -206,14 +125,7 @@
|
||||
</el-tabs>
|
||||
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="请输入密码(8-16位)"
|
||||
maxlength="16"
|
||||
size="large"
|
||||
v-model="data.password"
|
||||
show-password
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="请输入密码(8-16位)" maxlength="16" size="large" v-model="data.password" show-password autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Lock />
|
||||
@@ -223,14 +135,7 @@
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="重复密码(8-16位)"
|
||||
size="large"
|
||||
maxlength="16"
|
||||
v-model="data.repass"
|
||||
show-password
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="重复密码(8-16位)" size="large" maxlength="16" v-model="data.repass" show-password autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Lock />
|
||||
@@ -240,12 +145,7 @@
|
||||
</div>
|
||||
|
||||
<div class="block">
|
||||
<el-input
|
||||
placeholder="邀请码(可选)"
|
||||
size="large"
|
||||
v-model="data.invite_code"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input placeholder="邀请码(可选)" size="large" v-model="data.invite_code" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Message />
|
||||
@@ -254,23 +154,14 @@
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<el-row class="btn-row" :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-button
|
||||
class="login-btn"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="submitRegister"
|
||||
>注册</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="text">
|
||||
已有账号?
|
||||
<el-tag @click="login = true">登录</el-tag>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="w-full">
|
||||
<el-button class="login-btn w-full" type="primary" size="large" @click="submitRegister">注 册</el-button>
|
||||
</div>
|
||||
|
||||
<div class="text text-sm flex justify-center items-center w-full pt-3">
|
||||
已有账号?
|
||||
<el-button size="small" @click="login = true">登录</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<div class="tip-result" v-else>
|
||||
@@ -291,11 +182,10 @@
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<captcha v-if="enableVerify" @success="submit" ref="captchaRef" />
|
||||
|
||||
<reset-pass @hide="showResetPass = false" :show="showResetPass" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -316,7 +206,7 @@ import { useSharedStore } from "@/store/sharedata";
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const props = defineProps({
|
||||
show: Boolean
|
||||
show: Boolean,
|
||||
});
|
||||
const showDialog = ref(false);
|
||||
watch(
|
||||
@@ -334,7 +224,7 @@ const data = ref({
|
||||
email: "",
|
||||
repass: "",
|
||||
code: "",
|
||||
invite_code: ""
|
||||
invite_code: "",
|
||||
});
|
||||
const enableMobile = ref(false);
|
||||
const enableEmail = ref(false);
|
||||
@@ -351,8 +241,6 @@ const enableVerify = ref(false);
|
||||
const showResetPass = ref(false);
|
||||
const router = useRouter();
|
||||
const store = useSharedStore();
|
||||
// 是否需要验证码,输入一次密码错之后就要验证码
|
||||
const needVerify = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
const returnURL = `${location.protocol}//${location.host}/login/callback?action=login`;
|
||||
@@ -410,7 +298,7 @@ const submitLogin = () => {
|
||||
if (data.value.password === "") {
|
||||
return ElMessage.error("请输入密码");
|
||||
}
|
||||
if (enableVerify.value && needVerify.value) {
|
||||
if (enableVerify.value) {
|
||||
captchaRef.value.loadCaptcha();
|
||||
action.value = "login";
|
||||
} else {
|
||||
@@ -429,11 +317,9 @@ const doLogin = (verifyData) => {
|
||||
ElMessage.success("登录成功!");
|
||||
emits("hide");
|
||||
emits("success");
|
||||
needVerify.value = false;
|
||||
})
|
||||
.catch((e) => {
|
||||
ElMessage.error("登录失败," + e.message);
|
||||
needVerify.value = true;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -458,10 +344,7 @@ const submitRegister = () => {
|
||||
return ElMessage.error("两次输入密码不一致");
|
||||
}
|
||||
|
||||
if (
|
||||
(activeName.value === "mobile" || activeName.value === "email") &&
|
||||
data.value.code === ""
|
||||
) {
|
||||
if ((activeName.value === "mobile" || activeName.value === "email") && data.value.code === "") {
|
||||
return ElMessage.error("请输入验证码");
|
||||
}
|
||||
if (enableVerify.value && activeName.value === "username") {
|
||||
@@ -486,52 +369,26 @@ const doRegister = (verifyData) => {
|
||||
emits("hide");
|
||||
emits("success");
|
||||
},
|
||||
duration: 1000
|
||||
duration: 1000,
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
ElMessage.error("注册失败," + e.message);
|
||||
});
|
||||
};
|
||||
|
||||
const close = function () {
|
||||
emits("hide", false);
|
||||
login.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.login-dialog {
|
||||
border-radius 10px
|
||||
max-width 600px
|
||||
|
||||
.header {
|
||||
position relative
|
||||
|
||||
.title {
|
||||
padding 0
|
||||
font-size 18px
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
cursor pointer
|
||||
position absolute
|
||||
right 0
|
||||
top 0
|
||||
font-weight normal
|
||||
font-size 20px
|
||||
|
||||
&:hover {
|
||||
color #20a0ff
|
||||
}
|
||||
}
|
||||
.el-tabs__nav {
|
||||
display flex
|
||||
width 100%
|
||||
justify-content space-between
|
||||
}
|
||||
|
||||
|
||||
.el-dialog__body {
|
||||
padding 10px 20px 20px 20px
|
||||
}
|
||||
|
||||
.form {
|
||||
.block {
|
||||
margin-bottom 10px
|
||||
@@ -541,6 +398,7 @@ const close = function () {
|
||||
display flex
|
||||
|
||||
.login-btn {
|
||||
font-size 16px
|
||||
width 100%
|
||||
}
|
||||
|
||||
@@ -566,7 +424,6 @@ const close = function () {
|
||||
align-items: center;
|
||||
}
|
||||
.login-type {
|
||||
padding 15px
|
||||
display flex
|
||||
justify-content center
|
||||
|
||||
@@ -582,14 +439,8 @@ const close = function () {
|
||||
}
|
||||
}
|
||||
|
||||
.reg {
|
||||
height 50px
|
||||
display flex
|
||||
align-items center
|
||||
|
||||
.el-button {
|
||||
margin-left 10px
|
||||
}
|
||||
.text {
|
||||
color var(--el-text-color-primary)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
<template>
|
||||
<div class="reset-pass">
|
||||
<el-dialog
|
||||
v-model="showDialog"
|
||||
:close-on-click-modal="true"
|
||||
width="540px"
|
||||
:before-close="close"
|
||||
:title="title"
|
||||
class="reset-pass-dialog"
|
||||
>
|
||||
<el-dialog v-model="showDialog" :close-on-click-modal="true" width="500px" :before-close="close" :title="title" class="reset-pass-dialog">
|
||||
<div class="form">
|
||||
<el-form :model="form" label-width="80px" label-position="left">
|
||||
<el-tabs v-model="form.type" class="demo-tabs">
|
||||
@@ -16,14 +9,10 @@
|
||||
<el-input v-model="form.mobile" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码">
|
||||
<el-row class="code-row">
|
||||
<el-col :span="16">
|
||||
<el-input v-model="form.code" maxlength="6" />
|
||||
</el-col>
|
||||
<el-col :span="8" class="send-button">
|
||||
<send-msg size="" :receiver="form.mobile" type="mobile" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="flex">
|
||||
<el-input v-model="form.code" maxlength="6" class="mr-2 w-1/2" />
|
||||
<send-msg size="" :receiver="form.mobile" type="mobile" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="邮箱验证" name="email">
|
||||
@@ -31,14 +20,10 @@
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码">
|
||||
<el-row class="code-row">
|
||||
<el-col :span="16">
|
||||
<el-input v-model="form.code" maxlength="6" />
|
||||
</el-col>
|
||||
<el-col :span="8" class="send-button">
|
||||
<send-msg size="" :receiver="form.email" type="email" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="flex">
|
||||
<el-input v-model="form.code" maxlength="6" class="mr-2 w-1/2" />
|
||||
<send-msg size="" :receiver="form.email" type="email" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -70,7 +55,7 @@ import { validateEmail, validateMobile } from "@/utils/validate";
|
||||
|
||||
const props = defineProps({
|
||||
show: Boolean,
|
||||
mobile: String
|
||||
mobile: String,
|
||||
});
|
||||
|
||||
const showDialog = computed(() => {
|
||||
@@ -84,7 +69,7 @@ const form = ref({
|
||||
type: "mobile",
|
||||
code: "",
|
||||
password: "",
|
||||
repass: ""
|
||||
repass: "",
|
||||
});
|
||||
|
||||
const emits = defineEmits(["hide"]);
|
||||
@@ -105,7 +90,7 @@ const save = () => {
|
||||
ElMessage.success({
|
||||
message: "重置密码成功",
|
||||
duration: 1000,
|
||||
onClose: () => emits("hide", false)
|
||||
onClose: () => emits("hide", false),
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
|
||||
172
web/src/components/SdTaskView.vue
Normal file
172
web/src/components/SdTaskView.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<el-dialog v-model="show" :fullscreen="true" @close="close" style="--el-dialog-border-radius: 0px">
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<h3 style="color: var(--text-theme-color)">绘画任务详情</h3>
|
||||
</div>
|
||||
</template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<div class="img-container">
|
||||
<el-image :src="item['img_url']" fit="contain">
|
||||
<template #placeholder>
|
||||
<div class="image-slot">正在加载图片</div>
|
||||
</template>
|
||||
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon>
|
||||
<i class="iconfont icon-image"></i>
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="task-info">
|
||||
<div class="info-line">
|
||||
<el-divider> 正向提示词 </el-divider>
|
||||
<div class="prompt">
|
||||
<span>{{ item.prompt }}</span>
|
||||
<el-icon class="copy-prompt-wall" :data-clipboard-text="item.prompt">
|
||||
<i class="iconfont icon-copy"></i>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<el-divider> 反向提示词 </el-divider>
|
||||
<div class="prompt">
|
||||
<span>{{ item.params.negative_prompt }}</span>
|
||||
<el-icon class="copy-prompt-wall" :data-clipboard-text="item.params.negative_prompt">
|
||||
<i class="iconfont icon-copy"></i>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>采样方法:</label>
|
||||
<div class="item-value">{{ item.params.sampler }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>图片尺寸:</label>
|
||||
<div class="item-value">{{ item.params.width }} x {{ item.params.height }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>迭代步数:</label>
|
||||
<div class="item-value">{{ item.params.steps }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>引导系数:</label>
|
||||
<div class="item-value">{{ item.params.cfg_scale }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>随机因子:</label>
|
||||
<div class="item-value">{{ item.params.seed }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="item.params.hd_fix">
|
||||
<el-divider> 高清修复 </el-divider>
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>重绘幅度:</label>
|
||||
<div class="item-value">{{ item.params.hd_redraw_rate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>放大算法:</label>
|
||||
<div class="item-value">{{ item.params.hd_scale_alg }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>放大倍数:</label>
|
||||
<div class="item-value">{{ item.params.hd_scale }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-line">
|
||||
<div class="wrapper">
|
||||
<label>迭代步数:</label>
|
||||
<div class="item-value">{{ item.params.hd_steps }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="copy-params">
|
||||
<el-button type="primary" round @click="drawSame(item)">画一张同款的</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import Clipboard from "clipboard";
|
||||
import { showMessageOK, showMessageError } from "@/utils/dialog";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
data: Object,
|
||||
});
|
||||
|
||||
const item = ref(props.data);
|
||||
const show = ref(props.modelValue);
|
||||
const emit = defineEmits(["drawSame", "close"]);
|
||||
|
||||
const clipboard = ref(null);
|
||||
onMounted(() => {
|
||||
clipboard.value = new Clipboard(".copy-prompt-wall");
|
||||
clipboard.value.on("success", () => {
|
||||
showMessageOK("复制成功!");
|
||||
});
|
||||
|
||||
clipboard.value.on("error", () => {
|
||||
showMessageError("复制失败!");
|
||||
});
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
show.value = newValue;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(newValue) => {
|
||||
item.value = newValue;
|
||||
}
|
||||
);
|
||||
|
||||
const drawSame = (item) => {
|
||||
emit("drawSame", item);
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
emit("close");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped></style>
|
||||
@@ -1,11 +1,6 @@
|
||||
<template>
|
||||
<el-container class="send-verify-code">
|
||||
<el-button
|
||||
type="success"
|
||||
:size="props.size"
|
||||
:disabled="!canSend"
|
||||
@click="sendMsg"
|
||||
>
|
||||
<el-button type="success" :size="props.size" :disabled="!canSend" @click="sendMsg">
|
||||
{{ btnText }}
|
||||
</el-button>
|
||||
|
||||
@@ -15,12 +10,12 @@
|
||||
|
||||
<script setup>
|
||||
// 发送短信验证码组件
|
||||
import {ref} from "vue";
|
||||
import {validateEmail, validateMobile} from "@/utils/validate";
|
||||
import {httpPost} from "@/utils/http";
|
||||
import {showMessageError, showMessageOK} from "@/utils/dialog";
|
||||
import { ref } from "vue";
|
||||
import { validateEmail, validateMobile } from "@/utils/validate";
|
||||
import { httpPost } from "@/utils/http";
|
||||
import { ElMessage } from "element-plus";
|
||||
import Captcha from "@/components/Captcha.vue";
|
||||
import {getSystemInfo} from "@/store/cache";
|
||||
import { getSystemInfo } from "@/store/cache";
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const props = defineProps({
|
||||
@@ -28,8 +23,8 @@ const props = defineProps({
|
||||
size: String,
|
||||
type: {
|
||||
type: String,
|
||||
default: "mobile"
|
||||
}
|
||||
default: "mobile",
|
||||
},
|
||||
});
|
||||
const btnText = ref("发送验证码");
|
||||
const canSend = ref(true);
|
||||
@@ -42,10 +37,10 @@ getSystemInfo().then((res) => {
|
||||
|
||||
const sendMsg = () => {
|
||||
if (!validateMobile(props.receiver) && props.type === "mobile") {
|
||||
return showMessageError("请输入合法的手机号");
|
||||
return ElMessage.error("请输入合法的手机号");
|
||||
}
|
||||
if (!validateEmail(props.receiver) && props.type === "email") {
|
||||
return showMessageError("请输入合法的邮箱地址");
|
||||
return ElMessage.error("请输入合法的邮箱地址");
|
||||
}
|
||||
|
||||
if (enableVerify.value) {
|
||||
@@ -65,10 +60,10 @@ const doSendMsg = (data) => {
|
||||
receiver: props.receiver,
|
||||
key: data.key,
|
||||
dots: data.dots,
|
||||
x: data.x
|
||||
x: data.x,
|
||||
})
|
||||
.then(() => {
|
||||
showMessageOK("验证码发送成功");
|
||||
ElMessage.success("验证码发送成功");
|
||||
let time = 60;
|
||||
btnText.value = time;
|
||||
const handler = setInterval(() => {
|
||||
@@ -84,7 +79,7 @@ const doSendMsg = (data) => {
|
||||
})
|
||||
.catch((e) => {
|
||||
canSend.value = true;
|
||||
showMessageError("验证码发送失败:" + e.message);
|
||||
ElMessage.error("验证码发送失败:" + e.message);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,169 +1,177 @@
|
||||
<template>
|
||||
<div class="slide-captcha">
|
||||
<div class="bg-img">
|
||||
<el-image :src="backgroundImg" />
|
||||
<div :class="verifyMsgClass" v-if="checked !== 0">
|
||||
<span v-if="checked ===1">{{time}}s</span>
|
||||
{{verifyMsg}}
|
||||
<div class="flex justify-center items-center">
|
||||
<div class="slide-captcha">
|
||||
<div class="bg-img">
|
||||
<el-image :src="backgroundImg" />
|
||||
<div :class="verifyMsgClass" v-if="checked !== 0">
|
||||
<span v-if="checked === 1">{{ time }}s</span>
|
||||
{{ verifyMsg }}
|
||||
</div>
|
||||
<div class="refresh" @click="emits('refresh')">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
</div>
|
||||
<span class="block">
|
||||
<el-image :src="blockImg" :style="{ left: blockLeft + 'px' }" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="refresh" @click="emits('refresh')">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
</div>
|
||||
<span class="block">
|
||||
<el-image :src="blockImg" :style="{left: blockLeft+'px'}" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="verify">
|
||||
<div class="verify-bar-area">
|
||||
<span class="verify-msg">{{verifyText}}</span>
|
||||
<div class="verify">
|
||||
<div class="verify-bar-area">
|
||||
<span class="verify-msg">{{ verifyText }}</span>
|
||||
|
||||
<div :class="leftBarClass" :style="{width: leftBarWidth+'px'}">
|
||||
<div :class="blockClass" id="dragBlock"
|
||||
:style="{left: blockLeft+'px'}">
|
||||
<el-icon v-if="checked === 0"><ArrowRightBold /></el-icon>
|
||||
<el-icon v-if="checked === 1"><CircleCheckFilled /></el-icon>
|
||||
<el-icon v-if="checked === 2"><CircleCloseFilled /></el-icon>
|
||||
<div :class="leftBarClass" :style="{ width: leftBarWidth + 'px' }">
|
||||
<div :class="blockClass" id="dragBlock" :style="{ left: blockLeft + 'px' }">
|
||||
<el-icon v-if="checked === 0"><ArrowRightBold /></el-icon>
|
||||
<el-icon v-if="checked === 1"><CircleCheckFilled /></el-icon>
|
||||
<el-icon v-if="checked === 2"><CircleCloseFilled /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// eslint-disable-next-line no-undef
|
||||
import {onMounted, ref, watch} from "vue";
|
||||
import {ArrowRightBold, CircleCheckFilled, CircleCloseFilled, Refresh} from "@element-plus/icons-vue";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { ArrowRightBold, CircleCheckFilled, CircleCloseFilled, Refresh } from "@element-plus/icons-vue";
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const props = defineProps({
|
||||
bgImg: String,
|
||||
bkImg: String,
|
||||
result: Number,
|
||||
})
|
||||
|
||||
const verifyText = ref('向右滑动完成验证')
|
||||
const verifyMsg = ref('')
|
||||
const verifyMsgClass = ref("verify-text success")
|
||||
const blockClass = ref('verify-move-block')
|
||||
const leftBarClass = ref('verify-left-bar')
|
||||
const backgroundImg = ref('')
|
||||
const blockImg = ref('')
|
||||
const leftBarWidth = ref(0)
|
||||
const blockLeft = ref(0)
|
||||
const checked = ref(0)
|
||||
const time = ref('')
|
||||
|
||||
watch(() => props.bgImg, (newVal) => {
|
||||
backgroundImg.value = newVal;
|
||||
});
|
||||
watch(() => props.bkImg, (newVal) => {
|
||||
blockImg.value = newVal;
|
||||
});
|
||||
watch(() => props.result, (newVal) => {
|
||||
checked.value = newVal;
|
||||
if (newVal === 1) {
|
||||
verifyMsgClass.value = "verify-text success"
|
||||
blockClass.value = 'verify-move-block success'
|
||||
leftBarClass.value = 'verify-left-bar success'
|
||||
verifyMsg.value = '验证成功'
|
||||
setTimeout(() => emits('hide'), 1000)
|
||||
} else if (newVal ===2) {
|
||||
verifyMsgClass.value = "verify-text error"
|
||||
blockClass.value = 'verify-move-block error'
|
||||
leftBarClass.value = 'verify-left-bar error'
|
||||
verifyMsg.value = '验证失败'
|
||||
setTimeout(() => {
|
||||
reset()
|
||||
emits('refresh')
|
||||
}, 1000)
|
||||
} else {
|
||||
reset()
|
||||
|
||||
const verifyText = ref("向右滑动完成验证");
|
||||
const verifyMsg = ref("");
|
||||
const verifyMsgClass = ref("verify-text success");
|
||||
const blockClass = ref("verify-move-block");
|
||||
const leftBarClass = ref("verify-left-bar");
|
||||
const backgroundImg = ref("");
|
||||
const blockImg = ref("");
|
||||
const leftBarWidth = ref(0);
|
||||
const blockLeft = ref(0);
|
||||
const checked = ref(0);
|
||||
const time = ref("");
|
||||
|
||||
watch(
|
||||
() => props.bgImg,
|
||||
(newVal) => {
|
||||
backgroundImg.value = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
);
|
||||
watch(
|
||||
() => props.bkImg,
|
||||
(newVal) => {
|
||||
blockImg.value = newVal;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.result,
|
||||
(newVal) => {
|
||||
checked.value = newVal;
|
||||
if (newVal === 1) {
|
||||
verifyMsgClass.value = "verify-text success";
|
||||
blockClass.value = "verify-move-block success";
|
||||
leftBarClass.value = "verify-left-bar success";
|
||||
verifyMsg.value = "验证成功";
|
||||
setTimeout(() => emits("hide"), 1000);
|
||||
} else if (newVal === 2) {
|
||||
verifyMsgClass.value = "verify-text error";
|
||||
blockClass.value = "verify-move-block error";
|
||||
leftBarClass.value = "verify-left-bar error";
|
||||
verifyMsg.value = "验证失败";
|
||||
setTimeout(() => {
|
||||
reset();
|
||||
emits("refresh");
|
||||
}, 1000);
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const emits = defineEmits(['confirm','refresh','hide']);
|
||||
const emits = defineEmits(["confirm", "refresh", "hide"]);
|
||||
|
||||
let offsetX = 0, isDragging = false
|
||||
let start = 0
|
||||
let offsetX = 0,
|
||||
isDragging = false;
|
||||
let start = 0;
|
||||
onMounted(() => {
|
||||
const dragBlock = document.getElementById('dragBlock');
|
||||
dragBlock.addEventListener('mousedown', (evt) => {
|
||||
blockClass.value = 'verify-move-block active'
|
||||
leftBarClass.value = 'verify-left-bar active'
|
||||
leftBarWidth.value = 32
|
||||
isDragging = true
|
||||
verifyText.value = ""
|
||||
offsetX = evt.clientX
|
||||
start = new Date().getTime()
|
||||
const dragBlock = document.getElementById("dragBlock");
|
||||
dragBlock.addEventListener("mousedown", (evt) => {
|
||||
blockClass.value = "verify-move-block active";
|
||||
leftBarClass.value = "verify-left-bar active";
|
||||
leftBarWidth.value = 32;
|
||||
isDragging = true;
|
||||
verifyText.value = "";
|
||||
offsetX = evt.clientX;
|
||||
start = new Date().getTime();
|
||||
evt.preventDefault();
|
||||
})
|
||||
});
|
||||
|
||||
document.body.addEventListener('mousemove',(evt) => {
|
||||
document.body.addEventListener("mousemove", (evt) => {
|
||||
if (!isDragging) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const x = Math.max(evt.clientX - offsetX, 0)
|
||||
const x = Math.max(evt.clientX - offsetX, 0);
|
||||
blockLeft.value = x;
|
||||
leftBarWidth.value = x + 32
|
||||
})
|
||||
leftBarWidth.value = x + 32;
|
||||
});
|
||||
|
||||
document.body.addEventListener('mouseup', () => {
|
||||
document.body.addEventListener("mouseup", () => {
|
||||
if (!isDragging) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
time.value = ((new Date().getTime() - start)/1000).toFixed(2)
|
||||
isDragging = false
|
||||
emits('confirm', Math.floor(blockLeft.value))
|
||||
})
|
||||
time.value = ((new Date().getTime() - start) / 1000).toFixed(2);
|
||||
isDragging = false;
|
||||
emits("confirm", Math.floor(blockLeft.value));
|
||||
});
|
||||
|
||||
// 触摸事件
|
||||
dragBlock.addEventListener('touchstart', function (e) {
|
||||
dragBlock.addEventListener("touchstart", function (e) {
|
||||
isDragging = true;
|
||||
blockClass.value = 'verify-move-block active'
|
||||
leftBarClass.value = 'verify-left-bar active'
|
||||
leftBarWidth.value = 32
|
||||
isDragging = true
|
||||
verifyText.value = ""
|
||||
blockClass.value = "verify-move-block active";
|
||||
leftBarClass.value = "verify-left-bar active";
|
||||
leftBarWidth.value = 32;
|
||||
isDragging = true;
|
||||
verifyText.value = "";
|
||||
offsetX = e.touches[0].clientX - dragBlock.getBoundingClientRect().left;
|
||||
start = new Date().getTime()
|
||||
start = new Date().getTime();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener('touchmove', function (e) {
|
||||
document.addEventListener("touchmove", function (e) {
|
||||
if (!isDragging) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const x = Math.max(e.touches[0].clientX - offsetX, 0)
|
||||
const x = Math.max(e.touches[0].clientX - offsetX, 0);
|
||||
blockLeft.value = x;
|
||||
leftBarWidth.value = x + 32
|
||||
leftBarWidth.value = x + 32;
|
||||
});
|
||||
|
||||
document.addEventListener('touchend', function () {
|
||||
document.addEventListener("touchend", function () {
|
||||
if (!isDragging) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
time.value = ((new Date().getTime() - start)/1000).toFixed(2)
|
||||
isDragging = false
|
||||
emits('confirm', Math.floor(blockLeft.value))
|
||||
time.value = ((new Date().getTime() - start) / 1000).toFixed(2);
|
||||
isDragging = false;
|
||||
emits("confirm", Math.floor(blockLeft.value));
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
// 重置验证码
|
||||
const reset = () => {
|
||||
blockClass.value = 'verify-move-block'
|
||||
leftBarClass.value = 'verify-left-bar'
|
||||
leftBarWidth.value = 0
|
||||
blockLeft.value = 0
|
||||
checked.value = 0
|
||||
verifyText.value = "向右滑动完成验证"
|
||||
}
|
||||
blockClass.value = "verify-move-block";
|
||||
leftBarClass.value = "verify-left-bar";
|
||||
leftBarWidth.value = 0;
|
||||
blockLeft.value = 0;
|
||||
checked.value = 0;
|
||||
verifyText.value = "向右滑动完成验证";
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="stylus">
|
||||
@@ -177,6 +185,7 @@ const reset = () => {
|
||||
}
|
||||
|
||||
.slide-captcha {
|
||||
width 310px
|
||||
* {
|
||||
margin 0
|
||||
padding 0
|
||||
@@ -294,4 +303,4 @@ const reset = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div :class="'sidebar ' + theme">
|
||||
<a class="logo w-full" href="/" target="_blank">
|
||||
<el-image :src="logo" />
|
||||
<a class="logo w-full flex items-center" href="/" target="_blank">
|
||||
<img :src="logo" style="height: 36px" />
|
||||
<span class="text" v-show="!sidebar.collapse">{{ title }}</span>
|
||||
</a>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user