feat(auth): 添加验证码功能并优化登录注册页面 #1
@ -1,5 +1,5 @@
|
|||||||
import alova, { type AlovaResponse } from '@/plugins/alova';
|
import alova, { type AlovaResponse } from '@/plugins/alova';
|
||||||
import type { LoginBody, RegisterBody, ResUserInfo } from '@/apis/auth/type.ts';
|
import type { LoginBody, RegisterBody, ResCaptcha, ResUserInfo } from '@/apis/auth/type.ts';
|
||||||
|
|
||||||
export const login = (lb: LoginBody) =>
|
export const login = (lb: LoginBody) =>
|
||||||
alova.Post<AlovaResponse<string>>('/auth/login', lb, {
|
alova.Post<AlovaResponse<string>>('/auth/login', lb, {
|
||||||
@ -14,3 +14,8 @@ export const register = (rb: RegisterBody) => {
|
|||||||
export const info = () => {
|
export const info = () => {
|
||||||
return alova.Get<AlovaResponse<ResUserInfo>>('/auth/info', { meta: { notbefore: true } });
|
return alova.Get<AlovaResponse<ResUserInfo>>('/auth/info', { meta: { notbefore: true } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const captcha = () =>
|
||||||
|
alova.Get<AlovaResponse<ResCaptcha>>('/auth/captcha', {
|
||||||
|
meta: { notbefore: true },
|
||||||
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export interface LoginBody {
|
export interface LoginBody {
|
||||||
passWold: string;
|
passWold: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
|
uuid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RegisterBody {
|
export interface RegisterBody {
|
||||||
@ -27,3 +28,7 @@ export interface ResUserInfo {
|
|||||||
user: User;
|
user: User;
|
||||||
login: boolean;
|
login: boolean;
|
||||||
}
|
}
|
||||||
|
export interface ResCaptcha {
|
||||||
|
captcha: string;
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
@ -14,10 +14,18 @@
|
|||||||
<div v-loading="regis_login" class="card" style="margin-top: 20px">
|
<div v-loading="regis_login" class="card" style="margin-top: 20px">
|
||||||
<div f-c-c>
|
<div f-c-c>
|
||||||
<NGradientText v-if="data.carData.p_result === 2 && data.carData.status === 2" size="65">可上磅</NGradientText>
|
<NGradientText v-if="data.carData.p_result === 2 && data.carData.status === 2" size="65">可上磅</NGradientText>
|
||||||
<NGradientText v-if="data.carData.p_result === 40 && data.carData.status === 1" size="65">已出库</NGradientText>
|
<NGradientText v-else-if="data.carData.p_result === 40 && data.carData.status === 1" size="65">
|
||||||
<NGradientText v-if="data.carData.p_result === 2 && data.carData.status === 0" size="65">已入库</NGradientText>
|
已撤销
|
||||||
<NGradientText v-if="data.carData.p_result === 40 && data.carData.status === 2" size="65">已撤销</NGradientText>
|
</NGradientText>
|
||||||
<NGradientText v-if="data.carData.p_result === 2 && data.carData.status === 1" size="65">已出库</NGradientText>
|
<NGradientText v-else-if="data.carData.p_result === 2 && data.carData.status === 0" size="65">
|
||||||
|
已入库
|
||||||
|
</NGradientText>
|
||||||
|
<NGradientText v-else-if="data.carData.p_result === 40 && data.carData.status === 2" size="65">
|
||||||
|
已撤销
|
||||||
|
</NGradientText>
|
||||||
|
<NGradientText v-else-if="data.carData.p_result === 2 && data.carData.status === 1" size="65">
|
||||||
|
已出库
|
||||||
|
</NGradientText>
|
||||||
<NGradientText v-else size="65" type="error">不可上磅</NGradientText>
|
<NGradientText v-else size="65" type="error">不可上磅</NGradientText>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-line"></div>
|
<div class="card-line"></div>
|
||||||
@ -58,13 +66,7 @@ import { onMounted, ref } from 'vue';
|
|||||||
import { getMyCar } from '@/apis/bacth';
|
import { getMyCar } from '@/apis/bacth';
|
||||||
|
|
||||||
import { UserStore } from '@/plugins';
|
import { UserStore } from '@/plugins';
|
||||||
import {
|
import { NAlert, NButton, NDescriptions, NDescriptionsItem, NGradientText } from 'naive-ui';
|
||||||
NAlert,
|
|
||||||
NButton,
|
|
||||||
NDescriptions,
|
|
||||||
NDescriptionsItem,
|
|
||||||
NGradientText
|
|
||||||
} from 'naive-ui';
|
|
||||||
import type { CarDataResType } from '@/apis/bacth/type.ts';
|
import type { CarDataResType } from '@/apis/bacth/type.ts';
|
||||||
import UseApiLoading from '@/utils/UseApiLoading.ts';
|
import UseApiLoading from '@/utils/UseApiLoading.ts';
|
||||||
|
|
||||||
@ -99,6 +101,7 @@ function getdata() {
|
|||||||
getMyCars().then((a) => {
|
getMyCars().then((a) => {
|
||||||
console.log(a.json().Data);
|
console.log(a.json().Data);
|
||||||
data.value = a.json().Data;
|
data.value = a.json().Data;
|
||||||
|
console.log(data.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -17,6 +17,21 @@
|
|||||||
<NFormItem label="密码" path="passWold">
|
<NFormItem label="密码" path="passWold">
|
||||||
<NInput v-model:value="fromdata.passWold" placeholder="请输入密码" type="password" />
|
<NInput v-model:value="fromdata.passWold" placeholder="请输入密码" type="password" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
<NFormItem label="验证码" path="captcha">
|
||||||
|
<div style="display: flex; width: 100%">
|
||||||
|
<NInput
|
||||||
|
v-model:value="fromdata.captcha"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
style="flex-grow: 1; border-bottom-right-radius: 0; border-top-right-radius: 0" />
|
||||||
|
<img
|
||||||
|
:src="cpaimg"
|
||||||
|
b-r
|
||||||
|
height="34"
|
||||||
|
style="border-bottom-right-radius: 3px; border-top-right-radius: 3px"
|
||||||
|
width="85"
|
||||||
|
@click="captchas" />
|
||||||
|
</div>
|
||||||
|
</NFormItem>
|
||||||
<NFormItem label=" ">
|
<NFormItem label=" ">
|
||||||
<NCheckbox v-model:checked="userStore.userDataRemberData.renb">记住我</NCheckbox>
|
<NCheckbox v-model:checked="userStore.userDataRemberData.renb">记住我</NCheckbox>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
@ -33,20 +48,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { type FormInst, NButton, NCheckbox, NForm, NFormItem, NGradientText, NInput, NText } from 'naive-ui';
|
import {
|
||||||
|
type FormInst,
|
||||||
|
type FormItemRule,
|
||||||
|
NButton,
|
||||||
|
NCheckbox,
|
||||||
|
NForm,
|
||||||
|
NFormItem,
|
||||||
|
NGradientText,
|
||||||
|
NInput,
|
||||||
|
NText,
|
||||||
|
} from 'naive-ui';
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
import message from '@/utils/message.ts';
|
import message from '@/utils/message.ts';
|
||||||
import { login } from '@/apis/auth';
|
import { captcha, login } from '@/apis/auth';
|
||||||
import { UserStore } from '@/plugins';
|
import { UserStore } from '@/plugins';
|
||||||
import UseApiLoading from '@/utils/UseApiLoading.ts';
|
import UseApiLoading from '@/utils/UseApiLoading.ts';
|
||||||
|
|
||||||
const formRef = ref<FormInst | null>(null);
|
const formRef = ref<FormInst | null>(null);
|
||||||
|
const cpaimg = ref('');
|
||||||
|
|
||||||
const userStore = UserStore();
|
const userStore = UserStore();
|
||||||
|
|
||||||
const fromdata = reactive({
|
const fromdata = reactive({
|
||||||
passWold: '',
|
passWold: '',
|
||||||
userName: '',
|
userName: '',
|
||||||
|
captcha: '',
|
||||||
|
uuid: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -54,6 +82,7 @@ onMounted(() => {
|
|||||||
fromdata.userName = userStore.userDataRemberData.user;
|
fromdata.userName = userStore.userDataRemberData.user;
|
||||||
fromdata.passWold = userStore.userDataRemberData.pass;
|
fromdata.passWold = userStore.userDataRemberData.pass;
|
||||||
}
|
}
|
||||||
|
captchas();
|
||||||
});
|
});
|
||||||
|
|
||||||
const [[loading_login], logins] = UseApiLoading(login);
|
const [[loading_login], logins] = UseApiLoading(login);
|
||||||
@ -61,7 +90,8 @@ const [[loading_login], logins] = UseApiLoading(login);
|
|||||||
const regis = () => {
|
const regis = () => {
|
||||||
formRef.value?.validate((errors: any) => {
|
formRef.value?.validate((errors: any) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
logins(fromdata).then((a) => {
|
logins(fromdata)
|
||||||
|
.then((a) => {
|
||||||
userStore.ishaslogin = true;
|
userStore.ishaslogin = true;
|
||||||
userStore.token = a.json().Data;
|
userStore.token = a.json().Data;
|
||||||
if (userStore.userDataRemberData.renb) {
|
if (userStore.userDataRemberData.renb) {
|
||||||
@ -69,12 +99,22 @@ const regis = () => {
|
|||||||
userStore.userDataRemberData.pass = fromdata.passWold;
|
userStore.userDataRemberData.pass = fromdata.passWold;
|
||||||
}
|
}
|
||||||
window.location.replace('/');
|
window.location.replace('/');
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
captchas();
|
||||||
|
fromdata.captcha = '';
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
message.error('请确认 填写信息是否正确');
|
message.error('请确认 填写信息是否正确');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const captchas = () => {
|
||||||
|
captcha().then((a) => {
|
||||||
|
fromdata.uuid = a.json().Data.uuid;
|
||||||
|
cpaimg.value = a.json().Data.captcha;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
userName: {
|
userName: {
|
||||||
@ -89,6 +129,17 @@ const rules = {
|
|||||||
message: '请输入密码',
|
message: '请输入密码',
|
||||||
trigger: ['input'],
|
trigger: ['input'],
|
||||||
},
|
},
|
||||||
|
captcha: {
|
||||||
|
key: 'captcha',
|
||||||
|
required: true,
|
||||||
|
message: '验证码格式不正确 4位数字',
|
||||||
|
trigger: ['input'],
|
||||||
|
validator(rule: FormItemRule, value: string) {
|
||||||
|
const a = RegExp('^\\d{4}$').test(value);
|
||||||
|
console.log(a);
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
@ -23,6 +23,21 @@
|
|||||||
<NFormItem label="确认密码" path="passre">
|
<NFormItem label="确认密码" path="passre">
|
||||||
<NInput v-model:value="fromdata.passre" placeholder="请输入确认密码" type="password" />
|
<NInput v-model:value="fromdata.passre" placeholder="请输入确认密码" type="password" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
<NFormItem label="验证码" path="captcha">
|
||||||
|
<div style="display: flex; width: 100%">
|
||||||
|
<NInput
|
||||||
|
v-model:value="fromdata.captcha"
|
||||||
|
placeholder="请输入验证码"
|
||||||
|
style="flex-grow: 1; border-bottom-right-radius: 0; border-top-right-radius: 0" />
|
||||||
|
<img
|
||||||
|
:src="cpaimg"
|
||||||
|
b-r
|
||||||
|
height="34"
|
||||||
|
style="border-bottom-right-radius: 3px; border-top-right-radius: 3px"
|
||||||
|
width="85"
|
||||||
|
@click="captchas" />
|
||||||
|
</div>
|
||||||
|
</NFormItem>
|
||||||
</NForm>
|
</NForm>
|
||||||
<div f-c-c>
|
<div f-c-c>
|
||||||
<NText style="padding-right: 5px">我已已经有账号了</NText>
|
<NText style="padding-right: 5px">我已已经有账号了</NText>
|
||||||
@ -46,33 +61,44 @@ import {
|
|||||||
NInput,
|
NInput,
|
||||||
NText
|
NText
|
||||||
} from 'naive-ui';
|
} from 'naive-ui';
|
||||||
import { reactive, ref } from 'vue';
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
import message from '@/utils/message.ts';
|
import message from '@/utils/message.ts';
|
||||||
import { register } from '@/apis/auth';
|
import { captcha, register } from '@/apis/auth';
|
||||||
import { router, UserStore } from '@/plugins';
|
import { UserStore } from '@/plugins';
|
||||||
import UseApiLoading from '@/utils/UseApiLoading.ts';
|
import UseApiLoading from '@/utils/UseApiLoading.ts';
|
||||||
|
|
||||||
|
const cpaimg = ref('');
|
||||||
const formRef = ref<FormInst | null>(null);
|
const formRef = ref<FormInst | null>(null);
|
||||||
|
|
||||||
const userStore = UserStore();
|
const userStore = UserStore();
|
||||||
|
|
||||||
const fromdata = reactive({ tel: '', car: '', pass: '', passre: '' });
|
const fromdata = reactive({ tel: '', car: '', pass: '', passre: '', captcha: '', uuid: '' });
|
||||||
const [[regis_login], regise] = UseApiLoading(register);
|
const [[regis_login], regise] = UseApiLoading(register);
|
||||||
const regis = () => {
|
const regis = () => {
|
||||||
formRef.value?.validate((errors: any) => {
|
formRef.value?.validate((errors: any) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
regise(fromdata).then((a) => {
|
regise(fromdata)
|
||||||
|
.then((a) => {
|
||||||
userStore.ishaslogin = true;
|
userStore.ishaslogin = true;
|
||||||
userStore.token = a.json().Data;
|
userStore.token = a.json().Data;
|
||||||
userStore.getLogin();
|
userStore.getLogin();
|
||||||
router.push({ name: 'index' });
|
window.location.replace('/');
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
captchas();
|
||||||
|
fromdata.captcha = '';
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
message.error('请确认 填写信息是否正确');
|
message.error('请确认 填写信息是否正确');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const captchas = () => {
|
||||||
|
captcha().then((a) => {
|
||||||
|
fromdata.uuid = a.json().Data.uuid;
|
||||||
|
cpaimg.value = a.json().Data.captcha;
|
||||||
|
});
|
||||||
|
};
|
||||||
const rules = {
|
const rules = {
|
||||||
tel: {
|
tel: {
|
||||||
key: 'tel',
|
key: 'tel',
|
||||||
@ -97,14 +123,10 @@ const rules = {
|
|||||||
pass: {
|
pass: {
|
||||||
key: 'pass',
|
key: 'pass',
|
||||||
required: true,
|
required: true,
|
||||||
message:
|
message: '最小8位,最大256位',
|
||||||
'密码强度低\n至少包含字母、数字、特殊字符,最少9位,并且不能连续出现3个大小连续或相同的数字(如:456、654、888)',
|
|
||||||
trigger: ['input'],
|
trigger: ['input'],
|
||||||
validator(rule: FormItemRule, value: string) {
|
min: 8,
|
||||||
return RegExp(
|
max: 256,
|
||||||
'^(?=.*\\d)(?!.*(\\d)\\1{2})(?!.*(012|123|234|345|456|567|678|789|987|876|765|654|543|432|321|210))(?=.*[a-zA-Z])(?=.*[^\\da-zA-Z\\s]).{1,9}$',
|
|
||||||
).test(value);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
passre: {
|
passre: {
|
||||||
key: 'passre',
|
key: 'passre',
|
||||||
@ -115,6 +137,18 @@ const rules = {
|
|||||||
return fromdata.pass === value;
|
return fromdata.pass === value;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
captcha: {
|
||||||
|
key: 'captcha',
|
||||||
|
required: true,
|
||||||
|
message: '验证码格式不正确 4位数字',
|
||||||
|
trigger: ['input'],
|
||||||
|
validator(rule: FormItemRule, value: string) {
|
||||||
|
const a = RegExp('^\\d{4}$').test(value);
|
||||||
|
console.log(a);
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
onMounted(captchas);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
html[theme="dark"] {
|
html[theme="dark"] {
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
color: #d8d8d8;
|
color: #d8d8d8;
|
||||||
|
|
||||||
|
*[b-r] {
|
||||||
|
border: 1px solid rgb(62, 62, 62);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*[f-c-c] {
|
*[f-c-c] {
|
||||||
@ -15,3 +19,7 @@ a {
|
|||||||
color: #1bbb44;
|
color: #1bbb44;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*[b-r] {
|
||||||
|
border: 1px solid rgba(194, 194, 194, 1);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user