login.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. <template>
  2. <view class="container">
  3. <!-- #ifdef MP-WEIXIN -->
  4. <image class="bg" src="@/static/image/bg_login.png" mode="widthFix"></image>
  5. <view class="force-login-wrap">
  6. <view :style="{height:menuButtonInfo.height,marginTop:menuButtonInfo.top}" class="backImg">
  7. <image @tap="goBack()" src="@/static/images/back.png"></image>
  8. </view>
  9. <view class="top-title">
  10. <view class="title-text">欢迎登录<text class="blue">小蜜蜂</text></view>
  11. <view class="login-notice">新用户首次登录即视为注册</view>
  12. </view>
  13. <view class="force-login__content">
  14. <!-- <image class="bg-type" :src="current==0?'/static/image/bg_tab_login.png':'/static/image/bg_tab_login2.png'" mode="widthFix"></image> -->
  15. <view class="logintype">
  16. <view :class="current==0 ? 'logintype-item active':'logintype-item'" @click="changeType(0)">验证码登录
  17. </view>
  18. <view class="line"></view>
  19. <view :class="current==1 ? 'logintype-item active':'logintype-item'" @click="changeType(1)">密码登录
  20. </view>
  21. </view>
  22. <view class="input-form">
  23. <view class="input-item">
  24. <input class="input-field" type="number" v-model="phone" placeholder="请输入手机号" maxlength="11" />
  25. </view>
  26. <view class="input-item code-input-item">
  27. <input v-if="current == 0" class="input-field code-input" type="number" v-model="verifyCode"
  28. placeholder="请输入验证码" maxlength="6" />
  29. <view v-else class="mima">
  30. <input class="input-field code-input" type="text" :password="showPassword"
  31. v-model="password" placeholder="请输入密码" />
  32. <image @click="closePwd"
  33. :src="showPassword?'/static/image/icon_invisible.png':'/static/image/icon_visible.png'"
  34. mode="aspectFill"></image>
  35. </view>
  36. <view v-if="current == 0" class="get-code-btn" @click="getVerifyCode">
  37. {{ codeText }}
  38. </view>
  39. </view>
  40. </view>
  41. <view class="forgot" v-if="current==1" @click="toForgetPassword">忘记密码?</view>
  42. <view class="encoding">企业编码:-</view>
  43. <view class="login-btn-wrap">
  44. <!-- <button class="login-btn" @click="handleLogin">{{ current == 0 ? '登录/注册用户' : '登录' }}</button> -->
  45. <button class="login-btn" @click="handleLogin">登录</button>
  46. </view>
  47. <view class="tips">
  48. <checkbox :checked="isAgreement" @click="handleAgreement()" />
  49. <view class="tips-text" @click="handleAgreement()">已阅读并接受</view>
  50. <view class="btn" @click="openH5('/web/userAgreement')">《用户注册协议》</view>
  51. <view class="btn" @click="openH5('/web/privacyPolicy')">《隐私保护政策》</view>
  52. </view>
  53. </view>
  54. </view>
  55. <!-- #endif -->
  56. </view>
  57. </template>
  58. <script>
  59. import {
  60. loginByMiniApp,
  61. getUserInfo,
  62. loginByMp
  63. } from '@/api/user'
  64. export default {
  65. data() {
  66. return {
  67. code: null, // 微信登录code
  68. isAgreement: false,
  69. current: 0, // 0-验证码登录 1-密码登录
  70. menuButtonInfo: {},
  71. phone: '', // 手机号
  72. verifyCode: '', // 验证码
  73. password: '', // 密码
  74. codeText: '获取验证码', // 验证码按钮文字
  75. countdown: 0, // 倒计时
  76. countdownTimer: null, // 倒计时定时器
  77. showPassword: true // 是否显示密码
  78. }
  79. },
  80. computed: {},
  81. onLoad(option) {
  82. this.getMenuButtonInfo()
  83. // #ifdef MP-WEIXIN
  84. uni.$on('refreshLogin', () => {
  85. uni.navigateBack({
  86. delta: 1
  87. })
  88. })
  89. //选获取CODE,防止后请求的时候腾讯服务端未同步报错
  90. this.getCode();
  91. // #endif
  92. // #ifdef H5
  93. if (this.checkWeixin()) {
  94. this.getWxCode()
  95. } else {
  96. uni.showToast({
  97. icon: 'none',
  98. title: "请在微信中打开",
  99. });
  100. //跳转到手机号密码登录
  101. }
  102. // #endif
  103. },
  104. onUnload() {
  105. // 清除倒计时
  106. if (this.countdownTimer) {
  107. clearInterval(this.countdownTimer);
  108. this.countdownTimer = null;
  109. }
  110. },
  111. mounted() {
  112. },
  113. methods: {
  114. closePwd() {
  115. this.showPassword = !this.showPassword
  116. },
  117. // 获取胶囊按钮布局参数
  118. getMenuButtonInfo() {
  119. // 微信小程序API(Uniapp可直接用uni.getMenuButtonBoundingClientRect)
  120. const menuBtn = uni.getMenuButtonBoundingClientRect();
  121. if (menuBtn) {
  122. this.menuButtonInfo = {
  123. top: menuBtn.top + 'px', // 胶囊顶部距离
  124. height: menuBtn.height + 'px', // 胶囊高度
  125. centerY: (menuBtn.top + menuBtn.height / 2) + 'px', // 胶囊垂直居中Y坐标
  126. right: menuBtn.right + 'px' // 胶囊右侧距离
  127. };
  128. }
  129. },
  130. changeType(index) {
  131. this.current = index;
  132. // 切换时清空输入
  133. if (index == 0) {
  134. this.password = '';
  135. } else {
  136. this.verifyCode = '';
  137. }
  138. },
  139. // 返回主页
  140. goBack() {
  141. uni.navigateBack({
  142. delta: 1
  143. })
  144. },
  145. // 获取验证码
  146. getVerifyCode() {
  147. if (this.countdown > 0) {
  148. return;
  149. }
  150. if (!this.phone) {
  151. uni.showToast({
  152. icon: 'none',
  153. title: "请输入手机号",
  154. });
  155. return;
  156. }
  157. if (!/^1[3-9]\d{9}$/.test(this.phone)) {
  158. uni.showToast({
  159. icon: 'none',
  160. title: "请输入正确的手机号",
  161. });
  162. return;
  163. }
  164. // TODO: 调用发送验证码API
  165. // 这里需要对接真实的发送验证码接口
  166. uni.showLoading({
  167. title: "发送中..."
  168. });
  169. // 模拟发送验证码
  170. setTimeout(() => {
  171. uni.hideLoading();
  172. uni.showToast({
  173. icon: 'success',
  174. title: "验证码已发送",
  175. });
  176. // 开始倒计时
  177. this.countdown = 60;
  178. this.countdownTimer = setInterval(() => {
  179. this.countdown--;
  180. this.codeText = this.countdown + '秒重新获取';
  181. if (this.countdown <= 0) {
  182. clearInterval(this.countdownTimer);
  183. this.countdownTimer = null;
  184. this.codeText = '获取验证码';
  185. }
  186. }, 1000);
  187. }, 1000);
  188. },
  189. // 登录
  190. handleLogin() {
  191. if (!this.isAgreement) {
  192. uni.showToast({
  193. icon: 'none',
  194. title: "请先同意协议后再登录",
  195. });
  196. return;
  197. }
  198. uni.navigateBack({
  199. delta: 1
  200. })
  201. // if(!this.phone) {
  202. // uni.showToast({
  203. // icon:'none',
  204. // title: "请输入手机号",
  205. // });
  206. // return;
  207. // }
  208. // if(!/^1[3-9]\d{9}$/.test(this.phone)) {
  209. // uni.showToast({
  210. // icon:'none',
  211. // title: "请输入正确的手机号",
  212. // });
  213. // return;
  214. // }
  215. // if(this.current == 0) {
  216. // // 验证码登录
  217. // if(!this.verifyCode) {
  218. // uni.showToast({
  219. // icon:'none',
  220. // title: "请输入验证码",
  221. // });
  222. // return;
  223. // }
  224. // // TODO: 调用验证码登录API
  225. // this.loginByCode();
  226. // } else {
  227. // // 密码登录
  228. // if(!this.password) {
  229. // uni.showToast({
  230. // icon:'none',
  231. // title: "请输入密码",
  232. // });
  233. // return;
  234. // }
  235. // // TODO: 调用密码登录API
  236. // this.loginByPassword();
  237. // }
  238. },
  239. // 验证码登录
  240. loginByCode() {
  241. uni.showLoading({
  242. title: "登录中..."
  243. });
  244. // TODO: 调用验证码登录接口
  245. // 示例:loginByCode({ phone: this.phone, code: this.verifyCode })
  246. setTimeout(() => {
  247. uni.hideLoading();
  248. uni.showToast({
  249. icon: 'none',
  250. title: "验证码登录接口待对接",
  251. });
  252. }, 1000);
  253. },
  254. // 密码登录
  255. loginByPassword() {
  256. uni.showLoading({
  257. title: "登录中..."
  258. });
  259. // TODO: 调用密码登录接口
  260. // 示例:loginByPassword({ phone: this.phone, password: this.password })
  261. setTimeout(() => {
  262. uni.hideLoading();
  263. uni.showToast({
  264. icon: 'none',
  265. title: "密码登录接口待对接",
  266. });
  267. }, 1000);
  268. },
  269. checkWeixin() {
  270. var ua = window.navigator.userAgent.toLowerCase();
  271. if (ua.match(/micromessenger/i) == 'micromessenger') {
  272. return true;
  273. } else {
  274. return false;
  275. }
  276. },
  277. //URL地址是否存在CODE
  278. getUrlCode(name) {
  279. return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) ||
  280. [, ''
  281. ])[1]
  282. .replace(/\+/g, '%20')) || null
  283. },
  284. //获取微信CODE
  285. getWxCode() {
  286. //在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;
  287. //http://shequ.natapp1.cc/#/pages/index/index?deviceId=8
  288. var appId = "wx40593595e62f61ad";
  289. var url = "http://h5.yjf.runtzh.com";
  290. window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + appId +
  291. '&redirect_uri=' + encodeURIComponent(url + "/#/pages/auth/wxLogin") +
  292. '&response_type=code&scope=snsapi_userinfo&state=JeffreySu-954&connect_redirect=1#wechat_redirect';
  293. //console.log('https://open.weixin.qq.com/connect/oauth2/authorize?appid='+appId+'&redirect_uri=' +encodeURIComponent("http://shequ.natapp1.cc/#/pages/index/index?deviceId="+this.deviceId) +'&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect')
  294. // redirect_uri是授权成功后,跳转的url地址,微信会帮我们跳转到该链接,并且通过?的形式拼接code
  295. },
  296. handleAgreement() {
  297. this.isAgreement = !this.isAgreement;
  298. },
  299. openH5(url) {
  300. var requestPath = uni.getStorageSync('requestPath');
  301. uni.setStorageSync('url', requestPath + url);
  302. uni.navigateTo({
  303. url: '../home/web'
  304. })
  305. },
  306. toForgetPassword(){
  307. uni.navigateTo({
  308. url: '/pages/auth/forgetPassword'
  309. })
  310. },
  311. getCode() {
  312. var that = this;
  313. this.utils.getProvider()
  314. .then(provider => {
  315. console.log('当前的环境商', provider)
  316. if (!provider) {
  317. reject()
  318. }
  319. // uni登录
  320. uni.login({
  321. provider: provider,
  322. success: async loginRes => {
  323. that.code = loginRes.code
  324. }
  325. })
  326. })
  327. .catch(err => {
  328. })
  329. },
  330. // 微信用户手机号登录
  331. phoneLogin(e) {
  332. var that = this;
  333. if (!this.isAgreement) {
  334. uni.showToast({
  335. icon: 'none',
  336. title: "请先同意协议后再登录",
  337. });
  338. return false;
  339. }
  340. uni.showLoading({
  341. title: "处理中..."
  342. })
  343. console.log(e, "e")
  344. if (e.mp.detail.errMsg == 'getPhoneNumber:ok') {
  345. this.utils.getProvider()
  346. .then(provider => {
  347. console.log('当前的环境商', provider)
  348. if (!provider) {
  349. reject()
  350. }
  351. // uni登录
  352. uni.login({
  353. provider: provider,
  354. success: async loginRes => {
  355. console.log(loginRes)
  356. let code = loginRes.code // 获取开发code
  357. var userCode = uni.getStorageSync('userCode');
  358. loginByMiniApp({
  359. encryptedData: e.mp.detail.encryptedData,
  360. iv: e.mp.detail.iv,
  361. code: code,
  362. userCode: userCode
  363. })
  364. .then(res => {
  365. if (res.code == 200) {
  366. uni.hideLoading();
  367. uni.showToast({
  368. icon: 'none',
  369. title: "登录成功",
  370. });
  371. uni.setStorageSync('AppToken', res.token);
  372. uni.setStorageSync('userInfo', JSON.stringify(res
  373. .user));
  374. uni.hideLoading()
  375. //that.getUserInfo()
  376. uni.$emit('refreshLogin');
  377. uni.navigateBack({
  378. delta: 1
  379. })
  380. } else {
  381. uni.hideLoading();
  382. uni.showToast({
  383. icon: 'none',
  384. title: "授权登录失败,请重新登录",
  385. });
  386. }
  387. })
  388. .catch(error => {
  389. console.log(error)
  390. uni.hideLoading();
  391. uni.showToast({
  392. icon: 'none',
  393. title: "登录接口调用失败",
  394. });
  395. })
  396. }
  397. })
  398. })
  399. .catch(err => {
  400. uni.showToast({
  401. icon: 'none',
  402. title: err,
  403. });
  404. })
  405. } else {
  406. uni.showToast({
  407. title: '已拒绝授权',
  408. icon: 'none',
  409. duration: 2000,
  410. })
  411. }
  412. },
  413. back() {
  414. uni.switchTab({
  415. url: '/pages/home/index'
  416. });
  417. // uni.navigateBack()
  418. }
  419. }
  420. }
  421. </script>
  422. <style lang="scss">
  423. .container {
  424. flex: 1;
  425. padding: 0 24rpx;
  426. display: flex;
  427. flex-direction: column;
  428. justify-content: flex-start;
  429. position: relative;
  430. .bg {
  431. width: 100%;
  432. position: absolute;
  433. top: 0;
  434. left: 0;
  435. }
  436. .backImg {
  437. display: flex;
  438. align-items: center;
  439. image {
  440. width: 40rpx;
  441. height: 40rpx;
  442. }
  443. margin-left: 32rpx;
  444. // position: absolute;
  445. // left: 30rpx;
  446. // z-index: 100;
  447. }
  448. }
  449. .force-login-wrap {
  450. width: 100%;
  451. height: 100vh;
  452. position: relative;
  453. .top-title {
  454. padding: 0 32rpx;
  455. text-align: left;
  456. margin-top: 20rpx;
  457. .title-text {
  458. font-weight: 600;
  459. font-size: 48rpx;
  460. color: #333333;
  461. margin-bottom: 20rpx;
  462. .blue {
  463. color: #157CF8;
  464. }
  465. }
  466. .login-notice {
  467. font-weight: 400;
  468. font-size: 32rpx;
  469. color: #666666;
  470. line-height: 40rpx;
  471. }
  472. }
  473. .force-login__content {
  474. margin-top: 54rpx;
  475. padding: 0 32rpx;
  476. position: relative;
  477. .bg-type {
  478. width: 100%;
  479. position: absolute;
  480. top: 0;
  481. left: 0;
  482. }
  483. .logintype {
  484. display: flex;
  485. align-items: center;
  486. margin-bottom: 66rpx;
  487. border-bottom: 2rpx solid #f0f0f0;
  488. .line {
  489. margin: 0 32rpx;
  490. width: 2rpx;
  491. height: 32rpx;
  492. background: #D7E1F0;
  493. border-radius: 0rpx 0rpx 0rpx 0rpx;
  494. }
  495. .logintype-item {
  496. // flex: 1;
  497. text-align: center;
  498. padding-top: 36rpx;
  499. padding-bottom: 48rpx;
  500. font-family: PingFang SC, PingFang SC;
  501. font-weight: 400;
  502. font-size: 32rpx;
  503. color: #666666;
  504. position: relative;
  505. &.active {
  506. font-size: 36rpx;
  507. color: #333333;
  508. font-weight: 600;
  509. &::after {
  510. content: '';
  511. position: absolute;
  512. bottom: 30rpx;
  513. left: 50%;
  514. transform: translateX(-50%);
  515. width: 52rpx;
  516. height: 6rpx;
  517. background: #157CF8;
  518. border-radius: 42rpx;
  519. }
  520. }
  521. }
  522. }
  523. .input-form {
  524. margin-bottom: 60rpx;
  525. .input-item {
  526. background: #FFFFFF;
  527. border-radius: 16rpx;
  528. padding: 30rpx 40rpx;
  529. margin-bottom: 48rpx;
  530. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  531. &::last-child {
  532. margin-bottom: 0
  533. }
  534. .input-field {
  535. width: 100%;
  536. font-size: 30rpx;
  537. font-family: PingFang SC;
  538. color: #333333;
  539. &::placeholder {
  540. color: #CCCCCC;
  541. }
  542. }
  543. .mima {
  544. width: 100%;
  545. display: flex;
  546. align-items: center;
  547. justify-content: space-between;
  548. image {
  549. width: 32rpx;
  550. height: 32rpx;
  551. }
  552. }
  553. &.code-input-item {
  554. display: flex;
  555. align-items: center;
  556. .code-input {
  557. flex: 1;
  558. }
  559. .get-code-btn {
  560. font-size: 28rpx;
  561. font-family: PingFang SC;
  562. font-weight: 500;
  563. color: #157CF8;
  564. padding-left: 20rpx;
  565. white-space: nowrap;
  566. }
  567. }
  568. }
  569. }
  570. .forgot {
  571. font-weight: 400;
  572. font-size: 24rpx;
  573. color: #388BFF;
  574. line-height: 40rpx;
  575. display: flex;
  576. justify-content: flex-end;
  577. margin: -40rpx 0 24rpx;
  578. }
  579. .encoding {
  580. width: 100%;
  581. height: 104rpx;
  582. line-height: 104rpx;
  583. text-align: center;
  584. background: #EDEFF2;
  585. border-radius: 16rpx 16rpx 16rpx 16rpx;
  586. font-size: 32rpx;
  587. color: #999999;
  588. }
  589. .login-btn-wrap {
  590. margin-bottom: 40rpx;
  591. margin-top: 140rpx;
  592. .login-btn {
  593. width: 100%;
  594. height: 88rpx;
  595. background: rgba(56, 139, 255, 1);
  596. border-radius: 44rpx;
  597. font-size: 32rpx;
  598. font-family: PingFang SC;
  599. font-weight: 500;
  600. color: #FFFFFF;
  601. border: none;
  602. display: flex;
  603. align-items: center;
  604. justify-content: center;
  605. &::after {
  606. border: none;
  607. }
  608. }
  609. }
  610. }
  611. }
  612. .tips {
  613. display: flex;
  614. justify-content: center;
  615. align-items: center;
  616. font-size: 24rpx;
  617. color: #666666;
  618. flex-wrap: nowrap;
  619. padding: 0 60rpx;
  620. checkbox {
  621. margin-right: 10rpx;
  622. flex-shrink: 0;
  623. transform: scale(0.8);
  624. }
  625. .tips-text {
  626. margin-right: 4rpx;
  627. white-space: nowrap;
  628. }
  629. .btn {
  630. color: #157CF8;
  631. margin: 0 2rpx;
  632. white-space: nowrap;
  633. }
  634. }
  635. .wx-login {
  636. background: rgba(0, 0, 0, 0.7);
  637. z-index: 99999;
  638. position: fixed;
  639. top: 0;
  640. left: 0;
  641. height: 100%;
  642. width: 100%;
  643. display: flex;
  644. align-items: center;
  645. justify-content: center;
  646. .form {
  647. border-radius: 20rpx;
  648. padding: 60rpx 30rpx;
  649. width: 500upx;
  650. height: 300upx;
  651. background-color: #fff;
  652. .title {
  653. font-size: 32upx;
  654. font-family: PingFang SC;
  655. font-weight: bold;
  656. }
  657. .desc {
  658. font-size: 28upx;
  659. margin: 60upx 0upx 60upx 0upx;
  660. font-family: PingFang SC;
  661. font-weight: 500;
  662. }
  663. .btn-box {
  664. margin-top: 30rpx;
  665. width: 100%;
  666. display: flex;
  667. align-items: center;
  668. justify-content: center;
  669. .btn {
  670. display: flex;
  671. align-items: center;
  672. justify-content: center;
  673. margin-left: 10upx;
  674. width: 50%;
  675. height: 80rpx;
  676. border-radius: 5rpx;
  677. background-color: #0bb3f2;
  678. font-size: 30rpx;
  679. font-family: PingFang SC;
  680. font-weight: 500;
  681. color: #fff;
  682. position: relative;
  683. }
  684. .btn-close {
  685. margin-right: 10upx;
  686. width: 50%;
  687. height: 80rpx;
  688. border-radius: 5rpx;
  689. border: 2rpx solid #0bb3f2;
  690. background: none;
  691. font-size: 30rpx;
  692. font-family: PingFang SC;
  693. font-weight: 500;
  694. color: #0bb3f2;
  695. }
  696. }
  697. }
  698. }
  699. .auth_btn {
  700. width: 100%;
  701. height: 100%;
  702. top: 0upx;
  703. position: absolute;
  704. opacity: 0.0;
  705. }
  706. </style>