main.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. <template>
  2. <view class="container">
  3. <!-- 页面头部 -->
  4. <view class="header">
  5. <view class="title">
  6. <text>手机号登录</text>
  7. </view>
  8. <view class="sub-title">
  9. <text>未注册的手机号登录后将自动注册</text>
  10. </view>
  11. </view>
  12. <!-- 表单 -->
  13. <view class="login-form">
  14. <!-- 手机号 -->
  15. <view class="form-item">
  16. <input class="form-item--input" type="number" v-model="mobile" maxlength="11" placeholder="请输入手机号码" />
  17. </view>
  18. <!-- 图形验证码 -->
  19. <view class="form-item">
  20. <input class="form-item--input" type="text" v-model="captchaCode" maxlength="5" placeholder="请输入图形验证码" />
  21. <view class="form-item--parts">
  22. <view class="captcha" @click="getCaptcha()">
  23. <image class="image" :src="captcha.base64"></image>
  24. </view>
  25. </view>
  26. </view>
  27. <!-- 短信验证码 -->
  28. <view class="form-item">
  29. <input class="form-item--input" type="number" v-model="smsCode" maxlength="6" placeholder="请输入短信验证码" />
  30. <view class="form-item--parts">
  31. <view class="captcha-sms" @click="handelSmsCaptcha()">
  32. <text v-if="!smsState" class="activate">获取验证码</text>
  33. <text v-else class="un-activate">重新发送({{ times }})秒</text>
  34. </view>
  35. </view>
  36. </view>
  37. <!-- 登录按钮 -->
  38. <view class="login-button" @click="handleLogin">
  39. <text>登录</text>
  40. </view>
  41. </view>
  42. </view>
  43. </template>
  44. <script>
  45. import store from '@/store'
  46. import * as LoginApi from '@/api/login'
  47. import { throttle, debounce } from '@/utils/util'
  48. import * as Verify from '@/utils/verify'
  49. // 倒计时时长(秒)
  50. const times = 60
  51. // 表单验证场景
  52. const GET_CAPTCHA = 10
  53. const SUBMIT_LOGIN = 20
  54. export default {
  55. props: {
  56. // 是否存在第三方用户信息
  57. isParty: {
  58. type: Boolean,
  59. default: () => false
  60. },
  61. // 第三方用户信息数据
  62. partyData: {
  63. type: Object
  64. }
  65. },
  66. data() {
  67. return {
  68. // 正在加载
  69. isLoading: false,
  70. // 图形验证码信息
  71. captcha: {},
  72. // 短信验证码发送状态
  73. smsState: false,
  74. // 倒计时
  75. times,
  76. // 手机号
  77. mobile: '',
  78. // 图形验证码
  79. captchaCode: '',
  80. // 短信验证码
  81. smsCode: ''
  82. }
  83. },
  84. /**
  85. * 生命周期函数--监听页面加载
  86. */
  87. created() {
  88. // 获取图形验证码
  89. this.getCaptcha()
  90. },
  91. methods: {
  92. // 获取图形验证码
  93. getCaptcha() {
  94. const app = this
  95. LoginApi.captcha()
  96. .then(result => app.captcha = result.data)
  97. },
  98. // 点击发送短信验证码
  99. handelSmsCaptcha() {
  100. const app = this
  101. if (!app.isLoading && !app.smsState && app.formValidation(GET_CAPTCHA)) {
  102. app.sendSmsCaptcha()
  103. app.getCaptcha()
  104. }
  105. },
  106. // 表单验证
  107. formValidation(scene = GET_CAPTCHA) {
  108. const app = this
  109. // 验证获取短信验证码
  110. if (scene === GET_CAPTCHA) {
  111. if (!app.validteMobile(app.mobile) || !app.validteCaptchaCode(app.captchaCode)) {
  112. return false
  113. }
  114. }
  115. // 验证提交登录
  116. if (scene === SUBMIT_LOGIN) {
  117. if (!app.validteMobile(app.mobile) || !app.validteSmsCode(app.smsCode)) {
  118. return false
  119. }
  120. }
  121. return true
  122. },
  123. // 验证手机号
  124. validteMobile(str) {
  125. if (Verify.isEmpty(str)) {
  126. this.$toast('请先输入手机号')
  127. return false
  128. }
  129. if (!Verify.isMobile(str)) {
  130. this.$toast('请输入正确格式的手机号')
  131. return false
  132. }
  133. return true
  134. },
  135. // 验证图形验证码
  136. validteCaptchaCode(str) {
  137. if (Verify.isEmpty(str)) {
  138. this.$toast('请先输入图形验证码')
  139. return false
  140. }
  141. return true
  142. },
  143. // 验证短信验证码
  144. validteSmsCode(str) {
  145. if (Verify.isEmpty(str)) {
  146. this.$toast('请先输入短信验证码')
  147. return false
  148. }
  149. return true
  150. },
  151. // 请求发送短信验证码接口
  152. sendSmsCaptcha() {
  153. const app = this
  154. app.isLoading = true
  155. LoginApi.sendSmsCaptcha({
  156. form: {
  157. captchaKey: app.captcha.key,
  158. captchaCode: app.captchaCode,
  159. mobile: app.mobile
  160. }
  161. })
  162. .then(result => {
  163. // 显示发送成功
  164. app.$toast(result.message)
  165. // 执行定时器
  166. app.timer()
  167. })
  168. .finally(() => app.isLoading = false)
  169. },
  170. // 执行定时器
  171. timer() {
  172. const app = this
  173. app.smsState = true
  174. const inter = setInterval(() => {
  175. app.times = app.times - 1
  176. if (app.times <= 0) {
  177. app.smsState = false
  178. app.times = times
  179. clearInterval(inter)
  180. }
  181. }, 1000)
  182. },
  183. // 点击登录
  184. handleLogin() {
  185. const app = this
  186. if (!app.isLoading && app.formValidation(SUBMIT_LOGIN)) {
  187. app.submitLogin()
  188. }
  189. },
  190. // 确认登录
  191. submitLogin() {
  192. const app = this
  193. app.isLoading = true
  194. store.dispatch('Login', {
  195. smsCode: app.smsCode,
  196. mobile: app.mobile,
  197. isParty: app.isParty,
  198. partyData: app.partyData
  199. })
  200. .then(result => {
  201. // 显示登录成功
  202. app.$toast(result.message)
  203. // 跳转回原页面
  204. setTimeout(() => {
  205. app.onNavigateBack(1)
  206. }, 2000)
  207. })
  208. .catch(err => {
  209. if (err.result.data.isBack) {
  210. // 跳转回原页面
  211. setTimeout(() => {
  212. app.onNavigateBack(1)
  213. }, 2000)
  214. }
  215. })
  216. .finally(() => app.isLoading = false)
  217. },
  218. /**
  219. * 登录成功-跳转回原页面
  220. */
  221. onNavigateBack(delta) {
  222. uni.navigateBack({
  223. delta: Number(delta || 1)
  224. })
  225. }
  226. }
  227. }
  228. </script>
  229. <style lang="scss" scoped>
  230. .container {
  231. padding: 100rpx 60rpx;
  232. min-height: 100vh;
  233. background-color: #fff;
  234. }
  235. // 页面头部
  236. .header {
  237. margin-bottom: 50rpx;
  238. .title {
  239. color: #191919;
  240. font-size: 50rpx;
  241. }
  242. .sub-title {
  243. margin-top: 20rpx;
  244. color: #b3b3b3;
  245. font-size: 25rpx;
  246. }
  247. }
  248. // 输入框元素
  249. .form-item {
  250. display: flex;
  251. padding: 18rpx;
  252. border-bottom: 1rpx solid #f3f1f2;
  253. margin-bottom: 25rpx;
  254. height: 96rpx;
  255. &--input {
  256. font-size: 26rpx;
  257. letter-spacing: 1rpx;
  258. flex: 1;
  259. height: 100%;
  260. }
  261. &--parts {
  262. min-width: 100rpx;
  263. height: 100%;
  264. }
  265. // 图形验证码
  266. .captcha {
  267. height: 100%;
  268. .image {
  269. display: block;
  270. width: 192rpx;
  271. height: 100%;
  272. }
  273. }
  274. // 短信验证码
  275. .captcha-sms {
  276. font-size: 22rpx;
  277. line-height: 50rpx;
  278. padding-right: 20rpx;
  279. .activate {
  280. color: #cea26a;
  281. }
  282. .un-activate {
  283. color: #9e9e9e;
  284. }
  285. }
  286. }
  287. // 登录按钮
  288. .login-button {
  289. width: 100%;
  290. height: 86rpx;
  291. margin-top: 70rpx;
  292. // background: #cea26a;
  293. background: linear-gradient(to right, #ecb53c, #ff9211);
  294. text-align: center;
  295. line-height: 86rpx;
  296. color: #fff;
  297. border-radius: 80rpx;
  298. box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.1);
  299. letter-spacing: 5rpx;
  300. }
  301. // 微信授权登录
  302. .wechat-auth {
  303. display: flex;
  304. justify-content: center;
  305. margin-top: 40rpx;
  306. .icon {
  307. width: 38rpx;
  308. height: 38rpx;
  309. margin-right: 15rpx;
  310. }
  311. .title {
  312. font-size: 28rpx;
  313. color: #666666;
  314. }
  315. }
  316. </style>