Files
lilishop-ui/buyer/src/components/verify/index.vue
lifenlong 88fc1b0b2a refactor: 四端完成 Options API → script setup + vuex → pinia 迁移
- buyer(95) / seller(169) / im(53) / manager(280) 共 597 个组件全部从 Options API 转换为 <script setup>
- 四端 vuex 全部移除,状态管理统一迁移至 pinia 4(stores/ 目录)
- util.js 等基础设施去除 vm 首参依赖;全局属性($Message/$filters 等)在 script 内改为具名导入
- 被外部 ref 访问的公共组件均已补齐 defineExpose(清单见各端 MIGRATION-VUE3.md)
- 各端 eslint 启用 vue/component-api-style 防止新代码回退 Options API
- 四端 yarn build 全部通过;迁移约定与注意事项已更新至各端 MIGRATION-VUE3.md
2026-10-13 07:06:59 +08:00

193 lines
4.6 KiB
Vue

<template>
<div class="verify-content" v-if="show" @mousemove="mouseMove" @mouseup="mouseUp" @click.stop>
<div class="imgBox" :style="{width:data.originalWidth+'px',height:data.originalHeight + 'px'}">
<img :src="data.backImage" style="width:100%;height:100%" alt="">
<img class="slider" :src="data.slidingImage" :style="{left:distance+'px',top:data.randomY+'px'}" :width="data.sliderWidth" :height="data.sliderHeight" alt="">
<el-icon class="refresh" @click="init"><Refresh /></el-icon>
</div>
<div class="handle" :style="{width:data.originalWidth+'px'}">
<span class="bgcolor" :style="{width:distance + 'px',background:bgColor}"></span>
<span class="swiper" :style="{left:distance + 'px'}" @mousedown="mouseDown">
<el-icon><ArrowRight /></el-icon>
</span>
<span class="text">{{verifyText}}</span>
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
import { Message } from "@/utils/message";
import { Refresh, ArrowRight } from '@element-plus/icons-vue';
import { getVerifyImg, postVerifyImg } from './verify.js';
const props = defineProps({
// 传入数据,判断是登录、注册、修改密码
verifyType: {
defalut: 'LOGIN',
type: String
}
});
const emit = defineEmits(['change']);
const show = ref(false); // 验证码显隐
const type = ref('LOGIN'); // 请求类型
const data = ref({ // 验证码数据
backImage: '',
slidingImage: '',
originalHeight: 150,
originalWidth: 300,
sliderWidth: 60,
sliderHeight: 60
});
const distance = ref(0); // 拼图移动距离
const flag = ref(false); // 判断滑块是否按下
const downX = ref(0); // 鼠标按下位置
const bgColor = ref('#04ad11'); // 滑动背景颜色
const verifyText = ref('拖动滑块解锁'); // 文字提示
// 鼠标按下事件,开始拖动滑块
function mouseDown (e) {
downX.value = e.clientX;
flag.value = true;
}
// 鼠标移动事件,计算距离
function mouseMove (e) {
if (flag.value) {
let offset = e.clientX - downX.value;
if (offset > data.value.originalWidth - 43) {
distance.value = data.value.originalWidth - 43;
} else if (offset < 0) {
distance.value = 0;
} else {
distance.value = offset;
}
}
}
// 鼠标抬起事件,验证是否正确
function mouseUp () {
if (!flag.value) return false;
flag.value = false;
let params = {
verificationEnums: type.value,
xPos: distance.value
};
postVerifyImg(params).then(res => {
if (res.success) {
if (res.result) {
bgColor.value = 'green';
verifyText.value = '解锁成功';
emit('change', { status: true, distance: distance.value });
} else {
bgColor.value = 'red';
verifyText.value = '解锁失败';
setTimeout(() => {
init();
}, 1000);
emit('change', { status: false, distance: distance.value });
}
} else {
init()
}
}).catch(()=>{
init()
});
}
function close () {
show.value = false;
}
function init () { // 初始化数据
flag.value = false;
downX.value = 0;
distance.value = 0;
bgColor.value = '#04ad11';
verifyText.value = '拖动滑块解锁';
getVerifyImg(type.value).then(res => {
if (res.result) {
data.value = res.result;
show.value = true;
} else {
Message.warning('请求失败请重试!')
}
});
}
// 父组件通过 ref 调用 init/close
defineExpose({ init, close });
watch(() => props.verifyType, (v) => {
type.value = v;
}, { immediate: true });
</script>
<style lang="scss" scoped>
.verify-content{
padding: 10px;
background: #fff;
border: 1px solid #eee;
border-radius: 5px;
box-shadow: 1px 1px 3px #999;
}
.imgBox {
width: 300px;
height: 150px;
position: relative;
overflow: hidden;
.slider {
position: absolute;
cursor: pointer;
}
.refresh {
position: absolute;
right: 5px;
top: 5px;
font-size: 20px;
color: #fff;
cursor: pointer;
}
}
.handle {
border: 1px solid #e4dede;
margin-top: 5px;
height: 42px;
background: #ddd;
position: relative;
.bgcolor {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 40px;
opacity: 0.5;
background: #04ad11;
}
.swiper {
position: absolute;
width: 40px;
height: 40px;
background-color: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
.el-icon {
font-size: 20px;
}
}
.text {
display: inline-block;
width: inherit;
text-align: center;
line-height: 42px;
font-size: 14px;
user-select: none;
}
}
</style>