232 lines
6.0 KiB
Plaintext
232 lines
6.0 KiB
Plaintext
<template>
|
|
<div class="password-box" :class="{ 'block-box': block }">
|
|
<a-popover
|
|
ref="popoverRef"
|
|
:trigger="['focus']"
|
|
:visibleChange="popoverChange"
|
|
destroyTooltipOnHide
|
|
:class="{ 'block-box': block }"
|
|
:visible="isShowIntensity"
|
|
>
|
|
<template #content v-if="isShowIntensity">
|
|
<Intensity v-bind="intensityValue" />
|
|
</template>
|
|
<a-form :model="formValue" :rules="rules" ref="formRef">
|
|
<a-form-item name="password">
|
|
<a-input-password
|
|
:id="`${getId}-1`"
|
|
ref="passwordRef"
|
|
v-model:value="formValue.password"
|
|
@change="passwordChange"
|
|
placeholder="请输入密码"
|
|
:maxlength="maxLength"
|
|
@focus="onFocus"
|
|
@blur="onBlur"
|
|
>
|
|
<template #prefix>
|
|
<LockOutlined style="color: #808695; font-size: 18px" />
|
|
</template>
|
|
</a-input-password>
|
|
</a-form-item>
|
|
<a-form-item name="repeat" v-if="repeat">
|
|
<a-input-password
|
|
:id="`${getId}-2`"
|
|
type="password"
|
|
v-model:value="formValue.repeat"
|
|
placeholder="请再次输入密码"
|
|
:maxlength="maxLength"
|
|
@focus="onFocus"
|
|
@blur="onBlur"
|
|
>
|
|
<template #prefix>
|
|
<LockOutlined style="color: #808695; font-size: 18px" />
|
|
</template>
|
|
</a-input-password>
|
|
</a-form-item>
|
|
</a-form>
|
|
</a-popover>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, unref, computed, nextTick, reactive } from 'vue';
|
|
import { LockOutlined } from '@ant-design/icons-vue';
|
|
import Intensity from './components/Intensity.vue';
|
|
import { basicProps } from './props';
|
|
import { bindUUid } from '@/utils';
|
|
|
|
const props = defineProps({ ...basicProps });
|
|
|
|
defineEmits(['change', 'focus']);
|
|
|
|
const isSuccess = ref(false);
|
|
|
|
const isShowIntensity = ref(false);
|
|
|
|
const getId = bindUUid();
|
|
|
|
const formValue = reactive({
|
|
password: props.value,
|
|
repeat: '',
|
|
});
|
|
|
|
const password = ref({
|
|
strength: 0,
|
|
tips: null,
|
|
length: false,
|
|
format: false,
|
|
complexity: false,
|
|
});
|
|
|
|
const rules = {
|
|
password: [{ required: true, validator: checkPasswordVal, trigger: 'change' }],
|
|
repeat: [{ required: props.repeat, validator: checkRepeat, trigger: 'change' }],
|
|
};
|
|
|
|
const popoverRef = ref();
|
|
const passwordRef = ref();
|
|
|
|
const intensityValue: any = computed(() => {
|
|
return {
|
|
value: formValue.password,
|
|
complexity: props.complexity,
|
|
minLength: props.minLength,
|
|
maxLength: props.maxLength,
|
|
password: password.value,
|
|
complexityTip: props.complexityTip,
|
|
};
|
|
});
|
|
|
|
function onFocus() {
|
|
isShowIntensity.value = true;
|
|
}
|
|
|
|
function onBlur() {
|
|
isShowIntensity.value = false;
|
|
}
|
|
|
|
function passwordChange() {
|
|
const value: string = formValue.password as string;
|
|
password.value.strength = getStrength(value);
|
|
}
|
|
|
|
async function checkPasswordVal(_, value) {
|
|
if (!props.required && !value) {
|
|
isSuccess.value = true;
|
|
return Promise.resolve();
|
|
}
|
|
if (!value) {
|
|
password.value = {
|
|
strength: 0,
|
|
tips: null,
|
|
length: false,
|
|
format: false,
|
|
complexity: false,
|
|
};
|
|
isSuccess.value = false;
|
|
return Promise.reject('请设置密码');
|
|
} else {
|
|
password.value.format = true;
|
|
if (value.length < props.minLength) {
|
|
password.value.length = false;
|
|
password.value.strength = 0;
|
|
password.value.tips = null;
|
|
return Promise.reject(`密码长度至少为${props.minLength}个字符`);
|
|
}
|
|
if (props.complexity) {
|
|
if (checkPassword(value)) {
|
|
password.value.length = true;
|
|
const strength = getStrength(value);
|
|
password.value.strength = strength;
|
|
password.value.tips = props.level[strength];
|
|
if (strength <= 1) {
|
|
password.value.complexity = false;
|
|
return Promise.reject(props.complexityTip);
|
|
} else {
|
|
password.value.complexity = true;
|
|
isSuccess.value = true;
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
} else {
|
|
password.value.length = true;
|
|
const strength = getStrength(value);
|
|
password.value.strength = strength;
|
|
password.value.tips = props.level[strength];
|
|
password.value.complexity = true;
|
|
isSuccess.value = true;
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
isSuccess.value = true;
|
|
return Promise.resolve();
|
|
}
|
|
|
|
function checkRepeat(_, value) {
|
|
if (!props.required && !value) {
|
|
isSuccess.value = true;
|
|
return Promise.resolve();
|
|
}
|
|
if (!value) {
|
|
return Promise.reject('请再次输入密码');
|
|
} else {
|
|
if (formValue.password !== value) {
|
|
return Promise.reject('两次密码输入不一致');
|
|
}
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
function checkPassword(password: string): boolean {
|
|
const regExp = /^[A-Za-z0-9~!@#$%^&*()_+=\-.,]{6,32}$/;
|
|
return regExp.test(password);
|
|
}
|
|
|
|
function getStrength(password: string): number {
|
|
const reg = {
|
|
lower: /[a-z]/,
|
|
upper: /[A-Z]/,
|
|
number: /[\d]/,
|
|
character: /[~!@#$%^&*()_+=\-.,]/,
|
|
};
|
|
let strength = 0;
|
|
if (reg.lower.test(password)) strength++;
|
|
if (reg.upper.test(password)) strength++;
|
|
if (reg.number.test(password)) strength++;
|
|
if (reg.character.test(password)) strength++;
|
|
return strength;
|
|
}
|
|
|
|
function showValidator() {
|
|
passwordRef.value.focus();
|
|
passwordRef.value.blur();
|
|
nextTick(() => {
|
|
passwordRef.value.focus();
|
|
});
|
|
}
|
|
|
|
function isValidator() {
|
|
return unref(isSuccess);
|
|
}
|
|
|
|
function popoverChange(visible) {
|
|
console.log(visible);
|
|
}
|
|
|
|
defineExpose({
|
|
isValidator,
|
|
showValidator,
|
|
});
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.password-box {
|
|
display: inline-block;
|
|
}
|
|
|
|
.block-box {
|
|
display: block;
|
|
width: 100%;
|
|
}
|
|
</style>
|