Login.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. <template>
  2. <div class="wavy-line">
  3. <div id="content" style="height: 100%">
  4. <div id="Login">
  5. <div class="log_on">
  6. <div class="left_content"></div>
  7. <div class="right_content">
  8. <img
  9. v-if="toggleQrCode"
  10. class="img1"
  11. src="../assets//image/log_code.png"
  12. alt=""
  13. @click="switchLogin"
  14. />
  15. <img
  16. v-else
  17. class="img1"
  18. src="../assets//image/QR_code.png"
  19. alt=""
  20. @click="switchCode"
  21. />
  22. <div style="padding: 15% 20%">
  23. <img class="img2" src="../assets//image/logo_img.png" alt="" />
  24. <div v-show="toggleQrCode" style="text-align: center">
  25. <div
  26. class="img3"
  27. v-loading="loadingCode"
  28. id="qrcode"
  29. ref="qrcode"
  30. >
  31. <transition name="el-fade-in">
  32. <el-result
  33. v-if="tipVisibility"
  34. class="scanSuccess"
  35. icon="success"
  36. title="扫码成功"
  37. ></el-result>
  38. </transition>
  39. </div>
  40. <el-button
  41. icon="el-icon-refresh-right"
  42. size="small"
  43. style="margin-top: 10px"
  44. @click="refresh"
  45. >刷新二维码</el-button
  46. >
  47. <p class="code_word">打开<b>客户端APP</b>扫描二维码</p>
  48. </div>
  49. <el-form
  50. v-show="!toggleQrCode"
  51. size="medium"
  52. :model="loginForm"
  53. :rules="fieldRules"
  54. ref="loginForm"
  55. label-position="left"
  56. label-width="0"
  57. >
  58. <el-form-item prop="account" label="">
  59. <el-input
  60. type="text"
  61. prefix-icon="el-icon-user"
  62. v-model="loginForm.account"
  63. auto-complete="off"
  64. placeholder="账号"
  65. ></el-input>
  66. </el-form-item>
  67. <el-form-item prop="password" label="">
  68. <el-input
  69. type="password"
  70. prefix-icon="el-icon-lock"
  71. v-model="loginForm.password"
  72. auto-complete="off"
  73. placeholder="密码"
  74. ></el-input>
  75. </el-form-item>
  76. <el-row>
  77. <el-col :span="14">
  78. <el-form-item prop="captcha" label="">
  79. <el-input
  80. type="test"
  81. prefix-icon="el-icon-success"
  82. v-model="loginForm.captcha"
  83. auto-complete="off"
  84. placeholder="验证码"
  85. >
  86. </el-input>
  87. </el-form-item>
  88. </el-col>
  89. <el-col class="line" :span="1">&nbsp;</el-col>
  90. <el-col :span="9">
  91. <img
  92. style="width: 100%; height: 32px; margin: 2px"
  93. class="pointer"
  94. :src="loginForm.src"
  95. @click="refreshCaptcha"
  96. />
  97. </el-col>
  98. <el-col :span="14">
  99. <el-form-item prop="captcha" label="">
  100. <el-select v-model="sysId">
  101. <el-option
  102. v-for="item in optionList"
  103. :key="item.id"
  104. :value="item.id"
  105. :label="item.systemName"
  106. >
  107. </el-option>
  108. </el-select>
  109. </el-form-item>
  110. </el-col>
  111. </el-row>
  112. <el-row style="width: 100%; margin-top: 15px">
  113. <el-button
  114. size="medium"
  115. type="primary"
  116. plain
  117. style="width: 48%; float: left"
  118. @click.native.prevent="reset"
  119. >重 置</el-button
  120. >
  121. <el-button
  122. size="medium"
  123. type="primary"
  124. style="width: 48%; float: right"
  125. @click.native.prevent="login('loginForm')"
  126. :loading="loading"
  127. >登 录</el-button
  128. >
  129. </el-row>
  130. </el-form>
  131. </div>
  132. </div>
  133. </div>
  134. <div class="L_footer">
  135. <div class="w1100" style="padding-top: 15px">
  136. <p style="font-weight: bold">
  137. 版权所有©1994-2014山西掌柜科技有限公司
  138. 未经许可不得复制转载或者摘编
  139. </p>
  140. <p style="font-weight: bold">
  141. copyright 1994-2014 ZhangGui Property Insurance Co.Lid All rights
  142. reserved
  143. </p>
  144. </div>
  145. </div>
  146. </div>
  147. </div>
  148. </div>
  149. </template>
  150. <script>
  151. import { mapState } from "vuex";
  152. import Cookies from "js-cookie";
  153. import QRCode from "qrcodejs2";
  154. import { md5 } from "@/utils/md5";
  155. import ThemePicker from "@/components/ThemePicker";
  156. import LangSelector from "@/components/LangSelector";
  157. import { login } from "@/api/user";
  158. import CryptoJS from "crypto-js";
  159. // import { getSysList } from "../http/moudules/sys";
  160. import { sendWebsocket, closeWebsocket } from "@/utils/websocket.js";
  161. import {
  162. getUserIP,
  163. getUserLocation,
  164. getAddressLocation,
  165. } from "@/utils/ipAndAddress.js";
  166. export default {
  167. name: "Login",
  168. inject: ["reload"],
  169. components: {
  170. ThemePicker,
  171. LangSelector,
  172. },
  173. data() {
  174. return {
  175. loadingCode: false,
  176. qrcode: null,
  177. rememberPassword: false,
  178. loading: false,
  179. loginForm: {
  180. account: "",
  181. password: "",
  182. captcha: "",
  183. src: "",
  184. },
  185. fieldRules: {
  186. account: [{ required: true, message: "请输入账号", trigger: "blur" }],
  187. password: [{ required: true, message: "请输入密码", trigger: "blur" }],
  188. captcha: [{ required: true, message: "请输入验证码", trigger: "blur" }],
  189. },
  190. checked: true,
  191. toggleQrCode: false,
  192. uuid: "",
  193. polling: null,
  194. tipVisibility: false,
  195. optionList: [],
  196. sysId: null,
  197. systemType: "1", //系统类型
  198. addressInfo: {}, //当前登录信息
  199. locationIp:'',//当前ip
  200. };
  201. },
  202. created() {
  203. // 记住密码
  204. if (Cookies.get("accountInfo")) {
  205. const accountInfo = JSON.parse(Cookies.get("accountInfo"));
  206. this.loginForm.account = accountInfo.account;
  207. this.loginForm.password = accountInfo.password;
  208. this.rememberPassword = true;
  209. }
  210. this.enterEvent(); //初始化回车事件
  211. this.getSysList();
  212. },
  213. methods: {
  214. getSysList() {
  215. this.$api.sys.sysDictList().then((res) => {
  216. if (res.code === 200) {
  217. this.optionList = [...res.data];
  218. this.sysId = res.data && res.data.length > 0 && res.data[0].id;
  219. }
  220. });
  221. },
  222. enterEvent() {
  223. if (this.$route.name === "登录") {
  224. document.onkeydown = (e) => {
  225. const url = e.target.baseURI.match(/login/);
  226. if (e.keyCode == 13 && url.includes("login")) {
  227. this.login();
  228. }
  229. };
  230. }
  231. },
  232. login(formName) {
  233. // let token = CryptoJS.AES.encrypt(
  234. // "2856c49f-7b34-4e83-b3c8-2c37dba7cb3b",
  235. // "token"
  236. // ).toString();
  237. // console.log(token);
  238. // window.location.href =
  239. // "http://localhost:8080/#/form/agreement?token=" + token;
  240. this.$refs[formName].validate((valid) => {
  241. if (valid) {
  242. this.loading = true;
  243. let userInfo = {
  244. account: this.loginForm.account,
  245. password: this.loginForm.password,
  246. captcha: this.loginForm.captcha.toLowerCase(),
  247. captchaId: this.loginForm.captchaId,
  248. sysId: this.sysId,
  249. // systemType: this.systemType
  250. };
  251. // this.$store
  252. // .dispatch("login", userInfo)
  253. // .then(() => {
  254. // if (this.rememberPassword) {
  255. // //是否保存密码
  256. // Cookies.set("accountInfo", {
  257. // account: this.loginForm.account,
  258. // password: this.loginForm.password,
  259. // });
  260. // } else {
  261. // Cookies.remove("accountInfo");
  262. // }
  263. // Cookies.set("user", userInfo.account) /
  264. // sessionStorage.setItem("user", userInfo.account); // 保存用户到本地会话
  265. // this.$store.commit("menuRouteLoaded", false); // 要求重新加载导航菜单
  266. // this.$router.push("/");
  267. // this.loading = false;
  268. // })
  269. // .catch(() => {
  270. // this.loading = false;
  271. // });
  272. this.$api.login
  273. .login2(userInfo)
  274. .then((res) => {
  275. if (res.code != 200) {
  276. this.$message({
  277. message: res.msg,
  278. type: "error",
  279. duration: 2000,
  280. });
  281. if (res.code == 500 && res.msg == "验证码不正确") {
  282. this.refreshCaptcha();
  283. }
  284. } else {
  285. if (this.rememberPassword) {
  286. //是否保存密码
  287. Cookies.set("accountInfo", {
  288. account: this.loginForm.account,
  289. password: this.loginForm.password,
  290. });
  291. } else {
  292. Cookies.remove("accountInfo");
  293. }
  294. if (this.sysId === 2) {
  295. let token = CryptoJS.AES.encrypt(
  296. res.data,
  297. "token"
  298. ).toString();
  299. window.location.href =
  300. process.env.CONSOLE_BASE_URL + "/#/index?token=" + token;
  301. // alert(res.data);
  302. }else if (this.sysId === 3) {
  303. Cookies.set("user", this.loginForm.account);
  304. let userId = this.loginForm.account;
  305. let data ={
  306. userId: userId,
  307. token: res.data
  308. }
  309. let jsonStr = JSON.stringify(data);
  310. let token = CryptoJS.AES.encrypt(
  311. jsonStr,
  312. "token"
  313. ).toString();
  314. window.location.href =process.env.CONSOLE_KHGX_URL + "?token=" + token;
  315. }
  316. else {
  317. this.getUser();
  318. Cookies.set("token", res.data); // 放置token到Cookie
  319. // this.submitLocation();
  320. this.getDictItems();
  321. setTimeout(() => {
  322. let userId = sessionStorage.getItem("user");
  323. let data = {
  324. // ...this.addressInfo,
  325. ip:this.locationIp,
  326. userId,
  327. systemType: this.systemType,
  328. };
  329. sendWebsocket(
  330. `${process.env.SOCKET_Url}/pcWebsocket/${userId}`,
  331. data
  332. );
  333. // sendWebsocket(`/pcWebsocket/${userId}`,data)
  334. }, 1000);
  335. }
  336. }
  337. this.loading = false;
  338. })
  339. .catch((res) => {
  340. this.$message({
  341. message: res.message,
  342. type: "error",
  343. duration: 2000,
  344. });
  345. });
  346. } else {
  347. return false;
  348. }
  349. });
  350. },
  351. /**提交当前位置信息 */
  352. submitLocation() {
  353. let location = {
  354. systemType: this.systemType,
  355. ...this.addressInfo,
  356. };
  357. this.$api.login.uploadLocationInfo(location).then((res) => {
  358. if (res.code !== 200) {
  359. this.$message({
  360. message: res.msg,
  361. type: "error",
  362. });
  363. }
  364. });
  365. },
  366. getDictItems() {
  367. //--数据字典--
  368. // 性别
  369. this.$api.dict.findByLableName("sex").then((response) => {
  370. localStorage.setItem("sexOptions", JSON.stringify(response.data)); // 保存用户到本地会话
  371. });
  372. // 状态
  373. this.$api.dict.findByLableName("user_status").then((response) => {
  374. localStorage.setItem(
  375. "user_statusoptions",
  376. JSON.stringify(response.data)
  377. ); // 保存用户到本地会话
  378. });
  379. },
  380. // 用户信息
  381. getUser() {
  382. this.$api.user.getLoginUser().then((response) => {
  383. if (response.code == 200) {
  384. //头像地址拼接
  385. if (
  386. response.data.headSculpture != "" &&
  387. response.data.headSculpture != null &&
  388. response.data.headSculpture != undefined
  389. ) {
  390. response.data.headSculpture =
  391. process.env.BASE_URL + response.data.headSculpture;
  392. }
  393. localStorage.setItem("user_data", JSON.stringify(response.data));
  394. this.$store.commit("SET_USER", response.data);
  395. sessionStorage.setItem("user", response.data.id);
  396. Cookies.set("user", response.data.id);
  397. localStorage.setItem("routerId", "420");
  398. this.$store.commit("menuRouteLoaded", false);
  399. this.$router.push("/");
  400. this.loadingCode = false;
  401. } else {
  402. this.$message.error(response.msg);
  403. }
  404. });
  405. this.$api.role.findAll().then((res) => {
  406. localStorage.setItem("find_all", JSON.stringify(res.data));
  407. });
  408. },
  409. refreshCaptcha() {
  410. let randnum = Math.floor(Math.random() * (1000000 - 1 + 1)) + 1;
  411. this.loginForm.src =
  412. process.env.BASE_URL +
  413. "/captchaById?t=" +
  414. new Date().getTime() +
  415. "&captchaId=" +
  416. randnum;
  417. this.loginForm.captchaId = randnum;
  418. },
  419. reset() {
  420. this.$refs.loginForm.resetFields();
  421. },
  422. // 切换主题
  423. onThemeChange: function (themeColor) {
  424. this.$store.commit("setThemeColor", themeColor);
  425. },
  426. switchLogin() {
  427. this.toggleQrCode = !this.toggleQrCode;
  428. this.stopPolling();
  429. },
  430. switchCode() {
  431. this.toggleQrCode = !this.toggleQrCode;
  432. this.generateQrCode(); //获取二维码
  433. },
  434. generateQrCode() {
  435. let randnum = new Date().getTime();
  436. let uuid = md5(randnum);
  437. let url = process.env.BASE_URL + "/scanQrCode?uuid=" + uuid;
  438. this.$nextTick(() => {
  439. this.creatQrCode(url);
  440. this.$api.login.getQRCode(uuid).then((res) => {
  441. this.uuid = res.data.uuid;
  442. this.startPolling();
  443. });
  444. });
  445. },
  446. checkScanStatus() {
  447. this.$api.login.QrCodeStatusQuery(this.uuid).then((res) => {
  448. if (res.data.statusCode == 20000) {
  449. this.tipVisibility = true;
  450. this.loadingCode = true;
  451. setTimeout(() => {
  452. this.CodeLoginSuccess(res.data.token);
  453. }, 1500);
  454. }
  455. });
  456. },
  457. startPolling() {
  458. if (this.polling) {
  459. this.stopPolling();
  460. }
  461. this.polling = setInterval(this.checkScanStatus, 1000);
  462. },
  463. stopPolling() {
  464. clearInterval(this.polling);
  465. this.polling = null;
  466. },
  467. CodeLoginSuccess(token) {
  468. Cookies.set("token", token); // 放置token到Cookie
  469. this.getDictItems(); //获取字典
  470. this.getUser();
  471. },
  472. refresh() {
  473. this.generateQrCode();
  474. },
  475. //生成二维码
  476. creatQrCode(text) {
  477. if (this.qrcode) {
  478. this.qrcode.clear();
  479. this.qrcode.makeCode(text);
  480. } else {
  481. this.qrcode = new QRCode("qrcode", {
  482. text: text,
  483. width: 200,
  484. height: 200,
  485. colorDark: "#000000",
  486. colorLight: "#ffffff",
  487. correctLevel: QRCode.CorrectLevel.H,
  488. });
  489. }
  490. },
  491. },
  492. beforeDestroy() {
  493. // 组件销毁前确保轮询被清除
  494. this.stopPolling();
  495. },
  496. mounted() {
  497. clearInterval(this.$store.state.user.myTimer)
  498. this.refreshCaptcha();
  499. /**获取当前登录的ip地址 */
  500. getUserIP((ip) => {
  501. this.locationIp=ip
  502. // getAddressLocation(ip, (info) => {
  503. // this.addressInfo = info;
  504. // });
  505. });
  506. },
  507. computed: {
  508. ...mapState({
  509. themeColor: (state) => state.app.themeColor,
  510. }),
  511. },
  512. //销毁函数
  513. destroyed() {
  514. document.onkeydown = null;
  515. },
  516. };
  517. </script>
  518. <style lang="scss" scoped>
  519. .wavy-line {
  520. font: 13px/150% Arial, Verdana, "\5B8B\4F53";
  521. color: #666;
  522. background: #fff;
  523. height: 100%;
  524. }
  525. #content {
  526. overflow: auto;
  527. }
  528. .ORcode {
  529. width: 100%;
  530. height: auto;
  531. display: flex;
  532. justify-content: center;
  533. align-items: center;
  534. padding: 30px;
  535. box-sizing: border-box;
  536. & > div {
  537. width: 176px;
  538. height: 176px;
  539. border: 1px solid var(--themeColor);
  540. border-radius: 5px;
  541. }
  542. }
  543. #qrCode {
  544. display: inline-block;
  545. margin: 0 auto;
  546. position: relative;
  547. top: 15%;
  548. img {
  549. width: 200px;
  550. height: 200px;
  551. background-color: #fff;
  552. padding: 6px;
  553. }
  554. }
  555. #Login {
  556. width: 100%;
  557. height: 100%;
  558. background-image: url(../assets/image/bgImg.png) !important;
  559. background-size: 100% 100%;
  560. background-repeat: no-repeat;
  561. background-position: 100% 100%;
  562. display: flex;
  563. align-items: center;
  564. flex-direction: column;
  565. .log_on {
  566. width: 70%;
  567. height: 80%;
  568. margin: 80px 0 30px 0;
  569. .left_content {
  570. float: left;
  571. width: 50%;
  572. height: 100%;
  573. background: url(../assets/image/leftImg.png);
  574. background-size: 100% 100%;
  575. }
  576. .right_content {
  577. float: right;
  578. width: 50%;
  579. height: 100%;
  580. position: relative;
  581. // display: flex;
  582. // align-items: center;
  583. // flex-direction: column;
  584. // background: url(../assets/image/QR_code.png) top right no-repeat #fff;
  585. background-color: #fff;
  586. .img1 {
  587. position: absolute;
  588. right: 0;
  589. }
  590. .img2 {
  591. margin-bottom: 50px;
  592. display: block;
  593. margin-left: auto;
  594. margin-right: auto;
  595. }
  596. .img3 {
  597. width: 200px;
  598. height: 200px;
  599. padding: 15px;
  600. display: block;
  601. margin-left: auto;
  602. margin-right: auto;
  603. border: 1px solid #eaedf1;
  604. position: relative;
  605. }
  606. .el-form-item {
  607. margin-bottom: 30px;
  608. }
  609. .code_word {
  610. font-size: 16px;
  611. font-weight: bold;
  612. margin-top: 20px;
  613. b {
  614. color: #b20404;
  615. }
  616. }
  617. }
  618. }
  619. .L_footer {
  620. height: 64px;
  621. bottom: 0;
  622. color: #eaedf1;
  623. font-size: 12px;
  624. p {
  625. margin: 0;
  626. }
  627. }
  628. }
  629. .scanSuccess {
  630. position: absolute;
  631. background: #ffffffef;
  632. font-weight: bold;
  633. width: 200px;
  634. height: 200px;
  635. }
  636. </style>