You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

494 lines
18 KiB

2 years ago
  1. <template>
  2. <div :class="['tw-h-full tw-p-[30px] tw-bg-white md:tw-bg-primary-pale']">
  3. <div
  4. 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]">
  5. <div class="tw-hidden xl:tw-block xl:tw-mt-[30px]">
  6. <p class="welcome tw-text-primary-light">{{ $t("Welcome to ShowEasy") }}</p>
  7. <p class="sub tw-text-neutral-400">
  8. {{
  9. $t(
  10. "Your best guide from trip to show and from show to the world."
  11. )
  12. }}
  13. </p>
  14. <img class="mt-11 ml-15" :src="require('@/assets/img/UserLoginMain.png')" />
  15. </div>
  16. <div class="md:tw-w-[414px] md:tw-mx-auto">
  17. <div class="tw-bg-white tw-mt-[30px] md:tw-rounded-[24px] md:tw-pt-[60px] md:tw-pb-[150px] md:tw-px-[30px]">
  18. <h1 class="tw-text-[40px] tw-font-bold tw-mb-[20px] md:tw-text-[24px]">{{ $t('Login') }}</h1>
  19. <p class="tw-body-3 tw-text-neutral-400 tw-mb-[16px] md:tw-mb-[12px]">
  20. {{ $t('Welcome back! Please enter your details') }}
  21. </p>
  22. <p class="tw-body-3 tw-mb-[24px] md:tw-mb-[32px]">{{ $t('Not a member?') }} <nuxt-link
  23. :to="localePath('/user/signup')" class="primary--text text-decoration-none">{{ $t('Sign up') }}</nuxt-link>
  24. </p>
  25. <!-- <div class="tw-grid tw-grid-cols-1 tw-gap-[10px] tw-mb-[30px] md:tw-gap-[12px] md:tw-mb-[12px]">
  26. <button @click="googleLogin"
  27. 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
  28. width="20px" height="20px" src="~/assets/img/g-normal.png" class="mr-5" />{{ $t('Login with Google')
  29. }}</button>
  30. <button @click="facebookLogin"
  31. 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
  32. width="20px" height="20px" src="~/assets/img/f_logo_RGB-Blue_72.png" class="mr-5" />
  33. {{ $t("Login with Facebook")
  34. }}</button>
  35. </div>
  36. <div class="tw-grid tw-grid-cols-[auto_16px_auto] tw-gap-[28px] tw-mb-[6px]">
  37. <div class="tw-flex tw-justify-center tw-items-center">
  38. <div class="tw-w-full tw-h-[1px] tw-bg-neutral-200"></div>
  39. </div>
  40. <div class="tw-text-neutral-400 tw-body-3 tw-font-normal">{{ $t("or") }}</div>
  41. <div class="tw-flex tw-justify-center tw-items-center">
  42. <div class="tw-w-full tw-h-[1px] tw-bg-neutral-200"></div>
  43. </div>
  44. </div> -->
  45. <div v-if="serviceExceptionActive" class="warning--text text-size-14 ps-1 mb-3">
  46. {{ $t('Service exception') }}
  47. </div>
  48. <div v-if="wrongMessageActive" class="warning--text text-size-14 ps-1 mb-3">
  49. {{ $t('The username or password entered is incorrect') }}
  50. </div>
  51. <v-form ref="loginFormRef" lazy-validation>
  52. <!-- <div v-if="$auth.$storage.getUniversal('userAccount') && $auth.$storage.getUniversal('userPassword')"></div>
  53. <div v-else></div> -->
  54. <v-text-field
  55. v-model="userData.Account" background-color="neutrals darken-1" :label="this.$t('Email')"
  56. :placeholder="this.$t('Email')" height="40px" filled rounded dense single-line persistent-placeholder
  57. :rules="[rules.email,rules.require]" v-on:input="updateValid"
  58. />
  59. <v-text-field
  60. v-model="userData.Password" background-color="neutrals darken-1" :label="this.$t('Password')"
  61. :type=" showPass ? 'text' : 'password'" :placeholder="this.$t('Password')" filled rounded dense single-line
  62. persistent-placeholder :append-icon=" showPass ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showPass = !showPass"
  63. :rules="[rules.checkPassword,rules.require]" v-on:input="updateValid" @keyup.enter="userLogin"
  64. />
  65. </v-form>
  66. <div class="tw-flex tw-justify-between tw-items-center tw-mb-[28px] md:tw-mb-[32px]">
  67. <div class="tw-flex tw-items-center">
  68. <div class="tw-flex tw-items-center">
  69. <div class="tw-flex tw-flex-col">
  70. <label class="tw-body-4 container-checkbox" for="remember">
  71. {{ $t('Remember me')
  72. }}
  73. <input id="remember" type="checkbox" value="remember" v-model="remember" />
  74. <span class="checkmark"></span>
  75. </label>
  76. </div>
  77. </div>
  78. </div>
  79. <div class="tw-flex tw-items-center">
  80. <nuxt-link class="complementary--text text-decoration-none text-size-14" :to="localePath('/user/forgot')">{{
  81. $t('Forgot Password?') }}</nuxt-link>
  82. </div>
  83. </div>
  84. <div class="md:tw-flex md:tw-justify-center md:tw-items-center"> <button @click="userLogin" :disabled="!valid"
  85. :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']">{{
  86. $t("Login")
  87. }}</button></div>
  88. <v-dialog v-model="dialog" :width="$vuetify.breakpoint.smAndUp ? 423 : 294"
  89. @click:outside="colseDialog()">
  90. <v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290">
  91. <v-spacer class="d-flex align-center tw-justify-between tw-mb-[30px]">
  92. <div class="tw-text-[20px] tw-font-bold tw-text-black">
  93. {{ $t("Verify your email") }}
  94. </div>
  95. <v-btn @click="colseDialog()" icon>
  96. <v-icon> mdi-close </v-icon>
  97. </v-btn>
  98. </v-spacer>
  99. <v-spacer class="tw-mb-[40px]">
  100. <div class="tw-text-[16px] tw-text-neutrals-800">
  101. {{ $t("Oops! Seems like you haven't verified your email,please click the button below to resend a verification email.")}}
  102. </div>
  103. </v-spacer>
  104. <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]']">
  105. {{ $t("Resend verification email") }}
  106. </button>
  107. <!-- <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]"
  108. :disabled="countdown > 0">
  109. {{ $t("Resend verification email") }}
  110. <span v-if="countdown > 0">
  111. {{ `(${this.countdown})` }}
  112. </span>
  113. </v-btn> -->
  114. </v-card>
  115. </v-dialog>
  116. <v-dialog v-model="deleteDialog" :width="$vuetify.breakpoint.smAndUp ? 423 : 294"
  117. @click:outside="colseDialog()">
  118. <v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290">
  119. <v-spacer class="d-flex tw-justify-between align-center tw-mb-[30px]">
  120. <div class="tw-text-[20px] tw-text-black tw-font-bold">
  121. {{ $t("Reactivate your account") }}
  122. </div>
  123. <v-btn @click="colseDialog()" icon>
  124. <v-icon> mdi-close </v-icon>
  125. </v-btn>
  126. </v-spacer>
  127. <v-spacer class="tw-mb-[40px]">
  128. <div class="tw-text-[16px] tw-text-neutrals-800 tw-font-bold">
  129. {{ $t("Welcome back!")}}
  130. </div>
  131. <div class="tw-text-[16px] tw-text-neutrals-800">
  132. {{ $t("Looks like your account has been deactivated.")}}
  133. <br />
  134. {{ $t("Would you like to reactivate this account?")}}
  135. </div>
  136. </v-spacer>
  137. <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]">
  138. {{ $t("Reactivate my account") }}
  139. </button>
  140. <!-- <v-btn class="primary tw-w-auto" rounded
  141. :disabled="countdown > 0">
  142. <span v-if="countdown > 0">
  143. {{ `(${this.countdown})` }}
  144. </span>
  145. </v-btn> -->
  146. </v-card>
  147. </v-dialog>
  148. </div>
  149. </div>
  150. </div>
  151. </div>
  152. </template>
  153. <script>
  154. import { getCurrentTime } from "~/utils/assist";
  155. export default {
  156. name: "login",
  157. layout: "login",
  158. auth: false,
  159. data() {
  160. return {
  161. timer: null,
  162. showPass: false,
  163. resendDialog: false,
  164. wrongMessageActive: false,
  165. verifyEmailSent: false,
  166. serviceExceptionActive: false,
  167. valid: false,
  168. remember: false,
  169. countdown: 60,
  170. userData: {
  171. Account: '',
  172. Password: '',
  173. },
  174. rules: {
  175. require: value => !!value || this.$t('Required.'),
  176. email: v => /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(v) || this.$t('Invalid email'),
  177. // checkPassword: v => (/(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])/.test(v) && v.length >= 8 && v.length <= 20) || '請輸入密碼',
  178. checkPassword: v => v.length >= 1 || '請輸入密碼',
  179. },
  180. deleteDialog: false,
  181. dialog: false,
  182. expireTime: new Date(),
  183. }
  184. },
  185. watch: {
  186. remember: {
  187. handler: function () {
  188. if (this.remember == true) {
  189. this.$auth.$storage.setUniversal("userPassword", this.userData.Password);
  190. this.$auth.$storage.setUniversal("userAccount", this.userData.Account);
  191. }else{
  192. this.$auth.$storage.removeUniversal("userPassword");
  193. this.$auth.$storage.removeUniversal("userAccount", this.userData.Account);
  194. }
  195. },
  196. },
  197. },
  198. created(){
  199. if(this.$auth.$storage.getUniversal('userAccount') && this.$auth.$storage.getUniversal('userPassword')){
  200. this.checkExpireTime();
  201. }
  202. },
  203. mounted(){
  204. if(this.$auth.$storage.getUniversal('userAccount') && this.$auth.$storage.getUniversal('userPassword')){
  205. this.remember = true;
  206. }else{
  207. this.remember = false;
  208. }
  209. var userAccount = this.$auth.$storage.getUniversal('userAccount');
  210. var userPassword = this.$auth.$storage.getUniversal('userPassword');
  211. this.userData.Account = userAccount ? userAccount : '';
  212. this.userData.Password = userPassword ? userPassword : '';
  213. if(this.userData.Account !=='' && this.userData.Password !==''){
  214. this.valid = true;
  215. }else{
  216. this.valid = false;
  217. }
  218. },
  219. methods: {
  220. colseDialog(){
  221. this.dialog = false;
  222. this.deleteDialog = false;
  223. },
  224. async userLogin() {
  225. let that = this;
  226. if (!that.$refs.loginFormRef.validate()) return;
  227. try {
  228. const response =await that.$auth.loginWith('local', { data: that.userData });
  229. that.serviceExceptionActive = false;
  230. if(response.data.STATUSCODE==200){
  231. let data = response.data.DATA;
  232. if(data.authtoken){
  233. const authtoken = data.authtoken;
  234. that.$auth.$storage.removeUniversal('authtoken');
  235. that.$auth.$storage.setUniversal('authtoken', authtoken);
  236. let path = that.$auth.$storage.getUniversal('userBeforePath');
  237. if(path == "/user"){
  238. path = "/";
  239. }
  240. that.$router.push({path: path});
  241. }
  242. }else if(response.data.STATUSCODE==500){
  243. that.$auth.redirect('login');
  244. }else if(response.data.STATUSCODE==401){
  245. if(response.data.MSG == "0"){
  246. that.dialog = true;
  247. }else if(response.data.MSG == "2"){
  248. that.deleteDialog = true;
  249. }else if(response.data.MSG == "帳號或密碼不正確"){
  250. that.wrongMessageActive = true;
  251. }
  252. }else{
  253. // that.resendDialog = !that.resendDialog;
  254. that.wrongMessageActive = true;
  255. }
  256. } catch(err) {
  257. console.log(err);
  258. that.serviceExceptionActive = true;
  259. // if(err && err.response && err.response.status){
  260. // err.response.status === 403 ? that.resendDialog = !that.resendDialog : err.response.status === 401 ? that.wrongMessageActive = true : that.resendDialog;
  261. // }
  262. }
  263. },
  264. resendVerifyEmail() {
  265. this.$axios
  266. .post(
  267. `/trending/api/Signup/ReSendVerifyMail?Email=${this.userData.Account}`
  268. )
  269. .then((response) => {
  270. //console.log(JSON.stringify(response))
  271. if(response && response.data){
  272. this.dialog = false;
  273. }
  274. })
  275. .catch((error) => {
  276. console.log(error);
  277. });
  278. },
  279. ReactivateAccount(){
  280. this.$axios
  281. .post(
  282. `/trending/api/Members/ReactivateAccountByAcc?Account=${this.userData.Account}`
  283. )
  284. .then((response) => {
  285. //console.log(JSON.stringify(response))
  286. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  287. let data = response.data.DATA.rel
  288. if(data){
  289. this.deleteDialog = false;
  290. }
  291. }
  292. })
  293. .catch((error) => {
  294. console.log(error);
  295. });
  296. },
  297. updateValid(){
  298. if(this.userData.Account !=='' && this.userData.Password !==''){
  299. this.valid = true;
  300. }else{
  301. this.valid = false;
  302. }
  303. },
  304. checkExpireTime(){
  305. console.log("給我時間");
  306. console.log("帳號:" + this.$auth.$storage.getUniversal('userAccount'));
  307. this.$axios
  308. .get(`/trending/api/System/RememberMe?Account=${this.$auth.$storage.getUniversal('userAccount')}`)
  309. .then((response) => {
  310. //console.log(response);
  311. const data = response.data.DATA.authtoken;
  312. this.expireTime = new Date(data.ExpireTime);
  313. const now = new Date(Date.now());
  314. const saveTime = this.expireTime - now;
  315. if(saveTime >= 0){
  316. const hour = saveTime / (60 * 60 * 1000);
  317. if(hour == 0){
  318. this.$auth.$storage.removeUniversal('userPassword');
  319. this.$auth.$storage.removeUniversal('userAccount');
  320. }
  321. }else{
  322. this.$auth.$storage.removeUniversal('userPassword');
  323. this.$auth.$storage.removeUniversal('userAccount');
  324. }
  325. })
  326. .catch((error) => {
  327. console.log(error);
  328. });
  329. }
  330. },
  331. beforeUnmount() {
  332. if(this.timer!=null){
  333. clearInterval(this.timer);
  334. }
  335. },
  336. beforeRouteEnter(to, from, next) {
  337. next(vm => {
  338. if (from.name) {
  339. if (!from.path.includes('user')) {
  340. vm.$auth.$storage.setUniversal("userBeforePath", from.fullPath, true)
  341. }
  342. }
  343. if (vm.$auth.loggedIn) {
  344. vm.$router.push({path: vm.$auth.$storage.getUniversal('userBeforePath') || '/'})
  345. }
  346. else {
  347. next()
  348. }
  349. })
  350. },
  351. }
  352. </script>
  353. <style lang="scss" scoped>
  354. $border-style: 1px solid #E5E5E5;
  355. #app {
  356. overflow-y: hidden;
  357. }
  358. .welcome {
  359. color: #f5cda8;
  360. font-family: Damion;
  361. font-size: 48px;
  362. margin-bottom: 0px;
  363. font-weight: 400;
  364. line-height: 66px;
  365. letter-spacing: 0.02em;
  366. }
  367. .sub {
  368. color: #9c9c9c;
  369. font-style: italic;
  370. font-weight: 400;
  371. font-size: 22px;
  372. line-height: 29px;
  373. letter-spacing: 0.02em;
  374. }
  375. .title {
  376. font-weight: 700;
  377. font-size: 26px;
  378. line-height: 34px;
  379. letter-spacing: 0.02em;
  380. color: #232323;
  381. }
  382. .btn-border {
  383. border: $border-style;
  384. }
  385. .seperator {
  386. border-bottom: $border-style;
  387. text-align: center;
  388. height: 12px;
  389. margin: 20px 0 30px;
  390. }
  391. :deep(.v-text-field.v-text-field--enclosed .v-text-field__details) {
  392. margin-bottom: 0;
  393. padding: 0;
  394. .v-messages {
  395. display: none;
  396. }
  397. .v-messages.error--text {
  398. display: block;
  399. margin-top: 4px;
  400. margin-bottom: 16px;
  401. }
  402. }
  403. /* The container */
  404. .container-checkbox {
  405. display: block;
  406. position: relative;
  407. padding-left: 28px;
  408. cursor: pointer;
  409. -webkit-user-select: none;
  410. -moz-user-select: none;
  411. -ms-user-select: none;
  412. user-select: none;
  413. }
  414. /* Hide the browser's default checkbox */
  415. .container-checkbox input {
  416. position: absolute;
  417. opacity: 0;
  418. cursor: pointer;
  419. }
  420. /* Create a custom checkbox */
  421. .container-checkbox .checkmark {
  422. position: absolute;
  423. top: 0;
  424. left: 0;
  425. height: 18px;
  426. width: 18px;
  427. background-color: transparent;
  428. border: 1px solid #f48800;
  429. border-radius: 4px;
  430. }
  431. /* On mouse-over, add a grey background color */
  432. .container-checkbox:hover input~.checkmark {
  433. border-color: #f48800;
  434. }
  435. /* When the checkbox is checked, add a blue background */
  436. .container-checkbox input:checked~.checkmark {
  437. background-color: #f48800;
  438. border-color: #f48800;
  439. }
  440. /* Create the checkmark/indicator (hidden when not checked) */
  441. .container-checkbox .checkmark:after {
  442. content: "";
  443. position: absolute;
  444. display: none;
  445. }
  446. /* Show the checkmark when checked */
  447. .container-checkbox input:checked~.checkmark:after {
  448. display: block;
  449. }
  450. /* Style the checkmark/indicator */
  451. .container-checkbox .checkmark:after {
  452. left: 5px;
  453. top: 2px;
  454. width: 5px;
  455. height: 10px;
  456. border: solid #ffffff;
  457. border-width: 0 2px 2px 0;
  458. -webkit-transform: rotate(45deg);
  459. -ms-transform: rotate(45deg);
  460. transform: rotate(45deg);
  461. }
  462. </style>