Browse Source

chore: 修复登陆重定向

master
wangxiang 2 years ago
parent
commit
32c6236972
No known key found for this signature in database
GPG Key ID: 1BA7946AB6B232E4
  1. 6
      src/enums/appEnum.ts
  2. 8
      src/layouts/default/feature/index.vue
  3. 19
      src/router/guard/permissionGuard.ts
  4. 8
      src/router/routes/demo/feat.ts
  5. 20
      src/router/routes/index.ts
  6. 4
      src/settings/projectSetting.ts
  7. 35
      src/store/modules/user.ts
  8. 9
      src/utils/http/axios/checkStatus.ts
  9. 10
      src/views/core/loginmini/MiniLogin.vue
  10. 48
      src/views/core/loginmini/SessionTimeoutLogin.vue
  11. 56
      src/views/demo/feat/session-timeout/index.vue
  12. 559
      src/views/system/ssoLogin/kics/index.vue
  13. 4
      types/config.d.ts

6
src/enums/appEnum.ts

@ -45,3 +45,9 @@ export enum RouterTransitionEnum { @@ -45,3 +45,9 @@ export enum RouterTransitionEnum {
FADE_BOTTOM = 'fade-bottom',
FADE_SCALE = 'fade-scale',
}
/** 会话超时处理(重新加载路由,覆盖还原路由) */
export enum SessionTimeoutProcessingEnum {
ROUTE_JUMP,
PAGE_COVERAGE,
}

8
src/layouts/default/feature/index.vue

@ -6,6 +6,8 @@ @@ -6,6 +6,8 @@
import { useDesign } from '/@/hooks/web/useDesign';
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import SessionTimeoutLogin from '/@/views/core/loginmini/SessionTimeoutLogin.vue';
import { useUserStoreWithOut } from '/@/store/modules/user';
export default defineComponent({
name: 'LayoutFeatures',
@ -13,12 +15,16 @@ @@ -13,12 +15,16 @@
BackTop,
LayoutLockPage: createAsyncComponent(() => import('/@/views/core/lock/index.vue')),
SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue')),
SessionTimeoutLogin,
},
setup() {
const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } = useRootSetting();
const userStore = useUserStoreWithOut();
const { prefixCls } = useDesign('setting-drawer-fearure');
const { getShowHeader } = useHeaderSetting();
const getIsSessionTimeout = computed(() => userStore.getSessionTimeout);
const getIsFixedSettingDrawer = computed(() => {
if (!unref(getShowSettingButton)) {
return false;
@ -36,6 +42,7 @@ @@ -36,6 +42,7 @@
getUseOpenBackTop,
getIsFixedSettingDrawer,
prefixCls,
getIsSessionTimeout
};
},
});
@ -45,6 +52,7 @@ @@ -45,6 +52,7 @@
<LayoutLockPage/>
<BackTop v-if="getUseOpenBackTop" :target="getTarget"/>
<SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls"/>
<SessionTimeoutLogin v-if="getIsSessionTimeout"/>
</template>
<style lang="less">

19
src/router/guard/permissionGuard.ts

@ -33,11 +33,24 @@ export function createPermissionGuard(router: Router) { @@ -33,11 +33,24 @@ export function createPermissionGuard(router: Router) {
return next(userStore.getUserInfo.homePath);
}
// 放过白名单路由
if (whitePathList.includes(to.path as PageEnum))
return next();
// 校验token权限信息
const token = userStore.getAccessToken;
// 放过白名单路由
if (whitePathList.includes(to.path as PageEnum)) {
if (to.path === LOGIN_PATH && token) {
const isSessionTimeout = userStore.getSessionTimeout;
try {
await userStore.afterLoginAction();
if (!isSessionTimeout) {
next((to.query?.redirect as string) || '/');
return;
}
} catch {
//
}
}
return next();
}
if (!token) {
// 重定向登录页面
const redirectLogin: { path: string; replace: boolean; query?: Recordable<string>; } = { path: LOGIN_PATH, replace: true };

8
src/router/routes/demo/feat.ts

@ -39,6 +39,14 @@ const feat: AppRouteModule = { @@ -39,6 +39,14 @@ const feat: AppRouteModule = {
title: t('routes.demo.feat.requestDemo'),
},
},
{
path: 'session-timeout',
name: 'SessionTimeout',
component: () => import('/@/views/demo/feat/session-timeout/index.vue'),
meta: {
title: t('routes.demo.feat.sessionTimeout'),
},
},
{
path: 'print',
name: 'Print',

20
src/router/routes/index.ts

@ -43,10 +43,30 @@ export const LoginRoute: AppRouteRecordRaw = { @@ -43,10 +43,30 @@ export const LoginRoute: AppRouteRecordRaw = {
},
};
export const SsoLoginRoute: AppRouteRecordRaw[] = [
{
path: '/sso/login/kics',
name: 'kicsLogin',
component: () => import('/@/views/system/ssoLogin/kics/index.vue'),
meta: {
title: t('routes.basic.login'),
},
},
{
path: '/sso/login/klab',
name: 'klabLogin',
component: () => import('/@/views/system/ssoLogin/klab/index.vue'),
meta: {
title: t('routes.basic.login'),
},
}
];
export const basicRoutes = [
LoginRoute,
RootRoute,
...mainOutRoutes,
...SsoLoginRoute,
REDIRECT_ROUTE,
PAGE_NOT_FOUND_ROUTE,
];

4
src/settings/projectSetting.ts

@ -14,6 +14,7 @@ import { @@ -14,6 +14,7 @@ import {
RouterTransitionEnum,
SettingButtonPositionEnum,
TabsThemeEnum,
SessionTimeoutProcessingEnum,
} from '/@/enums/appEnum';
import { SIDE_BAR_BG_COLOR_LIST, HEADER_PRESET_BG_COLOR_LIST } from './designSetting';
import { primaryColor } from '../../build/config/themeConfig';
@ -32,6 +33,9 @@ const setting: ProjectConfig = { @@ -32,6 +33,9 @@ const setting: ProjectConfig = {
// 权限相关的缓存存储在 sessionStorage 或 localStorage
permissionCacheType: CacheTypeEnum.LOCAL,
// 会话超时处理
sessionTimeoutProcessing: SessionTimeoutProcessingEnum.ROUTE_JUMP,
// 颜色
themeColor: primaryColor,

35
src/store/modules/user.ts

@ -25,6 +25,7 @@ import { h } from 'vue'; @@ -25,6 +25,7 @@ import { h } from 'vue';
interface UserState {
userInfo: Nullable<User>;
sessionTimeout?: boolean;
lastUpdateTime: number;
roleIds: string[];
permissions: string[];
@ -37,6 +38,8 @@ export const useUserStore = defineStore({ @@ -37,6 +38,8 @@ export const useUserStore = defineStore({
state: (): UserState => ({
// 用户信息
userInfo: getAuthCache<User>(USER_INFO_KEY),
// 登录是否过期记录(确保下次登陆不刷新路由直接还原)
sessionTimeout: false,
// 最后一次性更新用户信息时间
lastUpdateTime: 0,
// 角色ID用于权限校验
@ -64,6 +67,9 @@ export const useUserStore = defineStore({ @@ -64,6 +67,9 @@ export const useUserStore = defineStore({
getPermissions(): string[] {
return this.permissions;
},
getSessionTimeout(): boolean {
return !!this.sessionTimeout;
},
getLastUpdateTime(): number {
return this.lastUpdateTime;
},
@ -90,7 +96,11 @@ export const useUserStore = defineStore({ @@ -90,7 +96,11 @@ export const useUserStore = defineStore({
this.lastUpdateTime = new Date().getTime();
setAuthCache(USER_INFO_KEY, userInfo);
},
setSessionTimeout(flag: boolean) {
this.sessionTimeout = flag;
},
resetState(): void {
this.setSessionTimeout(false);
this.setUserInfo(null);
this.setAccessToken('');
this.setRefreshToken('');
@ -119,17 +129,22 @@ export const useUserStore = defineStore({ @@ -119,17 +129,22 @@ export const useUserStore = defineStore({
if (!this.getAccessToken) return null;
// 获取用户信息
const userInfo = await this.getUserInfoAction();
// 处理路由与菜单的构建,并且进行缓存
const permissionStore = usePermissionStore();
// 使用isDynamicAddedRoute字段做菜单路由缓存功能
if (!permissionStore.isDynamicAddedRoute) {
const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw);
});
permissionStore.setDynamicAddedRoute(true);
const sessionTimeout = this.sessionTimeout;
if (sessionTimeout) {
this.setSessionTimeout(false);
} else {
// 处理路由与菜单的构建,并且进行缓存
const permissionStore = usePermissionStore();
// 使用isDynamicAddedRoute字段做菜单路由缓存功能
if (!permissionStore.isDynamicAddedRoute) {
const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw);
});
permissionStore.setDynamicAddedRoute(true);
}
goHome && await router.replace(userInfo?.homePath || PageEnum.BASE_HOME);
}
goHome && await router.replace(userInfo?.homePath || PageEnum.BASE_HOME);
return userInfo;
},
/** 获取用户信息 */

9
src/utils/http/axios/checkStatus.ts

@ -9,7 +9,10 @@ import type { ErrorMessageMode } from '/#/axios'; @@ -9,7 +9,10 @@ import type { ErrorMessageMode } from '/#/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import { useUserStoreWithOut } from '/@/store/modules/user';
import projectSetting from '/@/settings/projectSetting';
import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum';
const stp = projectSetting.sessionTimeoutProcessing;
const { createMessage, createErrorModal } = useMessage();
export function checkStatus(status: number, msg: string, errorMessageMode: ErrorMessageMode = 'message'): boolean {
@ -40,6 +43,12 @@ export function checkStatus(status: number, msg: string, errorMessageMode: Error @@ -40,6 +43,12 @@ export function checkStatus(status: number, msg: string, errorMessageMode: Error
case 424:
// token 过期特殊处理返回 424 不是 401
errMessage = t('sys.api.errMsg424');
if (stp === SessionTimeoutProcessingEnum.PAGE_COVERAGE) {
userStore.setAccessToken('');
userStore.setSessionTimeout(true);
} else {
userStore.logout(true);
}
userStore.logout(true);
break;
case 426:

10
src/views/core/loginmini/MiniLogin.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<template>
<div :class="prefixCls" class="login-background-img">
<AppLocalePicker v-if="showLocale" class="absolute top-4 right-4 enter-x xl:text-gray-600" :showText="false"/>
<AppDarkModeToggle class="absolute top-3 right-10 enter-x"/>
<AppLocalePicker v-if="!sessionTimeout && showLocale" class="absolute top-4 right-4 enter-x xl:text-gray-600" :showText="false"/>
<AppDarkModeToggle v-if="!sessionTimeout" class="absolute top-3 right-10 enter-x"/>
<div v-if="!getIsMobile" class="aui-logo">
<div>
<h3>
@ -198,6 +198,12 @@ @@ -198,6 +198,12 @@
import { useAppInject } from '/@/hooks/web/useAppInject';
import { GithubFilled, WechatFilled, AlipayCircleFilled, DingtalkCircleFilled } from '@ant-design/icons-vue';
defineProps({
sessionTimeout: {
type: Boolean,
},
});
const { prefixCls } = useDesign('mini-login');
const { notification, createMessage } = useMessage();
const userStore = useUserStore();

48
src/views/core/loginmini/SessionTimeoutLogin.vue

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
<template>
<transition>
<div :class="prefixCls">
<MiniLogin sessionTimeout/>
</div>
</transition>
</template>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from 'vue';
import MiniLogin from './MiniLogin.vue';
import { useDesign } from '/@/hooks/web/useDesign';
import { useUserStore } from '/@/store/modules/user';
import { usePermissionStore } from '/@/store/modules/permission';
import { useAppStore } from '/@/store/modules/app';
const { prefixCls } = useDesign('st-login');
const userStore = useUserStore();
const permissionStore = usePermissionStore();
const appStore = useAppStore();
const userId = ref<Nullable<number | string>>(0);
onMounted(() => {
// UserId
userId.value = userStore.getUserInfo?.id;
console.log('Mounted', userStore.getUserInfo);
});
onBeforeUnmount(() => {
if (userId.value && userId.value !== userStore.getUserInfo.id) {
// 便
document.location.reload();
} else if (permissionStore.getLastBuildMenuTime === 0) {
// F5
document.location.reload();
}
});
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-st-login';
.@{prefix-cls} {
position: fixed;
z-index: 9999999;
width: 100%;
height: 100%;
background: @component-background;
}
</style>

56
src/views/demo/feat/session-timeout/index.vue

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
<template>
<PageWrapper
title="登录过期示例"
content="用户登录过期示例,不再跳转登录页,直接生成页面覆盖当前页面,方便保持过期前的用户状态!"
>
<a-card title="请点击下面的按钮访问测试接口" extra="所访问的接口会返回Token过期响应">
<a-card-grid style="width: 50%; text-align: center">
<a-button type="primary" @click="test1">HttpStatus == 401</a-button>
</a-card-grid>
<a-card-grid style="width: 50%; text-align: center">
<span/>
<a-button class="ml-4" type="primary" @click="test2">Response.code == 401</a-button>
</a-card-grid>
</a-card>
</PageWrapper>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { PageWrapper } from '/@/components/Page';
import { useUserStore } from '/@/store/modules/user';
//import { sessionTimeoutApi, tokenExpiredApi } from '/@/api/demo/account';
import { Card } from 'ant-design-vue';
export default defineComponent({
name: 'TestSessionTimeout',
components: { ACardGrid: Card.Grid, ACard: Card, PageWrapper },
setup() {
const userStore = useUserStore();
async function test1() {
userStore.setAccessToken('');
userStore.setSessionTimeout(true);
// mockHttp
//
// if (import.meta.env.PROD) {
// userStore.setToken(undefined);
// userStore.setSessionTimeout(true);
// } else {
// // api401
// await sessionTimeoutApi();
// }
}
async function test2() {
// apicode401jsonHttp200
try {
//await tokenExpiredApi();
} catch (err) {
console.log('接口访问错误:', (err as Error).message || '错误');
}
}
return { test1, test2 };
},
});
</script>

559
src/views/system/ssoLogin/kics/index.vue

@ -0,0 +1,559 @@ @@ -0,0 +1,559 @@
<template>
<div :class="prefixCls" class="login-background-img">
<AppLocalePicker v-if="showLocale" class="absolute top-4 right-4 enter-x xl:text-gray-600" :showText="false"/>
<AppDarkModeToggle class="absolute top-3 right-10 enter-x"/>
<div v-if="!getIsMobile" class="aui-logo">
<div>
<h3>
<img :src="logoImg">
</h3>
</div>
</div>
<div v-else class="aui-phone-logo">
<img :src="logoPhoneImg">
</div>
<div v-show="type === 'login'">
<div class="aui-content">
<div class="aui-container">
<div class="aui-form">
<div class="aui-image">
<div class="aui-image-text"/>
</div>
<div class="aui-formBox">
<div class="aui-formWell">
<div class="aui-flex aui-form-nav">
<div
class="aui-flex-box"
:class="activeIndex === 'accountLogin' ? 'activeNav on' : ''"
@click="loginClick('accountLogin')"
>{{ t('sys.login.signInFormTitle') }}</div>
<div
class="aui-flex-box"
:class="activeIndex === 'phoneLogin' ? 'activeNav on' : ''"
@click="loginClick('phoneLogin')"
>{{ t('sys.login.mobileSignInFormTitle') }}</div>
</div>
<div class="aui-form-box" style="height: 180px">
<a-form
v-if="activeIndex === 'accountLogin'"
ref="loginRef"
:model="formData"
@keypress.enter="loginHandleClick"
>
<div class="aui-account">
<div class="aui-inputClear">
<i class="icon icon-code"/>
<a-form-item>
<a-input v-model:value="formData.username" class="fix-auto-fill" :placeholder="t('sys.login.userName')"/>
</a-form-item>
</div>
<div class="aui-inputClear">
<i class="icon icon-password"/>
<a-form-item>
<a-input
v-model:value="formData.password"
class="fix-auto-fill"
type="password"
:placeholder="t('sys.login.password')"
/>
</a-form-item>
</div>
<div class="aui-inputClear">
<i class="icon icon-code"/>
<a-form-item>
<a-input
v-model:value="formData.inputCode"
class="fix-auto-fill"
type="text"
:placeholder="t('sys.login.captcha')"
/>
</a-form-item>
<div class="aui-code">
<img v-if="randCodeData.requestCodeSuccess" :src="randCodeData.randCodeImage" @click="handleChangeCheckCode">
<img
v-else
style="margin-top: 2px; max-width: initial"
:src="defaultCaptchaImg"
@click="handleChangeCheckCode"
>
</div>
</div>
<div class="aui-flex">
<div class="aui-flex-box">
<div class="aui-choice">
<a-input v-model:value="rememberMe" class="fix-auto-fill" type="checkbox"/>
<span style="margin-left: 5px">{{ t('sys.login.rememberMe') }}</span>
</div>
</div>
<div class="aui-forget">
<a @click="forgetHandelClick"> {{ t('sys.login.forgetPassword') }}</a>
</div>
</div>
</div>
</a-form>
<a-form
v-else
ref="phoneFormRef"
:model="phoneFormData"
@keypress.enter="loginHandleClick"
>
<div class="aui-account phone">
<div class="aui-inputClear phoneClear">
<a-input v-model:value="phoneFormData.mobile" class="fix-auto-fill" :placeholder="t('sys.login.mobile')"/>
</div>
<div class="aui-inputClear">
<a-input
v-model:value="phoneFormData.smscode"
class="fix-auto-fill"
:maxlength="6"
:placeholder="t('sys.login.smsCode')"
/>
<div v-if="showInterval" class="aui-code" @click="getLoginCode">
<a>{{ t('component.countdown.normalText') }}</a>
</div>
<div v-else class="aui-code">
<span class="aui-get-code code-shape">{{ t('component.countdown.sendText', [unref(timeRuning)]) }}</span>
</div>
</div>
</div>
</a-form>
</div>
<div class="aui-formButton">
<div class="aui-flex">
<a-button
:loading="loginLoading"
class="aui-link-login aui-flex-box"
type="primary"
@click="loginHandleClick"
>{{ t('sys.login.loginButton') }}</a-button>
</div>
<div class="aui-flex">
<a class="aui-linek-code aui-flex-box" @click="codeHandleClick">{{ t('sys.login.qrSignInFormTitle') }}</a>
</div>
<!--<div class="aui-flex">
<a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton') }}</a>
</div>-->
</div>
</div>
<a-form>
<div class="aui-flex aui-third-text">
<div class="aui-flex-box aui-third-border">
<span>{{ t('sys.login.otherSignIn') }}</span>
</div>
</div>
<div class="aui-flex" :class="`${prefixCls}-sign-in-way`">
<div class="aui-flex-box">
<div class="aui-third-login">
<a title="github" @click="onThirdLogin('github')"><GithubFilled/></a>
</div>
</div>
<div class="aui-flex-box">
<div class="aui-third-login">
<a title="支付宝" @click="onThirdLogin('alipay')"><AlipayCircleFilled/></a>
</div>
</div>
<div class="aui-flex-box">
<div class="aui-third-login">
<a title="钉钉" @click="onThirdLogin('dingtalk')"><DingtalkCircleFilled/></a>
</div>
</div>
<div class="aui-flex-box">
<div class="aui-third-login">
<a title="微信" @click="onThirdLogin('wechat_open')"><WechatFilled/></a>
</div>
</div>
</div>
</a-form>
</div>
</div>
</div>
</div>
</div>
<div v-show="type === 'forgot'" :class="`${prefixCls}-form`">
<MiniForgotpad ref="forgotRef" @go-back="goBack" @success="handleSuccess"/>
</div>
<div v-show="type === 'register'" :class="`${prefixCls}-form`">
<MiniRegister ref="registerRef" @go-back="goBack" @success="handleSuccess"/>
</div>
<div v-show="type === 'codeLogin'" :class="`${prefixCls}-form`">
<MiniCodelogin ref="codeRef" @go-back="goBack" @success="handleSuccess"/>
</div>
</div>
</template>
<script lang="ts" setup>
import { getCaptcha } from '/@/api/platform/core/controller/user';
import { onMounted, reactive, ref, toRaw, unref } from 'vue';
import defaultCaptchaImg from '/@/assets/images/captcha.jpg';
import { useUserStore } from '/@/store/modules/user';
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import MiniForgotpad from './MiniForgotpad.vue';
import MiniRegister from './MiniRegister.vue';
import MiniCodelogin from './MiniCodelogin.vue';
import logoImg from '/@/assets/images/logo-tag.png';
import logoPhoneImg from '/@/assets/images/logo.png';
import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application';
import { useLocaleStore } from '/@/store/modules/locale';
import { useDesign } from '/@/hooks/web/useDesign';
import { useAppInject } from '/@/hooks/web/useAppInject';
import { GithubFilled, WechatFilled, AlipayCircleFilled, DingtalkCircleFilled } from '@ant-design/icons-vue';
const { prefixCls } = useDesign('mini-login');
const { notification, createMessage } = useMessage();
const userStore = useUserStore();
const { t } = useI18n();
const localeStore = useLocaleStore();
const showLocale = localeStore.getShowPicker;
const randCodeData = reactive<any>({
randCodeImage: '',
requestCodeSuccess: false,
});
const rememberMe = ref<string>('0');
//
const activeIndex = ref<string>('accountLogin');
const type = ref<string>('login');
//
const formData = reactive<any>({
realKey: '',
inputCode: '',
username: '',
password: '',
});
//
const phoneFormData = reactive<any>({
mobile: '',
smscode: '',
});
const loginRef = ref();
//
const codeRef = ref();
//
const showInterval = ref<boolean>(true);
// 60s
const timeRuning = ref<number>(60);
//
const timer = ref<any>(null);
//
const forgotRef = ref();
//
const registerRef = ref();
const loginLoading = ref<boolean>(false);
const { getIsMobile } = useAppInject();
/**
* 获取验证码
*/
async function handleChangeCheckCode() {
formData.inputCode = '';
try {
const codeModel = await getCaptcha();
randCodeData.randCodeImage = codeModel.img;
randCodeData.requestCodeSuccess = true;
formData.realKey = codeModel.realKey;
} catch(error) {
randCodeData.requestCodeSuccess = false;
}
}
/**
* 切换登录方式
*/
function loginClick(type) {
activeIndex.value = type;
}
/**
* 账号或者手机登录
*/
async function loginHandleClick() {
if (unref(activeIndex) === 'accountLogin') {
await accountLogin();
} else {
await phoneLogin();
}
}
async function accountLogin() {
if (!formData.username) {
createMessage.warn(t('sys.login.accountPlaceholder'));
return;
}
if (!formData.password) {
createMessage.warn(t('sys.login.passwordPlaceholder'));
return;
}
if (!formData.inputCode) {
createMessage.warn(t('sys.login.smsPlaceholder'));
return;
}
try {
loginLoading.value = true;
const userInfo = await userStore.login(toRaw({
password: formData.password,
username: formData.username,
realKey: formData.realKey,
code: formData.inputCode,
}));
if (userInfo) {
notification.success({
message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.nickName}`,
duration: 3,
});
}
} catch (error){
formData.code='';
formData.realKey='';
await handleChangeCheckCode();
} finally {
loginLoading.value = false;
}
}
/**
* 手机号登录
*/
async function phoneLogin() {
notification.success({
message: '功能待开发中.',
duration: 3,
});
}
/**
* 获取手机验证码
*/
async function getLoginCode() {
/*if (!phoneFormData.mobile) {
createMessage.warn(t('sys.login.mobilePlaceholder'));
return;
}*/
const TIME_COUNT = 60;
if (!unref(timer)) {
timeRuning.value = TIME_COUNT;
showInterval.value = false;
timer.value = setInterval(() => {
if (unref(timeRuning) > 0 && unref(timeRuning) <= TIME_COUNT) {
timeRuning.value = timeRuning.value - 1;
} else {
showInterval.value = true;
clearInterval(unref(timer));
timer.value = null;
}
}, 1000);
}
}
/**
* 第三方登录
* @param type
*/
function onThirdLogin(type) {
notification.success({
message: '功能待开发中.',
duration: 3,
});
}
/**
* 忘记密码
*/
function forgetHandelClick() {
type.value = 'forgot';
setTimeout(() => {
forgotRef.value.initForm();
}, 300);
}
/**
* 返回登录页面
*/
function goBack() {
activeIndex.value = 'accountLogin';
type.value = 'login';
}
/**
* 忘记密码/注册账号回调事件
* @param value
*/
function handleSuccess(value) {
Object.assign(formData, value);
Object.assign(phoneFormData, { mobile: '', smscode: '' });
type.value = 'login';
activeIndex.value = 'accountLogin';
handleChangeCheckCode();
}
/**
* 注册
*/
function registerHandleClick() {
type.value = 'register';
setTimeout(() => {
registerRef.value.initForm();
}, 300);
}
/**
* 二维码登录
*/
function codeHandleClick() {
type.value = 'codeLogin';
setTimeout(() => {
codeRef.value.initFrom();
}, 300);
}
onMounted(() => {
//
handleChangeCheckCode();
});
</script>
<style lang="less" scoped>
.login-background-img {
background-image: url(../icon/login-bg.png);
background-size: cover;
background-position: top center;
background-repeat: no-repeat;
}
.aui-logo {
width: 180px;
height: 80px;
position: absolute;
top: 2%;
left: 8%;
z-index: 4;
}
:deep(.ant-input:focus) {
box-shadow: none;
}
.aui-get-code {
float: right;
position: relative;
z-index: 3;
background: #ffffff;
color: #1573e9;
border-radius: 100px;
padding: 5px 16px;
margin: 7px;
border: 1px solid #1573e9;
top: 12px;
}
.aui-get-code:hover {
color: #1573e9;
}
.code-shape {
border-color: #dadada !important;
color: #aaa !important;
}
.aui-link-login{
height: 42px;
padding: 10px 15px;
font-size: 14px;
border-radius: 8px;
margin-top: 15px;
margin-bottom: 8px;
}
.aui-phone-logo{
position: absolute;
margin-left: 10px;
width: 60px;
top:2px;
z-index: 4;
}
.top-3{
top: 0.45rem;
}
</style>
<style lang="less">
@prefix-cls: ~'@{namespace}-mini-login';
@dark-bg: #293146;
html[data-theme='dark'] {
.@{prefix-cls} {
background-color: @dark-bg !important;
background-image: none;
&::before {
background-image: url(/@/assets/images/login-bg-dark.svg);
}
.aui-inputClear{
background-color: #232a3b !important;
}
.ant-input,
.ant-input-password {
background-color: #232a3b !important;
}
.ant-btn:not(.ant-btn-link):not(.ant-btn-primary) {
border: 1px solid #4a5569 !important;
}
&-form {
background: @dark-bg !important;
}
.app-iconify {
color: #fff !important;
}
.aui-inputClear input,.aui-input-line input,.aui-choice{
color: #c9d1d9 !important;
}
.aui-formBox{
background-color: @dark-bg !important;
}
.aui-third-text span{
background-color: @dark-bg !important;
}
.aui-form-nav .aui-flex-box{
color: #c9d1d9 !important;
}
.aui-formButton .aui-linek-code{
background: @dark-bg !important;
color: white !important;
}
.aui-code-line{
border-left: none !important;
}
.ant-checkbox-inner,.aui-success h3{
border-color: #c9d1d9;
}
}
input.fix-auto-fill,
.fix-auto-fill input {
-webkit-text-fill-color: #c9d1d9 !important;
box-shadow: inherit !important;
}
&-sign-in-way {
.anticon {
font-size: 22px !important;
color: #888 !important;
cursor: pointer !important;
&:hover {
color: @primary-color !important;
}
}
}
.ant-divider-inner-text {
font-size: 12px !important;
color: @text-color-secondary !important;
}
.aui-third-login a{
background: transparent;
}
}
</style>

4
types/config.d.ts vendored

@ -10,7 +10,7 @@ import { @@ -10,7 +10,7 @@ import {
ContentEnum,
ThemeEnum,
RouterTransitionEnum,
SettingButtonPositionEnum,
SettingButtonPositionEnum, SessionTimeoutProcessingEnum,
} from '/@/enums/appEnum';
import { CacheTypeEnum } from '/@/enums/cacheEnum';
@ -93,6 +93,8 @@ export interface ProjectConfig { @@ -93,6 +93,8 @@ export interface ProjectConfig {
showDarkModeToggle: boolean;
// 配置按钮的显示位置
settingButtonPosition: SettingButtonPositionEnum;
// Session timeout processing
sessionTimeoutProcessing: SessionTimeoutProcessingEnum;
// 网站灰色模式,打开可能的哀悼日期
grayMode: boolean;
// 是否开启色弱模式

Loading…
Cancel
Save