feat: complete admin panel and backend admin api migration
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<!--
|
||||
Ported from legacy henza_admin/src/views/auth/Login.vue.
|
||||
Same two fields, same Farsi copy, same logo, same submit gate. Vuesax's
|
||||
vs-input/vs-button and VeeValidate become ant-design-vue equivalents, and
|
||||
the loading overlay becomes the button's own loading state.
|
||||
-->
|
||||
<div id="page-login">
|
||||
<a-card class="login-card" :bordered="false">
|
||||
<div class="login-grid">
|
||||
<div class="login-form">
|
||||
<div class="vx-card__title">
|
||||
<h4>ورود به محیط مدیریت</h4>
|
||||
<p>لطفا شماره تلفن همراه خود به همراه رمز عبور وارد کنید.</p>
|
||||
</div>
|
||||
|
||||
<a-form layout="vertical" class="mt-8" @submit.prevent="loginJWT">
|
||||
<a-form-item
|
||||
label="موبایل"
|
||||
:validate-status="mobileError ? 'error' : ''"
|
||||
:help="mobileError"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="mobile"
|
||||
autocomplete="off"
|
||||
size="large"
|
||||
@blur="touchedMobile = true"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="رمز عبور"
|
||||
:validate-status="passwordError ? 'error' : ''"
|
||||
:help="passwordError"
|
||||
>
|
||||
<a-input-password
|
||||
v-model:value="password"
|
||||
size="large"
|
||||
@blur="touchedPassword = true"
|
||||
@pressEnter="loginJWT"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!validateForm"
|
||||
:loading="loading"
|
||||
@click="loginJWT"
|
||||
>
|
||||
ورود
|
||||
</a-button>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<div class="login-art">
|
||||
<img src="../../assets/images/logo/henza-icon.svg" alt="login" />
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { useAuthStore } from '../../stores/auth';
|
||||
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
|
||||
const mobile = ref('');
|
||||
const password = ref('');
|
||||
const loading = ref(false);
|
||||
const touchedMobile = ref(false);
|
||||
const touchedPassword = ref(false);
|
||||
|
||||
// legacy VeeValidate rules: mobile 'required|min:8', password 'required|min:5',
|
||||
// both validated on blur.
|
||||
const mobileError = computed(() => {
|
||||
if (!touchedMobile.value) return '';
|
||||
if (!mobile.value) return 'وارد کردن موبایل الزامی است';
|
||||
if (mobile.value.length < 8) return 'مقدار ورودی صحیح نیست';
|
||||
return '';
|
||||
});
|
||||
const passwordError = computed(() => {
|
||||
if (!touchedPassword.value) return '';
|
||||
if (!password.value) return 'وارد کردن رمز عبور الزامی است';
|
||||
if (password.value.length < 5) return 'مقدار ورودی صحیح نیست';
|
||||
return '';
|
||||
});
|
||||
|
||||
// legacy: !errors.any() && mobile !== '' && password !== ''
|
||||
const validateForm = computed(
|
||||
() => !mobileError.value && !passwordError.value && mobile.value !== '' && password.value !== '',
|
||||
);
|
||||
|
||||
async function loginJWT() {
|
||||
if (!validateForm.value || loading.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
// legacy also sent token_mobile from localStorage for Firebase push, which is
|
||||
// inactive in this port; the field is omitted rather than sent as null.
|
||||
await auth.login({ phone: mobile.value, password: password.value });
|
||||
// legacy did a hard `window.location.href = '/admin/my-data'`; a router push
|
||||
// reaches the same route without discarding the freshly-populated store.
|
||||
await router.push('/my-data');
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
message.error('خطا در ورود');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#page-login {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
}
|
||||
.login-card {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
}
|
||||
.login-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
align-items: center;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.login-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
.login-form {
|
||||
background-color: #eff2f7; /* legacy inline style */
|
||||
padding: 2rem;
|
||||
min-height: 505px; /* legacy .login-tabs-container */
|
||||
}
|
||||
.login-art {
|
||||
display: none;
|
||||
text-align: center;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.login-art {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.login-art img {
|
||||
max-width: 70%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.mt-8 {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user