18300102974
2 years ago
1 changed files with 495 additions and 0 deletions
@ -0,0 +1,495 @@ |
|||
<template> |
|||
<div :class="['tw-h-full tw-p-[30px] tw-bg-white md:tw-bg-primary-pale']"> |
|||
<div |
|||
class="xl:tw-grid xl:tw-grid-cols-[auto_414px] xl:tw-gap-[96px] xl:tw-max-w-[1246px] xl:tw-mx-auto xl:tw-px-[60px]"> |
|||
<div class="tw-hidden xl:tw-block xl:tw-mt-[30px]"> |
|||
<p class="welcome tw-text-primary-light">{{ $t("Welcome to ShowEasy") }}</p> |
|||
<p class="sub tw-text-neutral-400"> |
|||
{{ |
|||
$t( |
|||
"Your best guide from trip to show and from show to the world." |
|||
) |
|||
}} |
|||
</p> |
|||
<img class="mt-11 ml-15" :src="require('@/assets/img/UserLoginMain.png')" /> |
|||
</div> |
|||
<div class="md:tw-w-[414px] md:tw-mx-auto"> |
|||
<div class="tw-bg-white tw-mt-[30px] md:tw-rounded-[24px] md:tw-pt-[60px] md:tw-pb-[150px] md:tw-px-[30px]"> |
|||
<h1 class="tw-text-[40px] tw-font-bold tw-mb-[20px] md:tw-text-[24px]">{{ $t('Login') }}</h1> |
|||
<p class="tw-body-3 tw-text-neutral-400 tw-mb-[16px] md:tw-mb-[12px]"> |
|||
{{ $t('Welcome back! Please enter your details') }} |
|||
</p> |
|||
<p class="tw-body-3 tw-mb-[24px] md:tw-mb-[32px]">{{ $t('Not a member?') }} <nuxt-link |
|||
:to="localePath('/user/signup')" class="primary--text text-decoration-none">{{ $t('Sign up') }}</nuxt-link> |
|||
</p> |
|||
<!-- <div class="tw-grid tw-grid-cols-1 tw-gap-[10px] tw-mb-[30px] md:tw-gap-[12px] md:tw-mb-[12px]"> |
|||
<button @click="googleLogin" |
|||
class="tw-block tw-w-full tw-py-[8px] tw-rounded-[16px] tw-border tw-border-solid tw-text-black tw-border-neutrals-200"><img |
|||
width="20px" height="20px" src="~/assets/img/g-normal.png" class="mr-5" />{{ $t('Login with Google') |
|||
}}</button> |
|||
<button @click="facebookLogin" |
|||
class="tw-block tw-w-full tw-py-[8px] tw-rounded-[16px] tw-border tw-border-solid tw-text-black tw-border-neutrals-200"><img |
|||
width="20px" height="20px" src="~/assets/img/f_logo_RGB-Blue_72.png" class="mr-5" /> |
|||
{{ $t("Login with Facebook") |
|||
}}</button> |
|||
</div> |
|||
<div class="tw-grid tw-grid-cols-[auto_16px_auto] tw-gap-[28px] tw-mb-[6px]"> |
|||
<div class="tw-flex tw-justify-center tw-items-center"> |
|||
<div class="tw-w-full tw-h-[1px] tw-bg-neutral-200"></div> |
|||
</div> |
|||
<div class="tw-text-neutral-400 tw-body-3 tw-font-normal">{{ $t("or") }}</div> |
|||
<div class="tw-flex tw-justify-center tw-items-center"> |
|||
<div class="tw-w-full tw-h-[1px] tw-bg-neutral-200"></div> |
|||
</div> |
|||
</div> --> |
|||
<div v-if="serviceExceptionActive" class="warning--text text-size-14 ps-1 mb-3"> |
|||
{{ $t('Service exception') }} |
|||
</div> |
|||
<div v-if="wrongMessageActive" class="warning--text text-size-14 ps-1 mb-3"> |
|||
{{ $t('The username or password entered is incorrect') }} |
|||
</div> |
|||
<v-form ref="loginFormRef" lazy-validation> |
|||
<!-- <div v-if="$auth.$storage.getUniversal('userAccount') && $auth.$storage.getUniversal('userPassword')"></div> |
|||
<div v-else></div> --> |
|||
<v-text-field |
|||
v-model="userData.Account" background-color="neutrals darken-1" :label="this.$t('Email')" |
|||
:placeholder="this.$t('Email')" height="40px" filled rounded dense single-line persistent-placeholder |
|||
:rules="[rules.email,rules.require]" v-on:input="updateValid" |
|||
/> |
|||
<v-text-field |
|||
v-model="userData.Password" background-color="neutrals darken-1" :label="this.$t('Password')" |
|||
:type=" showPass ? 'text' : 'password'" :placeholder="this.$t('Password')" filled rounded dense single-line |
|||
persistent-placeholder :append-icon=" showPass ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showPass = !showPass" |
|||
:rules="[rules.checkPassword,rules.require]" v-on:input="updateValid" @keyup.enter="userLogin" |
|||
/> |
|||
</v-form> |
|||
<div class="tw-flex tw-justify-between tw-items-center tw-mb-[28px] md:tw-mb-[32px]"> |
|||
<div class="tw-flex tw-items-center"> |
|||
<div class="tw-flex tw-items-center"> |
|||
<div class="tw-flex tw-flex-col"> |
|||
<label class="tw-body-4 container-checkbox" for="remember"> |
|||
{{ $t('Remember me') |
|||
}} |
|||
<input id="remember" type="checkbox" value="remember" v-model="remember" /> |
|||
<span class="checkmark"></span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="tw-flex tw-items-center"> |
|||
<nuxt-link class="complementary--text text-decoration-none text-size-14" :to="localePath('/user/forgot')">{{ |
|||
$t('Forgot Password?') }}</nuxt-link> |
|||
</div> |
|||
</div> |
|||
<div class="md:tw-flex md:tw-justify-center md:tw-items-center"> <button @click="userLogin" :disabled="!valid" |
|||
:class="['tw-block tw-w-full tw-py-[10px] tw-rounded-[16px] tw-border tw-border-solid tw-body-3 tw-font-normal tw-transition-all tw-duration-200 tw-ease-in-out',valid?'tw-text-white tw-bg-primary-default tw-border-primary-default':'tw-text-base-disable tw-bg-neutral-100 tw-border-neutral-100']">{{ |
|||
$t("Login") |
|||
}}</button></div> |
|||
<v-dialog v-model="dialog" :width="$vuetify.breakpoint.smAndUp ? 423 : 294" |
|||
@click:outside="colseDialog()"> |
|||
<v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290"> |
|||
<v-spacer class="d-flex align-center tw-justify-between tw-mb-[30px]"> |
|||
<div class="tw-text-[20px] tw-font-bold tw-text-black"> |
|||
{{ $t("Verify your email") }} |
|||
</div> |
|||
<v-btn @click="colseDialog()" icon> |
|||
<v-icon> mdi-close </v-icon> |
|||
</v-btn> |
|||
</v-spacer> |
|||
<v-spacer class="tw-mb-[40px]"> |
|||
<div class="tw-text-[16px] tw-text-neutrals-800"> |
|||
{{ $t("Oops! Seems like you haven't verified your email,please click the button below to resend a verification email.")}} |
|||
</div> |
|||
</v-spacer> |
|||
<button @click="resendVerifyEmail()" :class="['tw-text-white tw-bg-primary-1 hover:tw-bg-primary-light tw-text-[18px] tw-rounded-[16px] tw-px-[77px] tw-py-[13px]']"> |
|||
{{ $t("Resend verification email") }} |
|||
</button> |
|||
<!-- <v-btn @click="resendVerifyEmail" class="tw-bg-primary-1 hover:tw-bg-primary-light tw-text-white tw-text-[18px] tw-rounded-[16px] tw-px-[77px] tw-py-[13px]" |
|||
:disabled="countdown > 0"> |
|||
{{ $t("Resend verification email") }} |
|||
<span v-if="countdown > 0"> |
|||
{{ `(${this.countdown})` }} |
|||
</span> |
|||
</v-btn> --> |
|||
</v-card> |
|||
</v-dialog> |
|||
<v-dialog v-model="deleteDialog" :width="$vuetify.breakpoint.smAndUp ? 423 : 294" |
|||
@click:outside="colseDialog()"> |
|||
<v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290"> |
|||
<v-spacer class="d-flex tw-justify-between align-center tw-mb-[30px]"> |
|||
<div class="tw-text-[20px] tw-text-black tw-font-bold"> |
|||
{{ $t("Reactivate your account") }} |
|||
</div> |
|||
<v-btn @click="colseDialog()" icon> |
|||
<v-icon> mdi-close </v-icon> |
|||
</v-btn> |
|||
</v-spacer> |
|||
<v-spacer class="tw-mb-[40px]"> |
|||
<div class="tw-text-[16px] tw-text-neutrals-800 tw-font-bold"> |
|||
{{ $t("Welcome back!")}} |
|||
</div> |
|||
<div class="tw-text-[16px] tw-text-neutrals-800"> |
|||
{{ $t("Looks like your account has been deactivated.")}} |
|||
<br /> |
|||
{{ $t("Would you like to reactivate this account?")}} |
|||
</div> |
|||
</v-spacer> |
|||
<button @click="ReactivateAccount()" class="tw-bg-primary-1 tw-text-white hover:tw-bg-primary-light tw-text-[18px] tw-rounded-[16px] tw-px-[86px] tw-py-[13px]"> |
|||
{{ $t("Reactivate my account") }} |
|||
</button> |
|||
<!-- <v-btn class="primary tw-w-auto" rounded |
|||
:disabled="countdown > 0"> |
|||
<span v-if="countdown > 0"> |
|||
{{ `(${this.countdown})` }} |
|||
</span> |
|||
</v-btn> --> |
|||
</v-card> |
|||
</v-dialog> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getCurrentTime } from "~/utils/assist"; |
|||
export default { |
|||
name: "login", |
|||
layout: "login", |
|||
auth: false, |
|||
data() { |
|||
return { |
|||
timer: null, |
|||
showPass: false, |
|||
resendDialog: false, |
|||
wrongMessageActive: false, |
|||
verifyEmailSent: false, |
|||
serviceExceptionActive: false, |
|||
valid: false, |
|||
remember: false, |
|||
countdown: 60, |
|||
userData: { |
|||
Account: '', |
|||
Password: '', |
|||
}, |
|||
rules: { |
|||
require: value => !!value || this.$t('Required.'), |
|||
email: v => /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(v) || this.$t('Invalid email'), |
|||
// checkPassword: v => (/(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])/.test(v) && v.length >= 8 && v.length <= 20) || '請輸入密碼', |
|||
checkPassword: v => v.length >= 1 || '請輸入密碼', |
|||
}, |
|||
deleteDialog: false, |
|||
dialog: false, |
|||
expireTime: new Date(), |
|||
} |
|||
}, |
|||
watch: { |
|||
remember: { |
|||
handler: function () { |
|||
if (this.remember == true) { |
|||
this.$auth.$storage.setUniversal("userPassword", this.userData.Password); |
|||
this.$auth.$storage.setUniversal("userAccount", this.userData.Account); |
|||
}else{ |
|||
this.$auth.$storage.removeUniversal("userPassword"); |
|||
this.$auth.$storage.removeUniversal("userAccount", this.userData.Account); |
|||
} |
|||
}, |
|||
}, |
|||
}, |
|||
created(){ |
|||
if(this.$auth.$storage.getUniversal('userAccount') && this.$auth.$storage.getUniversal('userPassword')){ |
|||
this.checkExpireTime(); |
|||
|
|||
} |
|||
}, |
|||
mounted(){ |
|||
if(this.$auth.$storage.getUniversal('userAccount') && this.$auth.$storage.getUniversal('userPassword')){ |
|||
this.remember = true; |
|||
|
|||
}else{ |
|||
this.remember = false; |
|||
|
|||
} |
|||
|
|||
var userAccount = this.$auth.$storage.getUniversal('userAccount'); |
|||
var userPassword = this.$auth.$storage.getUniversal('userPassword'); |
|||
|
|||
this.userData.Account = userAccount ? userAccount : ''; |
|||
this.userData.Password = userPassword ? userPassword : ''; |
|||
|
|||
if(this.userData.Account !=='' && this.userData.Password !==''){ |
|||
this.valid = true; |
|||
}else{ |
|||
this.valid = false; |
|||
} |
|||
|
|||
}, |
|||
methods: { |
|||
colseDialog(){ |
|||
this.dialog = false; |
|||
this.deleteDialog = false; |
|||
|
|||
}, |
|||
async userLogin() { |
|||
let that = this; |
|||
if (!that.$refs.loginFormRef.validate()) return; |
|||
try { |
|||
const response =await that.$auth.loginWith('local', { data: that.userData }); |
|||
that.serviceExceptionActive = false; |
|||
if(response.data.STATUSCODE==200){ |
|||
let data = response.data.DATA; |
|||
if(data.authtoken){ |
|||
const authtoken = data.authtoken; |
|||
that.$auth.$storage.removeUniversal('authtoken'); |
|||
that.$auth.$storage.setUniversal('authtoken', authtoken); |
|||
let path = that.$auth.$storage.getUniversal('userBeforePath'); |
|||
if(path == "/user"){ |
|||
path = "/"; |
|||
} |
|||
that.$router.push({path: path}); |
|||
} |
|||
}else if(response.data.STATUSCODE==500){ |
|||
that.$auth.redirect('login'); |
|||
}else if(response.data.STATUSCODE==401){ |
|||
if(response.data.MSG == "0"){ |
|||
that.dialog = true; |
|||
}else if(response.data.MSG == "2"){ |
|||
that.deleteDialog = true; |
|||
}else if(response.data.MSG == "帳號或密碼不正確"){ |
|||
that.wrongMessageActive = true; |
|||
} |
|||
}else{ |
|||
// that.resendDialog = !that.resendDialog; |
|||
that.wrongMessageActive = true; |
|||
} |
|||
} catch(err) { |
|||
console.log(err); |
|||
that.serviceExceptionActive = true; |
|||
// if(err && err.response && err.response.status){ |
|||
// err.response.status === 403 ? that.resendDialog = !that.resendDialog : err.response.status === 401 ? that.wrongMessageActive = true : that.resendDialog; |
|||
// } |
|||
} |
|||
}, |
|||
resendVerifyEmail() { |
|||
this.$axios |
|||
.post( |
|||
`/trending/api/Signup/ReSendVerifyMail?Email=${this.userData.Account}` |
|||
) |
|||
.then((response) => { |
|||
//console.log(JSON.stringify(response)) |
|||
if(response && response.data){ |
|||
this.dialog = false; |
|||
} |
|||
}) |
|||
.catch((error) => { |
|||
console.log(error); |
|||
}); |
|||
|
|||
}, |
|||
ReactivateAccount(){ |
|||
this.$axios |
|||
.post( |
|||
`/trending/api/Members/ReactivateAccountByAcc?Account=${this.userData.Account}` |
|||
) |
|||
.then((response) => { |
|||
//console.log(JSON.stringify(response)) |
|||
if(response && response.data && response.data.DATA && response.data.DATA.rel){ |
|||
let data = response.data.DATA.rel |
|||
if(data){ |
|||
this.deleteDialog = false; |
|||
|
|||
} |
|||
} |
|||
}) |
|||
.catch((error) => { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
updateValid(){ |
|||
if(this.userData.Account !=='' && this.userData.Password !==''){ |
|||
this.valid = true; |
|||
}else{ |
|||
this.valid = false; |
|||
} |
|||
}, |
|||
checkExpireTime(){ |
|||
console.log("給我時間"); |
|||
console.log("帳號:" + this.$auth.$storage.getUniversal('userAccount')); |
|||
this.$axios |
|||
.get(`/trending/api/System/RememberMe?Account=${this.$auth.$storage.getUniversal('userAccount')}`) |
|||
.then((response) => { |
|||
//console.log(response); |
|||
const data = response.data.DATA.authtoken; |
|||
this.expireTime = new Date(data.ExpireTime); |
|||
const now = new Date(Date.now()); |
|||
|
|||
const saveTime = this.expireTime - now; |
|||
if(saveTime >= 0){ |
|||
const hour = saveTime / (60 * 60 * 1000); |
|||
|
|||
if(hour == 0){ |
|||
this.$auth.$storage.removeUniversal('userPassword'); |
|||
this.$auth.$storage.removeUniversal('userAccount'); |
|||
} |
|||
}else{ |
|||
this.$auth.$storage.removeUniversal('userPassword'); |
|||
this.$auth.$storage.removeUniversal('userAccount'); |
|||
} |
|||
}) |
|||
.catch((error) => { |
|||
console.log(error); |
|||
}); |
|||
|
|||
} |
|||
}, |
|||
beforeUnmount() { |
|||
if(this.timer!=null){ |
|||
clearInterval(this.timer); |
|||
} |
|||
}, |
|||
beforeRouteEnter(to, from, next) { |
|||
next(vm => { |
|||
if (from.name) { |
|||
if (!from.path.includes('user')) { |
|||
vm.$auth.$storage.setUniversal("userBeforePath", from.fullPath, true) |
|||
} |
|||
} |
|||
if (vm.$auth.loggedIn) { |
|||
vm.$router.push({path: vm.$auth.$storage.getUniversal('userBeforePath') || '/'}) |
|||
} |
|||
else { |
|||
next() |
|||
} |
|||
}) |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
$border-style: 1px solid #E5E5E5; |
|||
#app { |
|||
overflow-y: hidden; |
|||
} |
|||
|
|||
.welcome { |
|||
color: #f5cda8; |
|||
font-family: Damion; |
|||
font-size: 48px; |
|||
margin-bottom: 0px; |
|||
font-weight: 400; |
|||
line-height: 66px; |
|||
letter-spacing: 0.02em; |
|||
} |
|||
|
|||
.sub { |
|||
color: #9c9c9c; |
|||
font-style: italic; |
|||
font-weight: 400; |
|||
font-size: 22px; |
|||
line-height: 29px; |
|||
letter-spacing: 0.02em; |
|||
} |
|||
|
|||
.title { |
|||
font-weight: 700; |
|||
font-size: 26px; |
|||
line-height: 34px; |
|||
letter-spacing: 0.02em; |
|||
color: #232323; |
|||
} |
|||
|
|||
.btn-border { |
|||
border: $border-style; |
|||
} |
|||
|
|||
.seperator { |
|||
border-bottom: $border-style; |
|||
text-align: center; |
|||
height: 12px; |
|||
margin: 20px 0 30px; |
|||
} |
|||
|
|||
:deep(.v-text-field.v-text-field--enclosed .v-text-field__details) { |
|||
margin-bottom: 0; |
|||
padding: 0; |
|||
|
|||
.v-messages { |
|||
display: none; |
|||
} |
|||
|
|||
.v-messages.error--text { |
|||
display: block; |
|||
margin-top: 4px; |
|||
margin-bottom: 16px; |
|||
} |
|||
} |
|||
|
|||
/* The container */ |
|||
.container-checkbox { |
|||
display: block; |
|||
position: relative; |
|||
padding-left: 28px; |
|||
cursor: pointer; |
|||
-webkit-user-select: none; |
|||
-moz-user-select: none; |
|||
-ms-user-select: none; |
|||
user-select: none; |
|||
} |
|||
|
|||
/* Hide the browser's default checkbox */ |
|||
.container-checkbox input { |
|||
position: absolute; |
|||
opacity: 0; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
/* Create a custom checkbox */ |
|||
.container-checkbox .checkmark { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
height: 18px; |
|||
width: 18px; |
|||
background-color: transparent; |
|||
border: 1px solid #f48800; |
|||
border-radius: 4px; |
|||
} |
|||
|
|||
/* On mouse-over, add a grey background color */ |
|||
.container-checkbox:hover input~.checkmark { |
|||
border-color: #f48800; |
|||
} |
|||
|
|||
/* When the checkbox is checked, add a blue background */ |
|||
.container-checkbox input:checked~.checkmark { |
|||
background-color: #f48800; |
|||
border-color: #f48800; |
|||
} |
|||
|
|||
/* Create the checkmark/indicator (hidden when not checked) */ |
|||
.container-checkbox .checkmark:after { |
|||
content: ""; |
|||
position: absolute; |
|||
display: none; |
|||
} |
|||
|
|||
/* Show the checkmark when checked */ |
|||
.container-checkbox input:checked~.checkmark:after { |
|||
display: block; |
|||
} |
|||
|
|||
/* Style the checkmark/indicator */ |
|||
.container-checkbox .checkmark:after { |
|||
left: 5px; |
|||
top: 2px; |
|||
width: 5px; |
|||
height: 10px; |
|||
border: solid #ffffff; |
|||
border-width: 0 2px 2px 0; |
|||
-webkit-transform: rotate(45deg); |
|||
-ms-transform: rotate(45deg); |
|||
transform: rotate(45deg); |
|||
} |
|||
</style> |
|||
|
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue