feat(ui): 登录新增验证码及记住密码功能

This commit is contained in:
廖彦棋 2024-03-11 10:49:13 +08:00
parent bc21a1d443
commit 2e7b75affb
3 changed files with 143 additions and 57 deletions

View File

@ -33,3 +33,10 @@ export const loginLog = (params?: Record<string, unknown>) => {
params
})
}
export const captcha = () => {
return http({
url: "/api/admin/login/captcha",
method: "get",
});
};

View File

@ -1,24 +1,82 @@
<script lang="ts" setup>
import { reactive } from "vue";
import { useRoute } from "vue-router";
import { onMounted, reactive } from "vue";
import { useAuthStore } from "@/stores/auth";
import { captcha } from "@/http/login";
import useState from "@/composables/useState";
import useRequest from "@/composables/useRequest";
const route = useRoute();
const authStore = useAuthStore();
const [loginRequest, _, loading] = useRequest(authStore.login);
const formData = reactive({
//
function useFormData() {
const formData = reactive({
username: "",
password: "",
});
async function handleSubmit({ errors, values }: any) {
if (errors) return;
await loginRequest({
...values,
...route.query,
captcha: "",
});
const rules = {
username: [{ required: true, message: "请输入您的账号" }],
password: [{ required: true, message: "请输入您的密码" }],
captcha: [{ required: true, message: "请输入验证码" }],
};
const authStore = useAuthStore();
const [loginRequest, _, submitting] = useRequest(authStore.login);
return { formData, loginRequest, submitting, rules };
}
//
function useCaptcha() {
const captchaImage = reactive({
pic_path: "",
captcha_id: "",
});
const getCaptchaImage = async () => {
const { data } = await captcha();
Object.assign(captchaImage, data);
};
onMounted(getCaptchaImage);
return { captchaImage, getCaptchaImage };
}
//
function useRemeberPWD(formData) {
const storageKey = "r-f";
const [isRemember, setIsRemember] = useState(false);
const onIsRememberChange = (v) => {
if (v) {
const value = {
username: formData.username,
password: formData.password,
};
localStorage.setItem(storageKey, JSON.stringify(value));
} else {
localStorage.removeItem(storageKey);
}
setIsRemember(v);
};
onMounted(() => {
const getter = localStorage.getItem(storageKey);
if (getter) {
setIsRemember(true);
Object.assign(formData, JSON.parse(getter));
}
});
return { isRemember, onIsRememberChange };
}
const { formData, loginRequest, submitting, rules } = useFormData();
const { captchaImage, getCaptchaImage } = useCaptcha();
const { isRemember, onIsRememberChange } = useRemeberPWD(formData);
//
async function handleSubmit({ errors }: any) {
if (errors) return;
try {
await loginRequest({
...formData,
captcha_id: captchaImage.captcha_id,
});
} catch (err) {
getCaptchaImage();
}
}
</script>
<template>
@ -38,29 +96,20 @@ async function handleSubmit({ errors, values }: any) {
class="form"
size="medium"
auto-label-width
:label-col-props="{ span: 0 }"
:wrapper-col-props="{ span: 24 }"
:rules="rules"
@submit="handleSubmit"
>
<a-space direction="vertical" style="width: 100%">
<a-form-item
field="username"
label="账号"
hide-label
hide-asterisk
:rules="[{ required: true, message: '请输入您的账号' }]"
>
<a-form-item field="username" label="账号">
<a-input
v-model="formData.username"
placeholder="请输入您的账号"
class="input"
></a-input>
</a-form-item>
<a-form-item
field="password"
label="密码"
hide-label
hide-asterisk
:rules="[{ required: true, message: '请输入您的密码' }]"
>
<a-form-item field="password" label="密码">
<a-input-password
v-model="formData.password"
placeholder="请输入您的密码"
@ -68,9 +117,33 @@ async function handleSubmit({ errors, values }: any) {
>
</a-input-password>
</a-form-item>
<a-form-item field="captcha" label="验证码">
<a-input v-model="formData.captcha" placeholder="请输入验证码" class="input">
<template #append>
<img
class="captcha-image"
:src="captchaImage.pic_path"
alt="验证码"
title="点击刷新验证码"
@click="getCaptchaImage()"
/>
</template>
</a-input>
</a-form-item>
<a-form-item hide-label>
<a-checkbox :model-value="isRemember" @change="onIsRememberChange"
>记住密码</a-checkbox
>
</a-form-item>
</a-space>
<a-form-item hide-label>
<a-button :disabled="loading" html-type="submit" long type="primary" class="sign-in-btn">
<a-button
:loading="submitting"
html-type="submit"
long
type="primary"
class="sign-in-btn"
>
登录
</a-button>
</a-form-item>

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { computed } from "vue";
import { computed, ref } from "vue";
import type { UploadInstance, FileItem } from "@arco-design/web-vue";
import { uploadUrl } from "@/http/config";
@ -10,6 +10,8 @@ defineProps({
const emits = defineEmits(["update:modelValue"]);
const uploadRef = ref();
const uploadProps = computed<UploadInstance["$props"]>(() => ({
action: uploadUrl,
name: "file",
@ -19,19 +21,23 @@ const uploadProps = computed<UploadInstance["$props"]>(() => ({
const handleChange = (_, file: FileItem) => {
console.log(file.response);
console.log(file);
};
</script>
<template>
<a-space>
<a-input-group>
<a-input :model-value="modelValue" :placeholder="placeholder" readonly />
<a-upload v-bind="uploadProps" @change="handleChange">
<a-input-group style="width: 100%">
<a-input
:model-value="modelValue"
:placeholder="placeholder"
readonly
@dblclick="uploadRef?.$el?.click()"
/>
<a-upload ref="uploadRef" v-bind="uploadProps" @change="handleChange">
<template #upload-button>
<a-button type="primary">
<a-button type="primary" style="width: 100px">
<icon-cloud />
</a-button>
</template>
</a-upload>
</a-input-group>
</a-space>
</template>