add(login):完善登录逻辑

This commit is contained in:
2025-12-14 21:40:34 +08:00
parent 6ca7a8275c
commit 82652efed7
14 changed files with 647 additions and 134 deletions
+6 -1
View File
@@ -2,7 +2,7 @@
<div id="Test">
<MyInput icon-name="user"></MyInput>
<MyButton >登录...</MyButton>
<MyButton @click="handler">登录...</MyButton>
</div>
</template>
@@ -10,7 +10,12 @@
<script setup>
import MyInput from '@/components/IconInput.vue';
import MyButton from '@/components/MyButton.vue';
import { useMessage } from '@/components/messages/useAlert';
const message = useMessage();
const handler = () => {
message.success('成功')
}
</script>
+47 -120
View File
@@ -8,7 +8,7 @@
<p class="hero-subtitle">下一代企业级即时通讯平台让沟通无距离</p>
</div>
<div class="visual-footer">
<span>© 2024 IM System</span>
<span>© 2025 IM System</span>
<div class="dots">
<span></span><span></span><span></span>
</div>
@@ -23,35 +23,14 @@
</div>
<form @submit.prevent="handleLogin">
<div class="input-group">
<label>用户名 / 邮箱</label>
<div class="field-wrap">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
<input type="text" v-model="form.username" placeholder="name@company.com" />
</div>
</div>
<IconInput class="input" placeholder="请输入用户名" lab="用户名 / 邮箱" type="text" icon-name="user" v-model="form.username"/>
<div class="input-group">
<div class="label-row">
<label>密码</label>
<a href="#" class="forgot-link">忘记密码?</a>
</div>
<div class="field-wrap">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
<input type="password" v-model="form.password" placeholder="••••••••" />
</div>
</div>
<IconInput class="input" placeholder="请输入密码" lab="密码" type="password" icon-name="user" v-model="form.password"/>
<button class="submit-btn" :disabled="loading">
{{ loading ? '登录中...' : '登 录' }}
<svg v-if="!loading" viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="arrow"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
</button>
<MyButton class="loginBtn" :loading="loading">
登录
<template #icon><i data-feather="arrow-right"></i></template>
</MyButton>
</form>
<div class="register-hint">
@@ -64,7 +43,14 @@
</template>
<script setup>
import { reactive, ref } from 'vue'
import { reactive, ref, onMounted } from 'vue'
import { useMessage } from '@/components/messages/useAlert'
import { authService } from '@/services/auth'
import { useRouter } from 'vue-router'
import feather from 'feather-icons'
const message = useMessage()
const router = useRouter()
const loading = ref(false)
const form = reactive({
@@ -72,13 +58,37 @@ const form = reactive({
password: ''
})
const handleLogin = () => {
loading.value = true
setTimeout(() => loading.value = false, 1500)
const handleLogin = async () => {
try{
loading.value = true;
const res = await authService.login(form);
if(res.code === 0){
message.success('登陆成功。')
loading.value = false;
router.push('/index')
}else{
message.error(res.message)
loading.value = false;
}
}finally{
loading.value = false;
}
}
onMounted(() => {
feather.replace()
})
</script>
<style scoped>
:deep(.loginBtn) {
width: 100%;
}
:deep(.input){
width: 100%;
}
/* 撑满 Window 组件的内容区 */
.login-layout {
display: flex;
@@ -127,6 +137,7 @@ const handleLogin = () => {
max-width: 300px;
}
.visual-footer {
position: absolute;
bottom: 30px;
@@ -175,94 +186,6 @@ const handleLogin = () => {
font-size: 14px;
}
.input-group {
margin-bottom: 20px;
}
.label-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
}
label {
display: block;
font-size: 13px;
font-weight: 600;
color: #475569;
margin-bottom: 6px;
}
.forgot-link {
font-size: 12px;
color: #4f46e5;
text-decoration: none;
}
/* 输入框样式:现代填充风格 */
.field-wrap {
position: relative;
display: flex;
align-items: center;
}
.field-wrap .icon {
position: absolute;
left: 12px;
width: 18px;
height: 18px;
color: #94a3b8;
transition: color 0.2s;
}
.field-wrap input {
width: 100%;
padding: 12px 12px 12px 40px;
background: #f1f5f9; /* 浅灰底色 */
border: 2px solid transparent;
border-radius: 8px;
font-size: 14px;
color: #1e293b;
outline: none;
transition: all 0.2s ease;
}
/* 聚焦交互 */
.field-wrap input:focus {
background: #fff;
border-color: #4f46e5; /* 品牌色 */
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.1);
}
.field-wrap input:focus + .icon,
.field-wrap input:focus ~ .icon {
color: #4f46e5;
}
/* 按钮 */
.submit-btn {
width: 100%;
margin-top: 10px;
padding: 12px;
background: #4f46e5;
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
font-size: 15px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: background 0.2s, transform 0.1s;
}
.submit-btn:hover {
background: #4338ca;
}
.submit-btn:active {
transform: scale(0.98);
}
.submit-btn:disabled {
opacity: 0.7;
cursor: wait;
}
.register-hint {
margin-top: 24px;
text-align: center;
@@ -289,4 +212,8 @@ label {
.visual-footer { display: none; }
.side-form { flex: 1; padding: 24px; }
}
.feather-arrow-right{
width: 18px;
}
</style>