index.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <template>
  2. <div class="wrapper">
  3. <img
  4. class="logo"
  5. src="./image/logo@2x.png" alt="">
  6. <ul class="form-wrap">
  7. <li>
  8. <label>
  9. <span
  10. v-for="(str, index) in '+86'"
  11. :key="index">{{ str }}</span>
  12. </label>
  13. <div class="value-wrap">
  14. <input
  15. type="tel"
  16. placeholder="请输入手机号码"
  17. v-myBlur
  18. v-model.trim="postData.phone"
  19. @input="funLimitLength">
  20. </div>
  21. </li>
  22. <li>
  23. <div class="value-wrap">
  24. <input
  25. type="tel"
  26. placeholder="请输入短信验证码"
  27. v-myBlur
  28. v-model.trim="postData.code"
  29. @input="funLimitLength">
  30. </div>
  31. <button
  32. class="get-code"
  33. @click="funGetCode">{{[0, 60].includes(numCount) ? '获取验证码' : numCount + '秒'}}
  34. </button>
  35. </li>
  36. </ul>
  37. <button
  38. class="submit"
  39. @click="funSubmit">登 录
  40. </button>
  41. <div class="footer">
  42. <van-checkbox
  43. v-model="checked"
  44. checked-color="#D32323"></van-checkbox>
  45. <p class="tip-text">
  46. <span
  47. class="label"
  48. v-for="(str, index) in '登录听邦即代表您已同意'"
  49. :key="'a' + index">{{ str }}</span>
  50. <span
  51. class="value"
  52. v-for="(str, index) in '《用户协议》'"
  53. :key="'b' + index">{{ str }}</span>
  54. <span
  55. class="label">与</span>
  56. <span
  57. class="value"
  58. v-for="(str, index) in '《隐私协议》'"
  59. :key="'c' + index">{{ str }}</span>
  60. </p>
  61. </div>
  62. </div>
  63. </template>
  64. <script>
  65. import { Toast, Checkbox } from 'vant'
  66. import { sendSMS } from '../api/common'
  67. import { login } from './api'
  68. import { isMobile, isSmscode } from '../utils/validate'
  69. import { clearLoginInfo } from '../utils'
  70. export default {
  71. name: 'login',
  72. components: {
  73. 'van-checkbox': Checkbox
  74. },
  75. data () {
  76. return {
  77. postData: {
  78. phone: '',
  79. code: ''
  80. },
  81. numCount: 60,
  82. timer: null,
  83. arrErrorList: [],
  84. checked: false
  85. }
  86. },
  87. async mounted () {
  88. await this.$nextTick()
  89. },
  90. methods: {
  91. funLimitLength () {
  92. const { phone, code } = this.postData
  93. this.postData.phone = phone.length > 11 ? phone.slice(0, 11) : phone
  94. this.postData.code = code.length > 6 ? code.slice(0, 6) : code
  95. },
  96. funCutDown () {
  97. clearInterval(this.timer)
  98. this.timer = setInterval(() => {
  99. if (this.numCount === 0) {
  100. clearInterval(this.timer)
  101. this.numCount = 0
  102. return
  103. }
  104. this.numCount--
  105. }, 1000)
  106. },
  107. // 获取验证码
  108. async funGetCode () {
  109. const numCount = this.numCount
  110. const { phone } = this.postData
  111. if (numCount < 60 && numCount > 0) {
  112. return
  113. }
  114. this.numCount = 60
  115. if (!isMobile(phone)) {
  116. Toast('请输入手机号码')
  117. return
  118. }
  119. this.funCutDown()
  120. try {
  121. const { status, msg } = await sendSMS(phone)
  122. if (status) {
  123. Toast('发送成功')
  124. } else {
  125. Toast(msg)
  126. clearInterval(this.timer)
  127. this.numCount = 60
  128. }
  129. } catch (err) {
  130. clearInterval(this.timer)
  131. this.numCount = 60
  132. }
  133. },
  134. verifyData () {
  135. const { phone, code } = this.postData
  136. this.arrErrorList = []
  137. if (!isMobile(phone)) {
  138. this.arrErrorList.push('请输入手机号码')
  139. }
  140. if (!isSmscode(code)) {
  141. this.arrErrorList.push('请输入验证码')
  142. }
  143. if (!this.checked) {
  144. this.arrErrorList.push('请勾选用户协议及隐私政策')
  145. }
  146. return this.arrErrorList.length <= 0
  147. },
  148. async funSubmit () {
  149. const { phone, code, msg } = this.postData
  150. if (!this.verifyData()) {
  151. Toast({
  152. message: this.arrErrorList[0],
  153. forbidClick: true
  154. })
  155. return
  156. }
  157. const myToast = Toast.loading({
  158. message: '提交中...',
  159. duration: 1000 * 100,
  160. forbidClick: true
  161. })
  162. try {
  163. const { status, data } = await login(phone, code)
  164. myToast.clear()
  165. if (status) {
  166. const { token } = data
  167. clearLoginInfo()
  168. this.$nextTick(() => {
  169. this.$store.commit('common/UPDATE_PHONE', phone)
  170. this.$store.commit('common/UPDATE_TOKEN', token)
  171. this.$cookie.set('afhousephone', phone, '30d')
  172. this.$cookie.set('afhousetoken', token, '30d')
  173. })
  174. Toast({
  175. type: 'success',
  176. message: '登录成功',
  177. forbidClick: true,
  178. onClose: () => {
  179. this.$router.go(-1)
  180. }
  181. })
  182. return
  183. }
  184. Toast(msg)
  185. } catch (err) {
  186. myToast.clear()
  187. }
  188. }
  189. }
  190. }
  191. </script>
  192. <style lang="scss" scoped>
  193. .wrapper {
  194. position: relative;
  195. left: 0;
  196. top: 0;
  197. display: flex;
  198. flex-direction: column;
  199. justify-content: center;
  200. align-items: center;
  201. width: 100%;
  202. height: 100%;
  203. padding-bottom: 50px;
  204. background: linear-gradient(180deg, #000000 0%, #272727 100%);
  205. }
  206. .logo {
  207. width: 121px;
  208. height: 138px;
  209. }
  210. .form-wrap {
  211. li {
  212. position: relative;
  213. left: 0;
  214. top: 0;
  215. display: flex;
  216. align-items: flex-start;
  217. width: 327px;
  218. padding: 13px 0;
  219. margin-top: 12px;
  220. border-bottom: 1px solid #2A2929;
  221. border-radius: 4px;
  222. &:nth-of-type(1) {
  223. margin-top: 53px;
  224. }
  225. }
  226. label {
  227. display: flex;
  228. margin-right: 9px;
  229. span {
  230. line-height: 22px;
  231. font-size: 16px;
  232. font-weight: 500;
  233. color: #A6A2A2;
  234. &.label-code:nth-of-type(5), {
  235. visibility: hidden;
  236. }
  237. }
  238. }
  239. .value-wrap {
  240. flex: 1;
  241. display: flex;
  242. }
  243. input,
  244. textarea {
  245. width: 100%;
  246. min-height: 20px;
  247. padding-top: 2px;
  248. line-height: 20px;
  249. font-size: 15px;
  250. color: #fff;
  251. word-break: break-all;
  252. resize: none;
  253. outline: 0 none;
  254. overflow: hidden;
  255. background: transparent;
  256. -webkit-text-fill-color: #fff;
  257. opacity: 1;
  258. &::-webkit-input-placeholder {
  259. color: #A6A2A2;
  260. -webkit-text-fill-color: #A6A2A2;
  261. opacity: 1;
  262. }
  263. }
  264. .get-code {
  265. @include vertical-center;
  266. right: 0;
  267. z-index: 1;
  268. display: block;
  269. min-width: 87px;
  270. padding: 6px;
  271. line-height: 14px;
  272. font-size: 12px;
  273. font-weight: 500;
  274. color: #C9A585;
  275. background: #D32323;
  276. border-radius: 14px;
  277. }
  278. }
  279. .submit {
  280. width: 343px;
  281. height: 50px;
  282. margin-top: 39px;
  283. background: #D32323;
  284. border-radius: 25px;
  285. font-size: 18px;
  286. color: #FFFFFF;
  287. line-height: 50px;
  288. letter-spacing: 1px;
  289. }
  290. .footer {
  291. position: absolute;
  292. left: 0;
  293. bottom: 24px;
  294. z-index: 1;
  295. display: flex;
  296. align-items: center;
  297. width: 100%;
  298. justify-content: center;
  299. .tip-text {
  300. display: flex;
  301. align-items: center;
  302. margin-left: 6px;
  303. span {
  304. font-size: 12px;
  305. font-family: STSongti-SC-Bold, STSongti-SC;
  306. font-weight: bold;
  307. color: #848484;
  308. line-height: 17px;
  309. &.value {
  310. color: #D32323;
  311. }
  312. }
  313. }
  314. }
  315. </style>