single-window-login.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. <template>
  2. <div class="single-window-login">
  3. <div class="swl-head">
  4. <div class="swl-head-center">
  5. <a href="https://www.singlewindow.cn" target="_blank"><img src="./img/swLogo.png"></a>
  6. <div class="swl-head-lang">
  7. <div class="__hover" :class="{ active: config.lang === 'zh-cn' }" @click="configLang('zh-cn')">简体中文</div>
  8. <div>/</div>
  9. <div class="__hover" :class="{ active: config.lang === 'en' }" @click="configLang('en')">English</div>
  10. </div>
  11. </div>
  12. </div>
  13. <div class="swl-content">
  14. <div class="swl-content-login">
  15. <div class="swl-content-login-left"/>
  16. <div class="swl-content-login-right">
  17. <div class="swlclr-login">
  18. <div class="swlclr-login-div">
  19. <div class="swlclr-login-div-title">
  20. <div class="swlclr-login-div-title-1 __hover" :class="{active: loginMode === 'account'}" @click="loginMode = 'account'">{{ $t('login.signInTitle') }}</div>
  21. <template v-if="config.lang === 'zh-cn'">
  22. <div class="swlclr-login-div-title-line"/>
  23. <div class="swlclr-login-div-title-2 __hover" :class="{active: loginMode === 'card'}" @click="loginMode = 'card'">卡介质登录</div>
  24. </template>
  25. </div>
  26. <template v-if="loginMode === 'account'">
  27. <a-form class="login-form" ref="loginForm" :model="ruleForm" :rules="rules">
  28. <a-form-item name="account">
  29. <a-input
  30. v-model:value="ruleForm.account"
  31. :placeholder="$t('login.accountPlaceholder')"
  32. size="large"
  33. @keyup.enter="login"
  34. >
  35. <template #prefix>
  36. <UserOutlined class="login-icon-gray" />
  37. </template>
  38. <template #addonAfter v-if="config.lang === 'zh-cn'">
  39. <a class="__hover" href="https://app.singlewindow.cn/userserver/user/findusername/choseFindUserNameType" target="_blank">忘记用户名</a>
  40. </template>
  41. </a-input>
  42. </a-form-item>
  43. <a-form-item name="password">
  44. <a-input-password
  45. v-model:value="ruleForm.password"
  46. :placeholder="$t('login.PWPlaceholder')"
  47. size="large"
  48. autocomplete="off"
  49. @keyup.enter="login"
  50. >
  51. <template #prefix>
  52. <LockOutlined class="login-icon-gray" />
  53. </template>
  54. <template #addonAfter>
  55. <template v-if="config.lang === 'zh-cn'">
  56. <a class="__hover" href="https://app.singlewindow.cn/nuserwebserver/static/#/resetPwd?projectFlag=0" target="_blank">忘记密码</a>
  57. </template>
  58. <template v-else>
  59. <a class="__hover" href="https://app.singlewindow.cn/userserver/rest/userNra/find/findPWIndex" target="_blank">Forgot Password</a>
  60. </template>
  61. </template>
  62. </a-input-password>
  63. </a-form-item>
  64. <a-form-item name="validCode" v-if="captchaOpen === 'true'">
  65. <a-row :gutter="8">
  66. <a-col :span="17">
  67. <a-input
  68. v-model:value="ruleForm.validCode"
  69. :placeholder="$t('login.validLaceholder')"
  70. size="large"
  71. @keyup.enter="login"
  72. >
  73. <template #prefix>
  74. <verified-outlined class="login-icon-gray" />
  75. </template>
  76. </a-input>
  77. </a-col>
  78. <a-col :span="7">
  79. <img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
  80. </a-col>
  81. </a-row>
  82. </a-form-item>
  83. </a-form>
  84. </template>
  85. <template v-else-if="loginMode === 'card'">
  86. <a-form class="login-form" ref="cardForm" :model="cardRuleForm">
  87. <a-form-item name="password">
  88. <a-input-password
  89. v-model:value="cardRuleForm.password"
  90. placeholder="卡介质密码"
  91. size="large"
  92. autocomplete="off"
  93. @keyup.enter="cardLogin"
  94. >
  95. <template #prefix>
  96. <LockOutlined class="login-icon-gray" />
  97. </template>
  98. <template #addonAfter>
  99. <a class="__hover" href="https://www.singlewindow.cn/#/detail?breadNum=bc9&articleId=0000000000002256" target="_blank">忘记卡密码?</a>
  100. </template>
  101. </a-input-password>
  102. </a-form-item>
  103. </a-form>
  104. </template>
  105. <div class="agree" v-if="config.lang === 'zh-cn'">
  106. <a-checkbox v-model:checked="loginAgree"/>
  107. <span style="color:#222222">已阅读并同意</span>
  108. <span style="color: #096ac6;text-decoration:underline dotted; cursor:pointer;" @click="agreeTipsYhfwxy = true">《用户服务协议》</span>
  109. <span>和</span>
  110. <span style="color: #096ac6;text-decoration:underline dotted; cursor:pointer;" @click="agreeTipsYhyszc = true">《用户隐私政策》</span>
  111. </div>
  112. <a-button type="primary" class="w-full mt-4" style="background-color: #00599c;border-radius: 4px;" :loading="loading" round size="large" @click="loginMode === 'account' ? login() : cardLogin()">
  113. {{ $t('login.signIn') }}
  114. </a-button>
  115. <div class="card-tips" v-if="loginMode === 'card'">
  116. <div>请按照以下步骤进行:</div>
  117. <div><div class="index">1</div>请确认已下载并启动了&nbsp;<a class="__hover" href="https://update.singlewindow.cn/downloads/EportClientSetup_V1.5.50.exe" target="_blank">客户端控件</a></div>
  118. <div><div class="index">2</div>插入中国电子口岸卡介质</div>
  119. <div><div class="index">3</div>输入卡介质密码</div>
  120. </div>
  121. <div class="tips">
  122. <template v-if="config.lang === 'zh-cn'">
  123. <template v-if="loginMode === 'account'">
  124. <div class="zhuce">卡介质丢失/损坏?<a class="__hover" href="https://app.singlewindow.cn/nuserwebserver/static/#/corp/accountActive?projectFlag=0" target="_blank">账号激活</a></div>
  125. </template>
  126. <template v-else-if="loginMode === 'card'">
  127. <div class="zhuce">卡介质有问题?<a class="__hover" href="https://www.singlewindow.cn/#/detail?breadNum=bc9&articleId=0000000000002287" target="_blank">制卡电话</a></div>
  128. </template>
  129. </template>
  130. <div class="zhuce">
  131. {{ $t('login.noAccount') }}
  132. <a class="__hover" :href="config.lang === 'zh-cn' ? 'https://app.singlewindow.cn/nuserwebserver/static/#/corp/accountActive?projectFlag=0' : 'https://app.singlewindow.cn/userserver/user/abroad/index'" target="_blank">{{ $t('login.registerAccount') }}</a></div>
  133. </div>
  134. </div>
  135. </div>
  136. </div>
  137. </div>
  138. </div>
  139. <div class="swl-foot" v-if="config.lang === 'zh-cn'">
  140. <div class="swl-foot-main">
  141. <div class="swl-foot-main-left">
  142. <div class="swl-foot-main-left-top">
  143. <div class="swlfmlt-item __hover"><a class="textUnderline footer-nav-text" href="https://www.singlewindow.cn/#/aboutUs" target="_blank">关于我们</a></div>
  144. <div class="swlfmlt-split">|</div>
  145. <div class="swlfmlt-item __hover"><a class="textUnderline footer-nav-text" href="https://www.singlewindow.cn/#/sitemap" target="_blank">网站地图</a></div>
  146. <div class="swlfmlt-split">|</div>
  147. <a-popover>
  148. <template #content>
  149. <a class="textUnderline footer-nav-text" target="_blank" href="http://www.gov.cn/hudong/ducha/2021-01/26/content_5582430.htm">
  150. <img class="nav-img" src="./img/hlwjd.jpg" alt="互联网+督查">
  151. </a>
  152. </template>
  153. <div class="swlfmlt-item __hover"><a class="textUnderline footer-nav-text" target="_blank" href="http://www.gov.cn/hudong/ducha/2021-01/26/content_5582430.htm">互联网+督查</a></div>
  154. </a-popover>
  155. <div class="swlfmlt-split">|</div>
  156. <a-popover>
  157. <template #content>
  158. <img class="nav-img" src="./img/zwfw.jpg" alt="政务服务投诉">
  159. </template>
  160. <div class="swlfmlt-item __hover"><div class="swlfmlt-item __hover">政务服务投诉</div></div>
  161. </a-popover>
  162. </div>
  163. <div class="swl-foot-main-left-bottom">
  164. <div class="swlfmlb-item">主办单位:国家口岸管理办公室</div>
  165. <div class="swlfmlb-item">承办单位:中国电子口岸数据中心</div>
  166. <div class="swlfmlb-item">京ICP备12005222号-2</div>
  167. <div class="swlfmlb-item"><a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11011302001653">京公网安备11011302001653号</a></div>
  168. </div>
  169. </div>
  170. <div class="swl-foot-main-right">
  171. <div class="footer-code">
  172. <div class="footer-code-top">
  173. <a-popover>
  174. <template #content>
  175. <div style="display: flex;flex-direction: column;">
  176. <img class="code-img" src="./img/wechat-cl.jpg" alt="">
  177. <span style="font-size: 12px;color: #333;line-height: 24px; text-align: center;">关注微信公众号</span>
  178. </div>
  179. </template>
  180. <div class="wct-wechat"/>
  181. </a-popover>
  182. <a-popover>
  183. <template #content>
  184. <div style="display: flex;flex-direction: column;">
  185. <img class="code-img" src="./img/weibo-cl.jpg" alt="">
  186. <span style="font-size: 12px;color: #333;line-height: 24px; text-align: center;">关注微博</span>
  187. </div>
  188. </template>
  189. <div class="wct-weibo"></div>
  190. </a-popover>
  191. </div>
  192. <div class="footer-code-bottom">
  193. <div class="fcb-phone"/>服务热线:<span>95198</span>
  194. </div>
  195. </div>
  196. </div>
  197. </div>
  198. </div>
  199. <a-modal
  200. v-model:open="agreeTipsYhfwxy"
  201. title="用户服务协议"
  202. centered
  203. width="730px"
  204. @ok="agreeTipsYhfwxy = false, loginAgree = true"
  205. >
  206. <iframe src="https://app.singlewindow.cn/userserver/user/document/nraServiceAgreement" style="width: 100%; height: 530px;"/>
  207. </a-modal>
  208. <a-modal
  209. v-model:open="agreeTipsYhyszc"
  210. title="用户隐私政策"
  211. centered
  212. width="730px"
  213. @ok="agreeTipsYhyszc = false, loginAgree = true"
  214. >
  215. <iframe src="https://app.singlewindow.cn/userserver/user/document/nraPrivacyPolicy" style="width: 100%; height: 530px;"/>
  216. </a-modal>
  217. </div>
  218. </template>
  219. <script setup>
  220. import loginApi from '@/api/auth/loginApi'
  221. import smCrypto from '@/utils/smCrypto'
  222. import { required } from '@/utils/formRules'
  223. import { afterLogin } from './util'
  224. import configData from '@/config'
  225. import configApi from '@/api/dev/configApi'
  226. import tool from '@/utils/tool'
  227. import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
  228. import {message, Modal} from "ant-design-vue";
  229. import {createVNode} from "vue";
  230. import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
  231. import router from "@/router";
  232. const { proxy } = getCurrentInstance()
  233. const activeKey = ref('userAccount')
  234. const captchaOpen = ref(configData.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN)
  235. const validCodeBase64 = ref('')
  236. const loading = ref(false)
  237. const loginAgree = ref(false)
  238. const agreeTipsYhfwxy = ref(false)
  239. const agreeTipsYhyszc = ref(false)
  240. const loginMode = ref('account')
  241. const ruleForm = reactive({
  242. account: '', // superAdmin
  243. password: '', // 123456
  244. validCode: '',
  245. validCodeReqNo: '',
  246. autologin: false
  247. })
  248. const cardRuleForm = reactive({
  249. password: '',
  250. })
  251. const rules = reactive({
  252. account: [required(proxy.$t('login.accountError'), 'blur')],
  253. password: [required(proxy.$t('login.PWError'), 'blur')]
  254. })
  255. const lang = ref([
  256. {
  257. name: '简体中文',
  258. value: 'zh-cn'
  259. },
  260. {
  261. name: 'English',
  262. value: 'en'
  263. }
  264. ])
  265. const config = ref({
  266. lang: tool.data.get('APP_LANG') || proxy.$CONFIG.LANG,
  267. theme: tool.data.get('APP_THEME') || 'default'
  268. })
  269. const store = globalStore()
  270. const kStore = keepAliveStore()
  271. const iStore = iframeStore()
  272. const vStore = viewTagsStore()
  273. const setSysBaseConfig = store.setSysBaseConfig
  274. const clearKeepLive = kStore.clearKeepLive
  275. const clearIframeList = iStore.clearIframeList
  276. const clearViewTags = vStore.clearViewTags
  277. const sysBaseConfig = computed(() => {
  278. return store.sysBaseConfig
  279. })
  280. onMounted(() => {
  281. let formData = ref(configData.SYS_BASE_CONFIG)
  282. configApi.configSysBaseList().then((data) => {
  283. if (data) {
  284. data.forEach((item) => {
  285. formData.value[item.configKey] = item.configValue
  286. })
  287. captchaOpen.value = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
  288. tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
  289. setSysBaseConfig(formData.value)
  290. refreshSwitch()
  291. }
  292. })
  293. })
  294. onBeforeMount(() => {
  295. clearViewTags()
  296. clearKeepLive()
  297. clearIframeList()
  298. })
  299. // 监听语言
  300. watch(
  301. () => config.value.lang,
  302. (newValue) => {
  303. proxy.$i18n.locale = newValue
  304. tool.data.set('APP_LANG', newValue)
  305. }
  306. )
  307. // 主题
  308. watch(
  309. () => config.value.theme,
  310. (newValue) => {
  311. document.body.setAttribute('data-theme', newValue)
  312. }
  313. )
  314. // 通过开关加载内容
  315. const refreshSwitch = () => {
  316. // 判断是否开启验证码
  317. if (captchaOpen.value === 'true') {
  318. // 加载验证码
  319. loginCaptcha()
  320. // 加入校验
  321. rules.validCode = [required(proxy.$t('login.validError'), 'blur')]
  322. }
  323. }
  324. // 获取验证码
  325. const loginCaptcha = () => {
  326. loginApi.getPicCaptcha().then((data) => {
  327. validCodeBase64.value = data.validCodeBase64
  328. ruleForm.validCodeReqNo = data.validCodeReqNo
  329. })
  330. }
  331. //登陆
  332. const loginForm = ref()
  333. const cardForm = ref()
  334. const login = async () => {
  335. if (loginAgree.value || config.value.lang === 'en') {
  336. loginForm.value
  337. .validate()
  338. .then(async () => {
  339. loading.value = true
  340. const loginData = {
  341. account: ruleForm.account,
  342. // 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
  343. password: smCrypto.doSm2Encrypt(ruleForm.password),
  344. validCode: ruleForm.validCode,
  345. validCodeReqNo: ruleForm.validCodeReqNo
  346. }
  347. // 获取token
  348. try {
  349. const loginToken = await loginApi.login(loginData)
  350. const loginAfter = afterLogin(loginToken)
  351. } catch (err) {
  352. loading.value = false
  353. loginCaptcha()
  354. }
  355. })
  356. .catch(() => {})
  357. } else {
  358. Modal.confirm({
  359. title: '提示',
  360. content: '请阅读并勾选《用户服务协议》和《用户隐私政策》!',
  361. centered: true,
  362. width: 420,
  363. icon: createVNode(ExclamationCircleOutlined),
  364. maskClosable: false,
  365. onOk() {},
  366. onCancel() {}
  367. })
  368. }
  369. }
  370. const cardLogin = async () => {
  371. if (loginAgree.value) {
  372. if (!cardRuleForm.password) {
  373. alert('IC卡/Key密码不允许为空')
  374. } else {
  375. loading.value = true
  376. const loginData = {
  377. account: 'yqyc',
  378. // 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
  379. password: smCrypto.doSm2Encrypt(cardRuleForm.password),
  380. validCode: 'szzf',
  381. validCodeReqNo: 'szzf'
  382. }
  383. // 获取token
  384. try {
  385. const loginToken = await loginApi.login(loginData)
  386. const loginAfter = afterLogin(loginToken)
  387. } catch (err) {
  388. loading.value = false
  389. // loginCaptcha()
  390. }
  391. }
  392. } else {
  393. Modal.confirm({
  394. title: '提示',
  395. content: '请阅读并勾选《用户服务协议》和《用户隐私政策》!',
  396. centered: true,
  397. width: 420,
  398. icon: createVNode(ExclamationCircleOutlined),
  399. maskClosable: false,
  400. onOk() {},
  401. onCancel() {}
  402. })
  403. }
  404. }
  405. const configLang = (key) => {
  406. config.value.lang = key
  407. loginMode.value = 'account'
  408. }
  409. </script>
  410. <style lang="less" scoped>
  411. .single-window-login {
  412. display: flex;
  413. flex-direction: column;
  414. width: 100%;
  415. height: 100%;
  416. .swl-head {
  417. background-color: #ffffff;
  418. min-width: 1200px;
  419. height: 90px;
  420. line-height: 90px;
  421. display: flex;
  422. .swl-head-center {
  423. width: 1200px;
  424. display: flex;
  425. align-items: center;
  426. margin: 0 auto;
  427. .swl-head-lang {
  428. margin-left: auto;
  429. display: flex;
  430. align-items: center;
  431. gap: 10px;
  432. color: #00599C;
  433. font-size: 15px;
  434. &:nth-child(2) {
  435. font-size: 12px;
  436. color: #00599C;
  437. }
  438. .active {
  439. color: #00599C;
  440. font-weight: bold;
  441. font-size: 16px;
  442. }
  443. }
  444. }
  445. }
  446. .swl-content {
  447. flex: 1;
  448. background-image: url('./img/icon_bgNew.png');
  449. background-repeat: no-repeat;
  450. background-size: 100% 100%;
  451. .swl-content-login {
  452. height: 659px;
  453. max-width: 1200px;
  454. display: flex;
  455. flex-direction: row;
  456. align-items: center;
  457. justify-content: center;
  458. margin: 0 auto;
  459. .swl-content-login-left {
  460. width: 553px;
  461. height: 478px;
  462. background-image: url('./img/leftimg_04.png');
  463. background-repeat: no-repeat;
  464. background-position: center;
  465. }
  466. .swl-content-login-right {
  467. width: 600px;
  468. height: 478px;
  469. .swlclr-login {
  470. width: 412px;
  471. height: auto;
  472. background-color: #FFFFFF;
  473. border: solid #ccc 0px;
  474. border-radius: 8px;
  475. margin: 0px auto;
  476. color: #666666;
  477. padding-bottom: 12px;
  478. .swlclr-login-div {
  479. width: 410px;
  480. height: 420px;
  481. background: #ffffff;
  482. border-radius: 10px;
  483. margin: 20px auto;
  484. padding: 26px 41px 0 39px;
  485. box-sizing: border-box;
  486. position: relative;
  487. .swlclr-login-div-title {
  488. font-weight: 400;
  489. color: #999999;
  490. font-size: 18px;
  491. margin-top: 18px;
  492. margin-bottom: 28px;
  493. text-align: center;
  494. display: flex;
  495. align-items: center;
  496. justify-content: center;
  497. gap: 20px;
  498. .swlclr-login-div-title-line {
  499. width: 1px;
  500. height: 16px;
  501. background-color: #c4c4c4;
  502. }
  503. .active {
  504. color: #00599c;
  505. font-weight: 700;
  506. }
  507. }
  508. :deep(.login-form) {
  509. .ant-form-item-control-input-content {
  510. border-bottom: 1px solid #e5e5e5;
  511. .ant-input-affix-wrapper {
  512. border: none;
  513. box-shadow: none;
  514. }
  515. .ant-input-group-addon {
  516. background-color: transparent;
  517. border: none;
  518. color: #096AC6;
  519. font-size: 13px;
  520. font-weight: 400;
  521. }
  522. }
  523. }
  524. .agree {
  525. font-size: 12px;
  526. }
  527. .card-tips {
  528. margin-top: 12px;
  529. width: 330px;
  530. height: 120px;
  531. background: rgba(222, 235, 247, 0.60);
  532. border-radius: 3px;
  533. padding-left: 20px;
  534. padding-top: 12px;
  535. cursor: default;
  536. font-size: 13px;
  537. color: #333333;
  538. line-height: 25px;
  539. >div {
  540. display: flex;
  541. align-items: center;
  542. .index {
  543. display: flex;
  544. justify-content: center;
  545. align-items: center;
  546. width: 15px;
  547. height: 15px;
  548. border-radius: 50%;
  549. color: #ffffff;
  550. line-height: 15px;
  551. margin-right: 8px;
  552. background-color: #00599C;
  553. font-size: 12px;
  554. }
  555. >a {
  556. color: #096AC6;
  557. font-weight: 700;
  558. }
  559. }
  560. }
  561. .tips {
  562. margin-top: 40px;
  563. width: 100%;
  564. display: flex;
  565. .zhuce {
  566. font-size: 13px;
  567. color: #999999;
  568. >a {
  569. color: #096AC6;
  570. font-weight: 700;
  571. }
  572. &:last-child {
  573. margin-left: auto;
  574. }
  575. }
  576. }
  577. }
  578. }
  579. }
  580. }
  581. }
  582. .swl-foot {
  583. width: 100%;
  584. height: 170px;
  585. background-color: rgba(230, 230, 230, 1);
  586. display: flex;
  587. .swl-foot-main {
  588. width: 1200px;
  589. margin: 0 auto;
  590. display: flex;
  591. justify-content: space-between;
  592. .swl-foot-main-left {
  593. .swl-foot-main-left-top {
  594. display: flex;
  595. gap: 15px;
  596. margin-top: 30px;
  597. line-height: 40px;
  598. .swlfmlt-item {
  599. display: flex;
  600. align-items: center;
  601. line-height: 40px;
  602. font-weight: 400;
  603. font-style: normal;
  604. font-size: 16px;
  605. color: #0C3D65;
  606. >a {
  607. color: #0C3D65;
  608. text-decoration: none;
  609. &:hover {
  610. text-decoration: underline;
  611. }
  612. }
  613. }
  614. .swlfmlt-split {
  615. color: #bbbbbb;
  616. }
  617. }
  618. .swl-foot-main-left-bottom {
  619. margin-top: 10px;
  620. display: grid;
  621. grid-template-columns: repeat(2, 220px);
  622. column-gap: 8px;
  623. .swlfmlb-item {
  624. display: block;
  625. line-height: 26px;
  626. color: #666;
  627. font-size: 14px;
  628. >a {
  629. color: #666;
  630. text-decoration: none;
  631. &:hover {
  632. text-decoration: underline;
  633. }
  634. }
  635. }
  636. }
  637. }
  638. .swl-foot-main-right {
  639. .footer-code {
  640. margin-top: 42px;
  641. .footer-code-top {
  642. display: flex;
  643. justify-content: flex-end;
  644. gap: 18px;
  645. .wct-wechat {
  646. width: 40px;
  647. height: 40px;
  648. background: #9eaebb;
  649. line-height: 40px;
  650. border-radius: 50%;
  651. cursor: pointer;
  652. position: relative;
  653. display: flex;
  654. align-items: center;
  655. justify-content: center;
  656. &:after {
  657. position: absolute;
  658. content: '';
  659. background-image: url('./img/bg.png');
  660. width: 30px;
  661. height: 26px;
  662. background-position: -49px -83px;
  663. transform: scale(.8);
  664. }
  665. }
  666. .wct-weibo {
  667. width: 40px;
  668. height: 40px;
  669. background: #9eaebb;
  670. line-height: 40px;
  671. border-radius: 50%;
  672. cursor: pointer;
  673. position: relative;
  674. display: flex;
  675. align-items: center;
  676. justify-content: center;
  677. &:after {
  678. position: absolute;
  679. content: '';
  680. background-image: url('./img/bg.png');
  681. width: 32px;
  682. height: 25px;
  683. background-position: -3px -83px;
  684. transform: scale(.8);
  685. }
  686. }
  687. }
  688. .footer-code-bottom {
  689. display: flex;
  690. align-items: center;
  691. margin-top: 10px;
  692. font-weight: 700;
  693. font-size: 20px;
  694. color: #0C3D65;
  695. vertical-align: top;
  696. height: 34px;
  697. line-height: 34px;
  698. .fcb-phone {
  699. background-image: url('./img/bg.png');
  700. width: 34px;
  701. height: 34px;
  702. background-position: -1px -364px;
  703. margin-right: 12px;
  704. margin-top: -2px;
  705. transform: scale(.8);
  706. }
  707. >span {
  708. font-size: 24px;
  709. }
  710. }
  711. }
  712. }
  713. }
  714. }
  715. }
  716. </style>