index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. <template>
  2. <view class="login-wrapper" :style="colorStyle">
  3. <view class="shading">
  4. <image :src="logoUrl" v-if="logoUrl" />
  5. <image src="/static/images/logo2.png" v-else />
  6. </view>
  7. <view class="whiteBg" v-if="formItem === 1">
  8. <view class="list" v-if="current !== 1">
  9. <form @submit.prevent="submit">
  10. <view class="item">
  11. <view class="acea-row row-middle">
  12. <image src="/static/images/phone_1.png" style="width: 24rpx; height: 34rpx;"></image>
  13. <input type="text" placeholder="输入手机号码" v-model="account" maxlength="11" required />
  14. </view>
  15. </view>
  16. <view class="item">
  17. <view class="acea-row row-middle">
  18. <image src="/static/images/code_1.png" style="width: 28rpx; height: 32rpx;"></image>
  19. <input type="password" placeholder="填写登录密码" v-model="password" required />
  20. </view>
  21. </view>
  22. </form>
  23. <!-- <navigator class="forgetPwd" hover-class="none" url="/pages/users/retrievePassword/index">
  24. <span class="iconfont icon-wenti"></span>忘记密码
  25. </navigator> -->
  26. </view>
  27. <view class="list" v-if="current !== 0 || appLoginStatus || appleLoginStatus">
  28. <view class="item">
  29. <view class="acea-row row-middle">
  30. <image src="/static/images/phone_1.png" style="width: 24rpx; height: 34rpx;"></image>
  31. <input type="text" placeholder="输入手机号码" v-model="account" maxlength="11" />
  32. </view>
  33. </view>
  34. <view class="item">
  35. <view class="acea-row row-middle">
  36. <image src="/static/images/code_2.png" style="width: 28rpx; height: 32rpx;"></image>
  37. <input type="text" placeholder="填写验证码" maxlength="6" class="codeIput" v-model="captcha" />
  38. <button class="code" :disabled="disabled" :class="disabled === true ? 'on' : ''" @click="code">
  39. {{ text }}
  40. </button>
  41. </view>
  42. </view>
  43. <view class="item" v-if="isShowCode">
  44. <view class="acea-row row-middle">
  45. <image src="/static/images/code_2.png" style="width: 28rpx; height: 32rpx;"></image>
  46. <input type="text" placeholder="填写验证码" class="codeIput" v-model="codeVal" />
  47. <view class="code" @click="again"><img :src="codeUrl" /></view>
  48. </view>
  49. </view>
  50. </view>
  51. <view class="logon" @click="loginMobile" v-if="current !== 0">登录</view>
  52. <view class="logon" @click="submit" v-if="current === 0">登录</view>
  53. <!-- #ifndef APP-PLUS -->
  54. <view class="tips">
  55. <view v-if="current==0" @click="current = 1">快速登录</view>
  56. <view v-if="current==1" @click="current = 0">账号登录</view>
  57. </view>
  58. <!-- #endif -->
  59. <!-- #ifdef APP-PLUS -->
  60. <view class="appLogin" v-if="!appLoginStatus && !appleLoginStatus">
  61. <view class="hds">
  62. <span class="line"></span>
  63. <p>其他方式登录</p>
  64. <span class="line"></span>
  65. </view>
  66. <view class="btn-wrapper">
  67. <view class="btn wx" @click="wxLogin">
  68. <span class="iconfont icon-s-weixindenglu1"></span>
  69. </view>
  70. <view class="btn mima" v-if="current == 1" @click="current =0">
  71. <span class="iconfont icon-s-mimadenglu1"></span>
  72. </view>
  73. <view class="btn yanzheng" v-if="current == 0" @click="current =1">
  74. <span class="iconfont icon-s-yanzhengmadenglu1"></span>
  75. </view>
  76. <view class="apple-btn" @click="appleLogin" v-if="appleShow">
  77. <view class="iconfont icon-s-pingguo"></view>通过Apple登录
  78. </view>
  79. </view>
  80. </view>
  81. <!-- #endif -->
  82. </view>
  83. <view class="bottom"></view>
  84. </view>
  85. </template>
  86. <script>
  87. import dayjs from "@/plugin/dayjs/dayjs.min.js";
  88. import sendVerifyCode from "@/mixins/SendVerifyCode";
  89. import {
  90. loginH5,
  91. loginMobile,
  92. registerVerify,
  93. register,
  94. getCodeApi,
  95. getUserInfo,
  96. appleLogin
  97. } from "@/api/user";
  98. import attrs, {
  99. required,
  100. alpha_num,
  101. chs_phone
  102. } from "@/utils/validate";
  103. import {
  104. validatorDefaultCatch
  105. } from "@/utils/dialog";
  106. import {
  107. getLogo
  108. } from "@/api/public";
  109. // import cookie from "@/utils/store/cookie";
  110. import {
  111. VUE_APP_API_URL
  112. } from "@/utils";
  113. // #ifdef APP-PLUS
  114. import {
  115. wechatAppAuth
  116. } from '@/api/api.js'
  117. // #endif
  118. const BACK_URL = "login_back_url";
  119. import colors from '@/mixins/color.js';
  120. export default {
  121. name: "Login",
  122. mixins: [sendVerifyCode, colors],
  123. data: function() {
  124. return {
  125. navList: ["快速登录", "账号登录"],
  126. current: 1,
  127. account: "",
  128. password: "",
  129. captcha: "",
  130. formItem: 1,
  131. type: "login",
  132. logoUrl: "",
  133. keyCode: "",
  134. codeUrl: "",
  135. codeVal: "",
  136. isShowCode: false,
  137. appLoginStatus: false, // 微信登录强制绑定手机号码状态
  138. appUserInfo: null, // 微信登录保存的用户信息
  139. appleLoginStatus: false, // 苹果登录强制绑定手机号码状态
  140. appleUserInfo: null,
  141. appleShow: false, // 苹果登录版本必须要求ios13以上的
  142. keyLock: true
  143. };
  144. },
  145. watch: {
  146. formItem: function(nval, oVal) {
  147. if (nval == 1) {
  148. this.type = 'login'
  149. } else {
  150. this.type = 'register'
  151. }
  152. }
  153. },
  154. onLoad() {
  155. let self = this
  156. uni.getSystemInfo({
  157. success: (res) => {
  158. if (res.platform.toLowerCase() == 'ios' && this.getSystem(res.system)) {
  159. self.appleShow = true
  160. }
  161. }
  162. });
  163. },
  164. mounted: function() {
  165. // this.getCode();
  166. this.getLogoImage();
  167. },
  168. methods: {
  169. // IOS 版本号判断
  170. getSystem(system) {
  171. let str
  172. system.toLowerCase().indexOf('ios') === -1 ? str = system : str = system.split(' ')[1]
  173. if (str.indexOf('.'))
  174. return str.split('.')[0] >= 13
  175. return str >= 13
  176. },
  177. // 苹果登录
  178. appleLogin() {
  179. let self = this
  180. this.account = ''
  181. this.captcha = ''
  182. uni.showLoading({
  183. title: '登录中'
  184. })
  185. uni.login({
  186. provider: 'apple',
  187. timeout: 10000,
  188. success(loginRes) {
  189. uni.getUserInfo({
  190. provider: 'apple',
  191. success: function(infoRes) {
  192. self.appleUserInfo = infoRes.userInfo
  193. self.appleLoginApi()
  194. },
  195. fail() {
  196. uni.showToast({
  197. title: '获取用户信息失败',
  198. icon: 'none',
  199. duration: 2000
  200. })
  201. },
  202. complete() {
  203. uni.hideLoading()
  204. }
  205. });
  206. },
  207. fail(error) {
  208. }
  209. })
  210. },
  211. // 苹果登录Api
  212. appleLoginApi() {
  213. let self = this
  214. appleLogin({
  215. openId: self.appleUserInfo.openId,
  216. email: self.appleUserInfo.email || '',
  217. phone: this.account,
  218. captcha: this.captcha
  219. }).then(({
  220. data
  221. }) => {
  222. if (data.isbind) {
  223. uni.showModal({
  224. title: '提示',
  225. content: '请绑定手机号后,继续操作',
  226. showCancel: false,
  227. success: function(res) {
  228. if (res.confirm) {
  229. self.current = 1
  230. self.appleLoginStatus = true
  231. }
  232. }
  233. });
  234. } else {
  235. self.$store.commit("LOGIN", {
  236. 'token': data.token,
  237. 'time': data.expires_time - self.$Cache.time()
  238. });
  239. let backUrl = self.$Cache.get(BACK_URL) || "/pages/index/index";
  240. self.$Cache.clear(BACK_URL);
  241. self.$store.commit("SETUID", data.userInfo.uid);
  242. uni.reLaunch({
  243. url: backUrl
  244. });
  245. }
  246. }).catch(error => {
  247. uni.showModal({
  248. title: '提示',
  249. content: `错误信息${error}`,
  250. success: function(res) {
  251. if (res.confirm) {
  252. console.log('用户点击确定');
  253. } else if (res.cancel) {
  254. console.log('用户点击取消');
  255. }
  256. }
  257. });
  258. })
  259. },
  260. // App微信登录
  261. wxLogin() {
  262. let self = this
  263. this.account = ''
  264. this.captcha = ''
  265. uni.showLoading({
  266. title: '登录中'
  267. })
  268. uni.login({
  269. provider: 'weixin',
  270. success: function(loginRes) {
  271. // 获取用户信息
  272. uni.getUserInfo({
  273. provider: 'weixin',
  274. success: function(infoRes) {
  275. self.appUserInfo = infoRes.userInfo
  276. self.wxLoginApi()
  277. },
  278. fail() {
  279. uni.showToast({
  280. title: '获取用户信息失败',
  281. icon: 'none',
  282. duration: 2000
  283. })
  284. },
  285. complete() {
  286. uni.hideLoading()
  287. }
  288. });
  289. },
  290. fail() {
  291. uni.showToast({
  292. title: '登录失败',
  293. icon: 'none',
  294. duration: 2000
  295. })
  296. }
  297. });
  298. },
  299. wxLoginApi() {
  300. let self = this
  301. wechatAppAuth({
  302. userInfo: self.appUserInfo,
  303. phone: this.account,
  304. code: this.captcha
  305. }).then(({
  306. data
  307. }) => {
  308. if (data.isbind) {
  309. uni.showModal({
  310. title: '提示',
  311. content: '请绑定手机号后,继续操作',
  312. showCancel: false,
  313. success: function(res) {
  314. if (res.confirm) {
  315. self.current = 1
  316. self.appLoginStatus = true
  317. }
  318. }
  319. });
  320. } else {
  321. self.$store.commit("LOGIN", {
  322. 'token': data.token,
  323. 'time': data.expires_time - self.$Cache.time()
  324. });
  325. let backUrl = self.$Cache.get(BACK_URL) || "/pages/index/index";
  326. self.$Cache.clear(BACK_URL);
  327. self.$store.commit("SETUID", data.userInfo.uid);
  328. uni.reLaunch({
  329. url: backUrl
  330. });
  331. }
  332. }).catch(error => {
  333. uni.showModal({
  334. title: '提示',
  335. content: `错误信息${error}`,
  336. success: function(res) {
  337. if (res.confirm) {
  338. console.log('用户点击确定');
  339. } else if (res.cancel) {
  340. console.log('用户点击取消');
  341. }
  342. }
  343. });
  344. })
  345. },
  346. again() {
  347. this.codeUrl =
  348. VUE_APP_API_URL +
  349. "/sms_captcha?" +
  350. "key=" +
  351. this.keyCode +
  352. Date.parse(new Date());
  353. },
  354. code() {
  355. let that = this
  356. getCodeApi()
  357. .then(res => {
  358. that.keyCode = res.data.key;
  359. that.getCode();
  360. })
  361. .catch(res => {
  362. that.$util.Tips({
  363. title: res
  364. });
  365. });
  366. },
  367. async getLogoImage() {
  368. let that = this;
  369. getLogo(2).then(res => {
  370. that.logoUrl = res.data.logo_url;
  371. });
  372. },
  373. async loginMobile() {
  374. let that = this;
  375. if (!that.account) return that.$util.Tips({
  376. title: '请填写手机号码'
  377. });
  378. if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
  379. title: '请输入正确的手机号码'
  380. });
  381. if (!that.captcha) return that.$util.Tips({
  382. title: '请填写验证码'
  383. });
  384. if (!/^[\w\d]+$/i.test(that.captcha)) return that.$util.Tips({
  385. title: '请输入正确的验证码'
  386. });
  387. if (that.appLoginStatus) {
  388. that.wxLoginApi()
  389. } else if (that.appleLoginStatus) {
  390. that.appleLoginApi()
  391. } else {
  392. if (this.keyLock) {
  393. this.keyLock = !this.keyLock
  394. } else {
  395. return that.$util.Tips({
  396. title: '请勿重复点击'
  397. });
  398. }
  399. loginMobile({
  400. phone: that.account,
  401. captcha: that.captcha,
  402. spread: that.$Cache.get("spread")
  403. })
  404. .then(res => {
  405. let data = res.data;
  406. that.$store.commit("LOGIN", {
  407. 'token': data.token,
  408. 'time': data.expires_time - this.$Cache.time()
  409. });
  410. let backUrl = that.$Cache.get(BACK_URL) || "/pages/index/index";
  411. that.$Cache.clear(BACK_URL);
  412. getUserInfo().then(res => {
  413. this.keyLock = true
  414. that.$store.commit("SETUID", res.data.uid);
  415. if (backUrl.indexOf('/pages/users/login/index') !== -1) {
  416. backUrl = '/pages/index/index';
  417. }
  418. uni.reLaunch({
  419. url: backUrl
  420. });
  421. })
  422. })
  423. .catch(res => {
  424. this.keyLock = true
  425. that.$util.Tips({
  426. title: res
  427. });
  428. });
  429. }
  430. },
  431. async register() {
  432. let that = this;
  433. if (!that.account) return that.$util.Tips({
  434. title: '请填写手机号码'
  435. });
  436. if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
  437. title: '请输入正确的手机号码'
  438. });
  439. if (!that.captcha) return that.$util.Tips({
  440. title: '请填写验证码'
  441. });
  442. if (!/^[\w\d]+$/i.test(that.captcha)) return that.$util.Tips({
  443. title: '请输入正确的验证码'
  444. });
  445. if (!that.password) return that.$util.Tips({
  446. title: '请填写密码'
  447. });
  448. if (/^([0-9]|[a-z]|[A-Z]){0,6}$/i.test(that.password)) return that.$util.Tips({
  449. title: '您输入的密码过于简单'
  450. });
  451. register({
  452. account: that.account,
  453. captcha: that.captcha,
  454. password: that.password,
  455. spread: that.$Cache.get("spread")
  456. })
  457. .then(res => {
  458. that.$util.Tips({
  459. title: res
  460. });
  461. that.formItem = 1;
  462. })
  463. .catch(res => {
  464. that.$util.Tips({
  465. title: res
  466. });
  467. });
  468. },
  469. async getCode() {
  470. let that = this;
  471. if (!that.account) return that.$util.Tips({
  472. title: '请填写手机号码'
  473. });
  474. if (!/^1(3|4|5|7|8|9|6)\d{9}$/i.test(that.account)) return that.$util.Tips({
  475. title: '请输入正确的手机号码'
  476. });
  477. if (that.formItem == 2) that.type = "register";
  478. await registerVerify({
  479. phone: that.account,
  480. type: that.type,
  481. key: that.keyCode,
  482. code: that.codeVal
  483. })
  484. .then(res => {
  485. that.$util.Tips({
  486. title: res.msg
  487. });
  488. that.sendCode();
  489. })
  490. .catch(res => {
  491. that.$util.Tips({
  492. title: res
  493. });
  494. });
  495. },
  496. navTap: function(index) {
  497. this.current = index;
  498. },
  499. async submit() {
  500. let that = this;
  501. if (!that.account) return that.$util.Tips({
  502. title: '请填写账号'
  503. });
  504. if (!/^[\w\d]{5,16}$/i.test(that.account)) return that.$util.Tips({
  505. title: '请输入正确的账号'
  506. });
  507. if (!that.password) return that.$util.Tips({
  508. title: '请填写密码'
  509. });
  510. if (this.keyLock) {
  511. this.keyLock = !this.keyLock
  512. } else {
  513. return that.$util.Tips({
  514. title: '请勿重复点击'
  515. });
  516. }
  517. loginH5({
  518. account: that.account,
  519. password: that.password,
  520. spread: that.$Cache.get("spread")
  521. })
  522. .then(({
  523. data
  524. }) => {
  525. that.$store.commit("LOGIN", {
  526. 'token': data.token,
  527. 'time': data.expires_time - this.$Cache.time()
  528. });
  529. let backUrl = that.$Cache.get(BACK_URL) || "/pages/index/index";
  530. that.$Cache.clear(BACK_URL);
  531. getUserInfo().then(res => {
  532. this.keyLock = true
  533. that.$store.commit("SETUID", res.data.uid);
  534. uni.reLaunch({
  535. url: backUrl
  536. });
  537. }).catch(error => {
  538. this.keyLock = true
  539. })
  540. })
  541. .catch(e => {
  542. this.keyLock = true
  543. that.$util.Tips({
  544. title: e
  545. });
  546. });
  547. }
  548. }
  549. };
  550. </script>
  551. <style>
  552. page {
  553. background: #fff;
  554. }
  555. </style>
  556. <style lang="scss">
  557. .appLogin {
  558. margin-top: 60rpx;
  559. .hds {
  560. display: flex;
  561. justify-content: center;
  562. align-items: center;
  563. font-size: 24rpx;
  564. color: #B4B4B4;
  565. .line {
  566. width: 68rpx;
  567. height: 1rpx;
  568. background: #CCCCCC;
  569. }
  570. p {
  571. margin: 0 20rpx;
  572. }
  573. }
  574. .btn-wrapper {
  575. display: flex;
  576. align-items: center;
  577. justify-content: center;
  578. margin-top: 30rpx;
  579. .btn {
  580. display: flex;
  581. align-items: center;
  582. justify-content: center;
  583. width: 68rpx;
  584. height: 68rpx;
  585. border-radius: 50%;
  586. }
  587. .apple-btn {
  588. display: flex;
  589. align-items: center;
  590. justify-content: center;
  591. width: 246rpx;
  592. height: 66rpx;
  593. margin-left: 30rpx;
  594. background: #EAEAEA;
  595. border-radius: 34rpx;
  596. font-size: 24rpx;
  597. .icon-s-pingguo {
  598. color: #333;
  599. margin-right: 10rpx;
  600. font-size: 34rpx;
  601. }
  602. }
  603. .iconfont {
  604. font-size: 40rpx;
  605. color: #fff;
  606. }
  607. .wx {
  608. margin-right: 30rpx;
  609. background-color: #61C64F;
  610. }
  611. .mima {
  612. background-color: #28B3E9;
  613. }
  614. .yanzheng {
  615. background-color: #F89C23;
  616. }
  617. }
  618. }
  619. .code img {
  620. width: 100%;
  621. height: 100%;
  622. }
  623. .acea-row.row-middle {
  624. input {
  625. margin-left: 20rpx;
  626. display: block;
  627. }
  628. }
  629. .login-wrapper {
  630. padding: 30rpx;
  631. .shading {
  632. display: flex;
  633. align-items: center;
  634. justify-content: center;
  635. width: 100%;
  636. /* #ifdef APP-VUE */
  637. margin-top: 50rpx;
  638. /* #endif */
  639. /* #ifndef APP-VUE */
  640. margin-top: 200rpx;
  641. /* #endif */
  642. image {
  643. width: 240rpx;
  644. height: 240rpx;
  645. }
  646. }
  647. .whiteBg {
  648. margin-top: 100rpx;
  649. .list {
  650. border-radius: 16rpx;
  651. overflow: hidden;
  652. .item {
  653. border-bottom: 1px solid #F0F0F0;
  654. background: #fff;
  655. .row-middle {
  656. position: relative;
  657. padding: 16rpx 45rpx;
  658. input {
  659. flex: 1;
  660. font-size: 28rpx;
  661. height: 80rpx;
  662. }
  663. .code {
  664. position: absolute;
  665. right: 30rpx;
  666. top: 50%;
  667. color: var(--view-theme);
  668. font-size: 26rpx;
  669. transform: translateY(-50%);
  670. }
  671. }
  672. }
  673. }
  674. .logon {
  675. display: flex;
  676. align-items: center;
  677. justify-content: center;
  678. width: 100%;
  679. height: 86rpx;
  680. margin-top: 80rpx;
  681. background-color: var(--view-theme);
  682. border-radius: 120rpx;
  683. color: #FFFFFF;
  684. font-size: 30rpx;
  685. }
  686. .tips {
  687. margin: 30rpx;
  688. text-align: center;
  689. color: #999;
  690. }
  691. }
  692. }
  693. </style>