This commit is contained in:
2026-02-11 17:46:22 +03:00
commit eacfacb13b
266 changed files with 51337 additions and 0 deletions

306
ui/src/pages/MainPage.vue Normal file
View File

@@ -0,0 +1,306 @@
<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>
<!-- 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
label="Giriş Yap"
color="primary"
glossy
unelevated
icon="login"
class="full-width"
:loading="loading"
@click="login"
/>
</q-card-actions>
</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'
import { usePermission } from 'src/composables/usePermission'
const { canRead, canWrite, canUpdate } = usePermission()
const canReadOrder = canRead('order')
const canWriteOrder = canWrite('order')
const canUpdateOrder = canUpdate('order')
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>