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.

538 lines
19 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
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
  18. class="tw-bg-white md:tw-rounded-[24px] md:tw-mt-[30px] md:tw-pt-[60px] md:tw-pb-[150px] md:tw-px-[30px]"
  19. >
  20. <div v-if="getPath == null">
  21. <p class="tw-text-[26px] tw-font-bold tw-mb-[20px] md:tw-text-[18px]">
  22. {{ $t("Forgot Password") }}
  23. </p>
  24. <p class="tw-body-3 tw-text-black tw-mb-[24px]">
  25. {{
  26. $t(
  27. "Dont worry! It happens. Please enter the address associated with your account."
  28. )
  29. }}
  30. </p>
  31. <div v-if="wrongMessageActive" class="warning--text text-size-14 ps-1 mb-3">
  32. {{ $t('The Email entered is incorrect') }}
  33. </div>
  34. <v-form v-model="resendValid">
  35. <v-text-field
  36. v-model="Email"
  37. background-color="neutrals darken-1"
  38. :label="this.$t('Email')"
  39. placeholder=""
  40. filled
  41. rounded
  42. dense
  43. single-line
  44. :rules="[rules.email, rules.require]"
  45. ></v-text-field>
  46. </v-form>
  47. <div class="md:tw-flex md:tw-justify-center md:tw-items-center">
  48. <button
  49. @click="sendForgotMail"
  50. :class="[
  51. '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',
  52. resendValid
  53. ? 'tw-text-white tw-bg-primary-default tw-border-primary-default'
  54. : 'tw-text-base-disable tw-bg-neutral-100 tw-border-neutral-100',
  55. ]"
  56. >
  57. {{ $t("Reset Password")
  58. }}
  59. <!-- <span v-if="disableBtn">({{ this.countdown }})</span> -->
  60. </button>
  61. </div>
  62. </div>
  63. <div v-if="getPath != null && resetSuccess == false">
  64. <p class="title">{{ $t("Reset Password") }}</p>
  65. <v-form v-model="resetValid">
  66. <v-text-field
  67. v-model="userData.Password"
  68. background-color="neutrals darken-1"
  69. :label="this.$t('Password') + '*'"
  70. :type="showPass ? 'text' : 'password'"
  71. placeholder=""
  72. filled
  73. rounded
  74. dense
  75. single-line
  76. persistent-hint
  77. :rules="[rules.checkPassword, rules.require]"
  78. :hint="
  79. this.$t(
  80. 'Passwords must be 8-20 characters with at least 1 number, 1 lower case letter and 1 upper case letter'
  81. )
  82. "
  83. :append-icon="showPass ? 'mdi-eye' : 'mdi-eye-off'"
  84. @click:append="showPass = !showPass"
  85. ></v-text-field>
  86. <v-text-field
  87. v-model="userConfirmPass"
  88. background-color="neutrals darken-1"
  89. :label="this.$t('Confirm Password') + '*'"
  90. :type="showConfirmPass ? 'text' : 'password'"
  91. placeholder=""
  92. filled
  93. rounded
  94. dense
  95. single-line
  96. :rules="[rules.checkPassword, rules.require, rules.confirmPass]"
  97. :append-icon="showConfirmPass ? 'mdi-eye' : 'mdi-eye-off'"
  98. @click:append="showConfirmPass = !showConfirmPass"
  99. ></v-text-field>
  100. </v-form>
  101. <div class="md:tw-flex md:tw-justify-center md:tw-items-center">
  102. <button
  103. @click="resetUserPass"
  104. :class="[
  105. '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 tw-text-white tw-bg-primary-default tw-border-primary-default']"
  106. >
  107. {{ $t("Reset Password") }}
  108. </button>
  109. </div>
  110. </div>
  111. <div v-if="resetSuccess">
  112. <p class="title">{{ $t("Password Reset") }}</p>
  113. <p class="neutrals--text text--darken-5 text-size-14">
  114. {{ $t("Congrats! Your password has been successfully reset") }}
  115. </p>
  116. <nuxt-link :to="localePath('/')">
  117. <v-btn
  118. @click="redirectHome"
  119. width="100%"
  120. color="primary"
  121. class="border-radius-16 mt-4"
  122. >
  123. <span class="text-capitalize">{{ $t("Explore with ShowEasy") }}</span>
  124. </v-btn>
  125. </nuxt-link>
  126. <v-spacer class="d-flex justify-center mt-5">
  127. <span
  128. class="text-size-12 primary--text"
  129. v-html="$t('Go to ShowEasy in sec', { second: this.countdown })"
  130. ></span>
  131. </v-spacer>
  132. </div>
  133. <!-- 會員未認證Modal -->
  134. <v-dialog v-model="dialog" :width="$vuetify.breakpoint.smAndUp ? 423 : 294"
  135. @click:outside="colseDialog()">
  136. <v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290">
  137. <v-spacer class="d-flex align-center tw-justify-between tw-mb-[30px]">
  138. <div class="tw-text-[20px] tw-font-bold tw-text-black">
  139. {{ $t("Verify your email") }}
  140. </div>
  141. <v-btn @click="colseDialog()" icon>
  142. <v-icon> mdi-close </v-icon>
  143. </v-btn>
  144. </v-spacer>
  145. <v-spacer class="tw-mb-[40px]">
  146. <div class="tw-text-[16px] tw-text-neutrals-800">
  147. {{ $t("Oops! Seems like you haven't verified your email,please click the button below to resend a verification email.")}}
  148. </div>
  149. </v-spacer>
  150. <button @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]">
  151. {{ $t("Resend verification email") }}
  152. </button>
  153. <!-- <v-btn @click="resendVerifyEmail" class="primary tw-text-[18px] tw-w-auto" rounded
  154. :disabled="countdown > 0">
  155. <span v-if="countdown > 0">
  156. {{ `(${this.countdown})` }}
  157. </span>
  158. </v-btn> -->
  159. </v-card>
  160. </v-dialog>
  161. <!-- 重啟帳號Modal -->
  162. <v-dialog v-model="deleteDialog" :width="$vuetify.breakpoint.smAndUp ? 423 : 294"
  163. @click:outside="colseDialog()">
  164. <v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290">
  165. <v-spacer class="d-flex tw-justify-between align-center tw-mb-[30px]">
  166. <div class="tw-text-[20px] tw-text-black tw-font-bold">
  167. {{ $t("Reactivate your account") }}
  168. </div>
  169. <v-btn @click="colseDialog()" icon>
  170. <v-icon> mdi-close </v-icon>
  171. </v-btn>
  172. </v-spacer>
  173. <v-spacer class="tw-mb-[40px]">
  174. <div class="tw-text-[16px] tw-text-neutrals-800 tw-font-bold">
  175. {{ $t("Welcome back!")}}
  176. </div>
  177. <div class="tw-text-[16px] tw-text-neutrals-800">
  178. {{ $t("Looks like your account has been deactivated.")}}
  179. <br />
  180. {{ $t("Would you like to reactivate this account?")}}
  181. </div>
  182. </v-spacer>
  183. <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]">
  184. {{ $t("Reactivate my account") }}
  185. </button>
  186. <!-- <v-btn class="primary tw-w-auto" rounded
  187. :disabled="countdown > 0">
  188. <span v-if="countdown > 0">
  189. {{ `(${this.countdown})` }}
  190. </span>
  191. </v-btn> -->
  192. </v-card>
  193. </v-dialog>
  194. <!-- 忘記密碼信件Modal -->
  195. <v-dialog v-model="chackMailDialog" :width="$vuetify.breakpoint.smAndUp ? 463 : 294"
  196. @click:outside="colseDialog()">
  197. <v-card class="tw-p-[30px]" :height="$vuetify.breakpoint.smAndUp ? 289 : 290">
  198. <v-spacer class="d-flex tw-justify-between align-center tw-mb-[30px]">
  199. <div class="tw-text-[20px] tw-text-black tw-font-bold">
  200. {{ $t("Check your email") }}
  201. </div>
  202. <v-btn @click="colseDialog()" icon>
  203. <v-icon> mdi-close </v-icon>
  204. </v-btn>
  205. </v-spacer>
  206. <v-spacer class="tw-mb-[40px]">
  207. <div class="tw-text-[16px] tw-text-neutrals-800 tw-font-bold">
  208. {{ $t("We've sent a password reset link to")}}
  209. </div>
  210. <div class="tw-text-[16px] tw-text-primary-1">
  211. {{ Email }}
  212. </div>
  213. <div class="tw-text-[16px] tw-text-neutrals-800 tw-font-bold">
  214. {{ $t("Please tap the link inside that email to continue.")}}
  215. </div>
  216. </v-spacer>
  217. <button @click="colseDialog()" class="tw-bg-primary-1 tw-text-white hover:tw-bg-primary-light tw-text-[18px] tw-rounded-[16px] tw-px-[169px] tw-py-[13px]">
  218. {{ $t("OK") }}
  219. </button>
  220. <!-- <v-btn class="primary tw-w-auto" rounded
  221. :disabled="countdown > 0">
  222. <span v-if="countdown > 0">
  223. {{ `(${this.countdown})` }}
  224. </span>
  225. </v-btn> -->
  226. </v-card>
  227. </v-dialog>
  228. <!-- 認證碼Modal -->
  229. <VerifyCode @user-verifyCode="userVerifyCode" @resend-mail="resendVerifyEmail" :error="error" :account="userData.Account"></VerifyCode>
  230. </div>
  231. </div>
  232. </div>
  233. </div>
  234. </template>
  235. <script>
  236. import VerifyCode from "@/components/newcomponent/modal/VerifyCodeModal.vue";
  237. export default {
  238. name: "Forgot",
  239. layout: "login",
  240. auth: false,
  241. components: {
  242. VerifyCode
  243. },
  244. data() {
  245. return {
  246. showPass: false,
  247. showConfirmPass: false,
  248. resendValid: false,
  249. resetValid: false,
  250. disableBtn: false,
  251. resetSuccess: false,
  252. countdown: 5,
  253. Email: "",
  254. userConfirmPass: "",
  255. userData: {
  256. //user_id: "",
  257. //auth_code: "",
  258. Password: "",
  259. },
  260. result: "",
  261. getPath: null,
  262. rules: {
  263. require: (value) => !!value || this.$t("Required."),
  264. email: (v) =>
  265. /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(
  266. v
  267. ) || this.$t("Invalid email"),
  268. checkPassword: (v) =>
  269. (/(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])/.test(v) &&
  270. v.length >= 8 &&
  271. v.length <= 20) ||
  272. this.$t(
  273. "Passwords must be 8-20 characters with at least 1 number, 1 lower case letter and 1 upper case letter"
  274. ),
  275. confirmPass: (v) =>
  276. v === this.userData.Password ||
  277. this.$t("Your password and confirmation password do not match"),
  278. },
  279. dialog: false,
  280. deleteDialog: false,
  281. wrongMessageActive: false,
  282. chackMailDialog: false,
  283. error: false,
  284. userInfo: {},
  285. user: {
  286. Account: '',
  287. Password: '',
  288. }
  289. };
  290. },
  291. created(){
  292. this.$auth.$storage.removeUniversal('userPassword');
  293. this.$auth.$storage.removeUniversal('userAccount');
  294. this.getPAth();
  295. },
  296. methods: {
  297. colseDialog(){
  298. this.dialog = false;
  299. if(this.dialog == false){
  300. this.resendValid = false;
  301. }
  302. this.deleteDialog = false;
  303. if(this.deleteDialog == false){
  304. this.resendValid = false;
  305. }
  306. this.chackMailDialog = false;
  307. if(this.chackMailDialog == false){
  308. this.resendValid = false;
  309. }
  310. },
  311. getPAth(){
  312. let vm = this;
  313. if (this.$route.query.Email) {
  314. vm.getPath = vm.$route.query.Email;
  315. }else{
  316. vm.getPath = null;
  317. }
  318. },
  319. //寄送忘記密碼信
  320. sendForgotMail() {
  321. this.resendValid = false;
  322. this.$axios
  323. .post(`/trending/api/Signup/SendForgotMail?Email=${this.Email}`)
  324. .then((response) => {
  325. //console.log(response);
  326. if(response.data.STATUSCODE == "404"){
  327. if(response.data.MSG == "0"){
  328. //this.dialog = true; //原先的認證moadl
  329. this.resendVerifyEmail();
  330. this.$modal.show('VerifyCode');
  331. }else if(response.data.MSG == "2"){
  332. this.deleteDialog = true;
  333. }else{
  334. this.wrongMessageActive = true;
  335. }
  336. }
  337. else if(response && response.data && response.data.DATA && response.data.DATA.rel){
  338. let data = response.data.DATA.rel
  339. if(data){
  340. this.result = data;
  341. this.disableBtn = false;
  342. this.resendValid = false;
  343. this.chackMailDialog = true;
  344. this.disableBtn = !this.disableBtn;
  345. // this.timeout = setInterval(() => {
  346. // if (this.countdown > 0) {
  347. // this.countdown--;
  348. // }
  349. // if (this.countdown == 0) {
  350. // this.resendValid = true;
  351. // this.disableBtn = true;
  352. // this.countdown = 60;
  353. // clearInterval(this.timeout);
  354. // }
  355. // }, 1000);
  356. }
  357. }
  358. })
  359. .catch((error) => {
  360. console.log(error);
  361. });
  362. },
  363. //重設密碼
  364. resetUserPass() {
  365. if (
  366. this.userData.Password === this.userConfirmPass &&
  367. this.resetValid
  368. ) {
  369. //this.userData.user_id = this.$route.query.user_uuid;
  370. //this.userData.auth_code = this.$route.query.auth_code;
  371. this.$axios
  372. .post(`/trending/api/Signup/ResetPassword?Email=${this.getPath}&Password=${this.userData.Password}`)
  373. .then((response) => {
  374. //console.log(JSON.stringify(response));
  375. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  376. let data = response.data.DATA.rel
  377. if(data){
  378. this.resetSuccess = !this.resetSuccess;
  379. this.countdown = 3;
  380. this.timer = setInterval(() => {
  381. if (this.countdown > 0) {
  382. this.countdown--;
  383. } else {
  384. clearInterval(this.timer);
  385. this.$router.push(this.localePath("/"));
  386. }
  387. }, 1000);
  388. }
  389. }
  390. })
  391. .catch((error) => {
  392. console.log(error);
  393. });
  394. }
  395. },
  396. //重寄認證信
  397. resendVerifyEmail() {
  398. this.$axios
  399. .post(
  400. `/trending/api/Signup/ReSendVerifyMail?Email=${this.Email}`
  401. )
  402. .then((response) => {
  403. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  404. let data = response.data.DATA.rel
  405. if(data){
  406. this.userInfo = data;
  407. this.resendValid = true;
  408. }
  409. }
  410. })
  411. .catch((error) => {
  412. console.log(error);
  413. });
  414. },
  415. //認證會員
  416. userVerifyCode(value){
  417. this.error = false;
  418. this.$axios
  419. .get(
  420. `/trending/api/Signup/VerifyAccount?OrgID=${this.userInfo.OrgID}&MemberID=${this.userInfo.MemberID}&Code=${value}`
  421. )
  422. .then((response) => {
  423. //console.log(response);
  424. if(response.data.STATUSCODE == 200){
  425. this.$modal.hide('VerifyCode');
  426. this.decrypt();
  427. }
  428. else{
  429. this.error = true;
  430. }
  431. })
  432. .catch((err) => {
  433. console.log(err);
  434. });
  435. },
  436. //解密
  437. decrypt(){
  438. this.$axios
  439. .post(
  440. `/trending/api/Signup/DecryptPassword?OrgID=${this.userInfo.OrgID}&Account=${this.userInfo.Account}`
  441. )
  442. .then((response) => {
  443. //console.log(response);
  444. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  445. let data = response.data.DATA.rel;
  446. if(data){
  447. this.user.Password = data;
  448. this.Login();
  449. }
  450. }
  451. })
  452. .catch((err) => {
  453. console.log(err);
  454. });
  455. },
  456. //重啟帳號
  457. ReactivateAccount(){
  458. this.$axios
  459. .post(
  460. `/trending/api/Members/ReactivateAccount?Email=${this.Email}`
  461. )
  462. .then((response) => {
  463. //console.log(JSON.stringify(response))
  464. if(response && response.data && response.data.DATA && response.data.DATA.rel){
  465. let data = response.data.DATA.rel
  466. if(data){
  467. this.deleteDialog = false;
  468. window.location.href = '/';
  469. }
  470. }
  471. })
  472. .catch((error) => {
  473. console.log(error);
  474. });
  475. },
  476. //登入
  477. async Login(){
  478. this.user.Account = this.userInfo.Account;
  479. const response = await this.$auth.loginWith('local', { data: this.user });
  480. if(response.data.STATUSCODE == 200){
  481. let data = response.data.DATA;
  482. if(data.authtoken){
  483. const authtoken = data.authtoken;
  484. this.$auth.$storage.removeUniversal('authtoken');
  485. this.$auth.$storage.setUniversal('authtoken', authtoken);
  486. let path = this.$auth.$storage.getUniversal('userBeforePath');
  487. if(path == "/user"){
  488. path = "/";
  489. }
  490. this.$router.push({path: path});
  491. }
  492. }
  493. }
  494. },
  495. beforeUnmount() {
  496. clearInterval(this.timeout);
  497. clearInterval(this.timer);
  498. },
  499. };
  500. </script>
  501. <style scoped>
  502. .title {
  503. font-weight: 700;
  504. font-size: 26px;
  505. line-height: 34px;
  506. letter-spacing: 0.02em;
  507. color: #232323;
  508. }
  509. </style>
  510. <style lang="scss" scoped>
  511. #app {
  512. overflow-y: hidden;
  513. }
  514. .welcome {
  515. color: #f5cda8;
  516. font-family: Damion;
  517. font-size: 48px;
  518. margin-bottom: 0px;
  519. font-weight: 400;
  520. line-height: 66px;
  521. letter-spacing: 0.02em;
  522. }
  523. .sub {
  524. color: #9c9c9c;
  525. font-style: italic;
  526. font-weight: 400;
  527. font-size: 22px;
  528. line-height: 29px;
  529. letter-spacing: 0.02em;
  530. }
  531. </style>