Signup.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <script setup lang="ts">
  2. import { appName, openRegisration } from "@/env";
  3. import { ref, reactive, computed, onMounted } from "vue";
  4. import { useMainStore } from "@/stores/main";
  5. import { useDisplay } from "vuetify";
  6. import { storeToRefs } from "pinia";
  7. import { useI18n } from "vue-i18n";
  8. import Navbar from "@/components/Navbar.vue";
  9. import TOS from "@/components/TOS.vue";
  10. const mainStore = useMainStore();
  11. const mainStoreRef = storeToRefs(mainStore);
  12. // variable
  13. const email = ref("");
  14. const password = ref("");
  15. const { name } = useDisplay();
  16. const { t } = useI18n();
  17. const confirmPassword = ref("");
  18. let data = reactive({
  19. email: "",
  20. password: "",
  21. full_name: ""
  22. });
  23. let dialog = ref(false);
  24. let confirmState = ref(false);
  25. let showPassword = ref(false);
  26. let showConfirmPassword = ref(false);
  27. // getter
  28. const loginError = mainStoreRef.readLoginError;
  29. const width = computed(() => {
  30. // name is reactive and
  31. // must use .value
  32. switch (name.value) {
  33. case "xs":
  34. return 12;
  35. case "sm":
  36. return 12;
  37. }
  38. return 6;
  39. });
  40. // action
  41. async function submit() {
  42. if (confirmPassword.value === data.password) {
  43. console.log("data", data.password);
  44. mainStore.register(data);
  45. } else {
  46. confirmState.value = true;
  47. setTimeout(() => {
  48. confirmState.value = false;
  49. }, 5000);
  50. }
  51. }
  52. </script>
  53. <template>
  54. <Navbar />
  55. <v-container fluid class="pa-0">
  56. <v-row align="center" no-gutters class="overflow-hidden">
  57. <v-col :cols="width">
  58. <section class="overflow-hidden banner-item">
  59. <img src="../assets/img/banner.png" alt="" />
  60. <h2>
  61. {{ t("describe_1") }}
  62. <br />
  63. {{ t("describe_2") }}
  64. </h2>
  65. </section>
  66. </v-col>
  67. <v-col :cols="width" class="px-6 my-8 my-md-0">
  68. <div class="form-title">
  69. <h3>{{ t("register") }}</h3>
  70. <span></span>
  71. </div>
  72. <v-form ref="form" class="login-form" lazy-validation>
  73. <v-text-field
  74. v-model="data.full_name"
  75. :rules="[(v) => !!v || '請輸入您的帳號']"
  76. :label="$t('userName')"
  77. required
  78. ></v-text-field>
  79. <v-text-field
  80. v-model="data.email"
  81. :rules="[(v) => !!v || '請輸入您的電子信箱']"
  82. :label="$t('emailAddress')"
  83. required
  84. ></v-text-field>
  85. <v-text-field
  86. v-model="data.password"
  87. :append-icon="showPassword ? 'visibility' : 'visibility_off'"
  88. :rules="[(v) => !!v || '請輸入您的密碼']"
  89. :type="showPassword ? 'text' : 'password'"
  90. :label="$t('registerPassword')"
  91. :hint="$t('passwordLength')"
  92. @click:append="showPassword = !showPassword"
  93. required
  94. ></v-text-field>
  95. <v-text-field
  96. v-model="confirmPassword"
  97. :append-icon="showConfirmPassword ? 'visibility' : 'visibility_off'"
  98. :rules="[(v) => !!v || '請輸入您的密碼']"
  99. :type="showConfirmPassword ? 'text' : 'password'"
  100. :label="$t('confirmPassword')"
  101. :hint="$t('passwordConfirm')"
  102. @click:append="showConfirmPassword = !showConfirmPassword"
  103. required
  104. ></v-text-field>
  105. <v-alert v-model="confirmState" type="error" variant="outlined">
  106. 該密碼與您輸入的確認密碼不一致
  107. </v-alert>
  108. <p class="text-center">
  109. {{ t("haveAccount") }}
  110. <router-link to="/login"> {{ t("login") }}</router-link>
  111. </p>
  112. <v-btn
  113. rounded="pill"
  114. color="primary"
  115. @click.prevent="submit"
  116. class="login-btn"
  117. >
  118. {{ t("registerLink") }}
  119. </v-btn>
  120. <section
  121. class="mt-5 d-flex align-center justify-center dialog-content"
  122. >
  123. <p>
  124. {{ t("privacy_term_1") }}
  125. <v-dialog v-model="dialog" max-width="700" scrollable>
  126. <template v-slot:activator="{ props }">
  127. <a
  128. href="javascript:;"
  129. color="primary"
  130. v-bind="props"
  131. class="ms-1"
  132. >
  133. {{ t("privacy_term_2") }}
  134. </a>
  135. </template>
  136. <v-card class="terms-card">
  137. <v-card-title>
  138. <v-spacer></v-spacer>
  139. <v-btn icon @click="dialog = false">
  140. <v-icon icon="md:close"></v-icon>
  141. </v-btn>
  142. </v-card-title>
  143. <v-card-text>
  144. <TOS/>
  145. </v-card-text>
  146. </v-card>
  147. </v-dialog>
  148. </p>
  149. </section>
  150. </v-form>
  151. </v-col>
  152. </v-row>
  153. </v-container>
  154. </template>
  155. <style lang="scss">
  156. .dialog-content {
  157. display: flex;
  158. align-items: center;
  159. justify-content: center;
  160. font-size: 13px;
  161. letter-spacing: 1px;
  162. .v-btn {
  163. &:hover > .v-btn__overlay {
  164. opacity: 0;
  165. }
  166. &:hover > .v-btn__content {
  167. color: rgba(234, 84, 19, 0.8);
  168. }
  169. }
  170. .v-btn__content {
  171. font-size: 14px;
  172. font-weight: bold;
  173. }
  174. }
  175. .terms-card {
  176. margin: auto;
  177. font-size: 16px;
  178. ul {
  179. padding: 20px;
  180. }
  181. .v-card-title {
  182. display: flex;
  183. .v-btn {
  184. box-shadow: none;
  185. }
  186. }
  187. .v-card-text {
  188. padding: 0px 50px 50px !important;
  189. }
  190. }
  191. </style>