refactor!: 升级 @nuxt/ui@3,重构所有页面和组件,调整配置,移除不在需求中的页面
This commit is contained in:
@@ -4,8 +4,9 @@ import { object, string, type InferType } from 'yup'
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
import { useFetchWrapped } from '~/composables/useFetchWrapped'
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const toast = useToast()
|
||||
const modal = useModal()
|
||||
const overlay = useOverlay()
|
||||
const loginState = useLoginState()
|
||||
|
||||
const sms_triggered = ref(false)
|
||||
@@ -55,7 +56,7 @@ function onSubmit(form: req.user.Login) {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: res.msg || '未知错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -64,7 +65,7 @@ function onSubmit(form: req.user.Login) {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: res.msg || '账号或密码错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -73,7 +74,7 @@ function onSubmit(form: req.user.Login) {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: res.msg || '无法获取登录状态',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -84,7 +85,8 @@ function onSubmit(form: req.user.Login) {
|
||||
.updateProfile()
|
||||
.then(() => {
|
||||
loginState.checkSession()
|
||||
modal.close()
|
||||
// TODO: only close the specific modal
|
||||
overlay.closeAll()
|
||||
toast.add({
|
||||
title: '登录成功',
|
||||
description: `${loginState.user.username}, 欢迎回来`,
|
||||
@@ -96,7 +98,7 @@ function onSubmit(form: req.user.Login) {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: err.msg || '网络错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
})
|
||||
@@ -108,7 +110,7 @@ function onSubmit(form: req.user.Login) {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: err.msg || '网络错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
})
|
||||
@@ -130,7 +132,7 @@ const obtainSmsCode = () => {
|
||||
toast.add({
|
||||
title: '验证码发送失败',
|
||||
description: res.msg || '未知错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -140,7 +142,7 @@ const obtainSmsCode = () => {
|
||||
sms_counting_down.value = 60 // TODO: save timestamp to localstorage
|
||||
toast.add({
|
||||
title: '短信验证码已发送',
|
||||
color: 'indigo',
|
||||
color: 'primary',
|
||||
icon: 'i-tabler-circle-check',
|
||||
})
|
||||
const interval = setInterval(() => {
|
||||
@@ -154,7 +156,7 @@ const obtainSmsCode = () => {
|
||||
toast.add({
|
||||
title: '验证码发送失败',
|
||||
description: err.msg || '网络错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
})
|
||||
@@ -175,7 +177,7 @@ const handle_sms_verify = (e: string[]) => {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: res.msg || '未知错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -185,7 +187,7 @@ const handle_sms_verify = (e: string[]) => {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: res.msg || '无法获取登录状态',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -196,7 +198,7 @@ const handle_sms_verify = (e: string[]) => {
|
||||
.updateProfile()
|
||||
.then(() => {
|
||||
loginState.checkSession()
|
||||
modal.close()
|
||||
emit('close')
|
||||
toast.add({
|
||||
title: '登录成功',
|
||||
description: `${loginState.user.username}, 欢迎回来`,
|
||||
@@ -208,7 +210,7 @@ const handle_sms_verify = (e: string[]) => {
|
||||
toast.add({
|
||||
title: '登录失败',
|
||||
description: err.msg || '网络错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
})
|
||||
@@ -251,7 +253,7 @@ const obtainForgetSmsCode = () => {
|
||||
toast.add({
|
||||
title: '验证码发送失败',
|
||||
description: res.msg || '未知错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -261,7 +263,7 @@ const obtainForgetSmsCode = () => {
|
||||
sms_counting_down.value = 60 // TODO: save timestamp to localstorage
|
||||
toast.add({
|
||||
title: '短信验证码已发送',
|
||||
color: 'indigo',
|
||||
color: 'primary',
|
||||
icon: 'i-tabler-circle-check',
|
||||
})
|
||||
const interval = setInterval(() => {
|
||||
@@ -275,7 +277,7 @@ const obtainForgetSmsCode = () => {
|
||||
toast.add({
|
||||
title: '验证码发送失败',
|
||||
description: err.msg || '网络错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
})
|
||||
@@ -299,7 +301,7 @@ const onForgetPasswordSubmit = (
|
||||
toast.add({
|
||||
title: '重置密码失败',
|
||||
description: res.msg || '未知错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
return
|
||||
@@ -307,7 +309,7 @@ const onForgetPasswordSubmit = (
|
||||
toast.add({
|
||||
title: '重置密码成功',
|
||||
description: '请您继续登录',
|
||||
color: 'green',
|
||||
color: 'success',
|
||||
icon: 'i-tabler-circle-check',
|
||||
})
|
||||
currentTab.value = 1
|
||||
@@ -316,7 +318,7 @@ const onForgetPasswordSubmit = (
|
||||
toast.add({
|
||||
title: '重置密码失败',
|
||||
description: err.msg || '未知错误',
|
||||
color: 'red',
|
||||
color: 'error',
|
||||
icon: 'i-tabler-circle-x',
|
||||
})
|
||||
})
|
||||
@@ -324,173 +326,101 @@ const onForgetPasswordSubmit = (
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal prevent-close>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3
|
||||
class="text-base font-semibold leading-6 text-gray-900 dark:text-white"
|
||||
>
|
||||
登录眩生花 AI 助手
|
||||
</h3>
|
||||
<UButton
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="-my-1"
|
||||
@click="modal.close()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<UTabs
|
||||
:items="items"
|
||||
class="w-full"
|
||||
v-model="currentTab"
|
||||
>
|
||||
<template #default="{ item, index, selected }">
|
||||
<div class="flex items-center gap-2 relative truncate">
|
||||
<span class="truncate">{{ item.label }}</span>
|
||||
<span
|
||||
v-if="selected"
|
||||
class="absolute -right-4 w-2 h-2 rounded-full bg-primary-500 dark:bg-primary-400"
|
||||
<UModal :dismissible="false">
|
||||
<template #content>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3
|
||||
class="text-base font-semibold leading-6 text-gray-900 dark:text-white"
|
||||
>
|
||||
登录眩生花 AI 助手
|
||||
</h3>
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
class="-my-1"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #item="{ item }">
|
||||
<UCard @submit.prevent="() => onSubmit(accountForm)">
|
||||
<template #header>
|
||||
<p
|
||||
class="text-base font-semibold leading-6 text-gray-900 dark:text-white"
|
||||
>
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-if="item.key === 'account'"
|
||||
class="space-y-3"
|
||||
>
|
||||
<UFormGroup
|
||||
label="用户名"
|
||||
name="username"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="accountForm.username"
|
||||
:disabled="final_loading"
|
||||
required
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="密码"
|
||||
name="password"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="accountForm.password"
|
||||
:disabled="final_loading"
|
||||
type="password"
|
||||
required
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UTabs
|
||||
:items="items"
|
||||
class="w-full"
|
||||
v-model="currentTab"
|
||||
>
|
||||
<!-- <template #default="{ item, index, selected }">
|
||||
<div class="relative flex items-center gap-2 truncate">
|
||||
<span class="truncate">{{ item.label }}</span>
|
||||
<span
|
||||
v-if="selected"
|
||||
class="bg-primary-500 dark:bg-primary-400 absolute -right-4 h-2 w-2 rounded-full"
|
||||
/>
|
||||
</div>
|
||||
</template> -->
|
||||
<template #content="{ item }">
|
||||
<UCard @submit.prevent="() => onSubmit(accountForm)">
|
||||
<template #header>
|
||||
<p
|
||||
class="text-base font-semibold leading-6 text-gray-900 dark:text-white"
|
||||
>
|
||||
{{ item.label }}
|
||||
</p>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ item.description }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-else-if="item.key === 'sms'"
|
||||
class="space-y-3"
|
||||
>
|
||||
<UFormGroup
|
||||
label="手机号"
|
||||
name="mobile"
|
||||
required
|
||||
>
|
||||
<UButtonGroup class="w-full">
|
||||
<UInput
|
||||
v-model="smsForm.mobile"
|
||||
:disabled="final_loading"
|
||||
type="sms"
|
||||
class="w-full"
|
||||
required
|
||||
>
|
||||
<template #leading>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">
|
||||
+86
|
||||
</span>
|
||||
</template>
|
||||
</UInput>
|
||||
<UButton
|
||||
:label="
|
||||
sms_counting_down
|
||||
? `${sms_counting_down}秒后重发`
|
||||
: '获取验证码'
|
||||
"
|
||||
@click="obtainSmsCode"
|
||||
:loading="sms_sending"
|
||||
:disabled="!!sms_counting_down || final_loading"
|
||||
class="text-xs font-bold"
|
||||
color="gray"
|
||||
/>
|
||||
</UButtonGroup>
|
||||
</UFormGroup>
|
||||
<Transition name="pin-root">
|
||||
<div v-if="sms_triggered">
|
||||
<Label
|
||||
for="pin-input"
|
||||
class="pin-label"
|
||||
>
|
||||
验证码
|
||||
</Label>
|
||||
<PinInputRoot
|
||||
id="sms-input"
|
||||
v-model="smsForm.sms_code"
|
||||
:disabled="sms_sending || final_loading"
|
||||
placeholder="○"
|
||||
class="w-full flex gap-2 justify-between md:justify-start items-center mt-1"
|
||||
@complete="handle_sms_verify"
|
||||
type="number"
|
||||
otp
|
||||
required
|
||||
>
|
||||
<PinInputInput
|
||||
v-for="(id, index) in 4"
|
||||
:key="id"
|
||||
:index="index"
|
||||
class="pin-input"
|
||||
:autofocus="index === 0"
|
||||
/>
|
||||
</PinInputRoot>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="item.key === 'recovery'"
|
||||
class="space-y-3"
|
||||
>
|
||||
<UForm
|
||||
<div
|
||||
v-if="item.key === 'account'"
|
||||
class="space-y-3"
|
||||
:schema="forgetPasswordSchema"
|
||||
:state="forgetPasswordState"
|
||||
@submit="onForgetPasswordSubmit"
|
||||
>
|
||||
<UFormGroup
|
||||
<UFormField
|
||||
label="用户名"
|
||||
name="username"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="accountForm.username"
|
||||
:disabled="final_loading"
|
||||
required
|
||||
/>
|
||||
</UFormField>
|
||||
<UFormField
|
||||
label="密码"
|
||||
name="password"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="accountForm.password"
|
||||
:disabled="final_loading"
|
||||
type="password"
|
||||
required
|
||||
/>
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="item.key === 'sms'"
|
||||
class="space-y-3"
|
||||
>
|
||||
<UFormField
|
||||
label="手机号"
|
||||
name="mobile"
|
||||
required
|
||||
>
|
||||
<UButtonGroup class="w-full">
|
||||
<UInput
|
||||
v-model="forgetPasswordState.mobile"
|
||||
v-model="smsForm.mobile"
|
||||
:disabled="final_loading"
|
||||
type="tel"
|
||||
type="sms"
|
||||
class="w-full"
|
||||
required
|
||||
>
|
||||
<template #leading>
|
||||
<span class="text-gray-500 dark:text-gray-400 text-xs">
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
+86
|
||||
</span>
|
||||
</template>
|
||||
@@ -501,78 +431,156 @@ const onForgetPasswordSubmit = (
|
||||
? `${sms_counting_down}秒后重发`
|
||||
: '获取验证码'
|
||||
"
|
||||
@click="obtainForgetSmsCode"
|
||||
@click="obtainSmsCode"
|
||||
:loading="sms_sending"
|
||||
:disabled="!!sms_counting_down"
|
||||
:disabled="!!sms_counting_down || final_loading"
|
||||
class="text-xs font-bold"
|
||||
color="gray"
|
||||
color="neutral"
|
||||
/>
|
||||
</UButtonGroup>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="验证码"
|
||||
name="sms_code"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="forgetPasswordState.sms_code"
|
||||
type="sms"
|
||||
class="w-full"
|
||||
:disabled="final_loading"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="新密码"
|
||||
name="password"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="forgetPasswordState.password"
|
||||
type="password"
|
||||
:disabled="final_loading"
|
||||
/>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
<Transition name="pin-root">
|
||||
<div v-if="sms_triggered">
|
||||
<Label
|
||||
for="pin-input"
|
||||
class="pin-label"
|
||||
>
|
||||
验证码
|
||||
</Label>
|
||||
<PinInputRoot
|
||||
id="sms-input"
|
||||
v-model="smsForm.sms_code"
|
||||
:disabled="sms_sending || final_loading"
|
||||
placeholder="○"
|
||||
class="mt-1 flex w-full items-center justify-between gap-2 md:justify-start"
|
||||
@complete="handle_sms_verify"
|
||||
type="number"
|
||||
otp
|
||||
required
|
||||
>
|
||||
<PinInputInput
|
||||
v-for="(id, index) in 4"
|
||||
:key="id"
|
||||
:index="index"
|
||||
class="pin-input"
|
||||
:autofocus="index === 0"
|
||||
/>
|
||||
</PinInputRoot>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div
|
||||
v-if="item.key === 'recovery'"
|
||||
class="space-y-3"
|
||||
>
|
||||
<UForm
|
||||
class="space-y-3"
|
||||
:schema="forgetPasswordSchema"
|
||||
:state="forgetPasswordState"
|
||||
@submit="onForgetPasswordSubmit"
|
||||
>
|
||||
<UFormField
|
||||
label="手机号"
|
||||
name="mobile"
|
||||
required
|
||||
>
|
||||
<UButtonGroup class="w-full">
|
||||
<UInput
|
||||
v-model="forgetPasswordState.mobile"
|
||||
:disabled="final_loading"
|
||||
type="tel"
|
||||
class="w-full"
|
||||
>
|
||||
<template #leading>
|
||||
<span
|
||||
class="text-xs text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
+86
|
||||
</span>
|
||||
</template>
|
||||
</UInput>
|
||||
<UButton
|
||||
:label="
|
||||
sms_counting_down
|
||||
? `${sms_counting_down}秒后重发`
|
||||
: '获取验证码'
|
||||
"
|
||||
@click="obtainForgetSmsCode"
|
||||
:loading="sms_sending"
|
||||
:disabled="!!sms_counting_down"
|
||||
class="text-xs font-bold"
|
||||
color="neutral"
|
||||
/>
|
||||
</UButtonGroup>
|
||||
</UFormField>
|
||||
<UFormField
|
||||
label="验证码"
|
||||
name="sms_code"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="forgetPasswordState.sms_code"
|
||||
type="sms"
|
||||
class="w-full"
|
||||
:disabled="final_loading"
|
||||
/>
|
||||
</UFormField>
|
||||
<UFormField
|
||||
label="新密码"
|
||||
name="password"
|
||||
required
|
||||
>
|
||||
<UInput
|
||||
v-model="forgetPasswordState.password"
|
||||
type="password"
|
||||
:disabled="final_loading"
|
||||
/>
|
||||
</UFormField>
|
||||
|
||||
<div>
|
||||
<UButton
|
||||
type="submit"
|
||||
:loading="final_loading"
|
||||
>
|
||||
重置密码
|
||||
</UButton>
|
||||
</div>
|
||||
</UForm>
|
||||
</div>
|
||||
|
||||
<template
|
||||
#footer
|
||||
v-if="item.key === 'account'"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<UButton
|
||||
type="submit"
|
||||
color="primary"
|
||||
:loading="final_loading"
|
||||
>
|
||||
重置密码
|
||||
登录
|
||||
</UButton>
|
||||
<UButton
|
||||
variant="link"
|
||||
color="neutral"
|
||||
@click="currentTab = 2"
|
||||
>
|
||||
忘记密码
|
||||
</UButton>
|
||||
</div>
|
||||
</UForm>
|
||||
</div>
|
||||
|
||||
<template
|
||||
#footer
|
||||
v-if="item.key === 'account'"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<UButton
|
||||
type="submit"
|
||||
color="black"
|
||||
:loading="final_loading"
|
||||
>
|
||||
登录
|
||||
</UButton>
|
||||
<UButton
|
||||
variant="link"
|
||||
color="gray"
|
||||
@click="currentTab = 2"
|
||||
>
|
||||
忘记密码
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
</UTabs>
|
||||
</UCard>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
</UTabs>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference '@/assets/css/main.css';
|
||||
|
||||
.pin-root-enter-active,
|
||||
.pin-root-leave-active {
|
||||
@apply transition duration-500;
|
||||
@@ -580,15 +588,15 @@ const onForgetPasswordSubmit = (
|
||||
|
||||
.pin-root-enter-from,
|
||||
.pin-root-leave-to {
|
||||
@apply opacity-0 -translate-y-2;
|
||||
@apply -translate-y-2 opacity-0;
|
||||
}
|
||||
|
||||
.pin-input {
|
||||
@apply w-full md:w-16 aspect-square rounded text-center shadow caret-transparent;
|
||||
@apply outline-0 ring-indigo-500 focus:ring-3 font-bold;
|
||||
@apply aspect-square w-full rounded text-center caret-transparent shadow md:w-16;
|
||||
@apply focus:ring-3 font-bold outline-0 ring-indigo-500;
|
||||
}
|
||||
|
||||
.pin-label {
|
||||
@apply block text-sm font-medium text-gray-700 dark:text-gray-200 after:content-['*'] after:ms-0.5 after:text-red-500 dark:after:text-red-400;
|
||||
@apply block text-sm font-medium text-gray-700 after:ms-0.5 after:text-red-500 after:content-['*'] dark:text-gray-200 dark:after:text-red-400;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user