302 lines
7.3 KiB
Vue
302 lines
7.3 KiB
Vue
<template>
|
||
<q-page class="flex flex-center login-bg">
|
||
|
||
<q-card class="q-pa-lg shadow-4 login-card">
|
||
<!-- HEADER -->
|
||
<q-card-section class="text-center">
|
||
<q-avatar size="80px" class="bg-white text-secondary shadow-2">
|
||
<q-icon name="lock" size="40px" />
|
||
</q-avatar>
|
||
<div class="login-title q-mt-sm">Kullanıcı Girişi</div>
|
||
</q-card-section>
|
||
|
||
<q-form @submit.prevent="login">
|
||
<!-- FORM -->
|
||
<q-card-section>
|
||
<q-input
|
||
v-model="username"
|
||
label="Kullanıcı Adı"
|
||
dense
|
||
standout="bg-white"
|
||
class="q-mb-md custom-input"
|
||
autocomplete="username"
|
||
/>
|
||
|
||
<q-input
|
||
v-model="password"
|
||
type="password"
|
||
label="Şifre"
|
||
dense
|
||
standout="bg-white"
|
||
class="custom-input"
|
||
autocomplete="current-password"
|
||
/>
|
||
|
||
<div class="q-mt-md row items-center justify-between">
|
||
<div>
|
||
<q-checkbox
|
||
v-model="rememberUser"
|
||
label="Kullanıcıyı hatırla"
|
||
color="secondary"
|
||
dense
|
||
/>
|
||
<q-checkbox
|
||
v-model="rememberPass"
|
||
label="Parolayı kaydet"
|
||
color="secondary"
|
||
dense
|
||
/>
|
||
</div>
|
||
|
||
<q-btn
|
||
flat
|
||
dense
|
||
color="primary"
|
||
label="Şifremi Unuttum"
|
||
@click="forgotOpen = true"
|
||
/>
|
||
</div>
|
||
</q-card-section>
|
||
|
||
<!-- ACTION -->
|
||
<q-card-actions align="center">
|
||
<q-btn
|
||
type="submit"
|
||
label="Giriş Yap"
|
||
color="primary"
|
||
glossy
|
||
unelevated
|
||
icon="login"
|
||
class="full-width"
|
||
:loading="loading"
|
||
/>
|
||
</q-card-actions>
|
||
</q-form>
|
||
</q-card>
|
||
|
||
<!-- 🔐 FORGOT PASSWORD -->
|
||
<q-dialog v-model="forgotOpen" persistent>
|
||
<q-card style="width:420px; max-width:90vw">
|
||
<q-card-section class="text-h6">
|
||
Parola Sıfırlama
|
||
</q-card-section>
|
||
|
||
<q-card-section>
|
||
<div class="text-caption text-grey-7 q-mb-sm">
|
||
Kullanıcı adınızı girin.
|
||
</div>
|
||
|
||
<q-input
|
||
v-model="forgotUsername"
|
||
label="Kullanıcı Adı"
|
||
dense
|
||
outlined
|
||
:disable="forgotLoading"
|
||
/>
|
||
|
||
<q-banner
|
||
v-if="forgotMessage"
|
||
class="q-mt-md"
|
||
:class="forgotSuccess ? 'bg-green-1 text-green' : 'bg-red-1 text-red'"
|
||
rounded
|
||
>
|
||
{{ forgotMessage }}
|
||
</q-banner>
|
||
</q-card-section>
|
||
|
||
<q-card-actions align="right">
|
||
<q-btn flat label="Vazgeç" v-close-popup />
|
||
<q-btn
|
||
color="primary"
|
||
label="Gönder"
|
||
:loading="forgotLoading"
|
||
@click="sendResetMail"
|
||
/>
|
||
</q-card-actions>
|
||
</q-card>
|
||
</q-dialog>
|
||
|
||
</q-page>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { useAuthStore } from 'stores/authStore'
|
||
import { useQuasar } from 'quasar'
|
||
import api from 'src/services/api'
|
||
|
||
const router = useRouter()
|
||
const auth = useAuthStore()
|
||
const $q = useQuasar()
|
||
|
||
const username = ref('')
|
||
const password = ref('')
|
||
const rememberUser = ref(false)
|
||
const rememberPass = ref(false)
|
||
const loading = ref(false)
|
||
|
||
/* 🔐 Forgot password */
|
||
const forgotOpen = ref(false)
|
||
const forgotUsername = ref('')
|
||
const forgotLoading = ref(false)
|
||
const forgotMessage = ref('')
|
||
const forgotSuccess = ref(false)
|
||
|
||
onMounted(() => {
|
||
if (localStorage.getItem('remember_user') === 'true') {
|
||
username.value = localStorage.getItem('username') || ''
|
||
rememberUser.value = true
|
||
}
|
||
if (localStorage.getItem('remember_pass') === 'true') {
|
||
password.value = localStorage.getItem('password') || ''
|
||
rememberPass.value = true
|
||
}
|
||
})
|
||
|
||
/* =========================================================
|
||
🔐 LOGIN
|
||
========================================================= */
|
||
async function login () {
|
||
loading.value = true
|
||
|
||
try {
|
||
await auth.login(username.value, password.value)
|
||
|
||
// remember checks
|
||
rememberUser.value
|
||
? localStorage.setItem('username', username.value)
|
||
: localStorage.removeItem('username')
|
||
|
||
rememberPass.value
|
||
? localStorage.setItem('password', password.value)
|
||
: localStorage.removeItem('password')
|
||
|
||
localStorage.setItem('remember_user', rememberUser.value ? 'true' : 'false')
|
||
localStorage.setItem('remember_pass', rememberPass.value ? 'true' : 'false')
|
||
|
||
// 🔥 YÖNLENDİRME
|
||
if (auth.mustChangePassword) {
|
||
router.replace('/first-password-change')
|
||
} else {
|
||
router.replace('/app')
|
||
}
|
||
} catch (err) {
|
||
console.error('❌ Login error:', err)
|
||
|
||
$q.notify({
|
||
type: 'negative',
|
||
message: 'Kullanıcı adı veya şifre hatalı',
|
||
position: 'top-right'
|
||
})
|
||
|
||
auth.clearSession()
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
/* =========================================================
|
||
🔐 FORGOT PASSWORD
|
||
========================================================= */
|
||
async function sendResetMail () {
|
||
if (!forgotUsername.value) return
|
||
|
||
forgotLoading.value = true
|
||
forgotMessage.value = ''
|
||
|
||
try {
|
||
await api.post('/password/forgot', {
|
||
email: forgotUsername.value
|
||
})
|
||
|
||
forgotSuccess.value = true
|
||
forgotMessage.value =
|
||
'Eğer hesabınız aktif ise parola sıfırlama bağlantısı e-posta adresinize gönderilmiştir.'
|
||
} catch {
|
||
// 👈 bilgi sızdırmamak için bilinçli olarak aynı mesaj
|
||
forgotSuccess.value = true
|
||
forgotMessage.value =
|
||
'Eğer hesabınız aktif ise parola sıfırlama bağlantısı e-posta adresinize gönderilmiştir.'
|
||
} finally {
|
||
forgotLoading.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
|
||
<style scoped>
|
||
.login-bg {
|
||
position: relative;
|
||
min-height: 100%;
|
||
}
|
||
.login-bg::before {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
background: url("/images/Baggi-Fabrika-resmi.jpg") no-repeat center;
|
||
background-size: cover;
|
||
opacity: 0.3;
|
||
}
|
||
.login-bg > * {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.login-card {
|
||
width: 400px;
|
||
max-width: 90%;
|
||
border-radius: 16px;
|
||
background: var(--q-secondary);
|
||
color: #fff;
|
||
}
|
||
|
||
.login-title {
|
||
font-size: 1.3rem;
|
||
font-weight: 700;
|
||
color: var(--q-primary);
|
||
}
|
||
|
||
.custom-input {
|
||
background: #fdfcfc;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
|
||
.full-width {
|
||
width: 100%;
|
||
}
|
||
/* ===============================
|
||
LOGIN INPUT TEXT COLOR (GOLD)
|
||
=============================== */
|
||
|
||
/* Input içindeki yazı */
|
||
.login-card :deep(.q-field__native),
|
||
.login-card :deep(.q-field__input) {
|
||
color: var(--q-primary) !important; /* gold */
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* Placeholder rengi */
|
||
.login-card :deep(.q-field__native::placeholder) {
|
||
color: rgba(149, 113, 22, 0.6); /* gold soft */
|
||
}
|
||
|
||
/* Label rengi */
|
||
.login-card :deep(.q-field__label) {
|
||
color: var(--q-primary);
|
||
}
|
||
|
||
/* Focus olunca */
|
||
.login-card :deep(.q-field--focused .q-field__native) {
|
||
color: var(--q-primary);
|
||
}
|
||
|
||
/* Autofill (Chrome sarı arkaplanı bastırmak için) */
|
||
.login-card :deep(input:-webkit-autofill) {
|
||
-webkit-text-fill-color: var(--q-primary) !important;
|
||
transition: background-color 9999s ease-in-out 0s;
|
||
}
|
||
|
||
</style>
|