login.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <template>
  2. <view class="wrap">
  3. <view class="logo">
  4. <image :src="topImage || '/static/imgs/login_top_loading.jpg'" mode="widthFix"></image>
  5. </view>
  6. <view class="main">
  7. <template v-if="loginMethod === 'name_code'">
  8. <view class="form">
  9. <view class="b-row">
  10. <view class="b-input">
  11. <view class="s-icon iconfont icon-account"></view>
  12. <input type="text" :value="form.name" @input="onInputName" placeholder="请输入成员姓名" />
  13. </view>
  14. </view>
  15. <view class="b-row">
  16. <view class="b-input">
  17. <view class="s-icon iconfont icon-password"></view>
  18. <input type="text" :value="form.code" @input="onInputCode" placeholder="请输入登录码" />
  19. </view>
  20. </view>
  21. </view>
  22. <view class="submit" :class="{ disable: disable.submit }" @click="onLoginByNameCode">立即登录</view>
  23. </template>
  24. <template v-else-if="loginMethod === 'number_code'">
  25. <view class="form">
  26. <view class="b-row">
  27. <view class="b-input">
  28. <view class="s-icon iconfont icon-card"></view>
  29. <input type="text" :value="form.number" @input="onInputNumber" placeholder="请输入成员编号" />
  30. </view>
  31. </view>
  32. <view class="b-row">
  33. <view class="b-input">
  34. <view class="s-icon iconfont icon-password"></view>
  35. <input type="text" :value="form.code" @input="onInputCode" placeholder="请输入登录码" />
  36. </view>
  37. </view>
  38. </view>
  39. <view class="submit" :class="{ disable: disable.submit }" @click="onLoginByNumberCode">立即登录</view>
  40. </template>
  41. <template v-else-if="loginMethod === 'phone_captcha'">
  42. <view class="form">
  43. <view class="b-row">
  44. <view class="b-input">
  45. <view class="s-icon iconfont icon-account"></view>
  46. <input type="text" :value="form.phone" @input="onInputPhone" placeholder="请输入手机号" />
  47. </view>
  48. </view>
  49. <view class="b-row">
  50. <view class="b-input">
  51. <view class="s-icon iconfont icon-password"></view>
  52. <input type="text" :value="form.captcha" @input="onInputCaptcha" placeholder="请输入验证码" />
  53. <view class="s-captcha" :class="{ disable: captcha.second > 0 }" @click="onPhoneCaptcha">
  54. <text v-if="!captcha.retry && !captcha.second">获取验证码</text>
  55. <text v-else-if="captcha.second > 0">重新获取 {{ captcha.second }}秒</text>
  56. <text v-else-if="captcha.retry">重新获取</text>
  57. </view>
  58. </view>
  59. </view>
  60. </view>
  61. <view class="submit" :class="{ disable: disable.submit }" @click="onLoginByPhoneCaptcha">立即登录</view>
  62. </template>
  63. <!-- #ifdef MP-WEIXIN -->
  64. <button
  65. class="submit f-wechat open-data-btn"
  66. open-type="getPhoneNumber"
  67. @getphonenumber="onGetPhoneNumber"
  68. v-if="loginMethods.length === 1 && loginMethod === 'wechat_phone'"
  69. >
  70. 微信快捷登录
  71. </button>
  72. <!-- #endif -->
  73. <view class="other" v-if="loginMethods.length >= 3 || (loginMethods.length === 2 && loginMethods.indexOf('wechat_phone') === -1)">
  74. <view class="split">
  75. <view class="s-line"></view>
  76. <view class="s-text">其他登录方式</view>
  77. <view class="s-line"></view>
  78. </view>
  79. <view class="login-method">
  80. <view class="b-method f-name" v-if="loginMethods.indexOf('name_code') !== -1 && loginMethod !== 'name_code'" @click="onChangeMethod('name_code')">
  81. <view class="iconfont icon-key"></view>
  82. <view class="s-text">姓名登录码</view>
  83. </view>
  84. <view class="b-method f-number" v-if="loginMethods.indexOf('number_code') !== -1 && loginMethod !== 'number_code'" @click="onChangeMethod('number_code')">
  85. <view class="iconfont icon-key"></view>
  86. <view class="s-text">编号登录码</view>
  87. </view>
  88. <view class="b-method f-phone" v-if="loginMethods.indexOf('phone_captcha') !== -1 && loginMethod !== 'phone_captcha'" @click="onChangeMethod('phone_captcha')">
  89. <view class="iconfont icon-phone"></view>
  90. <view class="s-text">手机验证码</view>
  91. </view>
  92. <!-- #ifdef MP-WEIXIN -->
  93. <button
  94. class="b-method f-wechat open-data-btn"
  95. open-type="getPhoneNumber"
  96. @getphonenumber="onGetPhoneNumber"
  97. v-if="loginMethods.indexOf('wechat_phone') !== -1"
  98. >
  99. <view class="iconfont icon-wechat"></view>
  100. <view class="s-text">微信快捷登录</view>
  101. </button>
  102. <!-- #endif -->
  103. </view>
  104. </view>
  105. <view class="tips">{{ loginNote }}</view>
  106. </view>
  107. <view class="select-activity" v-if="selectActivity" @click="onJumpActivity">
  108. <view class="iconfont icon-dashboard"></view>
  109. </view>
  110. </view>
  111. </template>
  112. <script>
  113. import { loginByNameCode, loginByNumberCode, loginByPhoneCaptcha, loginByWechatPhone, sendPhoneCaptcha } from '@/service/api/user.js';
  114. import { smartLogin } from '@/service/request/main.js';
  115. import mixinsCommon from '@/mixins/common.js';
  116. import { decodeRedirectUrl } from '../../common/util';
  117. export default {
  118. mixins: [mixinsCommon],
  119. data() {
  120. return {
  121. form: {
  122. name: '',
  123. number: '',
  124. code: '',
  125. phone: '',
  126. captcha: ''
  127. },
  128. loginMethod: '',
  129. disable: {
  130. captcha: false,
  131. submit: false
  132. },
  133. captcha: {
  134. retry: false,
  135. second: 0
  136. }
  137. };
  138. },
  139. onLoad(options) {
  140. this.returnPage = options.from ? decodeRedirectUrl(options.from) : 'pages/home/index';
  141. console.log('login returnPage', this.returnPage);
  142. smartLogin('', true); // 判断是否扫码或进入活动列表页,因为当前页没有接口请求和权限校验
  143. },
  144. computed: {
  145. selectActivity() {
  146. return this.$store.getters.globalConfig.select_activity;
  147. },
  148. topImage() {
  149. return this.$store.getters.globalConfig.login_top_img;
  150. },
  151. loginNote() {
  152. return this.$store.getters.globalConfig.login_note || '欢迎参加答题竞赛活动。';
  153. },
  154. loginMethods() {
  155. // ['name_code','number_code',phone_captcha','wechat_phone']
  156. let loginMethods = this.$store.getters.globalConfig.login_methods || [];
  157. if (loginMethods.length > 0) {
  158. this.loginMethod = loginMethods[0];
  159. console.log('this.loginMethod');
  160. }
  161. return loginMethods;
  162. }
  163. },
  164. methods: {
  165. onInputName(e) {
  166. // console.log('onInputName', e)
  167. this.form.name = e.detail.value;
  168. },
  169. onInputNumber(e) {
  170. // console.log('onInputName', e)
  171. this.form.number = e.detail.value;
  172. },
  173. onInputCode(e) {
  174. // console.log('onInputCode', e)
  175. this.form.code = e.detail.value;
  176. },
  177. onInputPhone(e) {
  178. // console.log('onInputPhone', e)
  179. this.form.phone = e.detail.value;
  180. },
  181. onInputCaptcha(e) {
  182. // console.log('onInputCaptcha', e)
  183. this.form.captcha = e.detail.value;
  184. },
  185. onChangeMethod(method) {
  186. this.loginMethod = method;
  187. },
  188. onPhoneCaptcha() {
  189. if (this.disable.captcha) {
  190. return;
  191. }
  192. this.disable.captcha = true;
  193. uni.login().then(([err, res]) => {
  194. console.log('uni.login', err, res);
  195. sendPhoneCaptcha(this.form.phone, res ? res.code : '', true).then(([err, res]) => {
  196. console.log('sendPhoneCaptcha', err, res);
  197. if (!err) {
  198. uni.showToast({
  199. title: '发送成功'
  200. });
  201. // 验证码倒计时
  202. this.captcha.second = 60;
  203. var interval = setInterval(() => {
  204. this.captcha.second--;
  205. }, 1000);
  206. setTimeout(() => {
  207. clearInterval(interval);
  208. this.captcha.retry = true;
  209. this.captcha.second = 0;
  210. this.disable.captcha = false;
  211. }, this.captcha.second * 1000);
  212. } else {
  213. this.disable.captcha = false;
  214. }
  215. });
  216. });
  217. },
  218. onLoginByNameCode() {
  219. if (this.disable.submit) {
  220. return;
  221. }
  222. if (!this.form.name) {
  223. return this.$logic.showToast('成员姓名不能为空');
  224. }
  225. if (!this.form.code) {
  226. return this.$logic.showToast('登录码不能为空');
  227. }
  228. this.disable.submit = true;
  229. uni.login().then(([err, res]) => {
  230. console.log('uni.login', err, res);
  231. loginByNameCode(this.form.name, this.form.code, res ? res.code : '').then(([err, res]) => {
  232. console.log('loginByNameCode', err, res);
  233. this.disable.submit = false;
  234. if (!err) {
  235. this.$store.commit('setAccessToken', res.token);
  236. this.$store.commit('setActivityId', res.activity_id);
  237. this.$logic.showToast('登录成功').then(([err, res]) => {
  238. uni.reLaunch({
  239. url: '/' + this.returnPage
  240. });
  241. });
  242. }
  243. });
  244. });
  245. },
  246. onLoginByNumberCode() {
  247. if (this.disable.submit) {
  248. return;
  249. }
  250. if (!this.form.number) {
  251. return this.$logic.showToast('成员编号不能为空');
  252. }
  253. if (!this.form.code) {
  254. return this.$logic.showToast('登录码不能为空');
  255. }
  256. this.disable.submit = true;
  257. uni.login().then(([err, res]) => {
  258. console.log('uni.login', err, res);
  259. loginByNumberCode(this.form.number, this.form.code, res ? res.code : '').then(([err, res]) => {
  260. console.log('loginByNumberCode', err, res);
  261. this.disable.submit = false;
  262. if (!err) {
  263. this.$store.commit('setAccessToken', res.token);
  264. this.$store.commit('setActivityId', res.activity_id);
  265. this.$logic.showToast('登录成功').then(([err, res]) => {
  266. uni.reLaunch({
  267. url: '/' + this.returnPage
  268. });
  269. });
  270. }
  271. });
  272. });
  273. },
  274. onLoginByPhoneCaptcha() {
  275. if (this.disable.submit) {
  276. return;
  277. }
  278. if (!this.form.phone) {
  279. return this.$logic.showToast('手机号不能为空');
  280. }
  281. if (!this.form.captcha) {
  282. return this.$logic.showToast('验证码不能为空');
  283. }
  284. this.disable.submit = true;
  285. uni.login().then(([err, res]) => {
  286. console.log('uni.login', err, res);
  287. loginByPhoneCaptcha(this.form.phone, this.form.captcha, res ? res.code : '').then(([err, res]) => {
  288. console.log('loginByPhoneCaptcha', err, res);
  289. this.disable.submit = false;
  290. if (!err) {
  291. this.$store.commit('setAccessToken', res.token);
  292. this.$store.commit('setActivityId', res.activity_id);
  293. this.$logic.showToast('登录成功').then(([err, res]) => {
  294. uni.reLaunch({
  295. url: '/' + this.returnPage
  296. });
  297. });
  298. }
  299. });
  300. });
  301. },
  302. onGetPhoneNumber(e) {
  303. console.log('onGetPhoneNumber', e);
  304. if (e.detail.errMsg.indexOf(':ok') === -1) {
  305. // fail user deny
  306. this.$logic.showToast(e.detail.errMsg.replace('getPhoneNumber:', ''));
  307. return;
  308. }
  309. uni.showLoading({
  310. title: '尝试登录中'
  311. });
  312. uni.login().then(([err, res]) => {
  313. console.log('uni.login', err, res);
  314. loginByWechatPhone(e.detail.encryptedData, e.detail.iv, e.detail.code || '', res[1].code).then(([err, res]) => {
  315. console.log('loginByWechatPhone', err, res);
  316. uni.hideLoading();
  317. if (!err) {
  318. this.$store.commit('setAccessToken', res.token);
  319. this.$store.commit('setActivityId', res.activity_id);
  320. this.$logic.showToast('登录成功').then(([err, res]) => {
  321. uni.reLaunch({
  322. url: '/' + this.returnPage
  323. });
  324. });
  325. }
  326. });
  327. });
  328. },
  329. onJumpActivity() {
  330. uni.redirectTo({
  331. url: '/answer_pages/home/dashboard'
  332. });
  333. }
  334. }
  335. };
  336. </script>
  337. <style lang="scss">
  338. page {
  339. padding-bottom: env(safe-area-inset-bottom);
  340. background: #ffffff;
  341. }
  342. .wrap {
  343. }
  344. .logo {
  345. image {
  346. width: 100%;
  347. height: 460upx;
  348. }
  349. }
  350. .main {
  351. padding: 50upx;
  352. }
  353. .form {
  354. .b-row {
  355. display: flex;
  356. align-items: center;
  357. justify-content: space-between;
  358. margin-bottom: 30upx;
  359. border-bottom: 1upx solid #e5e5e5;
  360. }
  361. .b-input {
  362. flex: 1;
  363. padding: 0 20upx;
  364. width: 100%;
  365. height: 90upx;
  366. display: flex;
  367. align-items: center;
  368. .s-icon {
  369. color: #ccc;
  370. font-size: 40upx;
  371. }
  372. input {
  373. margin-left: 30upx;
  374. flex: 1;
  375. color: #333;
  376. font-size: 28upx;
  377. }
  378. .s-captcha {
  379. padding: 0 30upx;
  380. background: #fff;
  381. border: 2upx #ccc solid;
  382. height: 64upx;
  383. line-height: 64upx;
  384. border-radius: 32upx;
  385. color: #808080;
  386. font-size: 24upx;
  387. &.disable {
  388. color: #999;
  389. }
  390. }
  391. }
  392. }
  393. .submit {
  394. margin-top: 80upx;
  395. height: 100upx;
  396. line-height: 100upx;
  397. text-align: center;
  398. color: #fff;
  399. font-size: 32upx;
  400. background: #da5650;
  401. border-radius: 50upx;
  402. letter-spacing: 10upx;
  403. &.f-wechat {
  404. background: #35c773;
  405. }
  406. &.disable {
  407. background: rgba($color: #da5650, $alpha: 0.2);
  408. }
  409. }
  410. .split {
  411. margin-top: 50upx;
  412. display: flex;
  413. align-items: center;
  414. justify-content: space-between;
  415. .s-line {
  416. width: 200upx;
  417. height: 1upx;
  418. background: #eee;
  419. }
  420. .s-text {
  421. font-size: 28upx;
  422. color: #808080;
  423. }
  424. }
  425. .login-method {
  426. margin-top: 30upx;
  427. display: flex;
  428. align-items: center;
  429. justify-content: center;
  430. flex-wrap: wrap;
  431. .b-method {
  432. margin: 0 20upx 20upx 20upx;
  433. width: 250upx;
  434. // padding: 0 20upx;
  435. height: 80upx;
  436. border-radius: 10upx;
  437. background: #808080;
  438. display: flex;
  439. justify-content: center;
  440. align-items: center;
  441. color: #fff;
  442. &.f-name {
  443. background: #64a2fa;
  444. }
  445. &.f-number {
  446. background: #ee6c77;
  447. }
  448. &.f-phone {
  449. background: #ff9c45;
  450. }
  451. &.f-wechat {
  452. background: #35c773;
  453. }
  454. .iconfont {
  455. margin-right: 10upx;
  456. font-size: 40upx;
  457. }
  458. .s-text {
  459. font-size: 26upx;
  460. }
  461. }
  462. }
  463. .tips {
  464. margin-top: 50upx;
  465. width: 100%;
  466. color: #383838;
  467. font-size: 24upx;
  468. }
  469. .select-activity {
  470. position: absolute;
  471. bottom: 50upx;
  472. right: 50upx;
  473. background: #fff;
  474. border: 2upx solid #ddd;
  475. width: 100upx;
  476. height: 100upx;
  477. border-radius: 50upx;
  478. display: flex;
  479. align-items: center;
  480. justify-content: center;
  481. .iconfont {
  482. font-size: 50upx;
  483. color: #da5650;
  484. }
  485. }
  486. </style>