login.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <template>
  2. <view class="container">
  3. <!--顶部返回按钮-->
  4. <text class="back-btn iconfont iconzuojiantou-up" @tap="navBack"></text>
  5. <view class="login-title">
  6. <image
  7. class="logo"
  8. mode="widthFix"
  9. src="@/static/img/logo-xd.png"
  10. ></image>
  11. <view class="title">商家端管理后台登录</view>
  12. </view>
  13. <!-- 设置白色背景防止软键盘把下部绝对定位元素顶上来盖住输入框等 -->
  14. <view class="wrapper">
  15. <view class="input-content">
  16. <view class="input-item">
  17. <input
  18. type="text"
  19. name="username"
  20. v-model="loginParams.username"
  21. placeholder="请输入账户名"
  22. />
  23. </view>
  24. <view class="input-item" v-if="loginByPass">
  25. <input
  26. name="password"
  27. type="password"
  28. v-model="loginParams.password"
  29. placeholder="请输入密码"
  30. />
  31. </view>
  32. <view class="input-item relative" v-if="loginByPass">
  33. <input class="codenum"
  34. name="code"
  35. type="text"
  36. v-model="loginParams.code"
  37. placeholder="请输入验证码"
  38. />
  39. <image
  40. @tap="getCaptchaImage"
  41. class="codeImage"
  42. mode="widthFix"
  43. :src="codeImage"
  44. ></image>
  45. </view>
  46. <button
  47. class="confirm-btn"
  48. :disabled="btnLoading"
  49. :loading="btnLoading"
  50. @tap="toLogin"
  51. >
  52. 登录
  53. </button>
  54. </view>
  55. <view class="forget-section" @tap="navTo()">
  56. 忘记密码?
  57. </view>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. import { authLogin, loginByPass, loginBySmsCode, smsCode } from '@/api/login';
  63. import moment from '@/common/moment';
  64. export default {
  65. data() {
  66. return {
  67. loginParams: {
  68. username: 'wljq',
  69. code: '',
  70. password: 'Ectrip2020',
  71. uuid: null,
  72. },
  73. codeImage: null,
  74. btnLoading: false,
  75. reqBody: {},
  76. codeSeconds: 0, // 验证码发送时间间隔
  77. loginByPass: true,
  78. smsCodeBtnDisabled: true,
  79. userInfo: null,
  80. };
  81. },
  82. onShow() {
  83. if (this.$mStore.getters.hasLogin) {
  84. this.$mRouter.reLaunch({ route: '/pages/index/index' });
  85. }
  86. },
  87. // 页面生命周期 监听页面加载是否加载完成
  88. onLoad() {
  89. const time = moment().valueOf() / 1000 - uni.getStorageSync('loginSmsCodeTime'); // 从本地缓存中异步获取指定 key 对应的内容。
  90. if (time < 60) {
  91. this.codeSeconds = this.$mConstDataConfig.sendCodeTime - parseInt(time, 10);
  92. this.handleSmsCodeTime(this.codeSeconds);
  93. } else {
  94. this.codeSeconds = this.$mConstDataConfig.sendCodeTime;
  95. this.smsCodeBtnDisabled = false;
  96. uni.removeStorageSync('loginSmsCodeTime');
  97. }
  98. this.loginParams.mobile = uni.getStorageSync('loginMobile') || '';
  99. this.loginParams.password = uni.getStorageSync('loginPassword') || '';
  100. this.userInfo = uni.getStorageSync('wechatUserInfo');
  101. this.getCaptchaImage();
  102. },
  103. methods: {
  104. loginTest(mobile, password) {
  105. this.loginParams.mobile = mobile;
  106. this.loginParams.password = password;
  107. },
  108. // 发送验证码并进入倒计时
  109. async getSmsCode() {
  110. this.reqBody['mobile'] = this.loginParams['mobile'];
  111. let checkSendCode = this.$mGraceChecker.check(
  112. this.reqBody,
  113. this.$mFormRule.sendCodeRule
  114. );
  115. if (!checkSendCode) {
  116. this.$mHelper.toast(this.$mGraceChecker.error);
  117. return;
  118. }
  119. await this.$http
  120. .post(smsCode, {
  121. mobile: this.loginParams.mobile,
  122. usage: 'login',
  123. })
  124. .then((r) => {
  125. if (r.data) {
  126. this.$mHelper.toast(`验证码发送成功, 验证码是${r.data}`);
  127. } else {
  128. this.$mHelper.toast('验证码已发送.');
  129. }
  130. this.smsCodeBtnDisabled = true;
  131. uni.setStorageSync('loginSmsCodeTime', moment().valueOf() / 1000);
  132. this.handleSmsCodeTime(59);
  133. });
  134. },
  135. handleSmsCodeTime(time) {
  136. let timer = setInterval(() => {
  137. if (time === 0) {
  138. clearInterval(timer);
  139. this.smsCodeBtnDisabled = false;
  140. } else {
  141. this.codeSeconds = time;
  142. this.smsCodeBtnDisabled = true;
  143. time--;
  144. }
  145. }, 1000);
  146. },
  147. // 失去焦点的手机号
  148. blurMobileChange(e) {
  149. this.mobile = e.detail.value;
  150. },
  151. // 切换登录方式
  152. showLoginBySmsCode() {
  153. this.loginByPass = !this.loginByPass;
  154. },
  155. // 返回上一页
  156. navBack() {
  157. this.$mRouter.back();
  158. },
  159. // 统一跳转路由
  160. navTo() {
  161. this.$mRouter.redirectTo({ route: '/pages/public/resetpassword' });
  162. },
  163. // 返回主页
  164. toHome() {
  165. this.$mRouter.reLaunch({ route: '/pages/index/index' });
  166. },
  167. // 获取验证码
  168. async getCaptchaImage() {
  169. await this.$http
  170. .get('captchaImage', {})
  171. .then(async (r) => {
  172. this.codeImage = 'data:image/gif;base64,' + r.data.img;
  173. this.loginParams.uuid = r.data.uuid;
  174. })
  175. .catch(() => {
  176. this.loading = false;
  177. });
  178. },
  179. // 提交表单
  180. async toLogin() {
  181. let cheRes, loginApi;
  182. if (this.loginByPass) {
  183. loginApi = loginByPass;
  184. cheRes = this.$mGraceChecker.check(
  185. this.loginParams,
  186. this.$mFormRule.loginByPassRule
  187. );
  188. }
  189. //表单验证规则是否通过,否,终止登陆提示错误信息
  190. if (!cheRes) {
  191. this.$mHelper.toast(this.$mGraceChecker.error);
  192. return;
  193. }
  194. /* #ifdef APP-PLUS */
  195. this.reqBody.group = 'tinyShopApp';
  196. /* #endif */
  197. /* #ifdef H5 */
  198. this.reqBody.group = 'tinyShopH5';
  199. /* #endif */
  200. /* #ifdef MP-WEIXIN */
  201. this.reqBody.group = 'tinyShopWechatMq';
  202. /* #endif */
  203. /* #ifdef MP-QQ */
  204. this.reqBody.group = 'tinyShopQqMq';
  205. /* #endif */
  206. this.handleLogin(this.loginParams, loginApi);
  207. },
  208. // 登录
  209. async handleLogin(params, loginApi) {
  210. this.btnLoading = true;
  211. await this.$http
  212. .post(loginApi, params)
  213. .then((r) => {
  214. this.$mHelper.toast('恭喜您,登录成功!');
  215. this.$mStore.commit('login', r.data);
  216. const backToPage = uni.getStorageSync('backToPage');
  217. if (backToPage) {
  218. if (
  219. backToPage.indexOf('/pages/user/user') !== -1 ||
  220. backToPage.indexOf('/pages/cart/cart') !== -1 ||
  221. backToPage.indexOf('/pages/index/index') !== -1 ||
  222. backToPage.indexOf('/pages/notify/notify') !== -1 ||
  223. backToPage.indexOf('/pages/category/category') !== -1
  224. ) {
  225. this.$mRouter.reLaunch(JSON.parse(backToPage));
  226. } else {
  227. this.$mRouter.redirectTo(JSON.parse(backToPage));
  228. }
  229. uni.removeStorageSync('backToPage');
  230. uni.removeStorageSync('wechatUserInfo');
  231. } else {
  232. this.$mRouter.reLaunch({ route: '/pages/index/index' });
  233. }
  234. })
  235. .catch(() => {
  236. this.btnLoading = false;
  237. });
  238. },
  239. },
  240. };
  241. </script>
  242. <style lang="scss" scoped>
  243. page {
  244. background: #fff;
  245. }
  246. .container {
  247. padding-top: 115px;
  248. position: relative;
  249. width: 100vw;
  250. overflow: hidden;
  251. background: #fff;
  252. }
  253. .wrapper {
  254. position: relative;
  255. z-index: 90;
  256. background: #fff;
  257. padding-bottom: 40upx;
  258. }
  259. .back-btn {
  260. position: absolute;
  261. left: 40upx;
  262. z-index: 9999;
  263. padding-top: var(--status-bar-height);
  264. top: 40upx;
  265. font-size: 40upx;
  266. color: $font-color-dark;
  267. }
  268. .login-title {
  269. padding-left: 32upx;
  270. margin-bottom: 40upx;
  271. .logo {
  272. width: 156upx;
  273. }
  274. .title {
  275. font-size: 48upx;
  276. color: #2f2f2f;
  277. }
  278. }
  279. .left-top-sign {
  280. font-size: 120upx;
  281. color: $page-color-base;
  282. position: relative;
  283. left: -16upx;
  284. }
  285. .right-top-sign {
  286. position: absolute;
  287. top: 80upx;
  288. right: -30upx;
  289. z-index: 95;
  290. &:before,
  291. &:after {
  292. display: block;
  293. content: '';
  294. width: 400upx;
  295. height: 80upx;
  296. background: #b4f3e2;
  297. }
  298. &:before {
  299. transform: rotate(50deg);
  300. border-radius: 0 50px 0 0;
  301. }
  302. &:after {
  303. position: absolute;
  304. right: -198upx;
  305. top: 0;
  306. transform: rotate(-50deg);
  307. border-radius: 50px 0 0 0;
  308. }
  309. }
  310. .left-bottom-sign {
  311. position: absolute;
  312. left: -270upx;
  313. bottom: -320upx;
  314. border: 100upx solid #d0d1fd;
  315. border-radius: 50%;
  316. padding: 180upx;
  317. }
  318. .welcome {
  319. position: relative;
  320. left: 50upx;
  321. top: -90upx;
  322. font-size: 46upx;
  323. color: #555;
  324. text-shadow: 1px 0px 1px rgba(0, 0, 0, 0.3);
  325. }
  326. .input-content {
  327. padding: 0 32upx;
  328. }
  329. .input-item {
  330. display: flex;
  331. flex-direction: column;
  332. align-items: flex-start;
  333. justify-content: center;
  334. padding: 0 30upx;
  335. background: $page-color-light;
  336. height: 80upx;
  337. border-radius: 4px;
  338. margin-bottom: 30upx;
  339. background-color: #fff;
  340. border-bottom: 1px solid #e7e7e7;
  341. .tit {
  342. height: 50upx;
  343. line-height: 56upx;
  344. font-size: $font-sm + 2upx;
  345. color: $font-color-base;
  346. }
  347. input {
  348. height: 60upx;
  349. font-size: $font-base + 2upx;
  350. color: $font-color-dark;
  351. background-color: #fff;
  352. width: 100%;
  353. }
  354. .codenum {
  355. width: 65%;
  356. }
  357. }
  358. .input-item-sms-code {
  359. position: relative;
  360. width: 100%;
  361. .sms-code-btn {
  362. position: absolute;
  363. color: #111;
  364. right: 20upx;
  365. bottom: 20upx;
  366. font-size: 28upx;
  367. }
  368. .sms-code-resend {
  369. color: #999;
  370. }
  371. .sms-code-btn:after {
  372. border: none;
  373. background-color: transparent;
  374. }
  375. }
  376. .forget-section {
  377. font-size: $font-sm + 2upx;
  378. color: $font-color-spec;
  379. text-align: center;
  380. margin-top: 40upx;
  381. }
  382. .register-section {
  383. margin: 30upx 0 50upx 0;
  384. width: 100%;
  385. font-size: $font-sm + 2upx;
  386. color: $font-color-base;
  387. text-align: center;
  388. text {
  389. color: $font-color-spec;
  390. margin-left: 10upx;
  391. }
  392. text:first-child {
  393. margin-right: 10upx;
  394. }
  395. }
  396. .btn-group {
  397. display: flex;
  398. margin-bottom: 20upx;
  399. }
  400. .codeImage {
  401. width: 220upx;
  402. position: absolute;
  403. top: 0;
  404. right: 0;
  405. }
  406. .confirm-btn {
  407. background-color: rgb(255, 205, 0);
  408. color: rgb(35, 40, 40);
  409. font-weight: bold;
  410. border-radius: 40upx;
  411. }
  412. </style>