index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. <template>
  2. <div class="simple-login">
  3. <van-overlay :show="show" @click="show = false">
  4. <div class="wrapper flex justify-center items-center" @click.stop>
  5. <div class="block flex items-center flex-col py-6">
  6. <div class="close" @click="onClose"></div>
  7. <div class="title pb-6">
  8. {{
  9. formType === 'login'
  10. ? '登录'
  11. : formType === 'register'
  12. ? '注册'
  13. : '忘记密码'
  14. }}
  15. </div>
  16. <div class="form">
  17. <div class="form-item mb-4">
  18. <input
  19. type="text"
  20. placeholder="手机号"
  21. v-model="formData.mobile"
  22. maxlength="11"
  23. />
  24. </div>
  25. <div class="form-item mb-4 code" v-if="formType !== 'login'">
  26. <input
  27. type="text"
  28. placeholder="验证码"
  29. class="code"
  30. v-model="formData.verifyCode"
  31. maxlength="6"
  32. />
  33. <span class="send" @click="onSend">{{ sendCodeBtnText }}</span>
  34. </div>
  35. <div class="form-item mb-4">
  36. <input
  37. type="password"
  38. placeholder="密码"
  39. v-model="formData.password"
  40. maxlength="11"
  41. />
  42. </div>
  43. <div class="form-item mb-4" v-if="formType !== 'login'">
  44. <input
  45. type="password"
  46. placeholder="确认密码"
  47. v-model="formData.confirmPwd"
  48. />
  49. </div>
  50. <div
  51. class="submit"
  52. @click="onSubmit"
  53. :class="{ disabled: disabled }"
  54. >
  55. {{ submitText }}
  56. </div>
  57. <div
  58. class="flex justify-between control mt-2"
  59. v-if="formType === 'login'"
  60. >
  61. <span class="forget" @click="onForgetPwd">忘记密码</span>
  62. <span class="regist" @click="onRegister">立即注册</span>
  63. </div>
  64. </div>
  65. </div>
  66. </div>
  67. </van-overlay>
  68. </div>
  69. </template>
  70. <script>
  71. import { mapGetters } from 'vuex'
  72. import { isMobile } from '@/utils/validator'
  73. export default {
  74. name: 'simple-login',
  75. props: {
  76. type: {
  77. type: String,
  78. default: 'login',
  79. },
  80. },
  81. data() {
  82. return {
  83. formType: 'login',
  84. show: false,
  85. sendStatus: 0,
  86. formData: {
  87. authUserId: '',
  88. mobile: '',
  89. verifyCode: '',
  90. password: '',
  91. confirmPwd: '',
  92. },
  93. timer: null,
  94. }
  95. },
  96. computed: {
  97. ...mapGetters(['loginVisiable', 'authUserId', 'routePrefix']),
  98. sendCodeBtnText() {
  99. return this.sendStatus === 0
  100. ? '发送验证码'
  101. : `再次发送${this.sendStatus}s`
  102. },
  103. submitText() {
  104. return this.formType === 'login'
  105. ? '登录'
  106. : this.formType === 'forget'
  107. ? '确定'
  108. : '提交'
  109. },
  110. disabled() {
  111. return (
  112. (this.formType === 'login' &&
  113. (!this.formData.mobile || !this.formData.password)) ||
  114. ((this.formType === 'register' || this.formType === 'forget') &&
  115. (!this.formData.mobile ||
  116. !this.formData.password ||
  117. !this.formData.verifyCode ||
  118. !this.formData.confirmPwd))
  119. )
  120. },
  121. },
  122. created() {
  123. this.formType = this.type
  124. },
  125. watch: {
  126. loginVisiable() {
  127. this.show = this.loginVisiable
  128. },
  129. type: {
  130. handler: function (nval) {
  131. this.formType = nval
  132. console.log(nval)
  133. },
  134. immediate: true,
  135. },
  136. },
  137. methods: {
  138. // 忘记密码
  139. onForgetPwd() {
  140. this.$emit('click', 'forget')
  141. },
  142. // 立即注册
  143. onRegister() {
  144. this.$emit('click', 'register')
  145. },
  146. async onSubmit() {
  147. // 验证手机号是否合法
  148. if (!isMobile(this.formData.mobile)) {
  149. this.$toast('请输入正确的手机号')
  150. return
  151. }
  152. if (this.formType === 'register') {
  153. this.onRegisterSubmit()
  154. } else if (this.formType === 'forget') {
  155. this.onForgetSubmit()
  156. } else {
  157. this.onLoginSubmit()
  158. }
  159. },
  160. // 忘记密码
  161. async onForgetSubmit() {
  162. if (!this.formData.verifyCode) {
  163. this.$toast('请输入验证码')
  164. return
  165. }
  166. if (this.formData.password.length < 6) {
  167. this.$toast('密码长度需大于6位')
  168. return
  169. }
  170. if (this.formData.password !== this.formData.confirmPwd) {
  171. this.$toast('两次输入的密码不一致')
  172. return
  173. }
  174. try {
  175. await this.$http.api.clubUserReset({
  176. mobile: this.formData.mobile,
  177. verifyCode: this.formData.verifyCode,
  178. password: this.formData.password,
  179. authUserId: this.authUserId,
  180. })
  181. this.$toast('密码修改成功')
  182. this.$emit('click', 'login')
  183. } catch (error) {
  184. console.log(error)
  185. }
  186. },
  187. // 用户注册
  188. async onRegisterSubmit() {
  189. if (!this.formData.verifyCode) {
  190. this.$toast('请输入验证码')
  191. return
  192. }
  193. if (this.formData.password.length < 6) {
  194. this.$toast('密码长度需大于6位')
  195. return
  196. }
  197. if (this.formData.password !== this.formData.confirmPwd) {
  198. this.$toast('两次输入的密码不一致')
  199. return
  200. }
  201. try {
  202. await this.$http.api.clubUserRegister({
  203. mobile: this.formData.mobile,
  204. verifyCode: this.formData.verifyCode,
  205. password: this.formData.password,
  206. authUserId: this.authUserId,
  207. })
  208. this.$toast('注册成功,请登录')
  209. this.$emit('click', 'login')
  210. } catch (error) {
  211. console.log(error)
  212. this.$toast(error.msg)
  213. }
  214. },
  215. // 用户登录
  216. async onLoginSubmit() {
  217. if (!this.formData.password) {
  218. this.$toast('密码不能为空')
  219. return
  220. }
  221. try {
  222. const res = await this.$http.api.clubUserLogin({
  223. mobile: this.formData.mobile,
  224. password: this.formData.password,
  225. authUserId: this.authUserId,
  226. })
  227. this.login(res)
  228. } catch (error) {
  229. console.log(error)
  230. this.$toast(error.msg)
  231. }
  232. },
  233. login(res) {
  234. this.$store.dispatch('user/login', res.data)
  235. this.$setStorage(this.routePrefix, 'userInfo', res.data)
  236. // 关闭登录窗口
  237. this.onClose()
  238. // this.$router.push(this.routePrefix)
  239. // const clubRegisterLink = this.$getStorage(
  240. // this.routePrefix,
  241. // 'club-register-link'
  242. // )
  243. // if (clubRegisterLink) {
  244. // this.$removeStorage(this.routePrefix, 'club-register-link')
  245. // this.$setStorage(this.routePrefix, 'bind-flag', true)
  246. // this.$router.push(clubRegisterLink)
  247. // } else {
  248. // this.$router.push(this.routePrefix)
  249. // }
  250. window.location.reload()
  251. // 重定向
  252. // const login_redicret = this.$getStorage(
  253. // this.routePrefix,
  254. // 'login_redicret'
  255. // )
  256. // if (login_redicret && login_redicret !== this.$route.path) {
  257. // this.$router.push(login_redicret)
  258. // }
  259. },
  260. // 关闭登录窗口
  261. onClose() {
  262. this.$store.commit('app/HIDE_LOGIN')
  263. this.formData.mobile = ''
  264. this.formData.verifyCode = ''
  265. this.formData.password = ''
  266. this.formData.confirmPwd = ''
  267. },
  268. async onSend() {
  269. if (this.sendStatus > 0) return
  270. // 验证手机号是否合法
  271. if (!isMobile(this.formData.mobile)) {
  272. this.$toast('请输入正确的手机号')
  273. return
  274. }
  275. try {
  276. // 发送验证码
  277. await this.$http.api.clubUserCodeSend({
  278. mobile: this.formData.mobile,
  279. authUserId: this.authUserId,
  280. type: this.formType === 'register' ? 1 : 2,
  281. })
  282. this.$toast('验证码已发送')
  283. // 开启倒计时
  284. this.countdown()
  285. } catch (error) {
  286. console.log(error)
  287. }
  288. },
  289. countdown() {
  290. this.sendStatus = 30
  291. this.timer = setInterval(() => {
  292. if (this.sendStatus === 0) {
  293. clearInterval(this.timer)
  294. return
  295. }
  296. this.sendStatus--
  297. }, 1000)
  298. },
  299. },
  300. }
  301. </script>
  302. <style scoped lang="scss">
  303. @media screen and (min-width: 768px) {
  304. .van-overlay {
  305. z-index: 20;
  306. }
  307. .wrapper {
  308. height: 100vh;
  309. .block {
  310. position: relative;
  311. width: 400px;
  312. background: #fff;
  313. .close {
  314. position: absolute;
  315. right: 16px;
  316. top: 16px;
  317. width: 24px;
  318. height: 24px;
  319. background: url(~assets/theme-images/common/pc-icon-close.png) center
  320. no-repeat;
  321. background-size: 24px 24px;
  322. cursor: pointer;
  323. }
  324. .title {
  325. font-size: 24px;
  326. color: #101010;
  327. }
  328. .form-item {
  329. position: relative;
  330. width: 326px;
  331. input {
  332. width: 326px;
  333. display: block;
  334. padding: 14px 16px;
  335. font-size: 14px;
  336. border: 1px solid #d8d8d8;
  337. box-sizing: border-box;
  338. &.code {
  339. width: 225px;
  340. }
  341. }
  342. .send {
  343. position: absolute;
  344. right: 0;
  345. top: 50%;
  346. transform: translateY(-50%);
  347. font-size: 16px;
  348. cursor: pointer;
  349. @include themify($themes) {
  350. color: themed('color');
  351. }
  352. }
  353. }
  354. .control {
  355. font-size: 14px;
  356. .forget,
  357. .regist {
  358. cursor: pointer;
  359. }
  360. .forget {
  361. color: #666;
  362. &:hover {
  363. @include themify($themes) {
  364. color: themed('color');
  365. }
  366. }
  367. }
  368. .regist {
  369. @include themify($themes) {
  370. color: themed('color');
  371. }
  372. }
  373. }
  374. .submit {
  375. width: 326px;
  376. height: 46px;
  377. font-size: 16px;
  378. color: #fff;
  379. text-align: center;
  380. line-height: 46px;
  381. transition: all 0.4s;
  382. cursor: pointer;
  383. border-radius: 4px;
  384. &.disabled {
  385. opacity: 0.5;
  386. cursor: not-allowed;
  387. }
  388. @include themify($themes) {
  389. background: themed('color');
  390. }
  391. &:hover {
  392. @include themify($themes) {
  393. background: themed('hover-color');
  394. }
  395. }
  396. }
  397. }
  398. }
  399. }
  400. @media screen and (max-width: 768px) {
  401. .van-overlay {
  402. z-index: 20;
  403. }
  404. .wrapper {
  405. height: 100vh;
  406. .block {
  407. position: relative;
  408. width: 76vw;
  409. background: #fff;
  410. .close {
  411. position: absolute;
  412. right: 2.4vw;
  413. top: 2.4vw;
  414. width: 5.6vw;
  415. height: 5.6vw;
  416. background: url(~assets/theme-images/common/h5-icon-close.png) center
  417. no-repeat;
  418. background-size: 4.8vw 4.8vw;
  419. cursor: pointer;
  420. }
  421. .title {
  422. font-size: 4.8vw;
  423. color: #101010;
  424. }
  425. .form-item {
  426. position: relative;
  427. width: 62vw;
  428. input {
  429. width: 62vw;
  430. display: block;
  431. padding: 1.8vw 2.4vw;
  432. font-size: 14px;
  433. border: 0.1vw solid #d8d8d8;
  434. box-sizing: border-box;
  435. &.code {
  436. width: 42.8vw;
  437. }
  438. }
  439. .send {
  440. position: absolute;
  441. right: 0;
  442. top: 50%;
  443. transform: translateY(-50%);
  444. font-size: 3.2vw;
  445. cursor: pointer;
  446. @include themify($themes) {
  447. color: themed('color');
  448. }
  449. }
  450. }
  451. .control {
  452. font-size: 3.2vw;
  453. .forget,
  454. .regist {
  455. cursor: pointer;
  456. }
  457. .forget {
  458. color: #666;
  459. &:hover {
  460. @include themify($themes) {
  461. color: themed('color');
  462. }
  463. }
  464. }
  465. .regist {
  466. @include themify($themes) {
  467. color: themed('color');
  468. }
  469. }
  470. }
  471. .submit {
  472. width: 62vw;
  473. height: 8.8vw;
  474. font-size: 3.2vw;
  475. color: #fff;
  476. text-align: center;
  477. line-height: 8.8vw;
  478. transition: all 0.4s;
  479. border-radius: 4px;
  480. &.disabled {
  481. opacity: 0.5;
  482. cursor: not-allowed;
  483. }
  484. @include themify($themes) {
  485. background: themed('color');
  486. }
  487. }
  488. }
  489. }
  490. }
  491. </style>