index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <template>
  2. <div class="page-account">
  3. <div class="container" :class="[fullWidth > 768 ? 'containerSamll' : 'containerBig']">
  4. <swiper :options="swiperOption" class="swiperPross" v-if="fullWidth > 768">
  5. <swiper-slide class="swiperPic" v-for="(item, index) in swiperList" :key="index">
  6. <img :src="item.slide" alt="" />
  7. </swiper-slide>
  8. <div class="swiper-pagination" slot="pagination"></div>
  9. </swiper>
  10. <div class="index_from page-account-container from-wh">
  11. <div class="page-account-top">
  12. <div class="page-account-top-logo">
  13. <img :src="login_logo" alt="logo" style="width: 100%; height: 74px" />
  14. </div>
  15. </div>
  16. <Form ref="formInline" :model="formInline" :rules="ruleInline" @keyup.enter="handleSubmit('formInline')">
  17. <FormItem prop="username">
  18. <Input
  19. type="text"
  20. v-model="formInline.username"
  21. prefix="ios-contact-outline"
  22. placeholder="请输入用户名"
  23. size="large"
  24. />
  25. </FormItem>
  26. <FormItem prop="password">
  27. <Input
  28. type="password"
  29. v-model="formInline.password"
  30. prefix="ios-lock-outline"
  31. placeholder="请输入密码"
  32. size="large"
  33. />
  34. </FormItem>
  35. <!-- <FormItem prop="code">
  36. <div class="code">
  37. <Input
  38. type="text"
  39. v-model="formInline.code"
  40. prefix="ios-keypad-outline"
  41. placeholder="请输入验证码"
  42. size="large"
  43. />
  44. <img :src="imgcode" class="pictrue" @click="captchas" />
  45. </div>
  46. </FormItem> -->
  47. <FormItem>
  48. <Button type="primary" long :loading="loading" size="large" @click="handleSubmit('formInline')" class="btn"
  49. >登录</Button
  50. >
  51. </FormItem>
  52. </Form>
  53. </div>
  54. </div>
  55. <Verify
  56. @success="success"
  57. captchaType="blockPuzzle"
  58. :imgSize="{ width: '330px', height: '155px' }"
  59. ref="verify"
  60. ></Verify>
  61. <div class="footer">
  62. <div class="pull-right" v-if="copyright">{{ copyright }}</div>
  63. <div class="pull-right" v-else>
  64. Copyright © 2014-2022 <a href="https://www.crmeb.com" target="_blank">{{ version }}</a>
  65. </div>
  66. </div>
  67. </div>
  68. </template>
  69. <script>
  70. import { AccountLogin, loginInfoApi } from '@/api/account';
  71. import { getWorkermanUrl } from '@/api/kefu';
  72. import { setCookies } from '@/libs/util';
  73. import '@/assets/js/canvas-nest.min';
  74. import Verify from '@/components/verifition/Verify';
  75. export default {
  76. components: {
  77. Verify,
  78. },
  79. data() {
  80. return {
  81. fullWidth: document.documentElement.clientWidth,
  82. swiperOption: {
  83. pagination: '.swiper-pagination',
  84. autoplay: true,
  85. },
  86. loading: false,
  87. isShow: false,
  88. autoLogin: true,
  89. imgcode: '',
  90. formInline: {
  91. username: '',
  92. password: '',
  93. },
  94. ruleInline: {
  95. username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
  96. password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
  97. },
  98. login_captcha: 0,
  99. // jigsaw: null,
  100. login_logo: '',
  101. swiperList: [],
  102. defaultSwiperList: require('@/assets/images/sw.jpg'),
  103. key: '',
  104. copyright: '',
  105. version: '',
  106. };
  107. },
  108. created() {
  109. const _this = this;
  110. document.onkeydown = function () {
  111. if (_this.$route.name === 'login') {
  112. let key = window.event.keyCode;
  113. if (key === 13) {
  114. _this.handleSubmit('formInline');
  115. }
  116. }
  117. };
  118. window.addEventListener('resize', this.handleResize);
  119. },
  120. watch: {
  121. fullWidth(val) {
  122. // 为了避免频繁触发resize函数导致页面卡顿,使用定时器
  123. if (!this.timer) {
  124. // 一旦监听到的screenWidth值改变,就将其重新赋给data里的screenWidth
  125. this.screenWidth = val;
  126. this.timer = true;
  127. let that = this;
  128. setTimeout(function () {
  129. // 打印screenWidth变化的值
  130. that.timer = false;
  131. }, 400);
  132. }
  133. },
  134. $route(n) {},
  135. },
  136. mounted: function () {
  137. this.$nextTick(() => {
  138. // /* eslint-disable */
  139. let that = this;
  140. // this.jigsaw = jigsaw.init({
  141. // el: this.$refs.captcha,
  142. // onSuccess() {
  143. // that.modals = false;
  144. // that.closeModel();
  145. // },
  146. // onFail: this.closefail,
  147. // onRefresh() {},
  148. // });
  149. if (this.screenWidth < 768) {
  150. document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
  151. } else {
  152. document.getElementsByTagName('canvas')[0].className = 'index_bg';
  153. }
  154. this.swiperData();
  155. });
  156. },
  157. methods: {
  158. swiperData() {
  159. loginInfoApi()
  160. .then((res) => {
  161. localStorage.setItem('ADMIN_TITLE', res.data.site_name);
  162. let data = res.data || {};
  163. this.login_logo = data.login_logo ? data.login_logo : require('@/assets/images/logo.png');
  164. this.swiperList = data.slide.length ? data.slide : [{ slide: this.defaultSwiperList }];
  165. this.key = data.key;
  166. this.copyright = data.copyright;
  167. this.version = data.version;
  168. this.login_captcha = data.login_captcha;
  169. })
  170. .catch((err) => {
  171. this.$Message.error(err);
  172. this.login_logo = require('@/assets/images/logo.png');
  173. this.swiperList = [{ slide: this.defaultSwiperList }];
  174. });
  175. },
  176. success(params) {
  177. this.closeModel(params);
  178. },
  179. // 关闭模态框
  180. closeModel(params) {
  181. this.isShow = false;
  182. // noinspection JSVoidFunctionReturnValueUsed
  183. let msg = this.$Message.loading({
  184. content: '登录中...',
  185. duration: 0,
  186. });
  187. this.loading = true;
  188. AccountLogin({
  189. account: this.formInline.username,
  190. pwd: this.formInline.password,
  191. key: this.key,
  192. captchaType: 'blockPuzzle',
  193. captchaVerification: params ? params.captchaVerification : '',
  194. })
  195. .then(async (res) => {
  196. msg();
  197. let data = res.data;
  198. let expires = this.getExpiresTime(data.expires_time);
  199. // 记录用户登陆信息
  200. setCookies('uuid', data.user_info.id, expires);
  201. setCookies('token', data.token, expires);
  202. setCookies('expires_time', data.expires_time, expires);
  203. this.$store.commit('userInfo/uniqueAuth', data.unique_auth);
  204. this.$store.commit('userInfo/userInfo', data.user_info);
  205. // 保存菜单信息
  206. this.$store.commit('menus/setopenMenus', []);
  207. this.$store.commit('menus/getmenusNav', data.menus);
  208. // 记录用户信息
  209. this.$store.commit('userInfo/name', data.user_info.account);
  210. this.$store.commit('userInfo/avatar', data.user_info.head_pic);
  211. this.$store.commit('userInfo/access', data.unique_auth);
  212. this.$store.commit('userInfo/logo', data.logo);
  213. this.$store.commit('userInfo/logoSmall', data.logo_square);
  214. this.$store.commit('userInfo/version', data.version);
  215. this.$store.commit('userInfo/newOrderAudioLink', data.newOrderAudioLink);
  216. this.login_captcha = 0;
  217. // if (this.jigsaw) this.jigsaw.reset();
  218. try {
  219. if (data.queue === false) {
  220. this.$Notice.warning({
  221. title: '温馨提示',
  222. desc: '您的【消息队列】未开启,没有开启会导致异步任务无法执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/6963" target="_blank">点击查看开启方法</a>',
  223. duration: 30,
  224. });
  225. }
  226. if (data.timer === false) {
  227. this.$Notice.warning({
  228. title: '温馨提示',
  229. desc: '您的【定时任务】未开启,没有开启会导致定时执行的任务无法执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/6962" target="_blank">点击查看开启方法</a>',
  230. duration: 30,
  231. });
  232. }
  233. this.checkSocket();
  234. } catch (e) {}
  235. return this.$router.replace({ path: '/admin/home/' || '/admin/' });
  236. })
  237. .catch((res) => {
  238. msg();
  239. let data = res === undefined ? {} : res;
  240. this.login_captcha = res.data.login_captcha;
  241. this.$Message.error(data.msg || '登录失败');
  242. });
  243. setTimeout((e) => {
  244. this.loading = false;
  245. }, 1000);
  246. },
  247. checkSocket() {
  248. getWorkermanUrl().then((res) => {
  249. let url = res.data.admin;
  250. let isNotice = false;
  251. let socket = new WebSocket(url);
  252. socket.onopen = () => {
  253. isNotice = true;
  254. socket.close();
  255. };
  256. socket.onerror = (err) => {
  257. if (!isNotice) {
  258. isNotice = true;
  259. this.$Notice.warning({
  260. title: '温馨提示',
  261. desc: '您的【长连接】未开启,没有开启会导致客服消息无法发送,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/6931" target="_blank">点击查看开启方法</a>',
  262. duration: 30,
  263. });
  264. }
  265. };
  266. socket.onclose = (err) => {
  267. if (!isNotice) {
  268. isNotice = true;
  269. this.$Notice.warning({
  270. title: '温馨提示',
  271. desc: '您的【长连接】未开启,没有开启会导致客服消息无法发送,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/6931" target="_blank">点击查看开启方法</a>',
  272. duration: 30,
  273. });
  274. }
  275. };
  276. });
  277. },
  278. getExpiresTime(expiresTime) {
  279. let nowTimeNum = Math.round(new Date() / 1000);
  280. let expiresTimeNum = expiresTime - nowTimeNum;
  281. return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
  282. },
  283. closefail() {
  284. // if (this.jigsaw) this.jigsaw.reset();
  285. this.$Message.error('校验错误');
  286. },
  287. handleResize(event) {
  288. this.fullWidth = document.documentElement.clientWidth;
  289. if (this.fullWidth < 768) {
  290. document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
  291. } else {
  292. document.getElementsByTagName('canvas')[0].className = 'index_bg';
  293. }
  294. },
  295. handleSubmit(name) {
  296. this.$refs[name].validate((valid) => {
  297. if (valid) {
  298. if (this.login_captcha == 1) {
  299. this.$refs.verify.show();
  300. } else {
  301. this.closeModel();
  302. }
  303. }
  304. });
  305. },
  306. },
  307. beforeCreate() {
  308. if (this.fullWidth < 768) {
  309. document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
  310. } else {
  311. document.getElementsByTagName('canvas')[0].className = 'index_bg';
  312. }
  313. },
  314. beforeDestroy: function () {
  315. window.removeEventListener('resize', this.handleResize);
  316. document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
  317. },
  318. };
  319. </script>
  320. <style scoped lang="stylus">
  321. .page-account {
  322. display: flex;
  323. width: 100%;
  324. background-image: url('../../../assets/images/bg.jpg');
  325. background-size: cover;
  326. background-position: center;
  327. flex-direction: column;
  328. justify-content: center;
  329. align-items: center;
  330. height: 100vh;
  331. overflow: auto;
  332. }
  333. .page-account .code {
  334. display: flex;
  335. align-items: center;
  336. justify-content: center;
  337. }
  338. .page-account .code .pictrue {
  339. height: 40px;
  340. }
  341. .swiperPross {
  342. border-radius: 12px 0px 0px 12px;
  343. }
  344. .swiperPross, .swiperPic, .swiperPic img {
  345. width: 510px;
  346. height: 100%;
  347. }
  348. .swiperPic img {
  349. width: 100%;
  350. height: 100%;
  351. }
  352. .container {
  353. height: 400px !important;
  354. padding: 0 !important;
  355. border-radius: 12px;
  356. z-index: 1;
  357. display: flex;
  358. }
  359. .containerSamll {
  360. /* width: 56% !important; */
  361. background: #fff !important;
  362. }
  363. .containerBig {
  364. width: auto !important;
  365. background: #f7f7f7 !important;
  366. }
  367. .index_from {
  368. padding: 32px 40px 32px 40px;
  369. height: 400px;
  370. box-sizing: border-box;
  371. }
  372. .page-account-top {
  373. padding: 20px 0 !important;
  374. box-sizing: border-box !important;
  375. display: flex;
  376. justify-content: center;
  377. }
  378. .page-account-container {
  379. border-radius: 0px 6px 6px 0px;
  380. }
  381. .btn {
  382. background: linear-gradient(90deg, rgba(25, 180, 241, 1) 0%, rgba(14, 115, 232, 1) 100%) !important;
  383. }
  384. .captchaBox {
  385. width: 310px;
  386. }
  387. input {
  388. display: block;
  389. width: 290px;
  390. line-height: 40px;
  391. margin: 10px 0;
  392. padding: 0 10px;
  393. outline: none;
  394. border: 1px solid #c8cccf;
  395. border-radius: 4px;
  396. color: #6a6f77;
  397. }
  398. #msg {
  399. width: 100%;
  400. line-height: 40px;
  401. font-size: 14px;
  402. text-align: center;
  403. }
  404. a:link, a:visited, a:hover, a:active {
  405. margin-left: 100px;
  406. color: #0366D6;
  407. }
  408. .index_from >>> .ivu-input-large {
  409. font-size: 14px !important;
  410. }
  411. .from-wh {
  412. width: 400px;
  413. }
  414. .pull-right {
  415. float: right!important;
  416. }
  417. .footer{
  418. position: fixed;
  419. bottom: 0;
  420. width: 100%;
  421. left: 0;
  422. margin: 0;
  423. background: rgba(255,255,255,.8);
  424. border-top: 1px solid #e7eaec;
  425. overflow: hidden;
  426. padding: 10px 20px;
  427. height: 36px;
  428. z-index: 999;
  429. }
  430. .pull-right {
  431. float: right!important;
  432. color: #666;
  433. }
  434. .pull-right a {
  435. margin-left: 0;
  436. color: #666;
  437. }
  438. .footer{
  439. position: fixed;
  440. bottom: 0;
  441. width: 100%;
  442. left: 0;
  443. margin: 0;
  444. background: rgba(255,255,255,.8);
  445. border-top: 1px solid #e7eaec;
  446. overflow: hidden;
  447. padding: 10px 20px;
  448. height: 36px;
  449. }
  450. </style>