|
@@ -9,9 +9,9 @@
|
|
|
手机号登录
|
|
手机号登录
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <el-form class="login-form">
|
|
|
|
|
|
|
+ <el-form ref="formRef" :model="accountForm" :rules="rules" class="login-form">
|
|
|
<template v-if="activeTab === 'account'">
|
|
<template v-if="activeTab === 'account'">
|
|
|
- <el-form-item>
|
|
|
|
|
|
|
+ <el-form-item prop="username">
|
|
|
<el-input v-model="accountForm.username" placeholder="请输入手机号或账号" size="large">
|
|
<el-input v-model="accountForm.username" placeholder="请输入手机号或账号" size="large">
|
|
|
<template #prefix>
|
|
<template #prefix>
|
|
|
<div class="input-prefix">
|
|
<div class="input-prefix">
|
|
@@ -23,7 +23,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
</el-input>
|
|
</el-input>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
- <el-form-item>
|
|
|
|
|
|
|
+ <el-form-item prop="password">
|
|
|
<el-input v-model="accountForm.password" type="password" placeholder="请输入密码" size="large" show-password>
|
|
<el-input v-model="accountForm.password" type="password" placeholder="请输入密码" size="large" show-password>
|
|
|
<template #prefix>
|
|
<template #prefix>
|
|
|
<div class="input-prefix">
|
|
<div class="input-prefix">
|
|
@@ -35,42 +35,133 @@
|
|
|
</template>
|
|
</template>
|
|
|
</el-input>
|
|
</el-input>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
- <div class="form-end">
|
|
|
|
|
- <el-button size="large" style="width:100%" type="primary" class="is-gradient">发送验证码</el-button>
|
|
|
|
|
- <div>
|
|
|
|
|
- 还没有账号?<span>去注册</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
</template>
|
|
</template>
|
|
|
<template v-else>
|
|
<template v-else>
|
|
|
<el-form-item>
|
|
<el-form-item>
|
|
|
- <el-input v-model="phoneForm.phone" placeholder="请输入手机号" :prefix-icon="Iphone" size="large" />
|
|
|
|
|
|
|
+ <el-input v-model="phoneForm.phone" placeholder="请输入手机号" size="large">
|
|
|
|
|
+ <template #prefix>
|
|
|
|
|
+ <div class="input-prefix">
|
|
|
|
|
+ <el-icon :size="16">
|
|
|
|
|
+ <Iphone />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ <span>手机号</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-input>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
<el-form-item>
|
|
|
- <el-input v-model="phoneForm.code" placeholder="请输入验证码" :prefix-icon="CircleCheck" size="large">
|
|
|
|
|
- </el-input>
|
|
|
|
|
|
|
+ <div class="login-code">
|
|
|
|
|
+ <el-input style="width: 60%;" v-model="phoneForm.code" placeholder="请输入验证码" size="large">
|
|
|
|
|
+ <template #prefix>
|
|
|
|
|
+ <div class="input-prefix">
|
|
|
|
|
+ <SvgIcon iconClass="protect" />
|
|
|
|
|
+ <span>验证码</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-input>
|
|
|
|
|
+ <el-button size="large" style="width: 30%; min-width: 100px;" type="primary" class="is-gradient"
|
|
|
|
|
+ :disabled="isCountingDown" @click="handleGetCode">
|
|
|
|
|
+ {{ isCountingDown ? `${countdown}s` : '获取验证码' }}
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
+ <div class="form-end">
|
|
|
|
|
+ <el-button size="large" style="width:100%" type="primary" class="is-gradient" :loading="loading" @click="handleLogin">立即登录</el-button>
|
|
|
|
|
+ <div class="form-links">
|
|
|
|
|
+ <div class="left-links">
|
|
|
|
|
+ <span class="link-text">还没有账号?</span>
|
|
|
|
|
+ <span class="link-btn" @click="handleRegister">立即注册</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="link-btn" @click="handleForgot">忘记密码?</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
+
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { User, Lock, Iphone, CircleCheck } from '@element-plus/icons-vue'
|
|
|
|
|
|
|
+import { User, Lock, Iphone } from '@element-plus/icons-vue'
|
|
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
|
|
+import type { FormInstance, FormRules } from 'element-plus'
|
|
|
|
|
+import { useUserStore } from '@/store/modules/user'
|
|
|
|
|
|
|
|
|
|
+const emit = defineEmits<{
|
|
|
|
|
+ (e: 'switch', component: 'register' | 'forgot'): void
|
|
|
|
|
+}>()
|
|
|
type TabType = 'account' | 'phone'
|
|
type TabType = 'account' | 'phone'
|
|
|
const activeTab = ref<TabType>('account')
|
|
const activeTab = ref<TabType>('account')
|
|
|
|
|
+const isCountingDown = ref(false)
|
|
|
|
|
+const countdown = ref(60)
|
|
|
|
|
+let countdownTimer: ReturnType<typeof setInterval> | null = null
|
|
|
|
|
+const formRef = ref<FormInstance>()
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
+const router = useRouter()
|
|
|
|
|
+const route = useRoute()
|
|
|
|
|
+const userStore = useUserStore()
|
|
|
|
|
|
|
|
const accountForm = reactive({
|
|
const accountForm = reactive({
|
|
|
- username: '',
|
|
|
|
|
- password: '',
|
|
|
|
|
- code: ''
|
|
|
|
|
|
|
+ username: 'admin',
|
|
|
|
|
+ password: '123456'
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const phoneForm = reactive({
|
|
const phoneForm = reactive({
|
|
|
phone: '',
|
|
phone: '',
|
|
|
code: ''
|
|
code: ''
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+const rules: FormRules = {
|
|
|
|
|
+ username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
|
|
|
+ password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function handleLogin() {
|
|
|
|
|
+ const valid = await formRef.value?.validate().catch(() => false)
|
|
|
|
|
+ if (!valid) return
|
|
|
|
|
+
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ await userStore.login(accountForm.username, accountForm.password)
|
|
|
|
|
+ const redirect = (route.query.redirect as string) || '/'
|
|
|
|
|
+ await router.replace(redirect)
|
|
|
|
|
+ ElMessage.success('登录成功')
|
|
|
|
|
+ } catch (error: unknown) {
|
|
|
|
|
+ ElMessage.error(error instanceof Error ? error.message : '登录失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+function handleGetCode() {
|
|
|
|
|
+ if (!phoneForm.phone) {
|
|
|
|
|
+ ElMessage.warning('请输入手机号')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isCountingDown.value) return
|
|
|
|
|
+
|
|
|
|
|
+ isCountingDown.value = true
|
|
|
|
|
+ countdown.value = 60
|
|
|
|
|
+
|
|
|
|
|
+ countdownTimer = setInterval(() => {
|
|
|
|
|
+ countdown.value--
|
|
|
|
|
+ if (countdown.value <= 0) {
|
|
|
|
|
+ clearInterval(countdownTimer!)
|
|
|
|
|
+ isCountingDown.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 1000)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function handleRegister() {
|
|
|
|
|
+ emit('switch', 'register')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function handleForgot() {
|
|
|
|
|
+ emit('switch', 'forgot')
|
|
|
|
|
+}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
+
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
.login-page {
|
|
.login-page {
|
|
|
margin-top: 242px;
|
|
margin-top: 242px;
|
|
@@ -128,7 +219,6 @@ const phoneForm = reactive({
|
|
|
color: #999;
|
|
color: #999;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /* 密码可见性切换按钮设置为白色 */
|
|
|
|
|
:deep(.el-input__password) {
|
|
:deep(.el-input__password) {
|
|
|
color: #fff;
|
|
color: #fff;
|
|
|
}
|
|
}
|
|
@@ -164,4 +254,36 @@ const phoneForm = reactive({
|
|
|
.form-end {
|
|
.form-end {
|
|
|
margin-top: 30px;
|
|
margin-top: 30px;
|
|
|
}
|
|
}
|
|
|
-</style>
|
|
|
|
|
|
|
+
|
|
|
|
|
+.form-links {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-top: 20px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+
|
|
|
|
|
+ .left-links {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .link-text {
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .link-btn {
|
|
|
|
|
+ color: #8077FF;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #9f95ff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.login-code {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|