login.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <template>
  2. <view class="login-box">
  3. <view class="login-title">骑手登录</view>
  4. <view class="logo">
  5. <image src="@/static/login/logo.png" mode="aspectFit"></image>
  6. </view>
  7. <view class="desc">
  8. <image src="@/static/login/desc.png"></image>
  9. </view>
  10. <view class="form">
  11. <view class="form_item">
  12. <image class="img1" src="@/static/login/phone.png"></image>
  13. <input class="inp1" placeholder-class="pl" type="number" v-model="phone" placeholder="请输入手机号码"
  14. @input="onInput" />
  15. </view>
  16. <view class="form_item">
  17. <image class="img1" src="@/static/login/password.png"></image>
  18. <input class="inp1" password="true" placeholder-class="pl" type="text" v-model="password" placeholder="请输入密码" />
  19. </view>
  20. </view>
  21. <view style="padding-top: 76rpx;">
  22. <button class="btn" @click="userLogin()">登录</button>
  23. <button class="btn" @click="goBack">返回</button>
  24. </view>
  25. <!-- #ifdef MP-WEIXIN -->
  26. <view class="other-login" v-if="!puserInfo.phone" @click="getUserProfile()">
  27. <view class="ol-tilte">
  28. <text>授权登录</text>
  29. </view>
  30. <div class="wx-login">
  31. <image src="@/static/login/weixin_icon.png" mode="aspectFit" />
  32. </div>
  33. </view>
  34. <view v-else class="other-login" @click="fakeLogin()">
  35. <view class="ol-tilte">
  36. <text>一键登录</text>
  37. </view>
  38. <div class="wx-login">
  39. <image src="@/static/login/weixin_icon.png" mode="aspectFit" />
  40. </div>
  41. </view>
  42. <!-- #endif -->
  43. <image class="bottom_img" src="@/static/login/bottom_img.png" mode="widthFix" />
  44. <view class="popup-box" v-show="showPopup">
  45. <view class="login-popup">
  46. <view class="lp-top">
  47. <view class="lpt-left">
  48. <view class="title"> <text>登录</text> </view>
  49. <view class="tips"> <text>登录即可解锁更多权益</text> </view>
  50. </view>
  51. <view class="lpt-right" @click="showPopup=false">
  52. <image src="@/static/login/close_icon.png" mode="aspectFill"></image>
  53. </view>
  54. </view>
  55. <view class="lp-center">
  56. <view class="title">申请获取以下权限</view>
  57. <view class="tips">获得你的公开信息(昵称、头像等)</view>
  58. <view class="tips">获得你的手机号码</view>
  59. </view>
  60. <view class="lp-bottom">
  61. <!-- getUserInfo -->
  62. <button class="option-btn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
  63. 获取手机号
  64. </button>
  65. </view>
  66. </view>
  67. </view>
  68. </view>
  69. </template>
  70. <script>
  71. import {
  72. mapState,
  73. mapMutations
  74. } from 'vuex';
  75. import appConfig from "@/config/appConfig.js";
  76. export default {
  77. data() {
  78. return {
  79. phone: '',
  80. password: '',
  81. puserInfo:{},
  82. appConfig,
  83. showLoding: true, // 初始化加载时显示遮挡页
  84. wxUserInfo: null, // 保存微信用户数据(临时)
  85. wxLoginInfo: {
  86. code: null,
  87. openid: null,
  88. session_key: null
  89. }, // 微信登录返回信息(临时)
  90. showPopup: false, // 获取电话弹窗
  91. }
  92. },
  93. onLoad() {
  94. this.initLogin();
  95. },
  96. onBackPress(e) {
  97. debugger
  98. // console.log(e)
  99. // 这里可以自定义返回逻辑,比如下面跳转其他页面
  100. uni.navigateTo({
  101. url: '/pages/login/index'
  102. });
  103. // return true 表示禁止默认返回
  104. return true
  105. },
  106. computed: {
  107. ...mapState(['token'])
  108. },
  109. methods: {
  110. ...mapMutations(['saveUserInfo', 'sessionToken']),
  111. userLogin() {
  112. if (!(/^1[3456789]\d{9}$/.test(this.phone))) {
  113. uni.showToast({
  114. title: '请输入正确的手机号',
  115. icon: 'none'
  116. })
  117. return false;
  118. }
  119. if (this.password == '') {
  120. uni.showToast({
  121. title: '请输入密码',
  122. icon: 'none'
  123. })
  124. return false;
  125. }
  126. let params = {
  127. phone: this.phone,
  128. password: this.password,
  129. ip: ''
  130. }
  131. let that = this
  132. that.request("get", "rider/app/loginRider", null, params).then(res => {
  133. if (res.code === 200) {
  134. // 返回带token, 进入订单页
  135. let duration = 1500; // 延迟跳转页面
  136. that.saveUserInfo(res.data); // 缓存用户基础数据
  137. that.sessionToken(res.data.accessToken); // 缓存token
  138. uni.showToast({
  139. title: '登录成功',
  140. duration
  141. })
  142. that.toTaskPage(duration);
  143. }
  144. })
  145. },
  146. /* 判断是否已登录 */
  147. /* 判断是否已登录 */
  148. async initLogin() {
  149. let that = this
  150. if (that.token) {
  151. try {
  152. let newUserData = await that.getUserInfo();
  153. if (newUserData && newUserData.code !== 500) { // 成功且有有效数据
  154. that.saveUserInfo(newUserData); // 缓存用户基础数据
  155. that.toTaskPage();
  156. } else {
  157. // 500错误或其他无效数据,视为未登录
  158. that.showLoding = false;
  159. }
  160. } catch (error) {
  161. // 请求出错,视为未登录
  162. console.error('获取用户信息失败:', error);
  163. that.showLoding = false;
  164. }
  165. } else {
  166. // #ifdef MP-WEIXIN
  167. uni.login({
  168. provider: 'weixin',
  169. success: (wxres => {
  170. this.logining = false
  171. that.request("post", 'rider/wxLogin/wechatLogin',null, {
  172. loginType: 1,
  173. code: wxres.code
  174. }, failres => {
  175. this.$api.msg(failres.msg)
  176. uni.hideLoading()
  177. }).then(res => {
  178. uni.hideLoading()
  179. this.puserInfo = res.data
  180. this.sessionKey = res.data.sessionKey
  181. })
  182. })
  183. })
  184. // #endif
  185. that.showLoding = false;
  186. }
  187. },
  188. onInput(e) {
  189. this.phone = e.target.value;
  190. },
  191. /* 前往任务列表页 */
  192. toTaskPage(duration = 100) {
  193. // debugger
  194. setTimeout(() => {
  195. uni.switchTab({
  196. url: '/pages/task/task'
  197. })
  198. }, duration)
  199. },
  200. goBack() {
  201. uni.navigateTo({
  202. url: '/pages/login/index'
  203. })
  204. },
  205. /* 获取后台用户信息(进入即判断是否过期) */
  206. getUserInfo() {
  207. let that = this;
  208. return new Promise((resolve, reject) => {
  209. that.request("get", "rider/wxLogin/getRiderInfo", that.token, null)
  210. .then(res => {
  211. console.log('getUserInfo', res)
  212. if (res.code === 200) {
  213. resolve(res.data)
  214. } else {
  215. reject(res) // 这里改为 reject,以便在 initLogin 中捕获
  216. }
  217. }).catch(err => {
  218. reject(err) // 捕获请求错误
  219. })
  220. })
  221. },
  222. /* 获取微信用户信息(登录使用) */
  223. getUserProfile() {
  224. // #ifdef MP-WEIXIN
  225. let that = this;
  226. if (that.wxLoginInfo.openid) {
  227. // 已登录,但未获取手机号
  228. that.showPopup = true;
  229. } else if (uni.getUserProfile) {
  230. // 未登录,且版本支持 uni.getUserProfile
  231. uni.getUserProfile({
  232. lang: 'zh_CN',
  233. desc: "获取您的昵称、头像、手机号",
  234. success: async (res) => {
  235. console.log('用户同意了授权', res)
  236. that.wxUserInfo = res.userInfo; // 临时保存微信用户基础数据
  237. that.wxUserInfo['phone'] = '';
  238. that.mpWeixinTologin(); // 微信一键登录
  239. },
  240. fail: (err) => {
  241. console.log('授权失败:', err)
  242. uni.showToast({
  243. title: err
  244. })
  245. }
  246. })
  247. } else {
  248. uni.showToast({
  249. title: '当前版本过低'
  250. })
  251. }
  252. // #endif
  253. // #ifdef H5
  254. this.tempH5Login()
  255. // #endif
  256. },
  257. fakeLogin(){
  258. const that = this
  259. uni.showLoading({})
  260. // 返回带token, 进入订单页
  261. let duration = 1500; // 延迟跳转页面
  262. that.saveUserInfo(that.puserInfo); // 缓存用户基础数据
  263. that.sessionToken(that.puserInfo.accessToken); // 缓存token
  264. uni.showToast({
  265. title: '登录成功',
  266. duration
  267. })
  268. that.toTaskPage(duration);
  269. },
  270. tempH5Login() {
  271. let data = {
  272. "accessToken": "29478626990E478DA9539866489DD87D",
  273. "avatarUrl": "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83epib9DbQJ7VsbLFhWMgiarZSibmRPXWb2tHOtzicnbzpj7Z8lIoBy6icUn0vESMicnMnv8lbGjxYKwSnspw/132",
  274. "deliveryEnd": "23:00",
  275. "deliveryStart": "8:30",
  276. "gmtCreate": 1666885726000,
  277. "gmtLastLogin": 1667054521000,
  278. "gmtUpdate": 1666885726000,
  279. "id": 151,
  280. "lastLoginIp": "27.10.60.71",
  281. "loginType": 1,
  282. "name": "L",
  283. "openId": "o7LCC5YUDftbpo907smJhvgsMnBs",
  284. "phone": "18522563339",
  285. "sessionKey": "yjKdFE0CMSLBKNmrXmFyyQ==",
  286. "state": 1,
  287. "storageId": 11,
  288. "workState": 1
  289. }
  290. let token = '29478626990E478DA9539866489DD87D';
  291. this.saveUserInfo(data); // 缓存用户基础数据
  292. this.sessionToken(token); // 缓存token
  293. this.toTaskPage(100);
  294. },
  295. /* 微信登录 */
  296. mpWeixinTologin() {
  297. let that = this;
  298. uni.login({
  299. provider: 'weixin',
  300. async success(res) {
  301. console.log('微信一键登录', res);
  302. if (res.errMsg == 'login:ok') {
  303. that.wxLoginInfo.code = res.code;
  304. that.serverLogin(1);
  305. }
  306. },
  307. fail(err) {
  308. console.log('uni.login', err);
  309. }
  310. });
  311. },
  312. /* 获取手机号 */
  313. getPhoneNumber(e) {
  314. console.log('获取手机号', e);
  315. let that = this;
  316. if (!that.wxLoginInfo.openid || !e.detail.encryptedData) {
  317. return false; // 未登录
  318. }
  319. that.showPopup = false; // 显示获取手机号按钮
  320. let content = {
  321. openid: that.wxLoginInfo.openid,
  322. sessionkey: that.wxLoginInfo.session_key,
  323. encryptedData: e.detail.encryptedData,
  324. iv: e.detail.iv,
  325. }
  326. let params = {
  327. raw: JSON.stringify(content)
  328. };
  329. that.request("get", "rider/wxLogin/decryptS5", null, params).then(resolve => {
  330. //console.log('获取解密手机号', resolve)
  331. if (resolve.code === 200) {
  332. //debugger
  333. let data = JSON.parse(resolve.data);
  334. that.wxUserInfo.phone = data.phoneNumber;
  335. that.serverLogin(2);
  336. } else {
  337. uni.showToast({
  338. title: resolve.msg
  339. })
  340. }
  341. })
  342. },
  343. /* 后台登录 */
  344. serverLogin(type) {
  345. // type: 1-第一次后台登录(返回无token) 2-第一次后台登录(返回带token)
  346. let that = this;
  347. let content = {
  348. code: that.wxLoginInfo.code,
  349. phone: that.wxUserInfo.phone,
  350. nickName: that.wxUserInfo.nickName,
  351. avatarUrl: that.wxUserInfo.avatarUrl,
  352. openid: that.wxLoginInfo.openid,
  353. session_key: that.wxLoginInfo.session_key,
  354. };
  355. that.request("post", "rider/wxLogin/wechatLogin", null, content).then(res => {
  356. console.log('获取数据库返回的用户信息', res);
  357. if (res.code === 200) {
  358. // 至此实际已登录
  359. that.wxLoginInfo.openid = res.data.openId;
  360. that.wxLoginInfo.session_key = res.data.sessionKey;
  361. // 保存数据库返回的用户信息
  362. if (type === 1) {
  363. // 返回无token, 另需获取手机号绑定对应的openid
  364. that.showPopup = true; // 显示获取手机号按钮
  365. } else {
  366. // 返回带token, 进入订单页
  367. let duration = 1500; // 延迟跳转页面
  368. that.saveUserInfo(res.data); // 缓存用户基础数据
  369. that.sessionToken(res.data.accessToken); // 缓存token
  370. uni.showToast({
  371. title: '登录成功',
  372. duration
  373. })
  374. that.toTaskPage(duration);
  375. }
  376. } else {
  377. uni.showToast({
  378. title: res.msg
  379. })
  380. }
  381. })
  382. }
  383. }
  384. }
  385. </script>
  386. <style lang="less" scoped>
  387. .login-box {
  388. position: relative;
  389. width: 100vw;
  390. height: 100vh;
  391. }
  392. .login-title {
  393. text-align: center;
  394. padding-top: 74rpx;
  395. font-size: 36rpx;
  396. color: #333333;
  397. font-weight: bold;
  398. }
  399. .logo {
  400. text-align: center;
  401. padding-top: 72rpx;
  402. image {
  403. width: 172rpx;
  404. height: 172rpx;
  405. }
  406. }
  407. .desc {
  408. text-align: center;
  409. padding-top: 48rpx;
  410. image {
  411. width: 284rpx;
  412. height: 46rpx;
  413. }
  414. }
  415. .form {
  416. width: 618rpx;
  417. margin: 0 auto;
  418. padding-top: 32rpx;
  419. .form_item {
  420. height: 100rpx;
  421. border-bottom: 2rpx solid #EFEFEF;
  422. position: relative;
  423. }
  424. .img1 {
  425. width: 36rpx;
  426. height: 40rpx;
  427. position: absolute;
  428. left: 26rpx;
  429. bottom: 28rpx;
  430. }
  431. .inp1 {
  432. width: 524rpx;
  433. display: inline-block;
  434. position: absolute;
  435. bottom: 0;
  436. height: 98rpx;
  437. left: 96rpx;
  438. /* color: #BBBBBB; */
  439. font-size: 30rpx;
  440. line-height: 98rpx;
  441. }
  442. .pl {
  443. color: #BBBBBB;
  444. font-size: 30rpx;
  445. }
  446. }
  447. .btn {
  448. width: 640rpx;
  449. height: 96rpx;
  450. line-height: 96rpx;
  451. color: #FFFFFF;
  452. background: linear-gradient(to right, #5095F4, #3662DD);
  453. font-size: 32rpx;
  454. border-radius: 8rpx;
  455. margin: 0 auto;
  456. }
  457. .btn+.btn {
  458. margin-top: 20rpx;
  459. }
  460. .other-login {
  461. position: relative;
  462. z-index: 5;
  463. width: 618rpx;
  464. margin: 80rpx auto 0;
  465. .ol-tilte {
  466. display: flex;
  467. align-items: center;
  468. justify-content: center;
  469. &:before,
  470. &:after {
  471. display: block;
  472. content: '';
  473. width: 30%;
  474. border-bottom: 2rpx solid #EFEFEF;
  475. }
  476. text {
  477. color: #666;
  478. font-size: 26rpx;
  479. padding: 0 20rpx;
  480. }
  481. }
  482. .wx-login {
  483. width: 88rpx;
  484. height: 88rpx;
  485. margin: 40rpx auto 0;
  486. image {
  487. display: block;
  488. width: 100%;
  489. height: 100%;
  490. }
  491. }
  492. }
  493. .bottom_img {
  494. position: absolute;
  495. left: 0;
  496. bottom: 0;
  497. display: block;
  498. width: 100%;
  499. }
  500. .popup-box {
  501. position: absolute;
  502. top: 0;
  503. left: 0;
  504. width: 100%;
  505. height: 100%;
  506. z-index: 10;
  507. background-color: rgba(0, 0, 0, .5);
  508. }
  509. .login-popup {
  510. position: absolute;
  511. left: 0;
  512. bottom: 0;
  513. width: 100%;
  514. z-index: 10;
  515. background-color: #fff;
  516. padding-bottom: 40rpx;
  517. .lp-top {
  518. display: flex;
  519. align-items: center;
  520. color: #000;
  521. line-height: 1.2;
  522. .lpt-left {
  523. flex: 1;
  524. padding: 30rpx;
  525. .title {
  526. font-size: 28rpx;
  527. font-weight: 500;
  528. }
  529. .tips {
  530. color: #9a9b9b;
  531. font-size: 18rpx;
  532. margin-top: 10rpx;
  533. }
  534. }
  535. .lpt-right {
  536. padding: 30rpx;
  537. image {
  538. display: block;
  539. width: 28rpx;
  540. height: 28rpx;
  541. }
  542. }
  543. }
  544. .lp-center {
  545. position: relative;
  546. padding: 10rpx 30rpx 40rpx;
  547. color: #000;
  548. &:after {
  549. position: absolute;
  550. bottom: 0;
  551. left: 30rpx;
  552. right: 30rpx;
  553. content: '';
  554. border-bottom: 1rpx solid #ededed;
  555. }
  556. .title {
  557. font-size: 28rpx;
  558. font-weight: 600;
  559. }
  560. .tips {
  561. font-size: 26rpx;
  562. margin-top: 10rpx;
  563. }
  564. }
  565. .lp-bottom {
  566. padding: 0 30rpx;
  567. margin-top: 40rpx;
  568. .option-btn {
  569. height: 86rpx;
  570. color: #fff;
  571. font-size: 22rpx;
  572. text-align: center;
  573. line-height: 86rpx;
  574. padding: 0 30rpx;
  575. background: linear-gradient(to right, #5095F4, #3662DD);
  576. }
  577. }
  578. }
  579. </style>