Change update UI Signin
This commit is contained in:
@@ -1,7 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<a @click="$router.push('/signin')">
|
||||
<div class="logo">
|
||||
<a class="link" @click="$router.push('/signin')">
|
||||
<img width="90px" src="/logo.png" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.logo,
|
||||
.logo .link {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.logo .link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
308
pages/signin.vue
308
pages/signin.vue
@@ -1,79 +1,94 @@
|
||||
<template>
|
||||
<div class="columns is-centered px-0 mx-0">
|
||||
<div
|
||||
:class="`column is-flex is-justify-content-center is-align-items-center wrapper-login is-${
|
||||
:class="`column wrapper-login is-${
|
||||
viewport >= 4 ? 4 : 6
|
||||
}`"
|
||||
>
|
||||
<div class="has-background-white px-6 py-6 login-box">
|
||||
<Logo />
|
||||
<Caption
|
||||
:class="`mt-5 pt-${viewport === 1 ? 0 : 3}`"
|
||||
v-bind="{ title: `${isVietnamese ? 'Đăng nhập' : 'Login'}`, size: 19 }"
|
||||
></Caption>
|
||||
<div class="field mt-5">
|
||||
<label class="label"
|
||||
>{{ isVietnamese ? 'Tên đăng nhập' : 'User name' }}<b class="ml-1 has-text-danger">*</b></label
|
||||
>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="isVietnamese ? 'Nhập tên đăng nhập' : 'Enter username'"
|
||||
v-model="username"
|
||||
@keyup.enter="signin()"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
class="help is-danger"
|
||||
v-if="errors.find((v) => v.name === 'username')"
|
||||
v-html="errors.find((v) => v.name === 'username').text"
|
||||
></p>
|
||||
</div>
|
||||
<div class="field mt-5">
|
||||
<label class="label">{{ isVietnamese ? 'Mật khẩu' : 'Password' }}<b class="ml-1 has-text-danger">*</b></label>
|
||||
<div class="field-body">
|
||||
<div class="field has-addons">
|
||||
<p class="control is-expanded">
|
||||
<input
|
||||
class="input"
|
||||
:type="showpass ? 'text' : 'password'"
|
||||
:placeholder="isVietnamese ? 'Nhập mật khẩu' : 'Enter password'"
|
||||
v-model="password"
|
||||
@keyup.enter="signin()"
|
||||
/>
|
||||
</p>
|
||||
<div class="control">
|
||||
<a
|
||||
class="button"
|
||||
@click="showpass = !showpass"
|
||||
:title="
|
||||
showpass ? (isVietnamese ? 'Đăng nhập' : 'Login') : isVietnamese ? 'Hiện mật khẩu' : 'Show Password'
|
||||
"
|
||||
>
|
||||
<span class="icon">
|
||||
<SvgIcon v-bind="{ name: showpass ? 'eye-off.svg' : 'view.svg', type: 'gray' }" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help is-danger" v-if="errors.find((v) => v.name === 'password')">
|
||||
{{ errors.find((v) => v.name === 'password').text }}
|
||||
<div class="has-background-white px-6 py-6 login-box ">
|
||||
<div class="login-header">
|
||||
<Logo />
|
||||
<h2 class="title mt-4">{{ isVietnamese ? 'Đăng nhập hệ thống' : 'Login' }}</h2>
|
||||
<p class="subtitle is-6 has-text-centered" v-if="getEnv">
|
||||
{{ getEnv }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="field is-grouped mt-5 is-align-items-center">
|
||||
<div class="control is-expanded">
|
||||
<button class="button is-primary" @click="signin()" @keyup.enter="signin()">
|
||||
{{ isVietnamese ? 'Đăng nhập' : 'Login' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="is-primary" @click="accountRecovery()"
|
||||
>{{ isVietnamese ? 'Đặt lại mật khẩu' : 'Forgot Password' }}?</a
|
||||
<div class="login-body mt-3">
|
||||
<div class="field mt-5">
|
||||
<label class="label"
|
||||
>{{ isVietnamese ? 'Tên đăng nhập' : 'User name' }}<b class="ml-1 has-text-danger">*</b></label
|
||||
>
|
||||
<div class="control">
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="isVietnamese ? 'Nhập tên đăng nhập' : 'Enter username'"
|
||||
v-model="username"
|
||||
@keyup.enter="signin()"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
class="help is-danger"
|
||||
v-if="errors.find((v) => v.name === 'username')"
|
||||
v-html="errors.find((v) => v.name === 'username').text"
|
||||
></p>
|
||||
</div>
|
||||
<div class="field mt-5">
|
||||
<label class="label"
|
||||
>{{ isVietnamese ? 'Mật khẩu' : 'Password' }}<b class="ml-1 has-text-danger">*</b></label
|
||||
>
|
||||
<div class="field-body">
|
||||
<div class="field has-addons">
|
||||
<p class="control is-expanded">
|
||||
<input
|
||||
class="input"
|
||||
:type="showpass ? 'text' : 'password'"
|
||||
:placeholder="isVietnamese ? 'Nhập mật khẩu' : 'Enter password'"
|
||||
v-model="password"
|
||||
@keyup.enter="signin()"
|
||||
/>
|
||||
</p>
|
||||
<div class="control">
|
||||
<a
|
||||
class="button view-pass-btn"
|
||||
@click="showpass = !showpass"
|
||||
:title="
|
||||
showpass
|
||||
? isVietnamese
|
||||
? 'Đăng nhập'
|
||||
: 'Login'
|
||||
: isVietnamese
|
||||
? 'Hiện mật khẩu'
|
||||
: 'Show Password'
|
||||
"
|
||||
>
|
||||
<span class="icon">
|
||||
<SvgIcon v-bind="{ name: showpass ? 'eye-off.svg' : 'view.svg', type: 'gray' }" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help is-danger" v-if="errors.find((v) => v.name === 'password')">
|
||||
{{ errors.find((v) => v.name === 'password').text }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="field is-grouped mt-5 is-align-items-center is-justify-content-space-between">
|
||||
<div class="control ">
|
||||
<button class="button btn-primary" @click="signin()" @keyup.enter="signin()">
|
||||
{{ isVietnamese ? 'Đăng nhập' : 'Login' }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="control reset-wrapper">
|
||||
<a class="reset-link" @click="accountRecovery()"
|
||||
>{{ isVietnamese ? 'Đặt lại mật khẩu' : 'Forgot Password' }}?</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="login-footer">
|
||||
<span>© 2026 {{ isVietnamese ? 'Bản quyền thuộc về Utopia' : 'Copyright by Utopia Technology JSC' }}</span>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -166,6 +181,42 @@ export default {
|
||||
isVietnamese() {
|
||||
return navigator.language.toLowerCase().startsWith('vi');
|
||||
},
|
||||
getEnv() {
|
||||
const link = (this.$route.query.link || '').replace(/^https?:\/\//, '').toLowerCase();
|
||||
const module = (this.$route.query.module || '').replace(/^https?:\/\//, '').toLowerCase();
|
||||
const isDev = link.includes('dev');
|
||||
|
||||
const ENV_MAP = [
|
||||
{
|
||||
key: 'system',
|
||||
module: 'system',
|
||||
vi: 'Cổng quản trị hệ thống',
|
||||
en: 'Admin Portal',
|
||||
},
|
||||
{
|
||||
key: 'biz',
|
||||
module: 'application',
|
||||
vi: 'Cổng thông tin Chủ đầu tư',
|
||||
en: 'Business Portal',
|
||||
},
|
||||
{
|
||||
key: 'dealer',
|
||||
module: 'dealer',
|
||||
vi: 'Cổng thông tin Đại lý',
|
||||
en: 'Dealer Portal',
|
||||
},
|
||||
];
|
||||
|
||||
const found = ENV_MAP.find((item) => link.includes(item.key) && module === item.module);
|
||||
if (found) {
|
||||
const title = this.isVietnamese ? found.vi : found.en;
|
||||
return isDev
|
||||
? `${title} - ${this.isVietnamese ? 'Môi trường phát triển (DEV)' : 'Development Environment (DEV)'}`
|
||||
: title;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
checkError() {
|
||||
@@ -176,13 +227,13 @@ export default {
|
||||
if (this.$empty(this.username)) {
|
||||
this.errors.push({
|
||||
name: 'username',
|
||||
text: this.isVietnamese ? 'Tên đăng nhập không được bỏ trống.' : 'Username is required.',
|
||||
text: this.isVietnamese ? 'Vui lòng nhập tên đăng nhập.' : 'Please enter your username.',
|
||||
});
|
||||
}
|
||||
if (this.$empty(this.password)) {
|
||||
this.errors.push({
|
||||
name: 'password',
|
||||
text: this.isVietnamese ? 'Mật khẩu không được bỏ trống.' : 'Password is required.',
|
||||
text: this.isVietnamese ? 'Vui lòng nhập mật khẩu.' : 'Please enter your password.',
|
||||
});
|
||||
} else if (this.password.length < 6) {
|
||||
this.errors.push({
|
||||
@@ -224,7 +275,7 @@ export default {
|
||||
},
|
||||
invalidLogin(data) {
|
||||
if (!data) {
|
||||
const text = this.isVietnamese ? 'Tài khoản hoặc mật khẩu không chính xác' : 'Invalid username or password.';
|
||||
const text = this.isVietnamese ? 'Tên đăng nhập hoặc mật khẩu không đúng.' : 'Incorrect username or password.';
|
||||
this.errors.push({ name: 'username', text: text });
|
||||
this.errors.push({ name: 'password', text: text });
|
||||
} else if (data.blocked) {
|
||||
@@ -266,7 +317,7 @@ export default {
|
||||
await this.$insertapi('authtoken', obj);
|
||||
let link = this.$store.state.link;
|
||||
if (data.type === 3 && link.indexOf('y99') >= 0) {
|
||||
link = link.indexOf('dev') >= 0 ? 'https://dev.ctv.y99.vn' : 'https://ctv.y99.vn';
|
||||
link = link.indexOf('dev') >= 0 ? '' : '';
|
||||
}
|
||||
let href = `${link}?username=${ele.username}&token=${ele.token}&fullname=${ele.fullname}&userid=${ele.id}`;
|
||||
if (ele.avatar) href = `${href}&avatar=${ele.avatar}`;
|
||||
@@ -299,12 +350,129 @@ export default {
|
||||
</script>
|
||||
<style>
|
||||
.wrapper-login {
|
||||
min-height: 100vh;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wrapper-login .login-box {
|
||||
margin-top: 20%;
|
||||
width: 100%;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.wrapper-login .login-box .login-header .title {
|
||||
text-align: center;
|
||||
color: #c66a1c;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
line-height: 36px;
|
||||
letter-spacing: -0.2px;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 15px;
|
||||
color: #3F6E73;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.wrapper-login .login-box .login-footer {
|
||||
margin-top: 24px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.wrapper-login .login-box .login-footer span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.wrapper-login .btn-primary {
|
||||
width: 100%;
|
||||
height: 46px;
|
||||
|
||||
background-color: #1F3A3D; /* primary from logo */
|
||||
color: #FFFFFF;
|
||||
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.wrapper-login .btn-primary:hover {
|
||||
background-color: #2C5054;
|
||||
}
|
||||
|
||||
.wrapper-login .btn-primary:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.wrapper-login .btn-primary:disabled {
|
||||
background-color: #9CA3AF;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.wrapper-login .reset-wrapper {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.wrapper-login .reset-link {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #3F6E73;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.wrapper-login .reset-link:hover {
|
||||
color: #1F3A3D;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* INPUT BASE */
|
||||
.wrapper-login input {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
padding: 10px 14px;
|
||||
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* PLACEHOLDER */
|
||||
.wrapper-login input::placeholder {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
/* FOCUS STATE */
|
||||
.wrapper-login input:focus {
|
||||
border-color: #1F3A3D;
|
||||
box-shadow: 0 0 0 3px rgba(31, 58, 61, 0.12);
|
||||
}
|
||||
|
||||
/* HOVER nhẹ */
|
||||
.wrapper-login input:hover {
|
||||
border-color: #cbd5e1;
|
||||
}
|
||||
.wrapper-login .view-pass-btn {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user