superIndex.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. <template>
  2. <div class="login-container flex z-10">
  3. <div class="login-left">
  4. <div class="login-left-logo">
  5. <img :src="siteLogo" /><!-- siteLogo -->
  6. <div class="login-left-logo-text">
  7. <span>{{ getSystemConfig['login.site_title'] || getThemeConfig.globalViceTitle }}</span><!-- -->
  8. <span class="login-left-logo-text-msg" style="margin-top: 5px">{{
  9. getSystemConfig['login.site_name'] || getThemeConfig.globalViceTitleMsg
  10. }}</span>
  11. </div>
  12. </div>
  13. </div>
  14. <div class="login-right flex z-10">
  15. <div class="login-right-warp flex-margin">
  16. <!-- <span class="login-right-warp-one"></span>-->
  17. <!-- <span class="login-right-warp-two"></span>-->
  18. <div class="login-right-warp-mian">
  19. <div class="login-right-warp-main-title">
  20. 超级管理员登陆
  21. </div>
  22. <div class="login-right-warp-main-form pt-4">
  23. <el-form ref="superformRef" size="large" class="login-content-form" :model="superForm"
  24. :rules="superRules" @keyup.enter="loginClick">
  25. <el-form-item class="login-animation1" prop="username">
  26. <el-input type="text" placeholder="请输入登录账号" v-model="superForm.username" clearable>
  27. <template #prefix>
  28. <el-icon class="el-input__icon"><ele-User /></el-icon>
  29. </template>
  30. </el-input>
  31. </el-form-item>
  32. <el-form-item class="login-animation2" prop="password">
  33. <el-input :type="isShowPassword ? 'text' : 'password'"
  34. :placeholder="$t('message.account.accountPlaceholder4')"
  35. v-model="superForm.password">
  36. <template #prefix>
  37. <el-icon class="el-input__icon"><ele-Unlock /></el-icon>
  38. </template>
  39. <template #suffix>
  40. <i class="iconfont el-input__icon login-content-password"
  41. :class="isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
  42. @click="isShowPassword = !isShowPassword">
  43. </i>
  44. </template>
  45. </el-input>
  46. </el-form-item>
  47. <el-form-item class="login-animation3" v-if="isShowCaptcha" prop="captcha">
  48. <el-col :span="15">
  49. <el-input type="text" maxlength="4"
  50. :placeholder="$t('message.account.accountPlaceholder3')"
  51. v-model="superForm.captcha" clearable autocomplete="off">
  52. <template #prefix>
  53. <el-icon class="el-input__icon"><ele-Position /></el-icon>
  54. </template>
  55. </el-input>
  56. </el-col>
  57. <el-col :span="1"></el-col>
  58. <el-col :span="8">
  59. <el-button class="login-content-captcha">
  60. <el-image :src="superForm.captchaImgBase" @click="refreshCaptcha" />
  61. </el-button>
  62. </el-col>
  63. </el-form-item>
  64. <el-form-item class="login-animation4">
  65. <el-button type="primary" class="login-content-submit w-full" round @click="loginClick"
  66. :loading="loading.signIn">
  67. <span>{{ $t('message.account.accountBtnText') }}</span>
  68. </el-button>
  69. </el-form-item>
  70. </el-form>
  71. </div>
  72. </div>
  73. </div>
  74. </div>
  75. <div class="login-authorization z-10">
  76. <!-- <p>Copyright © {{ getSystemConfig['login.copyright'] || '2021-2024 北京信码新创科技有限公司' }} 版权所有</p> -->
  77. <!-- <p class="la-other" style="margin-top: 5px">
  78. <a href="https://beian.miit.gov.cn" target="_blank">{{ getSystemConfig['login.keep_record'] || '京ICP备2021031018号' }}</a>
  79. |
  80. <a :href="getSystemConfig['login.help_url'] ? getSystemConfig['login.help_url'] : '#'" target="_blank">帮助</a>
  81. |
  82. <a :href="getSystemConfig['login.privacy_url'] ? getBaseURL(getSystemConfig['login.privacy_url']) : '#'">隐私</a>
  83. |
  84. <a :href="getSystemConfig['login.clause_url'] ? getBaseURL(getSystemConfig['login.clause_url']) : '#'">条款</a>
  85. </p> -->
  86. </div>
  87. </div>
  88. <div v-if="loginBg">
  89. <img :src="loginBg" class="loginBg fixed inset-0 z-1 w-full h-full" />
  90. </div>
  91. </template>
  92. <script setup lang="ts" name="loginIndex">
  93. import { defineAsyncComponent, onMounted, reactive, computed, watch, ref } from 'vue';
  94. import { storeToRefs } from 'pinia';
  95. import { useThemeConfig } from '/@/stores/themeConfig';
  96. import { NextLoading } from '/@/utils/loading';
  97. import logoMini from '/@/assets/logo-mini.svg';
  98. import loginMain from '/@/assets/login-main.svg';
  99. import loginBg from '/@/assets/login_background.jpg';
  100. import { SystemConfigStore } from '/@/stores/systemConfig';
  101. import { getBaseURL } from '/@/utils/baseUrl';
  102. import { useI18n } from 'vue-i18n';
  103. import * as api from './api';
  104. import * as loginApi from '/@/views/system/login/api';
  105. import { useUserInfo } from '/@/stores/userInfo';
  106. import { ElMessage } from 'element-plus';
  107. import { useRouter } from 'vue-router';
  108. import { Md5 } from 'ts-md5';
  109. import Cookies from 'js-cookie';
  110. import { Session } from '/@/utils/storage';
  111. import * as _ from 'lodash-es';
  112. // 引入组件
  113. const Account = defineAsyncComponent(() => import('/@/views/system/login/component/account.vue'));
  114. const Mobile = defineAsyncComponent(() => import('/@/views/system/login/component/mobile.vue'));
  115. const Scan = defineAsyncComponent(() => import('/@/views/system/login/component/scan.vue'));
  116. const ChangePwd = defineAsyncComponent(() => import('/@/views/system/login/component/changePwd.vue'));
  117. const { userInfos } = storeToRefs(useUserInfo());
  118. // 定义变量内容
  119. const storesThemeConfig = useThemeConfig();
  120. const { themeConfig } = storeToRefs(storesThemeConfig);
  121. const state = reactive({
  122. tabsActiveName: 'account',
  123. isScan: false,
  124. });
  125. const { t } = useI18n();
  126. watch(
  127. () => userInfos.value.pwd_change_count,
  128. (val) => {
  129. if (val === 0) {
  130. state.tabsActiveName = 'changePwd';
  131. } else {
  132. state.tabsActiveName = 'account';
  133. }
  134. },
  135. { deep: true, immediate: true }
  136. );
  137. // 获取布局配置信息
  138. const getThemeConfig = computed(() => {
  139. return themeConfig.value;
  140. });
  141. const systemConfigStore = SystemConfigStore();
  142. const { systemConfig } = storeToRefs(systemConfigStore);
  143. const getSystemConfig = computed(() => {
  144. return systemConfig.value;
  145. });
  146. const siteLogo = computed(() => {
  147. if (!_.isEmpty(getSystemConfig.value['login.site_logo'])) {
  148. return getSystemConfig.value['login.site_logo'];
  149. }
  150. return logoMini;
  151. });
  152. const siteBg = computed(() => {
  153. if (!_.isEmpty(getSystemConfig.value['login.login_background'])) {
  154. return getSystemConfig.value['login.login_background'];
  155. }
  156. });
  157. const superLogin = ref(true);
  158. // 添加loading状态
  159. const loading = reactive({
  160. signIn: false,
  161. });
  162. /* 超级管理员登录表单 */
  163. const superForm = ref({
  164. username: '', // 设置默认用户名
  165. password: '',
  166. captcha: '',
  167. captchaKey: '',
  168. captchaImgBase: '',
  169. });
  170. // 添加表单校验规则
  171. const superRules = reactive({
  172. username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
  173. password: [
  174. {
  175. required: true,
  176. message: '请填写密码',
  177. trigger: 'blur',
  178. },
  179. ],
  180. captcha: [
  181. {
  182. required: true,
  183. message: '请填写验证码',
  184. trigger: 'blur',
  185. },
  186. ],
  187. });
  188. const superformRef = ref();
  189. const router = useRouter();
  190. const formRef = ref();
  191. // 添加 formatAxis 函数定义
  192. const formatAxis = (date: Date): string => {
  193. const hours = date.getHours();
  194. const minutes = date.getMinutes();
  195. // 格式化时间为 HH:MM 格式
  196. return `${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}`;
  197. };
  198. // 时间获取
  199. const currentTime = computed(() => {
  200. return formatAxis(new Date());
  201. });
  202. // 是否关闭验证码
  203. const isShowCaptcha = computed(() => {
  204. return SystemConfigStore().systemConfig['base.captcha_state'];
  205. });
  206. const getCaptcha = async () => {
  207. loginApi.getCaptcha().then((ret: any) => {
  208. console.log(ret);
  209. superForm.value.captchaImgBase = ret.data.image_base;
  210. superForm.value.captchaKey = ret.data.key;
  211. console.log(superForm);
  212. });
  213. };
  214. const applyBtnClick = async () => {
  215. window.open(getBaseURL('/api/system/apply_for_trial/'));
  216. };
  217. const refreshCaptcha = async () => {
  218. superForm.value.captcha = '';
  219. loginApi.getCaptcha().then((ret: any) => {
  220. superForm.value.captchaImgBase = ret.data.image_base;
  221. superForm.value.captchaKey = ret.data.key;
  222. });
  223. };
  224. // 添加登录方法
  225. const loginClick = async () => {
  226. if (!superformRef.value) return;
  227. await superformRef.value.validate(async (valid: boolean) => {
  228. if (valid) {
  229. try {
  230. loading.signIn = true;
  231. // 创建一个简单的登录数据对象,避免直接使用响应式对象
  232. const loginData = {
  233. username: superForm.value.username,
  234. password: superForm.value.password,
  235. captcha: superForm.value.captcha,
  236. captchaKey: superForm.value.captchaKey,
  237. captchaImgBase: superForm.value.captchaImgBase,
  238. };
  239. /* const res = */
  240. loginApi.login({ ...loginData, password: Md5.hashStr(loginData.password) }).then((res: any) => {
  241. console.log(res);
  242. if (res?.code === 2000) {
  243. ElMessage.success('登录成功');
  244. Cookies.set('username', res.data.username);
  245. Session.set('token', res.data.access);
  246. Session.set('superKey',res.data.role_info[0].key)
  247. Session.set('merchant_info', res.data.merchant_info);
  248. router.push('/');
  249. } else {
  250. ElMessage.error(res?.msg || '登录失败');
  251. }
  252. })
  253. } catch (error: any) {
  254. console.error('登录失败:', error);
  255. ElMessage.error(error?.message || '登录失败,请稍后重试');
  256. } finally {
  257. loading.signIn = false;
  258. }
  259. }
  260. });
  261. };
  262. const isShowPassword = ref(false);
  263. /* 跳转至超级管理员登录 */
  264. const goSuper = async () => {
  265. superLogin.value = !superLogin.value;
  266. };
  267. // 页面加载时
  268. onMounted(() => {
  269. getCaptcha();
  270. NextLoading.done();
  271. });
  272. </script>
  273. <style scoped lang="scss">
  274. .login-container {
  275. height: 100%;
  276. background: var(--el-color-white);
  277. .login-left {
  278. flex: 1;
  279. position: relative;
  280. background-color: rgba(211, 239, 255, 1);
  281. margin-right: 100px;
  282. .login-left-logo {
  283. display: flex;
  284. align-items: center;
  285. position: absolute;
  286. top: 50px;
  287. left: 80px;
  288. z-index: 1;
  289. animation: logoAnimation 0.3s ease;
  290. img {
  291. width: 52px;
  292. height: 52px;
  293. }
  294. .login-left-logo-text {
  295. display: flex;
  296. flex-direction: column;
  297. span {
  298. margin-left: 10px;
  299. font-size: 16px;
  300. color: var(--el-color-primary);
  301. }
  302. .login-left-logo-text-msg {
  303. font-size: 12px;
  304. color: var(--el-color-primary);
  305. }
  306. }
  307. }
  308. .login-left-img {
  309. position: absolute;
  310. top: 50%;
  311. left: 50%;
  312. transform: translate(-50%, -50%);
  313. width: 100%;
  314. height: 52%;
  315. img {
  316. width: 100%;
  317. height: 100%;
  318. animation: error-num 0.6s ease;
  319. }
  320. }
  321. .login-left-waves {
  322. position: absolute;
  323. top: 0;
  324. right: -100px;
  325. }
  326. }
  327. .login-right {
  328. width: 700px;
  329. .login-right-warp {
  330. //border: 1px solid var(--el-color-primary-light-3);
  331. border-radius: 10px;
  332. width: 450px;
  333. height: 501px;
  334. position: relative;
  335. overflow: hidden;
  336. //background-color: var(--el-color-white);
  337. .login-right-warp-one,
  338. .login-right-warp-two {
  339. position: absolute;
  340. display: block;
  341. width: inherit;
  342. height: inherit;
  343. &::before,
  344. &::after {
  345. content: '';
  346. position: absolute;
  347. z-index: 1;
  348. }
  349. }
  350. .login-right-warp-one {
  351. &::before {
  352. filter: hue-rotate(0deg);
  353. top: 0px;
  354. left: 0;
  355. width: 100%;
  356. height: 3px;
  357. background: linear-gradient(90deg, transparent, var(--el-color-primary));
  358. animation: loginLeft 3s linear infinite;
  359. }
  360. &::after {
  361. filter: hue-rotate(60deg);
  362. top: -100%;
  363. right: 2px;
  364. width: 3px;
  365. height: 100%;
  366. background: linear-gradient(180deg, transparent, var(--el-color-primary));
  367. animation: loginTop 3s linear infinite;
  368. animation-delay: 0.7s;
  369. }
  370. }
  371. .login-right-warp-two {
  372. &::before {
  373. filter: hue-rotate(120deg);
  374. bottom: 2px;
  375. right: -100%;
  376. width: 100%;
  377. height: 3px;
  378. background: linear-gradient(270deg, transparent, var(--el-color-primary));
  379. animation: loginRight 3s linear infinite;
  380. animation-delay: 1.4s;
  381. }
  382. &::after {
  383. filter: hue-rotate(300deg);
  384. bottom: -100%;
  385. left: 0px;
  386. width: 3px;
  387. height: 100%;
  388. background: linear-gradient(360deg, transparent, var(--el-color-primary));
  389. animation: loginBottom 3s linear infinite;
  390. animation-delay: 2.1s;
  391. }
  392. }
  393. .login-right-warp-mian {
  394. display: flex;
  395. flex-direction: column;
  396. height: 100%;
  397. background: #fff;
  398. .login-right-warp-main-title {
  399. height: 130px;
  400. line-height: 130px;
  401. font-size: 32px;
  402. font-weight: 600;
  403. text-align: center;
  404. letter-spacing: 3px;
  405. animation: logoAnimation 0.3s ease;
  406. animation-delay: 0.3s;
  407. color: var(--el-text-color-primary);
  408. }
  409. .login-right-warp-main-form {
  410. flex: 1;
  411. padding: 0 50px 50px;
  412. .login-content-main-sacn {
  413. position: absolute;
  414. top: 2px;
  415. right: 12px;
  416. width: 50px;
  417. height: 50px;
  418. overflow: hidden;
  419. cursor: pointer;
  420. transition: all ease 0.3s;
  421. color: var(--el-color-primary);
  422. &-delta {
  423. position: absolute;
  424. width: 35px;
  425. height: 70px;
  426. z-index: 2;
  427. top: 2px;
  428. right: 21px;
  429. background: var(--el-color-white);
  430. transform: rotate(-45deg);
  431. }
  432. &:hover {
  433. opacity: 1;
  434. transition: all ease 0.3s;
  435. color: var(--el-color-primary) !important;
  436. }
  437. i {
  438. width: 47px;
  439. height: 50px;
  440. display: inline-block;
  441. font-size: 48px;
  442. position: absolute;
  443. right: 1px;
  444. top: 0px;
  445. }
  446. }
  447. }
  448. }
  449. }
  450. }
  451. .login-authorization {
  452. position: absolute;
  453. bottom: 30px;
  454. left: 0;
  455. right: 0;
  456. text-align: center;
  457. p {
  458. font-size: 14px;
  459. color: rgba(0, 0, 0, 0.5);
  460. }
  461. a {
  462. color: var(--el-color-primary);
  463. margin: 0 5px;
  464. }
  465. }
  466. }
  467. .login-content-form {
  468. @for $i from 1 through 4 {
  469. .login-animation#{$i} {
  470. opacity: 0;
  471. animation-name: error-num;
  472. animation-duration: 0.5s;
  473. animation-fill-mode: forwards;
  474. animation-delay: calc($i/10) + s;
  475. }
  476. }
  477. .login-content-password {
  478. display: inline-block;
  479. width: 20px;
  480. cursor: pointer;
  481. &:hover {
  482. color: #909399;
  483. }
  484. }
  485. .login-content-captcha {
  486. width: 100%;
  487. padding: 0;
  488. font-weight: bold;
  489. letter-spacing: 5px;
  490. }
  491. .login-content-submit {
  492. width: 100%;
  493. letter-spacing: 2px;
  494. font-weight: 800;
  495. margin-top: 15px;
  496. }
  497. }
  498. </style>