flameLogin.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <div class="box" :style="{'background-image': 'url(' + logoBgUrl + ')'}">
  3. <div class="content">
  4. <div class="login-content">
  5. <v-card height="392px" class="carousel mr-3" style="width: 792px; border-radius: 8px;">
  6. <v-carousel show-arrows="hover" cycle :model-value="0">
  7. <v-carousel-item v-for="(item, i) in carouselList" :key="i" @click="handleClick(item)">
  8. <div style="height: 392px; overflow: hidden;" :class="{'cursor-pointer': item.link}">
  9. <v-img :src="item.img" :lazy-src="item.src" cover style="height: 100%; overflow: hidden;">
  10. <template v-slot:placeholder>
  11. <v-row align="center" class="fill-height ma-0" justify="center">
  12. <v-progress-circular color="grey-lighten-5" indeterminate></v-progress-circular>
  13. </v-row>
  14. </template>
  15. </v-img>
  16. </div>
  17. </v-carousel-item>
  18. </v-carousel>
  19. </v-card>
  20. <div class="login-card">
  21. <div class="login-tab">
  22. <v-tabs v-model="tab" align-tabs="center" color="primary" class="mb-10">
  23. <v-tab :value="0">老师手机验证码登录</v-tab>
  24. </v-tabs>
  25. <phoneFrom ref="phoneRef" openVerify @handleEnter="handleLogin"></phoneFrom>
  26. </div>
  27. <div class="font-size-14">
  28. <span class="float-right color-error cursor-pointer border-bottom-error" @click="router.push('/register/school')">还没有登录账户?去注册</span>
  29. </div>
  30. <v-btn :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click.stop="handleLogin">
  31. {{ $t('login.login') }}
  32. </v-btn>
  33. <div class="login-tips mt-3">
  34. <v-icon v-if="isAgree" size="25" color="primary" class="mr-1" @click="isAgree = !isAgree">mdi-check-circle</v-icon>
  35. <v-icon v-else size="25" color="grey" class="mr-1" @click="isAgree = !isAgree">mdi-circle-outline</v-icon>
  36. {{ $t('login.agreeLogin') }}
  37. <span class="color" style="cursor: pointer;" @click="windowOpen('/userAgreement')"> [{{ $t('login.userAgreement') }}] </span>和
  38. <span class="color" style="cursor: pointer;" @click="windowOpen('/privacyPolicy')">[{{ $t('login.privacyPolicy') }}]</span>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. <navBar :showLoginBtn="false" class="navBar"></navBar>
  44. </div>
  45. <Verify
  46. ref="verify"
  47. captchaType="blockPuzzle"
  48. :imgSize="{ width: '400px', height: '200px' }"
  49. mode="pop"
  50. @success="verifySuccess"
  51. />
  52. </template>
  53. <script setup>
  54. defineOptions({ name: 'login-index' })
  55. import { ref } from 'vue'
  56. import phoneFrom from '@/components/VerificationCode'
  57. import { useUserStore } from '@/store/user'
  58. import { useRouter } from 'vue-router'
  59. import { useI18n } from '@/hooks/web/useI18n'
  60. import { getWebContent } from '@/api/common'
  61. import Snackbar from '@/plugins/snackbar'
  62. import Confirm from '@/plugins/confirm'
  63. import navBar from '@/layout/personal/navBar.vue'
  64. import about from '@/views/about/index.vue'
  65. import Verify from '@/components/Verifition'
  66. // 获取轮播图、背景图
  67. const logoBgUrl = ref('')
  68. const preferred = ref({})
  69. const carouselList = ref([])
  70. const getSystemWebContent = async () => {
  71. const data = await getWebContent()
  72. logoBgUrl.value = data.pcLoginBackground && data.pcLoginBackground.length ? data.pcLoginBackground[0].img : 'https://minio.menduner.com/dev/menduner/login-bgc.jpg'
  73. carouselList.value = data.pcLoginCarousel || []
  74. preferred.value = data.appPreferredGroup || {}
  75. }
  76. getSystemWebContent()
  77. const handleClick = (item) => {
  78. if (!item.link) return
  79. if (item.link.includes('http')) return window.open(item.link)
  80. // 优选集团
  81. if (preferred.value && Object.keys(preferred.value).length > 0 && preferred.value[item.link]) window.open(`/recruit/personal/advertisement/${item.link}`)
  82. else window.open(`/recruit/personal/company/details/${item.link}?key=briefIntroduction`)
  83. }
  84. const { t } = useI18n()
  85. const router = useRouter()
  86. const tab = ref(0)
  87. const isAgree = ref(false)
  88. // 验证码登录
  89. const phoneRef = ref()
  90. const loginLoading = ref(false)
  91. const userStore = useUserStore()
  92. const handleLogin = async () => {
  93. const { valid } = await phoneRef.value.phoneForm.validate()
  94. if (!valid) return
  95. if (!isAgree.value) return Snackbar.warning('请阅读并勾选底部协议')
  96. const params = {
  97. ...phoneRef.value.loginData,
  98. chooseRole: false,
  99. schoolRegister: true
  100. }
  101. loginLoading.value = true
  102. try {
  103. if (!params.captchaVerification && captchaStr.value) params.captchaVerification = captchaStr.value
  104. if (!params.captchaVerification) {
  105. getCode() // 验证码组件
  106. return
  107. }
  108. await userStore.handleSmsLogin(params)
  109. // Snackbar.success(t('login.loginSuccess'))
  110. } catch (err) {
  111. console.log(err)
  112. captchaStr.value = '' // 清空人机验证
  113. if (!err.code || (err?.message && err.message.includes('timeout'))) return
  114. // 登录未注册过的账号跳转注册
  115. const text = err.code === 1100016002 ? '您的手机号还未注册过' : '您的邮箱还未注册过'
  116. Confirm('系统提示', `${text},去注册?`, {
  117. cancelCallback: true
  118. }).then(() => {
  119. localStorage.setItem('loginAccount', phoneRef.value.loginData.phone)
  120. router.push('/register/school')
  121. }).catch(() => {})
  122. } finally {
  123. loginLoading.value = false
  124. }
  125. }
  126. // 获取验证码
  127. const verify = ref()
  128. const getCode = async () => {
  129. // 弹出验证码 // 已开启:则展示验证码;只有完成验证码的情况,才进行登录
  130. verify.value.show()
  131. }
  132. const captchaStr = ref('')
  133. const verifySuccess = (params) => {
  134. captchaStr.value = params.captchaVerification
  135. handleLogin()
  136. }
  137. const windowOpen = (url) => {
  138. if (url) window.open(url)
  139. }
  140. </script>
  141. <style lang="scss" scoped>
  142. .box {
  143. position: relative;
  144. width: 100%;
  145. height: 100vh;
  146. background-size: cover;
  147. overflow: hidden;
  148. .navBar {
  149. position: absolute;
  150. top: 0;
  151. }
  152. }
  153. .content {
  154. width: 100%;
  155. height: 100%;
  156. overflow-y: auto;
  157. }
  158. .login-content {
  159. display: flex;
  160. align-items: center;
  161. justify-content: center;
  162. width: 100%;
  163. height: 100vh;
  164. // height: calc(100vh - 50px);
  165. // margin-top: 50px;
  166. }
  167. .login-change {
  168. position: absolute;
  169. top: 0;
  170. right: 0;
  171. margin: 15px 44px;
  172. border-bottom: 1px solid orange;
  173. color: orange;
  174. cursor: pointer;
  175. font-weight: 400;
  176. &:hover {
  177. color: #fbb93e;
  178. }
  179. }
  180. .login-card {
  181. position: relative;
  182. width: 450px;
  183. background-color: #fff;
  184. border-radius: 8px;
  185. padding: 36px 50px;
  186. }
  187. .left {
  188. display: flex;
  189. }
  190. .login-tips {
  191. width: 100%;
  192. font-size: 12px;
  193. display: flex;
  194. justify-content: center;
  195. align-items: center;
  196. }
  197. .tips:hover {
  198. border-bottom: 1px solid #666;
  199. }
  200. .color {
  201. color: var(--v-primary-base);
  202. }
  203. .carousel {
  204. :deep(.v-window) {
  205. height: 392px !important;
  206. }
  207. }
  208. </style>