index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843
  1. <template>
  2. <div class="login-container">
  3. <div class="login-info">
  4. <img :src="require(`@/assets/logo/logo1.png`)"/>
  5. <div>
  6. <div class="title">{{$t('login.shuoming.title')}}</div>
  7. <div class="title">{{$t('login.shuoming.tips')}}</div>
  8. </div>
  9. </div>
  10. <el-form
  11. :model="loginForm"
  12. :rules="rules"
  13. autocomplete="off"
  14. class="login-form"
  15. label-position="left"
  16. ref="loginForm"
  17. >
  18. <el-tabs v-model="activeName" @tab-click="handleClick">
  19. <el-tab-pane label="扫码登录" name="first">
  20. <div class="saomaDom">
  21. <img :src="require(`@/assets/logo/saoma.png`)"/>
  22. <el-select
  23. v-model="opValue"
  24. :span="2"
  25. @change="selectChange"
  26. :placeholder="$t('common.pleaseSelect')"
  27. >
  28. <el-option
  29. v-for="item in options"
  30. :key="item.value"
  31. :label="item.name"
  32. :value="item.value"
  33. >
  34. </el-option>
  35. </el-select>
  36. <!-- <div>请选择上下料站并扫码登录<el-input id="qcodeUserInput" name="qcodeUserInput" type="password" style="z-index: -100" v-model="loginForm.qcodeUser" onfocus="this.style.imeMode = 'disabled'" @input="showQcodeUser()"/></div>-->
  37. <div>请选择上下料站并扫码登录<el-input id="qcodeUserInput" name="qcodeUserInput" v-model="loginForm.qcodeUser" @input="showQcodeUser()"/></div>
  38. </div>
  39. </el-tab-pane>
  40. <el-tab-pane label="密码登录" name="second">
  41. <div class="title-container">
  42. <h3 class="title">{{$t('login.title')}}</h3>
  43. <lang-select class="set-language"/>
  44. </div>
  45. <span v-if="login.type === 'up'">
  46. <el-form-item prop="tenant" v-show="isMultiTenant">
  47. <el-input
  48. :placeholder="$t('login.tenant')"
  49. @keyup.enter.native="handleLogin"
  50. autocomplete="off"
  51. name="tenantView"
  52. prefix-icon="el-icon-user"
  53. ref="tenant"
  54. type="text"
  55. v-model="loginForm.tenantView"
  56. />
  57. </el-form-item>
  58. <el-form-item prop="account">
  59. <el-input
  60. :placeholder="$t('login.username')"
  61. @keyup.enter.native="handleLogin"
  62. autocomplete="off"
  63. name="account"
  64. prefix-icon="el-icon-user"
  65. ref="account"
  66. type="text"
  67. v-model="loginForm.account"
  68. />
  69. </el-form-item>
  70. <el-form-item prop="password">
  71. <el-input
  72. :placeholder="$t('login.password')"
  73. :show-password="true"
  74. @keyup.enter.native="handleLogin"
  75. autocomplete="off"
  76. name="password"
  77. prefix-icon="el-icon-key"
  78. ref="password"
  79. type="password"
  80. v-model="loginForm.password"
  81. />
  82. </el-form-item>
  83. <el-form-item class="code-input" prop="code" v-show="isCaptcha">
  84. <el-input
  85. :placeholder="$t('login.code')"
  86. @keyup.enter.native="handleLogin"
  87. autocomplete="off"
  88. name="code"
  89. prefix-icon="el-icon-lock"
  90. ref="code"
  91. style="width: 70%"
  92. type="text"
  93. v-model="loginForm.code"
  94. />
  95. </el-form-item>
  96. <img
  97. v-show="isCaptcha"
  98. :src="imageCode"
  99. @click="getCodeImage"
  100. alt="codeImage"
  101. class="code-image"
  102. />
  103. <el-button
  104. :loading="loading"
  105. @click.native.prevent="handleLogin"
  106. style="width:100%;margin-bottom:14px;"
  107. type="primary"
  108. >{{ $t("login.logIn") }}</el-button
  109. >
  110. </span>
  111. <span v-if="login.type === 'social'">
  112. {{ $t("login.chooseToSignIn") }}
  113. <div>
  114. <template v-for="(l, index) in logo">
  115. <div :key="index" class="logo-wrapper">
  116. <img
  117. :class="{ radius: l.radius }"
  118. :src="resolveLogo(l.img)"
  119. @click="socialLogin(l.name)"
  120. alt
  121. />
  122. </div>
  123. </template>
  124. </div>
  125. </span>
  126. <span style="margin-top: -1rem" v-if="login.type === 'bind'">
  127. <el-tabs @tab-click="handleTabClick" v-model="tabActiveName">
  128. <el-tab-pane :label="$t('common.bindLogin')" name="bindLogin">
  129. <el-form-item prop="bindAccount">
  130. <el-input
  131. :placeholder="$t('login.account')"
  132. autocomplete="off"
  133. name="bindAccount"
  134. prefix-icon="el-icon-user"
  135. ref="bindAccount"
  136. type="text"
  137. v-model="loginForm.bindAccount"
  138. />
  139. </el-form-item>
  140. <el-form-item prop="bindPassword">
  141. <el-input
  142. :placeholder="$t('login.password')"
  143. :show-password="true"
  144. autocomplete="off"
  145. name="bindPassword"
  146. prefix-icon="el-icon-key"
  147. ref="bindPassword"
  148. type="password"
  149. v-model="loginForm.bindPassword"
  150. />
  151. </el-form-item>
  152. <el-button
  153. :loading="loading"
  154. @click.native.prevent="bindLogin"
  155. style="width:100%;margin-bottom:14px;"
  156. type="primary"
  157. >{{ $t("common.bindLogin") }}</el-button
  158. >
  159. </el-tab-pane>
  160. <el-tab-pane :label="$t('common.signLogin')" name="signLogin">
  161. <el-form-item prop="signAccount">
  162. <el-input
  163. :placeholder="$t('login.account')"
  164. autocomplete="off"
  165. name="signAccount"
  166. prefix-icon="el-icon-user"
  167. ref="signAccount"
  168. type="text"
  169. v-model="loginForm.signAccount"
  170. />
  171. </el-form-item>
  172. <el-form-item prop="signPassword">
  173. <el-input
  174. :placeholder="$t('login.password')"
  175. :show-password="true"
  176. autocomplete="off"
  177. name="signPassword"
  178. prefix-icon="el-icon-key"
  179. ref="signPassword"
  180. type="password"
  181. v-model="loginForm.signPassword"
  182. />
  183. </el-form-item>
  184. <el-button
  185. :loading="loading"
  186. @click.native.prevent="signLogin"
  187. style="width:100%;margin-bottom:14px;"
  188. type="primary"
  189. >{{ $t("common.signLogin") }}</el-button
  190. >
  191. </el-tab-pane>
  192. </el-tabs>
  193. </span>
  194. <!--<el-dropdown class="login-type" placement="top-end">
  195. <span class="el-dropdown-link">
  196. <el-link type="primary">{{ $t("login.ortherLoginType") }}</el-link>
  197. </span>
  198. <el-dropdown-menu slot="dropdown">
  199. <el-dropdown-item
  200. :disabled="login.type === 'up'"
  201. @click.native="login.type = 'up'"
  202. >{{ $t("login.type.up") }}
  203. </el-dropdown-item
  204. >
  205. <el-dropdown-item
  206. :disabled="login.type === 'social'"
  207. @click.native="login.type = 'social'"
  208. >{{ $t("login.type.social") }}
  209. </el-dropdown-item
  210. >
  211. </el-dropdown-menu>
  212. </el-dropdown>-->
  213. </el-tab-pane>
  214. </el-tabs>
  215. </el-form>
  216. <span class="login-footer">
  217. © 2019 - 2022
  218. <span>{{$t('login.shuoming.tips')}}</span>
  219. </span>
  220. </div>
  221. </template>
  222. <script>
  223. import LangSelect from "@/components/LangSelect";
  224. import db from "@/utils/localstorage";
  225. import {randomNum} from "@/utils";
  226. import {socialLoginUrl} from "@/settings";
  227. import loginApi from "@/api/Login.js";
  228. import oauthApi from '@/api/Oauth'
  229. import {Base64} from 'js-base64';
  230. import productionResourcesMgrApi from "@/api/resourceProductMgr/productionResourcesMgr";
  231. export default {
  232. name: "Login",
  233. components: {LangSelect},
  234. data() {
  235. return {
  236. options: [],
  237. opValue:'',
  238. activeName: 'first',
  239. //是否启用多租户
  240. isMultiTenant:
  241. false,
  242. isCaptcha:
  243. process.env.VUE_APP_IS_CAPTCHA === "true" ? true : false,
  244. tabActiveName: "bindLogin",
  245. login: {
  246. type: "up"
  247. },
  248. logo: [
  249. {img: "gitee.png", name: "gitee", radius: true},
  250. {img: "github.png", name: "github", radius: true},
  251. {img: "tencent_cloud.png", name: "tencent_cloud", radius: true},
  252. {img: "qq.png", name: "qq", radius: false},
  253. {img: "dingtalk.png", name: "dingtalk", radius: true},
  254. {img: "microsoft.png", name: "microsoft", radius: false}
  255. ],
  256. loginForm: {
  257. account: "zuihou",
  258. password: "", // zuihou
  259. tenantView: "0000", //显示用的
  260. tenant: "", //传递给后端的
  261. key: randomNum(24, 16),
  262. code: "",
  263. grantType: process.env.VUE_APP_IS_CAPTCHA === "true" ? "captcha" : "password",
  264. bindAccount: "",
  265. bindPassword: "",
  266. signAccount: "",
  267. signPassword: "",
  268. qcodeUser: "",
  269. stationResourceId: "",
  270. },
  271. rules: {
  272. account: {
  273. required: true,
  274. message: this.$t("rules.require"),
  275. trigger: "blur"
  276. },
  277. tenantView: {
  278. required: true,
  279. message: this.$t("rules.require"),
  280. trigger: "blur"
  281. },
  282. password: {
  283. required: true,
  284. message: this.$t("rules.require"),
  285. trigger: "blur"
  286. },
  287. code: {
  288. validator: (rule, value, callback) => {
  289. if (this.isCaptcha && value === '') {
  290. callback(this.$t("rules.require"))
  291. } else {
  292. callback()
  293. }
  294. callback()
  295. }, trigger: 'blur'
  296. },
  297. bindAccount: {
  298. required: true,
  299. message: this.$t("rules.require"),
  300. trigger: "blur"
  301. },
  302. bindPassword: {
  303. required: true,
  304. message: this.$t("rules.require"),
  305. trigger: "blur"
  306. },
  307. signAccount: [
  308. {
  309. required: true,
  310. message: this.$t("rules.require"),
  311. trigger: "blur"
  312. },
  313. {
  314. min: 4,
  315. max: 10,
  316. message: this.$t("rules.range4to10"),
  317. trigger: "blur"
  318. }
  319. ],
  320. signPassword: [
  321. {
  322. required: true,
  323. message: this.$t("rules.require"),
  324. trigger: "blur"
  325. },
  326. {
  327. min: 6,
  328. max: 20,
  329. message: this.$t("rules.range6to20"),
  330. trigger: "blur"
  331. }
  332. ]
  333. },
  334. authUser: null,
  335. loading: false,
  336. showDialog: false,
  337. redirect: undefined,
  338. otherQuery: {},
  339. imageCode: "",
  340. page: {
  341. width: window.screen.width * 0.5,
  342. height: window.screen.height * 0.5
  343. }
  344. };
  345. },
  346. created() {
  347. this.getStations()
  348. },
  349. mounted() {
  350. db.clear();
  351. this.getCodeImage();
  352. this.$nextTick(
  353. window.onload = function () { // 光标默认位置
  354. var oInput = document.getElementById('qcodeUserInput');
  355. oInput.focus();
  356. }
  357. )
  358. },
  359. destroyed() {
  360. window.removeEventListener("message", this.resolveSocialLogin);
  361. },
  362. methods: {
  363. // Tabs切换-事件
  364. handleClick(tab, event) {
  365. // tab切换初始化focus及内容
  366. if(tab.name === 'first'){
  367. this.$nextTick(
  368. window.onload = function () { // 光标默认位置
  369. document.getElementById('qcodeUserInput').value = "";
  370. var oInput = document.getElementById('qcodeUserInput');
  371. oInput.focus();
  372. }
  373. )
  374. }
  375. console.log(tab, event);
  376. },
  377. getCodeImage() {
  378. loginApi
  379. .getCaptcha(this.loginForm.key)
  380. .then(response => {
  381. const res = response.data;
  382. if (res.byteLength <= 100) {
  383. this.$message({
  384. message: this.$t("tips.systemError"),
  385. type: "error"
  386. });
  387. }
  388. return (
  389. "data:image/png;base64," +
  390. btoa(
  391. new Uint8Array(res).reduce(
  392. (data, byte) => data + String.fromCharCode(byte),
  393. ""
  394. )
  395. )
  396. );
  397. })
  398. .then(res => {
  399. this.imageCode = res;
  400. })
  401. .catch(e => {
  402. if (e.toString().indexOf("429") !== -1) {
  403. this.$message({
  404. message: this.$t("tips.tooManyRequest"),
  405. type: "error"
  406. });
  407. } else {
  408. this.$message({
  409. message: this.$t("tips.getCodeImageFailed"),
  410. type: "error"
  411. });
  412. }
  413. });
  414. },
  415. handleTabClick(tab) {
  416. this.tabActiveName = tab.name;
  417. },
  418. resolveLogo(logo) {
  419. return require(`@/assets/logo/${logo}`);
  420. },
  421. socialLogin(oauthType) {
  422. const url = `${socialLoginUrl}/${oauthType}/login`;
  423. window.open(
  424. url,
  425. "newWindow",
  426. `resizable=yes, height=${this.page.height}, width=${this.page.width}, top=10%, left=10%, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no, status=no`
  427. );
  428. window.addEventListener("message", this.resolveSocialLogin, false);
  429. },
  430. resolveSocialLogin(e) {
  431. const data = e.data;
  432. const that = this;
  433. if (data.message === "not_bind") {
  434. that.login.type = "bind";
  435. const authUser = data.data;
  436. that.authUser = authUser;
  437. that
  438. .$confirm(
  439. that.$t("common.current") +
  440. authUser.source +
  441. that.$t("common.socialAccount") +
  442. authUser.nickname +
  443. that.$t("common.socialTips"),
  444. that.$t("common.tips"),
  445. {
  446. confirmButtonText: that.$t("common.signLogin"),
  447. cancelButtonText: that.$t("common.bindLogin"),
  448. type: "warning"
  449. }
  450. )
  451. .then(() => {
  452. that.tabActiveName = "signLogin";
  453. })
  454. .catch(() => {
  455. that.tabActiveName = "bindLogin";
  456. });
  457. } else if (data.message === "social_login_success") {
  458. that.saveLoginData(data.data);
  459. that.getUserDetailInfo();
  460. that.loginSuccessCallback(data.account);
  461. } else {
  462. // do nothing
  463. }
  464. },
  465. bindLogin() {
  466. let account_c = false;
  467. let password_c = false;
  468. this.$refs.loginForm.validateField("bindAccount", e => {
  469. if (!e) {
  470. account_c = true;
  471. }
  472. });
  473. this.$refs.loginForm.validateField("bindPassword", e => {
  474. if (!e) {
  475. password_c = true;
  476. }
  477. });
  478. if (account_c && password_c) {
  479. this.loading = true;
  480. const that = this;
  481. const params = {
  482. bindAccount: that.loginForm.bindAccount,
  483. bindPassword: that.loginForm.bindPassword,
  484. ...that.authUser
  485. };
  486. params.token = null;
  487. that
  488. .$post("auth/social/bind/login", params)
  489. .then(r => {
  490. const data = r.data.data;
  491. this.saveLoginData(data);
  492. this.getUserDetailInfo();
  493. this.loginSuccessCallback(that.loginForm.bindAccount);
  494. })
  495. .catch(error => {
  496. console.error(error);
  497. that.loading = false;
  498. });
  499. }
  500. },
  501. signLogin() {
  502. let account_c = false;
  503. let password_c = false;
  504. this.$refs.loginForm.validateField("signAccount", e => {
  505. if (!e) {
  506. account_c = true;
  507. }
  508. });
  509. this.$refs.loginForm.validateField("signPassword", e => {
  510. if (!e) {
  511. password_c = true;
  512. }
  513. });
  514. if (account_c && password_c) {
  515. this.loading = true;
  516. const that = this;
  517. const params = {
  518. bindAccount: that.loginForm.signAccount,
  519. bindPassword: that.loginForm.signPassword,
  520. ...that.authUser
  521. };
  522. params.token = null;
  523. that
  524. .$post("auth/social/sign/login", params)
  525. .then(r => {
  526. const data = r.data.data;
  527. this.saveLoginData(data);
  528. this.getUserDetailInfo();
  529. this.loginSuccessCallback(that.loginForm.signAccount);
  530. })
  531. .catch(error => {
  532. console.error(error);
  533. that.loading = false;
  534. });
  535. }
  536. },
  537. handleLogin() {
  538. this.loginForm.tenant = `${Base64.encode(this.loginForm.tenantView)}`;
  539. this.$refs.loginForm.validate((valid) => {
  540. if (valid) {
  541. this.loginSubmit();
  542. } else {
  543. return false
  544. }
  545. })
  546. },
  547. loginSubmit() {
  548. this.loading = true;
  549. const that = this;
  550. this.$store.commit("account/setTenant", this.loginForm.tenant);
  551. loginApi.login(this.loginForm).then(response => {
  552. const res = response.data;
  553. if (res.isSuccess) {
  554. that.saveLoginData(res.data['token'], res.data['refreshToken'], res.data['expiration']);
  555. that.saveUserInfo(res.data);
  556. that.getResource();
  557. } else {
  558. that.getCodeImage();
  559. }
  560. }).finally(() => that.loading = false);
  561. },
  562. saveLoginData(token, refreshToken, expiration) {
  563. this.$store.commit("account/setToken", token);
  564. this.$store.commit("account/setRefreshToken", refreshToken);
  565. this.$store.commit("account/setExpireTime", expiration);
  566. },
  567. saveUserInfo(user) {
  568. this.$store.commit("account/setUser", {
  569. });
  570. this.$store.commit("account/setUser", {
  571. id: user.userId,
  572. account: user.account,
  573. name: user.name,
  574. avatar: user.avatar,
  575. expire: user.expire,
  576. workDescribe: user.workDescribe,
  577. roles: user.roles
  578. });
  579. },
  580. getResource() {
  581. oauthApi.getResource().then(response => {
  582. const res = response.data;
  583. if (res.isSuccess) {
  584. const permissionsList = res.data;
  585. this.$store.commit("account/setPermissions", permissionsList ? permissionsList : []);
  586. this.loginSuccess();
  587. } else {
  588. this.getCodeImage();
  589. }
  590. });
  591. },
  592. loginSuccess() {
  593. this.$message({
  594. message: this.$t("tips.loginSuccess"),
  595. type: "success"
  596. });
  597. this.$router.push("/");
  598. },
  599. loginSuccessCallback(user) {
  600. console.log(user);
  601. },
  602. qcodelogin(qcodeUserValue) {
  603. this.loading = true;
  604. const that = this;
  605. this.loginForm.tenant = `${Base64.encode(this.loginForm.tenantView)}`;
  606. this.$store.commit("account/setTenant", this.loginForm.tenant);
  607. this.loginForm.qcodeUserValue = qcodeUserValue
  608. this.loginForm.grantType="password";
  609. loginApi.qcodelogin(this.loginForm).then(response => {
  610. const res = response.data;
  611. if (res.isSuccess) {
  612. that.saveLoginData(res.data['token'], res.data['refreshToken'], res.data['expiration']);
  613. that.saveUserInfo(res.data);
  614. that.getResource();
  615. } else {
  616. that.getCodeImage();
  617. }
  618. }).finally(() => that.loading = false);
  619. },
  620. showQcodeUser(){
  621. console.log(this.loginForm.qcodeUser.substr(this.loginForm.qcodeUser.length-1,1));
  622. if(this.loginForm.qcodeUser.substr(this.loginForm.qcodeUser.length-1,1) == "#"){
  623. this.qcodelogin()
  624. }
  625. },
  626. getStations() {
  627. productionResourcesMgrApi.getStations({}).then((res) => {
  628. res = res.data;
  629. if (res.isSuccess) {
  630. if (res.data.length > 0) {
  631. this.options = res.data;
  632. }
  633. }
  634. });
  635. },
  636. selectChange(value) {
  637. console.log(value);
  638. this.loginForm.stationResourceId = value;
  639. this.$nextTick(
  640. window.onload = function () { // 光标默认位置
  641. document.getElementById('qcodeUserInput').value = "";
  642. var oInput = document.getElementById('qcodeUserInput');
  643. oInput.focus();
  644. }
  645. )
  646. },
  647. }
  648. };
  649. </script>
  650. <style lang="scss">
  651. .login-form {
  652. .el-tabs__item {
  653. font-size: 16px;
  654. color: white;
  655. }
  656. .el-tabs__item.is-active {
  657. color: #1890ff;
  658. }
  659. .el-tabs__active-bar {
  660. background: none;
  661. }
  662. }
  663. </style>
  664. <style lang="scss" scoped>
  665. $bg: #2d3a4b;
  666. $dark_gray: #aaa;
  667. $light_gray: #eee;
  668. .login-container {
  669. /*background: url(../../assets/logo/loginBg.gif) 50% no-repeat;
  670. background-size: cover;*/
  671. /*background: url(../../assets/background.jpg) 50% no-repeat;*/
  672. /*background: url(../../assets/logo/logoBg1.jpg) 50% no-repeat;*/
  673. /*background: url(../../assets/logo/logoBg2.png) 50% no-repeat;
  674. background-size: cover;*/
  675. background: #000000;
  676. width: 100%;
  677. height: 100vh;
  678. .saomaDom {
  679. text-align: center;
  680. color: white;
  681. cursor: pointer;
  682. }
  683. .login-info {
  684. display: flex;
  685. align-items: center;
  686. position: absolute;
  687. left: 10%;
  688. top: 44%;
  689. margin-top: -100px;
  690. color: #fff;
  691. img{
  692. width: 300px;
  693. margin-right: 40px;
  694. }
  695. .title {
  696. font-size: 1.8rem;
  697. font-weight: 600;
  698. }
  699. .title:first-child{
  700. margin-bottom: 15px;
  701. }
  702. .sub-title {
  703. font-size: 1.5rem;
  704. margin: 0.3rem 0 0.7rem 1rem;
  705. }
  706. .desc {
  707. font-size: 0.96rem;
  708. line-height: 1.9rem;
  709. }
  710. }
  711. .login-form {
  712. position: absolute;
  713. top: 45%;
  714. left: 70%;
  715. margin: -180px 0 0 -160px;
  716. width: 320px;
  717. height: 440px;
  718. padding: 10px 36px 36px 36px;
  719. background: #4F535B;
  720. border-radius: 3px;
  721. .el-tabs__item {
  722. font-size: 16px;
  723. }
  724. .code-input {
  725. width: 50%;
  726. display: inline-block;
  727. vertical-align: middle;
  728. }
  729. .code-image {
  730. display: inline-block;
  731. vertical-align: top;
  732. cursor: pointer;
  733. }
  734. .login-type {
  735. text-align: right;
  736. display: inline-block;
  737. width: 100%;
  738. }
  739. .logo-wrapper {
  740. display: inline-block;
  741. margin: 10px 0;
  742. img {
  743. width: 1.9rem;
  744. display: inline-block;
  745. margin: 0.8rem 0.8rem -0.8rem 0.8rem;
  746. cursor: pointer;
  747. &.radius {
  748. border-radius: 50%;
  749. }
  750. }
  751. }
  752. }
  753. .login-footer {
  754. position: fixed;
  755. bottom: 1rem;
  756. width: 100%;
  757. text-align: center;
  758. color: white;
  759. font-size: 0.85rem;
  760. line-height: 1rem;
  761. height: 1rem;
  762. }
  763. .tips {
  764. font-size: 14px;
  765. color: #fff;
  766. margin-bottom: 10px;
  767. span {
  768. &:first-of-type {
  769. margin-right: 16px;
  770. }
  771. }
  772. }
  773. .title-container {
  774. position: relative;
  775. .title {
  776. font-size: 20px;
  777. color: #FFFFFF;
  778. margin: 0 auto 40px auto;
  779. text-align: center;
  780. font-weight: bold;
  781. }
  782. .set-language {
  783. color: #aaa;
  784. position: absolute;
  785. top: 3px;
  786. font-size: 18px;
  787. right: 0;
  788. cursor: pointer;
  789. }
  790. }
  791. .thirdparty-button {
  792. position: absolute;
  793. right: 0;
  794. bottom: 6px;
  795. }
  796. @media only screen and (max-width: 470px) {
  797. .thirdparty-button {
  798. display: none;
  799. }
  800. }
  801. @media screen and (max-width: 1100px) {
  802. .login-info {
  803. left: 8%;
  804. }
  805. }
  806. @media screen and (max-width: 970px) {
  807. .login-form {
  808. left: 50%;
  809. }
  810. .login-info {
  811. display: none;
  812. }
  813. }
  814. }
  815. </style>