index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. <template>
  2. <div class="appBox">
  3. <div class="mainBox">
  4. <div class="leftBox">
  5. <!--大标题-->
  6. <div class="titleBox">
  7. <div class="titleEnglish">Operation Management Platform</div>
  8. <div class="titleChinaeseBox">
  9. <span class="titleChinasesTop">政讯通<br></span>
  10. <span class="titleChinasesBottom">运营管理平台</span>
  11. </div>
  12. </div>
  13. <!--背景颜色-->
  14. <div class="yellow" />
  15. <div class="blue" />
  16. <!--人物图片-->
  17. <img src="@/assets/login/Picture.png" class="TitleImg">
  18. </div>
  19. <div class="rightBox">
  20. <!--form登陆框-->
  21. <div class="loginFormBox">
  22. <!--开始验证表单 start-->
  23. <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
  24. <div class="inputBox greyBg">
  25. <img src="@/assets/login/id-card-outline.png" class="inputIcon">
  26. <el-form-item prop="username">
  27. <el-input
  28. ref="username"
  29. v-model="loginForm.username"
  30. placeholder="请输入手机号"
  31. name="username"
  32. type="text"
  33. tabindex="1"
  34. autocomplete="off"
  35. />
  36. </el-form-item>
  37. </div>
  38. <div class="inputBox greyBg">
  39. <img src="@/assets/login/bag-remove-outline.png" class="inputIcon">
  40. <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
  41. <el-form-item prop="password">
  42. <el-input
  43. :key="passwordType"
  44. ref="password"
  45. v-model="loginForm.password"
  46. :type="passwordType"
  47. placeholder="请输入密码"
  48. name="password"
  49. tabindex="2"
  50. autocomplete="off"
  51. @keyup.native="checkCapslock"
  52. @blur="capsTooltip = false"
  53. @keyup.enter.native="handleLogin"
  54. />
  55. <span class="show-pwd" @click="showPwd">
  56. <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
  57. </span>
  58. </el-form-item>
  59. </el-tooltip>
  60. </div>
  61. <div class="inputBoxSpecial">
  62. <div class="inputBoxLeft greyBg">
  63. <img src="@/assets/login/hardware-chip-outline.png" class="inputIcon">
  64. <el-form-item prop="captcha">
  65. <el-input
  66. ref="captcha"
  67. v-model="loginForm.captcha"
  68. placeholder="图形验证码"
  69. name="captcha"
  70. type="text"
  71. tabindex="3"
  72. maxlength="4"
  73. autocomplete="off"
  74. />
  75. </el-form-item>
  76. </div>
  77. <div class="inputBoxRight greyBg">
  78. <div class="submitCode">
  79. <img :src="codeImg" class="codeImg" @click="getImgCode">
  80. </div>
  81. <div class="reloadBtn" @click="getImgCode">看不清?换一张图</div>
  82. </div>
  83. </div>
  84. <el-button :loading="loading" type="primary" class="loginBtn" @click.native.prevent="singleLogin">
  85. 登录
  86. </el-button>
  87. <!-- <div class="singleLogin" @click="singleLogin"><i class="el-icon-cloudy" /> 单点登录测试</div> -->
  88. </el-form>
  89. <!--开始验证表单 end-->
  90. </div>
  91. </div>
  92. </div>
  93. </div>
  94. </template>
  95. <script>
  96. import { validUserPhone } from '@/utils/validate'
  97. export default {
  98. name: 'Login',
  99. data() {
  100. // 配置验证规则:用于表单验证
  101. const validateUsername = (rule, value, callback) => {
  102. if (!validUserPhone(value)) {
  103. callback(new Error('请输入正确的手机号!'))
  104. } else {
  105. callback()
  106. }
  107. }
  108. const validatePassword = (rule, value, callback) => {
  109. if (value.length < 6) {
  110. callback(new Error('密码不能低于6位!'))
  111. } else {
  112. callback()
  113. }
  114. }
  115. const validateCode = (rule, value, callback) => {
  116. if (value.length < 4) {
  117. callback(new Error('图形验证码不能低于4位!'))
  118. } else {
  119. callback()
  120. }
  121. }
  122. // 本页基础数据
  123. return {
  124. loginForm: { // 1.用户使用哪些信息登录
  125. username: '', // 15210211200
  126. password: '', // 111111
  127. type: 1, //1=账号密码登录
  128. captcha: ''
  129. },
  130. loginRules: { // 2.配置from表单验证规则
  131. username: [{ required: true, trigger: 'blur', validator: validateUsername }],
  132. password: [{ required: true, trigger: 'blur', validator: validatePassword }],
  133. captcha: [{ required: true, trigger: 'blur', validator: validateCode }]
  134. },
  135. passwordType: 'password', // 3.密码域默认type 当显示密码的时候改为text
  136. capsTooltip: false,
  137. loading: false,
  138. showDialog: false,
  139. redirect: undefined,
  140. otherQuery: {},
  141. // 图像验证码
  142. captchaText: '', // 保存生成的验证码文本
  143. captchaInput: '', // 用户输入的验证码
  144. codeImg: '' // 图形验证码
  145. }
  146. },
  147. watch: {
  148. $route: {
  149. handler: function(route) {
  150. const query = route.query
  151. if (query) {
  152. this.redirect = query.redirect
  153. this.otherQuery = this.getOtherQuery(query)
  154. }
  155. },
  156. immediate: true
  157. }
  158. },
  159. mounted() {
  160. this.getImgCode()
  161. },
  162. watch: {
  163. $route: {
  164. handler: function(route) {
  165. const query = route.query
  166. if (query) {
  167. this.redirect = query.redirect
  168. this.otherQuery = this.getOtherQuery(query)
  169. }
  170. },
  171. immediate: true
  172. }
  173. },
  174. methods: {
  175. // 检查输入状态
  176. checkCapslock(e) {
  177. const { key } = e
  178. this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
  179. },
  180. // 切换密码框的显示与隐藏
  181. showPwd() {
  182. if (this.passwordType === 'password') {
  183. this.passwordType = ''
  184. } else {
  185. this.passwordType = 'password'
  186. }
  187. this.$nextTick(() => {
  188. this.$refs.password.focus()
  189. })
  190. },
  191. // 提交表单并跳转
  192. handleLogin() {
  193. this.$refs.loginForm.validate(valid => {
  194. if (valid) {
  195. //console.log(this.loginForm)
  196. //开始登录
  197. this.loading = true
  198. this.$store.dispatch('user/login', this.loginForm)
  199. .then( res => {
  200. this.loading = false
  201. console.log(res)
  202. if(res.code==0){
  203. this.$message({
  204. type:'error',
  205. message:res.message
  206. })
  207. }else if(res.code==200){
  208. console.log("登录成功,将跳转至详情页面!")
  209. this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
  210. }else if(res.code!=0&&res.code!=200){
  211. this.$message({
  212. type:'error',
  213. message:"用户不存在!"
  214. })
  215. }
  216. })
  217. .catch(() => {
  218. this.loading = false
  219. })
  220. } else {
  221. console.log('表单填写错误!请检查!')
  222. return false
  223. }
  224. })
  225. },
  226. // 请求图形验证码
  227. getImgCode() {
  228. const that = this
  229. this.$store.dispatch('user/getImgCode').then( res => {
  230. console.log(res)
  231. that.codeImg = res.data
  232. }).catch(() => {
  233. this.loading = false
  234. })
  235. },
  236. getOtherQuery(query) {
  237. return Object.keys(query).reduce((acc, cur) => {
  238. if (cur !== 'redirect') {
  239. acc[cur] = query[cur]
  240. }
  241. return acc
  242. }, {})
  243. },
  244. // 单点登录 start ---------------------------------------->
  245. // 使用字符串操作提取 backurl 参数的值
  246. getBackUrl(url) {
  247. const params = url.split('?')[1]; // 获取问号后面的部分
  248. if (params) {
  249. const paramArray = params.split('&'); // 分割参数
  250. for (let param of paramArray) {
  251. const [key, value] = param.split('='); // 分割键值对
  252. if (key === 'backurl') {
  253. return decodeURIComponent(value); // 返回解码后的 backurl 值
  254. }
  255. }
  256. }
  257. return null; // 如果没有找到 backurl 参数,返回 null
  258. },
  259. //登录分路器 start ---------------------------------------->
  260. singleLogin() {
  261. // 获得当前域名
  262. const urlString = window.location.href;
  263. // 创建一个URL对象
  264. const url = new URL(urlString);
  265. // 获取hash部分(即#后面的部分)
  266. const hash = url.hash;
  267. // 从hash中提取查询参数
  268. const hashParams = new URLSearchParams(hash.split('?')[1]);
  269. // 获取backurl参数的值
  270. const backurl = hashParams.get('backurl');
  271. // 获取backurl参数的值
  272. const userurl = hashParams.get('userurl');
  273. // 解码backurl
  274. const decodedBackurl = decodeURIComponent(backurl);
  275. const decodedUserurl = decodeURIComponent(userurl);
  276. // 第一种情况, 不含有backUrl或者userUrl 说明登录者是超级管理员
  277. if(hashParams.size==0){
  278. console.log("执行超级管理员登录!")
  279. this.login(1)
  280. }else{
  281. // 第二种情况,含有backurl 说明是单点登录
  282. if(backurl!=null){
  283. console.log("执行单点登录!")
  284. const backurlObj = new URL(decodedBackurl);
  285. const back_url = backurlObj.hostname;
  286. this.login(2)
  287. }else if(userurl!=null){
  288. console.log("执行会员登录!")
  289. const backurlObj = new URL(decodedUserurl);
  290. const user_url = backurlObj.hostname;
  291. this.login(3,user_url)
  292. }else{
  293. this.$message.error("检查登录链接失败,请从正规渠道登录!")
  294. }
  295. }
  296. },
  297. // 登录分路器 end ---------------------------------------->
  298. // 登录 start ---------------------------------------->
  299. login(type,url){
  300. //超级管理员登录
  301. if(type==1){
  302. this.$refs.loginForm.validate(valid => {
  303. if (valid) {
  304. this.loading = true
  305. this.$store.dispatch('user/login', this.loginForm).then( res => {
  306. this.loading = false
  307. console.log(res)
  308. if(res.code==0){
  309. this.$message({
  310. type:'error',
  311. message:res.message
  312. })
  313. }else if(res.code==200){
  314. console.log("登录成功,将跳转至详情页面!")
  315. this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
  316. }else if(res.code!=0&&res.code!=200){
  317. this.$message({
  318. type:'error',
  319. message:"用户不存在!"
  320. })
  321. }
  322. })
  323. }else {
  324. console.log('表单填写错误!请检查!')
  325. return false;
  326. }
  327. })
  328. }
  329. //单点登录
  330. if(type==2){
  331. // 获取当前页面的 URL
  332. const currentUrl = window.location.href;
  333. const backurlValue = this.getBackUrl(currentUrl);
  334. this.$refs.loginForm.validate(valid => {
  335. if (valid) {
  336. this.loading = true
  337. this.$store.dispatch('user/login', this.loginForm)
  338. .then( res => {
  339. this.loading = false
  340. console.log(res)
  341. if(res.code==0){
  342. this.$message({
  343. type:'error',
  344. message:"表单项有误,请检查!"
  345. })
  346. }else if(res.code==200){
  347. console.log("单点登录成功,开始启动跳转!")
  348. window.location.href = 'http://admindev.bjzxtw.org.cn/auth/back_login.php?backurl=' + backurlValue + '&token='+res.data.token;
  349. }else if(res.code!=0&&res.code!=200){
  350. this.$message({
  351. type:'error',
  352. message:"用户不存在!"
  353. })
  354. }
  355. })
  356. .catch(() => {
  357. this.loading = false
  358. })
  359. } else {
  360. console.log('表单填写错误!请检查!')
  361. return false
  362. }
  363. })
  364. }
  365. //会员登录
  366. if(type==3){
  367. this.$refs.loginForm.validate(valid => {
  368. if (valid) {
  369. this.loading = true;
  370. this.loginForm.userurl = url;
  371. //console.log(this.loginForm)
  372. this.$store.dispatch('user/login', this.loginForm).then( res => {
  373. this.loading = false
  374. console.log(res)
  375. if(res.code==0){
  376. this.$message({
  377. type:'error',
  378. message:res.message
  379. })
  380. }else if(res.code==200){
  381. console.log("登录成功,将跳转至详情页面!")
  382. this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
  383. }else if(res.code!=0&&res.code!=200){
  384. this.$message({
  385. type:'error',
  386. message:"用户不存在!"
  387. })
  388. }
  389. })
  390. }else {
  391. console.log('表单填写错误!请检查!')
  392. return false;
  393. }
  394. })
  395. }
  396. }
  397. // 登录 end ---------------------------------------->
  398. }
  399. }
  400. </script>
  401. <style scoped lang="less">
  402. .singleLogin {
  403. font-size: 14px;
  404. color: #666;
  405. cursor: pointer;
  406. margin-top: 30px;
  407. width: 400px;
  408. text-align: center;
  409. }
  410. /*整体盒子模型 使用display flex布局保持中间主体始终居中*/
  411. .appBox{
  412. clear: both;
  413. width: 100%;
  414. height: 100%;
  415. display:flex;
  416. align-items: center;
  417. /*中央盒子模型 在1920x1080下将会保持恒定的显示效果 低于这个分辨率左侧将会自动收缩*/
  418. .mainBox {
  419. width: 100%;
  420. max-width: 1920px;
  421. display:flex;
  422. justify-content: center;
  423. margin: 0 auto;
  424. .leftBox{
  425. width: 55%; //左侧自动收缩 最低1057 最高1920 1057/1920=55%
  426. max-width: 1057px;
  427. margin-right: 50px;
  428. max-height:585px;
  429. height: 100vh;//自适应全屏高度
  430. position: relative;
  431. }
  432. .rightBox{
  433. max-width: 400px;
  434. height:360px;
  435. position: relative;
  436. }
  437. }
  438. /*中央左侧main内容*/
  439. /*1.标题文字 start*/
  440. .titleBox {
  441. width: 516px;
  442. height: 280px;
  443. position: absolute;
  444. z-index:9999;
  445. top:5%;
  446. left:2%;
  447. .titleEnglish{
  448. left: 0px;
  449. top: 238px;
  450. position: absolute;
  451. color: #333333;
  452. font-size: 32px;
  453. font-family: Microsoft YaHei;
  454. font-weight: 400;
  455. word-wrap: break-word
  456. }
  457. .titleChinaeseBox{
  458. left: 0px;
  459. top: 0px;
  460. position: absolute;
  461. .titleChinasesTop{
  462. color: #5570F1;
  463. font-size: 86px;
  464. font-family: Microsoft YaHei;
  465. font-weight: 700;
  466. word-wrap: break-word
  467. }
  468. .titleChinasesBottom{
  469. color: #333333;
  470. font-size: 86px;
  471. font-family: Microsoft YaHei;
  472. font-weight: 700;
  473. word-wrap: break-word
  474. }
  475. }
  476. }
  477. /*标题文字 end*/
  478. /*2.背景颜色 start*/
  479. .yellow,.blue {
  480. width: 226px;
  481. height: 226px;
  482. position: absolute;
  483. }
  484. .yellow{
  485. z-index:1000;
  486. opacity: 0.45;
  487. top:0;
  488. left:0;
  489. background: #DDA82A;
  490. border-radius: 50%;
  491. filter: blur(120px)
  492. }
  493. .blue{
  494. z-index:1001;
  495. bottom:15%;
  496. left:20%;
  497. background: #4461F2;
  498. border-radius: 50%;
  499. filter: blur(150px)
  500. }
  501. /*背景颜色 end*/
  502. /*3.背景图 start*/
  503. .TitleImg {
  504. display:block;
  505. position: absolute;
  506. z-index:1100;
  507. right:0;
  508. bottom:0;
  509. @media (max-width: 1366px) and (max-height: 768px) {
  510. transform: scale(0.7); //稍微缩小
  511. }
  512. }
  513. /*背景图 end*/
  514. /*中央右侧main内容*/
  515. /*登录框 start*/
  516. .loginFormBox {
  517. margin-top:15%;
  518. .inputBox {
  519. margin-bottom: 30px;
  520. .inputIcon {
  521. width: 24px;
  522. height: 24px;
  523. margin: 0 20px 0 20px;
  524. }
  525. .inputIconSmall {
  526. width: 18px;
  527. height: 18px;
  528. }
  529. }
  530. .inputBoxSpecial {
  531. justify-content: space-between;
  532. margin-bottom: 80px;
  533. }
  534. .inputBox,.inputBoxSpecial{
  535. height: 52px;
  536. width: 400px;
  537. box-sizing: border-box;
  538. align-items: center;
  539. display:flex;
  540. input {
  541. border:0;
  542. background: transparent;
  543. font-size: 18x;
  544. }
  545. input:focus {
  546. outline: none;
  547. }
  548. }
  549. .greyBg {
  550. background: rgba(239, 241, 249, 0.60);
  551. border-radius: 8px;
  552. }
  553. .inputBoxLeft {
  554. width:250px;
  555. height: 52px;
  556. box-sizing: border-box;
  557. align-items: center;
  558. display:flex;
  559. input {
  560. width: 150px;
  561. font-size: 16px;
  562. }
  563. .inputIcon {
  564. width: 24px;
  565. height: 24px;
  566. margin: 0 20px 0 20px;
  567. }
  568. }
  569. .inputBoxRight {
  570. width:140px;
  571. height: 52px;
  572. position: relative;
  573. .submitCode {
  574. height: 52px;
  575. box-sizing: border-box;
  576. padding-top: 5px;
  577. padding-left: 10px;
  578. cursor:pointer;
  579. .codeImg{
  580. display: block;
  581. width: 120px;
  582. height: 42px;
  583. }
  584. }
  585. }
  586. .reloadBtn {
  587. color: #5570F1;
  588. font-size: 12px;
  589. font-family: Microsoft YaHei;
  590. font-weight: 400;
  591. word-wrap: break-word;
  592. position: absolute;
  593. bottom: -20px;
  594. right: 0;
  595. cursor:pointer
  596. }
  597. .loginBtn {
  598. width: 400px;
  599. height: 58px;
  600. background: #5570F1;
  601. box-shadow: 0px 4px 19px rgba(85, 112, 241, 0.40);
  602. border-radius: 12px;
  603. font-size:24px;
  604. color:#fff;
  605. border:0;
  606. }
  607. }
  608. }
  609. /*验证码*/
  610. .captcha-img {
  611. cursor: pointer;
  612. width: 120px;
  613. height: 40px; /* 调整验证码图片大小 */
  614. }
  615. .show-pwd{
  616. margin-left: 30px;
  617. }
  618. /*登录框 end*/
  619. /*此处修改了element-ui中的部分内置样式,但是通过css-scope可以保证不会污染到全局*/
  620. /*在index中使用deep或者>>>深度选择器来修改el-input的默认样式*/
  621. /deep/ .el-input__inner {
  622. background: transparent;
  623. width:100%;
  624. border: 0;
  625. //border:0
  626. }
  627. /deep/ .el-form-item {
  628. margin-bottom: 0;
  629. }
  630. /deep/ .el-form-item__content {
  631. display: flex;
  632. width: 300px;
  633. }
  634. /deep/ .el-form-item__error {
  635. bottom: -34px;
  636. left:15px;
  637. line-height: 30px;
  638. }
  639. </style>