login.vue 16 KB

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