login.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. <template>
  2. <div>
  3. <div class="login-container" v-if="!forgotPwdFlag">
  4. <h2 class="title-big">登录</h2>
  5. <p class="title-name">欢迎来到二十一世纪英语智慧阅读平台</p>
  6. <div class="tabs-box">
  7. <a
  8. :class="[tabsIndex === 0 ? 'active' : '']"
  9. @click="handleChangeTabs(0)"
  10. >账号密码登录</a
  11. >
  12. <a
  13. :class="[tabsIndex === 1 ? 'active' : '']"
  14. @click="handleChangeTabs(1)"
  15. >验证码登录</a
  16. >
  17. </div>
  18. <!-- <template v-if="tabsIndex===0"> -->
  19. <el-form
  20. label-position="top"
  21. label-width="80px"
  22. ref="loginPwdForm"
  23. :model="loginPwdForm"
  24. class="form"
  25. :hide-required-asterisk="true"
  26. :rules="rulesPassword"
  27. v-show="tabsIndex === 0"
  28. >
  29. <el-form-item label="账号" prop="userName">
  30. <el-input
  31. v-model="loginPwdForm.userName"
  32. autocomplete="off"
  33. placeholder="用户名/邮箱/手机号"
  34. @blur="handleTrim('loginPwdForm', 'userName')"
  35. maxlength="100"
  36. >
  37. </el-input>
  38. </el-form-item>
  39. <el-form-item label="密码" prop="password">
  40. <el-input
  41. v-model="loginPwdForm.password"
  42. :type="passwordFlag ? 'text' : 'password'"
  43. autocomplete="off"
  44. placeholder="请输入密码"
  45. @blur="handleTrim('loginPwdForm', 'password')"
  46. maxlength="20"
  47. >
  48. <i
  49. slot="suffix"
  50. class="el-icon-view show-icon"
  51. @click="changeIcon('passwordFlag')"
  52. v-if="passwordFlag"
  53. ></i>
  54. <i
  55. slot="suffix"
  56. class="show-icon"
  57. @click="changeIcon('passwordFlag')"
  58. v-else
  59. >
  60. <svg-icon icon-class="eye-invisible"></svg-icon>
  61. </i>
  62. </el-input>
  63. </el-form-item>
  64. <el-form-item prop="userAgreeCheck" class="userAgree-box">
  65. <el-checkbox-group v-model="loginPwdForm.userAgreeCheck">
  66. <el-checkbox label="1" name="userAgreeCheck"
  67. ><a @click.prevent="lookUserAgreement"
  68. >阅读并同意《用户协议》</a
  69. ></el-checkbox
  70. >
  71. </el-checkbox-group>
  72. <a class="forgotPwd" @click="forgotPwd">忘记密码?</a>
  73. </el-form-item>
  74. <el-form-item class="btn-box">
  75. <el-button
  76. type="primary"
  77. @click="onSubmitPassword('loginPwdForm')"
  78. size="small"
  79. :loading="loading"
  80. >登录</el-button
  81. >
  82. <el-button @click="onCancel('loginPwdForm')" size="small"
  83. >取消</el-button
  84. >
  85. </el-form-item>
  86. </el-form>
  87. <!-- </template> -->
  88. <!-- <template v-if="tabsIndex===1"> -->
  89. <el-form
  90. label-position="top"
  91. label-width="80px"
  92. ref="loginCodeForm"
  93. :model="loginCodeForm"
  94. class="form"
  95. :hide-required-asterisk="true"
  96. :rules="rulesCode"
  97. v-show="tabsIndex === 1"
  98. >
  99. <el-form-item label="手机号" prop="phone">
  100. <el-input
  101. v-model="loginCodeForm.phone"
  102. autocomplete="off"
  103. placeholder="请输入完整手机号"
  104. @blur="handleTrim('loginCodeForm', 'phone')"
  105. maxlength="20"
  106. >
  107. <template slot="prepend">+86</template>
  108. </el-input>
  109. </el-form-item>
  110. <el-form-item label="验证码" prop="code" class="code-box">
  111. <el-input
  112. v-model="loginCodeForm.code"
  113. autocomplete="off"
  114. placeholder="请输入验证码"
  115. class="code-input"
  116. @blur="handleTrim('loginCodeForm', 'code')"
  117. maxlength="20"
  118. >
  119. </el-input>
  120. <el-button
  121. type="primary"
  122. @click="sendCode('time', 'phone', 'verificationCodeShow')"
  123. size="small"
  124. class="sendCode"
  125. >
  126. {{ verificationCodeShow ? time + "s" : "发送验证码" }}
  127. </el-button>
  128. </el-form-item>
  129. <el-form-item prop="userAgreeCheck" class="userAgree-box">
  130. <el-checkbox-group v-model="loginCodeForm.userAgreeCheck">
  131. <el-checkbox label="1" name="userAgreeCheck"
  132. ><a @click.prevent="lookUserAgreement"
  133. >阅读并同意《用户协议》</a
  134. ></el-checkbox
  135. >
  136. </el-checkbox-group>
  137. <a class="forgotPwd" @click="forgotPwd">忘记密码?</a>
  138. </el-form-item>
  139. <el-form-item class="btn-box">
  140. <el-button
  141. type="primary"
  142. @click="onSubmitPassword('loginCodeForm')"
  143. size="small"
  144. :loading="loading"
  145. >登录</el-button
  146. >
  147. <el-button @click="onCancel('loginCodeForm')" size="small"
  148. >取消</el-button
  149. >
  150. </el-form-item>
  151. </el-form>
  152. <!-- </template> -->
  153. </div>
  154. <forgot-pwd @cancelFot="cancelFot" v-if="forgotPwdFlag"></forgot-pwd>
  155. </div>
  156. </template>
  157. <script>
  158. import { getLogin } from "@/api/ajax";
  159. import { setToken } from "@/utils/auth";
  160. import ForgotPwd from "./forgotPwd.vue";
  161. export default {
  162. name: "login",
  163. props: ["toUrl", "linkType"],
  164. components: { ForgotPwd },
  165. data() {
  166. const validatePhone = (rule, value, callback) => {
  167. if (this.tabsIndex === 1) {
  168. if (value === "") {
  169. callback(new Error("请输入手机号"));
  170. } else {
  171. let reg = /^1[3-9]\d{9}$/;
  172. let result = reg.test(value);
  173. if (result) {
  174. callback();
  175. } else {
  176. callback(new Error("请输入正确的手机号"));
  177. }
  178. }
  179. }
  180. };
  181. return {
  182. tabsIndex: 0,
  183. loginPwdForm: {
  184. userName: "",
  185. password: "",
  186. userAgreeCheck: [],
  187. type: "USER",
  188. },
  189. passwordFlag: false,
  190. rulesPassword: {
  191. userName: [{ required: true, message: "请输入账号", trigger: "blur" }],
  192. password: [{ required: true, message: "请输入密码", trigger: "blur" }],
  193. userAgreeCheck: [
  194. {
  195. type: "array",
  196. required: true,
  197. message: "请阅读并同意《用户协议》",
  198. trigger: "change",
  199. },
  200. ],
  201. },
  202. loginCodeForm: {
  203. phone: "",
  204. code: "",
  205. userAgreeCheck: [],
  206. type: "USER",
  207. },
  208. rulesCode: {
  209. phone: [{ required: true, validator: validatePhone, trigger: "blur" }],
  210. code: [{ required: true, message: "请输入验证码", trigger: "blur" }],
  211. userAgreeCheck: [
  212. {
  213. type: "array",
  214. required: true,
  215. message: "请阅读并同意《用户协议》",
  216. trigger: "change",
  217. },
  218. ],
  219. },
  220. time: 60, //获取验证码的时间
  221. verificationCodeShow: false, //是否已经获取了验证码
  222. loading: false,
  223. timer: null,
  224. forgotPwdFlag: false,
  225. };
  226. },
  227. watch: {},
  228. methods: {
  229. // 切换tabs
  230. handleChangeTabs(value) {
  231. this.tabsIndex = value;
  232. },
  233. changeIcon(flag) {
  234. this[flag] = !this[flag];
  235. },
  236. // 查看用户协议
  237. lookUserAgreement() {},
  238. // 密码登录提交表单
  239. onSubmitPassword(formName) {
  240. this.$refs[formName].validate((valid) => {
  241. if (valid) {
  242. this.loading = true;
  243. let MethodName = "/OrgServer/LoginControl/Login";
  244. let data = null;
  245. if (this.tabsIndex === 0) {
  246. data = {
  247. user_type: this.loginPwdForm.type,
  248. user_name: this.loginPwdForm.userName,
  249. password: this.loginPwdForm.password,
  250. };
  251. } else {
  252. data = {
  253. user_type: this.loginCodeForm.type,
  254. user_name: this.loginCodeForm.phone,
  255. password: this.loginCodeForm.code,
  256. is_dynamic_verification_code_login: "true",
  257. dynamic_verification_code_send_type: "SMS",
  258. };
  259. }
  260. getLogin(MethodName, data)
  261. .then((res) => {
  262. this.loading = false;
  263. setToken(res);
  264. if (this.toUrl) {
  265. if (this.linkType === "url") {
  266. window.location.href =
  267. window.location.href.substring(
  268. 0,
  269. window.location.href.indexOf("/#/")
  270. ) +
  271. "/#" +
  272. this.toUrl;
  273. window.location.reload();
  274. } else {
  275. this.$router.push({
  276. path: this.toUrl,
  277. });
  278. }
  279. } else {
  280. if (this.$route.path !== "/register") {
  281. window.location.reload();
  282. } else {
  283. this.$router.push({
  284. path: "/",
  285. });
  286. }
  287. }
  288. })
  289. .catch(() => {
  290. this.loading = false;
  291. this.verificationCodeShow = false;
  292. clearInterval(this.timer);
  293. this.time = 60;
  294. });
  295. } else {
  296. return false;
  297. }
  298. });
  299. },
  300. // 取消 恢复到修改前状态
  301. onCancel(formName) {
  302. this.$refs[formName].resetFields();
  303. this.$emit("cancelLogin");
  304. },
  305. // 发送验证码
  306. sendCode(time, phone, flag, obj) {
  307. let this_ = this;
  308. if (this_[time] != 60) {
  309. return;
  310. }
  311. this_.timer = null;
  312. if (this_.loginCodeForm[phone]) {
  313. let reg = /^1[3-9]\d{9}$/;
  314. let result = reg.test(this_.loginCodeForm[phone]);
  315. if (!result) {
  316. this_.$message.warning("请输入正确的手机号");
  317. return;
  318. }
  319. this_[flag] = true;
  320. this_.timer = setInterval(() => {
  321. this_[time]--;
  322. if (this_[time] == 0) {
  323. this_[flag] = false;
  324. clearInterval(this_.timer);
  325. this_.timer = null;
  326. this_[time] = 60;
  327. }
  328. }, 1000);
  329. let MethodName = "/OrgServer/LoginControl/SendVerificationCode";
  330. let data = {
  331. send_type: "SMS",
  332. phone_or_email: this_.loginCodeForm.phone,
  333. };
  334. getLogin(MethodName, data)
  335. .then((res) => {})
  336. .catch(() => {
  337. this_[flag] = false;
  338. clearInterval(this_.timer);
  339. this_.timer = null;
  340. this_[time] = 60;
  341. });
  342. } else {
  343. this_.$message.warning("请先输入手机号");
  344. }
  345. },
  346. // 去掉前后空格
  347. handleTrim(form, fild) {
  348. this[form][fild] = this[form][fild].trim();
  349. },
  350. // 忘记密码
  351. forgotPwd() {
  352. this.forgotPwdFlag = true;
  353. },
  354. cancelFot() {
  355. this.forgotPwdFlag = false;
  356. },
  357. },
  358. mounted() {},
  359. };
  360. </script>
  361. <style lang="scss" scoped>
  362. .login-container {
  363. background: #ffffff;
  364. padding: 64px 72px;
  365. .title-big {
  366. font-weight: 400;
  367. font-size: 32px;
  368. line-height: 40px;
  369. margin: 0;
  370. color: #1d2129;
  371. }
  372. .title-name {
  373. font-size: 14px;
  374. line-height: 22px;
  375. color: #86909c;
  376. margin: 0 0 40px 0;
  377. }
  378. .tabs-box {
  379. display: flex;
  380. a {
  381. font-size: 14px;
  382. line-height: 22px;
  383. color: #4e5969;
  384. border-radius: 100px;
  385. padding: 5px 16px;
  386. margin-right: 16px;
  387. &:hover {
  388. background: #f2f3f5;
  389. }
  390. &.active {
  391. background: #f2f3f5;
  392. font-weight: 500;
  393. color: #165dff;
  394. }
  395. }
  396. }
  397. .form {
  398. margin-top: 40px;
  399. .show-icon {
  400. cursor: pointer;
  401. color: #4e5969;
  402. }
  403. .forgotPwd {
  404. font-size: 14px;
  405. line-height: 22px;
  406. color: #165dff;
  407. }
  408. }
  409. }
  410. </style>
  411. <style lang="scss">
  412. .login-container {
  413. .form {
  414. .el-form-item__label {
  415. font-weight: 400;
  416. font-size: 14px;
  417. line-height: 22px;
  418. color: #4e5969;
  419. padding-bottom: 8px;
  420. }
  421. .userAgree-box {
  422. .el-form-item__content {
  423. display: flex;
  424. justify-content: space-between;
  425. line-height: 22px;
  426. }
  427. .el-checkbox-group {
  428. flex: 1;
  429. .el-checkbox {
  430. color: rgba(0, 0, 0, 0.88);
  431. font-weight: 400;
  432. }
  433. }
  434. }
  435. .btn-box {
  436. .el-button {
  437. width: 100%;
  438. }
  439. .el-button + .el-button {
  440. margin-left: 0;
  441. margin-top: 8px;
  442. }
  443. }
  444. .el-button--primary {
  445. background: #165dff;
  446. border-color: #165dff;
  447. border-radius: 2px;
  448. &:hover {
  449. background: #4080ff;
  450. border-color: #4080ff;
  451. }
  452. &:focus {
  453. background: #0e42d2;
  454. border-color: #0e42d2;
  455. }
  456. }
  457. .el-button--default {
  458. background: #f2f3f5;
  459. border-radius: 2px;
  460. border: none;
  461. color: #4e5969;
  462. &:hover {
  463. background: #e5e6eb;
  464. }
  465. &:focus {
  466. background: #c9cdd4;
  467. }
  468. }
  469. .code-box {
  470. .el-form-item__content {
  471. display: flex;
  472. }
  473. }
  474. .code-input {
  475. height: 32px;
  476. .el-input__inner {
  477. border-radius: 4px 0 0 4px;
  478. }
  479. }
  480. .sendCode {
  481. border-radius: 0 4px 4px 0;
  482. margin-top: 1px;
  483. width: 92px;
  484. flex-shrink: 0;
  485. }
  486. .el-form-item__content,
  487. .el-input__icon {
  488. line-height: 32px;
  489. color: #4e5969 !important;
  490. }
  491. .el-input__inner {
  492. height: 32px;
  493. color: #1d2129;
  494. background: #f2f3f5;
  495. border: none;
  496. }
  497. .el-textarea__inner,
  498. .el-input-group__prepend {
  499. color: #1d2129;
  500. }
  501. .el-checkbox__input.is-checked + .el-checkbox__label {
  502. color: #165dff;
  503. }
  504. .el-checkbox__input.is-checked .el-checkbox__inner,
  505. .el-checkbox__input.is-indeterminate .el-checkbox__inner {
  506. background: #165dff;
  507. border-color: #165dff;
  508. }
  509. .el-input-group__prepend {
  510. width: 54px;
  511. height: 32px;
  512. border: none;
  513. background: #f2f3f5;
  514. border-radius: 2px 0px 0px 2px;
  515. line-height: 32px;
  516. text-align: center;
  517. padding: 0;
  518. }
  519. .el-input-group--prepend {
  520. display: flex;
  521. .el-input__inner {
  522. margin-left: 8px;
  523. flex: 1;
  524. }
  525. }
  526. }
  527. }
  528. </style>