login.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <template>
  2. <view class="app-login-page">
  3. <view class="app-login">
  4. <view class="app-icon mb-30">
  5. <image src="https://sylwt.top/api/visitor/resources/image?name=/ydl/menber-center/login-icon.png"
  6. mode="aspectFit" style="height: 40px;"></image>
  7. </view>
  8. <view class="app-title mb-30">
  9. 欢迎使用会员中心系统小程序
  10. </view>
  11. <view class="mb-30 login-form">
  12. <view class="loginType">
  13. <text :class="[loginType=='phone'? 'loginType-text-active': 'loginType-text']"
  14. @click="loginType = 'phone'">手机登录</text>
  15. <text :class="[loginType=='username'? 'loginType-text-active': 'loginType-text']"
  16. @click="loginType = 'username'">账号登录</text>
  17. </view>
  18. <view class="phone-form" v-if="loginType=='phone'">、
  19. <view class="form-item">
  20. <u-input height="80" placeholder="请输入手机号" border-color="#d0d0d0" v-model="phoneForm.phone"
  21. :border="true" class="form-item-input" type="number" @confirm="phoneLoginHandle" />
  22. </view>
  23. <view class="form-item">
  24. <u-input height="80" placeholder="请输入验证码" border-color="#d0d0d0" v-model="phoneForm.captcha"
  25. :border="true" class="form-item-input" @confirm="phoneLoginHandle" />
  26. <text class="form-item-text" @click="getCode">{{tips}}</text>
  27. <!-- <text class="form-item-text" v-if="!isCounting" @click="requestVerificationCode">
  28. 发送验证码</text>
  29. <text class="form-item-text" v-else>
  30. {{ `发送验证码(${countdown})` }}</text> -->
  31. </view>
  32. <view class="form-button" @click="phoneLoginHandle">
  33. 立即登录
  34. </view>
  35. </view>
  36. <view class="phone-form" v-if="loginType=='username'">、
  37. <view class="form-item">
  38. <u-input height="80" placeholder="请输入账号" border-color="#d0d0d0" v-model="userNameForm.username"
  39. :border="true" class="form-item-input" @confirm="userNameLoginHandle" />
  40. </view>
  41. <view class="form-item">
  42. <u-input height="80" placeholder="请输入密码" border-color="#d0d0d0" v-model="userNameForm.password"
  43. :border="true" class="form-item-input" @confirm="userNameLoginHandle" />
  44. </view>
  45. <view class="form-button" @click="userNameLoginHandle">
  46. 立即登录
  47. </view>
  48. </view>
  49. <view class="risgiter-forget">
  50. <view @click="toPage('/pages/forget/forget')">忘记密码?</view>
  51. <view @click="toPage('/pages/register/register')">无账号?<text class="text-red">立即注册</text></view>
  52. </view>
  53. </view>
  54. <view class="app-user-book mb-30">
  55. <u-checkbox-group style="display: flex;justify-content: center;">
  56. <u-checkbox v-model="userBook" name="yes" shape="circle">我已阅读&#x300A;用户手册&#x300B;及隐私政策</u-checkbox>
  57. </u-checkbox-group>
  58. </view>
  59. <u-divider bg-color="transparent" margin-bottom="30" color="#010101" border-color="#010101"
  60. half-width="200">使用第三方账号登录</u-divider>
  61. <view class="app-icon mb-30">
  62. <u-button v-if="canIUseGetUserProfile" @click="getUserProfile" class="custom-button"
  63. style="width: 40px;" plain :hair-line="false">
  64. <image src="https://sylwt.top/api/visitor/resources/image?name=/ydl/menber-center/weixin.png"
  65. mode="aspectFit" style="width: 40px;height: 40px;" />
  66. </u-button>
  67. <u-button v-else open-type="getPhoneNumber" @getuserinfo="decryptPhoneNumber" class="custom-button"
  68. style="width: 40px;" plain :hair-line="false">
  69. <image src="https://sylwt.top/api/visitor/resources/image?name=/ydl/menber-center/weixin.png"
  70. mode="aspectFit" style="width: 40px;height: 40px;" />
  71. </u-button>
  72. <!-- <button type="default" open-type="getPhoneNumber" @getphonenumber="decryptPhoneNumber">获取手机号</button> -->
  73. <!-- <image src="https://sylwt.top/api/visitor/resources/image?name=/ydl/menber-center/weixin.png" mode="aspectFit" style="height: 40px;"></image> -->
  74. </view>
  75. </view>
  76. <u-verification-code :seconds="seconds" ref="uCode1" @change="codeChange"></u-verification-code>
  77. <u-popup v-model="show" mode="center" border-radius="10">
  78. <view class="popup">
  79. <text class="popup-title">请输入验证码</text>
  80. <view class="popup-content">
  81. <u-input height="80" placeholder="请输入验证码" border-color="#d0d0d0"
  82. v-model="numberCaptchaForm.numberCaptcha" :border="true" class="form-item-input"
  83. style="flex-grow: 1;" @confirm="submitCode" />
  84. <image :src="numberCaptchaSrc" mode="aspectFit"
  85. style="height:40px;margin-left:20rpx;width: 180rpx;flex: 0 0 auto;"></image>
  86. </view>
  87. <view class="popup-btn">
  88. <u-button type="primary" @click="submitCode" style="width: 48%;flex: 0 0 auto;">提交</u-button>
  89. <u-button type="default" @click="closePopup" style="width: 48%;flex: 0 0 auto;">取消</u-button>
  90. </view>
  91. </view>
  92. </u-popup>
  93. <u-modal v-model="userBookModal" mask-close-able class="modal" show-cancel-button
  94. :title-style="{fontWeight: 'bold'}" @confirm="confirmModal">
  95. <view class="modal-content">
  96. 为了更好地保障你的合法权益,进行下一步前,请阅读并同意
  97. <text class="content-a">&#x300A;用户手册&#x300B;及隐私政策</text>
  98. </view>
  99. </u-modal>
  100. </view>
  101. </template>
  102. <script>
  103. import {
  104. usernameLogin
  105. } from "@/api/user.js"
  106. import {
  107. msg,
  108. msgSuccess
  109. } from "@/utils/common.js"
  110. import {
  111. useAuthStore
  112. } from '@/store/authStore'
  113. import {
  114. encryptAESCBC
  115. } from "@/utils/crypto.js"
  116. export default {
  117. data() {
  118. return {
  119. canIUseGetUserProfile: false,
  120. loginCode: '',
  121. userBookModal: false,
  122. // ----验证码 start -----
  123. numberCaptchaForm: {
  124. numberCaptcha: '',
  125. numberCaptchaUuid: ''
  126. },
  127. numberCaptchaSrc: 'https://imgconvert.csdnimg.cn/aHR0cDovL3RjLnhpYW55dWNvZGVyLmNuL2Jsb2cyMDIwMDEwNDIwMzUwNy5wbmc?x-oss-process=image/format,png',
  128. show: false,
  129. tips: '',
  130. seconds: 60,
  131. // ----验证码 end -----
  132. loginType: "phone",
  133. phoneForm: {
  134. phone: '15312341234',
  135. captcha: '123456',
  136. captchaUuid: ''
  137. },
  138. userNameForm: {
  139. username: "纪学卫",
  140. password: "123456"
  141. },
  142. userBook: false, //协议
  143. }
  144. },
  145. methods: {
  146. // 检查用户手册是否勾选
  147. checkUserBook() {
  148. if (!this.userBook) {
  149. this.userBookModal = true
  150. return false;
  151. }
  152. return true
  153. },
  154. // 用户手册模拟态确认勾选
  155. confirmModal() {
  156. this.userBook = true;
  157. const loginTypeHandler = {
  158. phone: this.phoneLoginHandle,
  159. username: this.userNameLoginHandle
  160. };
  161. // 调用相应的登录处理函数
  162. (loginTypeHandler[this.loginType] || (() => {})).call(this);
  163. },
  164. // 手机登录
  165. async phoneLoginHandle() {
  166. const {
  167. phone,
  168. captcha
  169. } = this.phoneForm;
  170. // 手机号正则验证
  171. if (!/^1[3-9]\d{9}$/.test(phone)) {
  172. msg("请输入正确的手机号");
  173. return;
  174. }
  175. // 验证码存在性检查
  176. if (!captcha) {
  177. msg("请输入验证码");
  178. return;
  179. }
  180. let checkUserBook = await this.checkUserBook()
  181. if (!this.checkUserBook()) return;
  182. console.log(this.phoneForm)
  183. // 联调
  184. // 1.登录 发送请求
  185. // 2.保存 token
  186. // 3.获取个人信息,保存个人新
  187. msg("登录成功");
  188. setTimeout(() => {
  189. this.useAuthStore.setAuthToken("test")
  190. uni.setStorageSync("userinfo", {
  191. userId: "2121",
  192. isMember: true
  193. })
  194. uni.switchTab({
  195. url: "/pages/index/index"
  196. })
  197. }, 1000)
  198. },
  199. // 账号登录
  200. async userNameLoginHandle() {
  201. if (!this.userNameForm.username) {
  202. msg("请输入账号")
  203. return;
  204. }
  205. if (!this.userNameForm.password) {
  206. msg("请输入密码")
  207. return;
  208. }
  209. let checkUserBook = await this.checkUserBook()
  210. if (!this.checkUserBook()) {
  211. return;
  212. };
  213. const form = {
  214. ...this.userNameForm
  215. }
  216. form.password = encryptAESCBC(form.password);
  217. usernameLogin(form).then(res => {
  218. if (res?.token) {
  219. msgSuccess("登录成功!")
  220. this.useAuthStore.setAuthToken(res.token)
  221. setTimeout(() => {
  222. uni.switchTab({
  223. url: "/pages/index/index"
  224. })
  225. }, 1000)
  226. }
  227. })
  228. },
  229. toPage(url) {
  230. uni.navigateTo({
  231. url: url
  232. })
  233. },
  234. // --------验证码 start---------
  235. codeChange(text) {
  236. this.tips = text;
  237. },
  238. getCode() {
  239. let {
  240. phone
  241. } = this.phoneForm
  242. if (!/^1[3-9]\d{9}$/.test(phone)) {
  243. msg("请输入正确的手机号");
  244. return;
  245. }
  246. if (this.$refs.uCode1.canGetCode) {
  247. this.showPopup()
  248. } else {
  249. msg('倒计时结束后再发送');
  250. }
  251. },
  252. end() {
  253. msg('倒计时结束');
  254. },
  255. start() {
  256. msg('倒计时开始');
  257. },
  258. showPopup() {
  259. // 模拟向后端请求验证码
  260. // 1.获取数字校验码图片
  261. // 2.显示弹窗
  262. uni.showLoading({
  263. title: '正在获取图片'
  264. })
  265. console.log("获取数字验证码图片")
  266. setTimeout(() => {
  267. uni.hideLoading();
  268. msg('获取成功');
  269. // 显示模拟态,把获取过来的数字校对码的uuid赋给 numberCaptchaForm.numberCaptchaUuid
  270. this.show = true;
  271. }, 1500);
  272. // 联调
  273. // this.loadImage()
  274. // this.show = true;
  275. },
  276. closePopup() {
  277. this.show = false;
  278. this.numberCaptchaForm.numberCaptcha = ''; // 清空输入框
  279. },
  280. async submitCode() {
  281. if (this.numberCaptchaForm.numberCaptcha.length !== 4) {
  282. uni.showToast({
  283. title: '请输入4位验证码',
  284. icon: 'none'
  285. });
  286. return;
  287. }
  288. console.log("联调:验证数字验证码是否正确")
  289. console.log("联调:发送手机验证码")
  290. // 联调 检验是否正确
  291. // const checkRes = await checknumberCaptcha();
  292. // if(!checkRes){
  293. // uni.showToast({
  294. // title: '验证码输入错误',
  295. // icon: 'none'
  296. // });
  297. // return;
  298. // }
  299. // // 发送手机验证码
  300. // const codeRes = await getCodeApi();
  301. // if(codeRes && codeRes.captchaUuid){
  302. // this.phoneForm.captchaUuid = codeRes.captchaUuid
  303. // this.closePopup();
  304. // this.$refs.uCode1.start()
  305. // }
  306. uni.showLoading({
  307. title: '正在校验验证码'
  308. })
  309. setTimeout(() => {
  310. uni.hideLoading();
  311. msg('填写正确');
  312. this.closePopup();
  313. this.$refs.uCode1.start()
  314. }, 1500);
  315. },
  316. // 加载验证码图片
  317. async loadImage() {
  318. // 联调
  319. // const img = await loadnumberCaptcha();
  320. // this.numberCaptchaForm.numberCaptchaUuid = img.numberCaptchaUuid
  321. // this.numberCaptchaSrc = img.numberCaptchaSrc
  322. console.log("加载图片")
  323. },
  324. // --------验证码 end---------
  325. handleWxLogin() {
  326. console.log("weixindenglu")
  327. },
  328. decryptPhoneNumber(e) {
  329. if (e.detail.encryptedData) {
  330. const {
  331. encryptedData,
  332. iv
  333. } = e.detail;
  334. // 将 encryptedData 和 iv 发送到后端进行解密
  335. } else {
  336. msg('取消授权手机号');
  337. }
  338. },
  339. getUserProfile() {
  340. this.toPage("/pages/wxLogin/wxLogin")
  341. // 用户微信登录
  342. // let that = this;
  343. // 推荐使用uni.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
  344. // 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
  345. // uni.getUserProfile({
  346. // desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
  347. // success: (resp) => {
  348. // //登录远程服务器
  349. // console.log(resp)
  350. // if (that.loginCode) {
  351. // //登录远程服务器
  352. // console.log("登录远程服务器")
  353. // // that.loginByWeixin(resp)
  354. // } else {
  355. // uni.login({
  356. // success: function(resp) {
  357. // if (resp.code) {
  358. // that.code = resp.code
  359. // console.log(resp)
  360. // // that.loginByWeixin(resp)
  361. // }
  362. // }
  363. // });
  364. // }
  365. // }
  366. // })
  367. }
  368. },
  369. // 在组件销毁时清理定时器
  370. beforeDestroy() {
  371. // 在组件销毁时清理定时器
  372. },
  373. computed: {
  374. useAuthStore() {
  375. return useAuthStore(); // 获取 store 实例
  376. }
  377. },
  378. onLoad() {
  379. const that = this;
  380. if (uni.getUserProfile) {
  381. that.canIUseGetUserProfile = true
  382. }
  383. }
  384. }
  385. </script>
  386. <style lang="scss">
  387. .form-item .u-input--border {
  388. border-radius: 16rpx !important;
  389. }
  390. .custom-button {
  391. .u-btn {
  392. display: block !important;
  393. width: fit-content;
  394. padding: 0 !important;
  395. border-radius: 50rpx;
  396. }
  397. .u-btn--default {
  398. border: none !important;
  399. background-color: transparent !important;
  400. }
  401. }
  402. </style>
  403. <style lang="scss" scoped>
  404. .app-login-page {
  405. background-color: #f7f7f7;
  406. width: 100vw;
  407. height: 100vh;
  408. display: flex;
  409. justify-content: center;
  410. align-items: center;
  411. }
  412. .app-login {
  413. width: 90%;
  414. }
  415. .app-icon {
  416. text-align: center;
  417. }
  418. .app-title {
  419. text-align: center;
  420. font-size: 44rpx;
  421. letter-spacing: 2px;
  422. font-weight: 700;
  423. }
  424. .mb-30 {
  425. margin-bottom: 30rpx;
  426. }
  427. .text-red {
  428. color: #df0505;
  429. }
  430. .login-form {
  431. background-color: #ffffff;
  432. width: 100%;
  433. padding: 50rpx 40rpx;
  434. border-radius: 15rpx;
  435. box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
  436. border: 1px solid #036df6;
  437. }
  438. .loginType {
  439. color: #000000;
  440. margin-bottom: 15rpx;
  441. .loginType-text {
  442. font-size: 30rpx;
  443. margin-right: 30rpx;
  444. }
  445. .loginType-text-active {
  446. font-size: 40rpx;
  447. margin-right: 30rpx;
  448. }
  449. }
  450. .form-item {
  451. display: flex;
  452. align-items: center;
  453. margin-bottom: 60rpx;
  454. .form-item-input {
  455. width: 100%;
  456. background-color: #f7f7f7 !important;
  457. }
  458. .form-item-text {
  459. width: 200rpx;
  460. flex: 0 0 auto;
  461. text-align: center;
  462. color: #000000;
  463. // margin: 0 20px;
  464. }
  465. }
  466. .form-button {
  467. background: linear-gradient(90deg, #006af5, #21b0fc);
  468. border-radius: 20rpx;
  469. line-height: 80rpx;
  470. text-align: center;
  471. color: #fff;
  472. margin-bottom: 50rpx;
  473. }
  474. .risgiter-forget {
  475. font-size: 30rpx;
  476. display: flex;
  477. justify-content: space-between;
  478. }
  479. // 数字验证码
  480. .popup {
  481. padding: 40rpx;
  482. border-radius: 20rpx;
  483. .popup-title {
  484. font-size: 18px;
  485. text-align: center;
  486. display: inline-block;
  487. width: 100%;
  488. // margin-bottom: 15px;
  489. }
  490. .popup-content {
  491. display: flex;
  492. align-items: center;
  493. margin: 50rpx 0;
  494. }
  495. .popup-btn {
  496. display: flex;
  497. justify-content: space-between;
  498. }
  499. }
  500. // 用户手册模拟态
  501. .modal {
  502. .modal-content {
  503. padding: 50rpx;
  504. .content-a {
  505. color: #2979ff;
  506. }
  507. }
  508. }
  509. </style>