系统各配置优化

This commit is contained in:
Xubx 2025-03-04 15:47:57 +08:00
parent 0e890d96c5
commit dbc9d8b458
15 changed files with 1304 additions and 1354 deletions

2
.env
View File

@ -2,7 +2,7 @@
VITE_PORT = 3100 VITE_PORT = 3100
# 网站标题 # 网站标题
VITE_GLOB_APP_TITLE = JeecgBoot 企业级低代码平台 VITE_GLOB_APP_TITLE = 哈尔滨师范大学评阅人员管理系统
# 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符 # 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
VITE_GLOB_APP_SHORT_NAME = JeecgBootAdmin VITE_GLOB_APP_SHORT_NAME = JeecgBootAdmin

View File

@ -157,7 +157,7 @@
</style> </style>
<div class="app-loading"> <div class="app-loading">
<div class="app-loading-wrap"> <div class="app-loading-wrap">
<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" /> <!--<img src="/logo.png" class="app-loading-logo" alt="Logo" />-->
<div class="app-loading-dots"> <div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span> <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div> </div>

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -4,89 +4,93 @@
--> -->
<template> <template>
<div class="anticon" :class="getAppLogoClass" @click="goHome"> <div class="anticon" :class="getAppLogoClass" @click="goHome">
<img src="../../../assets/images/logo.png" /> <img style="width: 100%;" src="../../../assets/images/logo-red.png" />
<div class="ml-2 truncate md:opacity-100" :class="getTitleClass" v-show="showTitle"> <div style="display: flex;" class="ml-2 truncate md:opacity-100" :class="getTitleClass" v-show="showTitle">
{{ title }} <!-- {{ title }} -->
<!-- <span>英语四六级综合管理平台</span> -->
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, unref } from 'vue'; import { computed, unref } from 'vue';
import { useGlobSetting } from '/@/hooks/setting'; import { useGlobSetting } from '/@/hooks/setting';
import { useGo } from '/@/hooks/web/usePage'; import { useGo } from '/@/hooks/web/usePage';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { useUserStore } from '/@/store/modules/user'; import { useUserStore } from '/@/store/modules/user';
const props = defineProps({ const props = defineProps({
/** /**
* The theme of the current parent component * The theme of the current parent component
*/ */
theme: { type: String, validator: (v: string) => ['light', 'dark'].includes(v) }, theme: { type: String, validator: (v: string) => ['light', 'dark'].includes(v) },
/** /**
* Whether to show title * Whether to show title
*/ */
showTitle: { type: Boolean, default: true }, showTitle: { type: Boolean, default: true },
/** /**
* The title is also displayed when the menu is collapsed * The title is also displayed when the menu is collapsed
*/ */
alwaysShowTitle: { type: Boolean }, alwaysShowTitle: { type: Boolean },
}); });
const { prefixCls } = useDesign('app-logo'); const { prefixCls } = useDesign('app-logo');
const { getCollapsedShowTitle } = useMenuSetting(); const { getCollapsedShowTitle } = useMenuSetting();
const userStore = useUserStore(); const userStore = useUserStore();
const { title } = useGlobSetting(); const { title } = useGlobSetting();
const go = useGo(); const go = useGo();
const getAppLogoClass = computed(() => [prefixCls, props.theme, { 'collapsed-show-title': unref(getCollapsedShowTitle) }]); const getAppLogoClass = computed(() => [prefixCls, props.theme, { 'collapsed-show-title': unref(getCollapsedShowTitle) }]);
const getTitleClass = computed(() => [ const getTitleClass = computed(() => [
`${prefixCls}__title`, `${prefixCls}__title`,
{ {
'xs:opacity-0': !props.alwaysShowTitle, 'xs:opacity-0': !props.alwaysShowTitle,
}, },
]); ]);
function goHome() { function goHome() {
go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME); go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@prefix-cls: ~'@{namespace}-app-logo'; @prefix-cls: ~'@{namespace}-app-logo';
.@{prefix-cls} { .@{prefix-cls} {
display: flex; display: flex;
align-items: center; align-items: center;
padding-left: 7px; padding-left: 7px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
//
&.jeecg-layout-mix-sider-logo,&.jeecg-layout-menu-logo{
background:@sider-logo-bg-color;
}
// &.light {
// border-bottom: 1px solid @border-color-base;
// }
&.collapsed-show-title { //
padding-left: 20px; &.jeecg-layout-mix-sider-logo,
} &.jeecg-layout-menu-logo {
background: @sider-logo-bg-color;
&.light &__title {
color: @primary-color;
}
&.dark &__title {
color: @white;
}
&__title {
font-size: 16px;
font-weight: 700;
transition: all 0.5s;
line-height: normal;
}
} }
// &.light {
// border-bottom: 1px solid @border-color-base;
// }
&.collapsed-show-title {
padding-left: 20px;
}
&.light &__title {
color: @primary-color;
}
&.dark &__title {
color: @white;
}
&__title {
font-size: 16px;
font-weight: 700;
transition: all 0.5s;
line-height: normal;
}
}
</style> </style>

View File

@ -1,6 +1,20 @@
<template> <template>
<div class="scrollbar"> <div class="scrollbar">
<div ref="wrap" :class="[wrapClass, 'scrollbar__wrap', native ? '' : 'scrollbar__wrap--hidden-default']" :style="style" @scroll="handleScroll"> <div ref="wrap" :class="[wrapClass, 'scrollbar__wrap', native ? '' : 'scrollbar__wrap--hidden-default']"
:style="style" @scroll="handleScroll">
<div style="display: flex; justify-content: center; align-items: center">
<span style="
font-size: 18px;
font-weight: 700;
transition: all 0.5s;
line-height: normal;
padding: 5px;
">
评阅人员管理系统
</span>
</div>
<component :is="tag" ref="resize" :class="['scrollbar__view', viewClass]" :style="viewStyle"> <component :is="tag" ref="resize" :class="['scrollbar__view', viewClass]" :style="viewStyle">
<slot></slot> <slot></slot>
</component> </component>
@ -12,182 +26,182 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { addResizeListener, removeResizeListener } from '/@/utils/event'; import { addResizeListener, removeResizeListener } from '/@/utils/event';
import componentSetting from '/@/settings/componentSetting'; import componentSetting from '/@/settings/componentSetting';
const { scrollbar } = componentSetting; const { scrollbar } = componentSetting;
import { toObject } from './util'; import { toObject } from './util';
import { defineComponent, ref, onMounted, onBeforeUnmount, nextTick, provide, computed, unref } from 'vue'; import { defineComponent, ref, onMounted, onBeforeUnmount, nextTick, provide, computed, unref } from 'vue';
import Bar from './bar'; import Bar from './bar';
export default defineComponent({ export default defineComponent({
name: 'Scrollbar', name: 'Scrollbar',
// inheritAttrs: false, // inheritAttrs: false,
components: { Bar }, components: { Bar },
props: { props: {
native: { native: {
type: Boolean, type: Boolean,
default: scrollbar?.native ?? false, default: scrollbar?.native ?? false,
},
wrapStyle: {
type: [String, Array],
default: '',
},
wrapClass: {
type: [String, Array],
default: '',
},
viewClass: {
type: [String, Array],
default: '',
},
viewStyle: {
type: [String, Array],
default: '',
},
noresize: Boolean, // container
tag: {
type: String,
default: 'div',
},
}, },
setup(props) { wrapStyle: {
const sizeWidth = ref('0'); type: [String, Array],
const sizeHeight = ref('0'); default: '',
const moveX = ref(0);
const moveY = ref(0);
const wrap = ref();
const resize = ref();
provide('scroll-bar-wrap', wrap);
const style = computed(() => {
if (Array.isArray(props.wrapStyle)) {
return toObject(props.wrapStyle);
}
return props.wrapStyle;
});
const handleScroll = () => {
if (!props.native) {
moveY.value = (unref(wrap).scrollTop * 100) / unref(wrap).clientHeight;
moveX.value = (unref(wrap).scrollLeft * 100) / unref(wrap).clientWidth;
}
};
const update = () => {
if (!unref(wrap)) return;
const heightPercentage = (unref(wrap).clientHeight * 100) / unref(wrap).scrollHeight;
const widthPercentage = (unref(wrap).clientWidth * 100) / unref(wrap).scrollWidth;
sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : '';
sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : '';
};
onMounted(() => {
if (props.native) return;
nextTick(update);
if (!props.noresize) {
addResizeListener(unref(resize), update);
addResizeListener(unref(wrap), update);
addEventListener('resize', update);
}
});
onBeforeUnmount(() => {
if (props.native) return;
if (!props.noresize) {
removeResizeListener(unref(resize), update);
removeResizeListener(unref(wrap), update);
removeEventListener('resize', update);
}
});
return {
moveX,
moveY,
sizeWidth,
sizeHeight,
style,
wrap,
resize,
update,
handleScroll,
};
}, },
}); wrapClass: {
type: [String, Array],
default: '',
},
viewClass: {
type: [String, Array],
default: '',
},
viewStyle: {
type: [String, Array],
default: '',
},
noresize: Boolean, // container
tag: {
type: String,
default: 'div',
},
},
setup(props) {
const sizeWidth = ref('0');
const sizeHeight = ref('0');
const moveX = ref(0);
const moveY = ref(0);
const wrap = ref();
const resize = ref();
provide('scroll-bar-wrap', wrap);
const style = computed(() => {
if (Array.isArray(props.wrapStyle)) {
return toObject(props.wrapStyle);
}
return props.wrapStyle;
});
const handleScroll = () => {
if (!props.native) {
moveY.value = (unref(wrap).scrollTop * 100) / unref(wrap).clientHeight;
moveX.value = (unref(wrap).scrollLeft * 100) / unref(wrap).clientWidth;
}
};
const update = () => {
if (!unref(wrap)) return;
const heightPercentage = (unref(wrap).clientHeight * 100) / unref(wrap).scrollHeight;
const widthPercentage = (unref(wrap).clientWidth * 100) / unref(wrap).scrollWidth;
sizeHeight.value = heightPercentage < 100 ? heightPercentage + '%' : '';
sizeWidth.value = widthPercentage < 100 ? widthPercentage + '%' : '';
};
onMounted(() => {
if (props.native) return;
nextTick(update);
if (!props.noresize) {
addResizeListener(unref(resize), update);
addResizeListener(unref(wrap), update);
addEventListener('resize', update);
}
});
onBeforeUnmount(() => {
if (props.native) return;
if (!props.noresize) {
removeResizeListener(unref(resize), update);
removeResizeListener(unref(wrap), update);
removeEventListener('resize', update);
}
});
return {
moveX,
moveY,
sizeWidth,
sizeHeight,
style,
wrap,
resize,
update,
handleScroll,
};
},
});
</script> </script>
<style lang="less"> <style lang="less">
.scrollbar { .scrollbar {
position: relative; position: relative;
height: 100%;
overflow: hidden;
&__wrap {
height: 100%; height: 100%;
overflow: hidden; overflow: auto;
&__wrap { &--hidden-default {
height: 100%; scrollbar-width: none;
overflow: auto;
&--hidden-default { &::-webkit-scrollbar {
scrollbar-width: none; display: none;
width: 0;
&::-webkit-scrollbar { height: 0;
display: none; opacity: 0;
width: 0;
height: 0;
opacity: 0;
}
}
}
&__thumb {
position: relative;
display: block;
width: 0;
height: 0;
cursor: pointer;
background-color: rgba(144, 147, 153, 0.3);
border-radius: inherit;
transition: 0.3s background-color;
&:hover {
background-color: rgba(144, 147, 153, 0.5);
}
}
&__bar {
position: absolute;
right: 2px;
bottom: 2px;
z-index: 1;
border-radius: 4px;
opacity: 0;
-webkit-transition: opacity 80ms ease;
transition: opacity 80ms ease;
&.is-vertical {
top: 2px;
width: 6px;
& > div {
width: 100%;
}
}
&.is-horizontal {
left: 2px;
height: 6px;
& > div {
height: 100%;
}
} }
} }
} }
.scrollbar:active > .scrollbar__bar, &__thumb {
.scrollbar:focus > .scrollbar__bar, position: relative;
.scrollbar:hover > .scrollbar__bar { display: block;
opacity: 1; width: 0;
transition: opacity 340ms ease-out; height: 0;
cursor: pointer;
background-color: rgba(144, 147, 153, 0.3);
border-radius: inherit;
transition: 0.3s background-color;
&:hover {
background-color: rgba(144, 147, 153, 0.5);
}
} }
&__bar {
position: absolute;
right: 2px;
bottom: 2px;
z-index: 1;
border-radius: 4px;
opacity: 0;
-webkit-transition: opacity 80ms ease;
transition: opacity 80ms ease;
&.is-vertical {
top: 2px;
width: 6px;
&>div {
width: 100%;
}
}
&.is-horizontal {
left: 2px;
height: 6px;
&>div {
height: 100%;
}
}
}
}
.scrollbar:active>.scrollbar__bar,
.scrollbar:focus>.scrollbar__bar,
.scrollbar:hover>.scrollbar__bar {
opacity: 1;
transition: opacity 340ms ease-out;
}
</style> </style>

View File

@ -11,12 +11,8 @@
<template #overlay> <template #overlay>
<Menu @click="handleMenuClick"> <Menu @click="handleMenuClick">
<MenuItem key="doc" :text="t('layout.header.dropdownItemDoc')" icon="ion:document-text-outline" v-if="getShowDoc" /> <MenuItem key="password" :text="t('layout.header.dropdownItemSwitchPassword')"
<MenuDivider v-if="getShowDoc" /> icon="ant-design:edit-outlined" />
<MenuItem key="account" :text="t('layout.header.dropdownItemSwitchAccount')" icon="ant-design:setting-outlined" />
<MenuItem key="password" :text="t('layout.header.dropdownItemSwitchPassword')" icon="ant-design:edit-outlined" />
<MenuItem key="depart" :text="t('layout.header.dropdownItemSwitchDepart')" icon="ant-design:cluster-outlined" />
<MenuItem key="cache" :text="t('layout.header.dropdownItemRefreshCache')" icon="ion:sync-outline" />
<!-- <MenuItem <!-- <MenuItem
v-if="getUseLockPage" v-if="getUseLockPage"
key="lock" key="lock"
@ -32,220 +28,221 @@
<UpdatePassword v-if="passwordVisible" ref="updatePasswordRef" /> <UpdatePassword v-if="passwordVisible" ref="updatePasswordRef" />
</template> </template>
<script lang="ts"> <script lang="ts">
// components // components
import { Dropdown, Menu } from 'ant-design-vue'; import { Dropdown, Menu } from 'ant-design-vue';
import { defineComponent, computed, ref } from 'vue'; import { defineComponent, computed, ref } from 'vue';
import { SITE_URL } from '/@/settings/siteSetting'; import { SITE_URL } from '/@/settings/siteSetting';
import { useUserStore } from '/@/store/modules/user'; import { useUserStore } from '/@/store/modules/user';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { useModal } from '/@/components/Modal'; import { useModal } from '/@/components/Modal';
import { useMessage } from '/src/hooks/web/useMessage'; import { useMessage } from '/src/hooks/web/useMessage';
import { useGo } from '/@/hooks/web/usePage'; import { useGo } from '/@/hooks/web/usePage';
import headerImg from '/@/assets/images/header.jpg'; import headerImg from '/@/assets/images/header.jpg';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
import { openWindow } from '/@/utils'; import { openWindow } from '/@/utils';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import { refreshCache, queryAllDictItems } from '/@/views/system/dict/dict.api'; import { refreshCache, queryAllDictItems } from '/@/views/system/dict/dict.api';
import { DB_DICT_DATA_KEY } from '/src/enums/cacheEnum'; import { DB_DICT_DATA_KEY } from '/src/enums/cacheEnum';
import { removeAuthCache, setAuthCache } from '/src/utils/auth'; import { removeAuthCache, setAuthCache } from '/src/utils/auth';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils'; import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { getRefPromise } from '/@/utils/index'; import { getRefPromise } from '/@/utils/index';
type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart'; type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart';
const { createMessage } = useMessage(); const { createMessage } = useMessage();
export default defineComponent({ export default defineComponent({
name: 'UserDropdown', name: 'UserDropdown',
components: { components: {
Dropdown, Dropdown,
Menu, Menu,
MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')), MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
MenuDivider: Menu.Divider, MenuDivider: Menu.Divider,
LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')), LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
DepartSelect: createAsyncComponent(() => import('./DepartSelect.vue')), DepartSelect: createAsyncComponent(() => import('./DepartSelect.vue')),
UpdatePassword: createAsyncComponent(() => import('./UpdatePassword.vue')), UpdatePassword: createAsyncComponent(() => import('./UpdatePassword.vue')),
}, },
props: { props: {
theme: propTypes.oneOf(['dark', 'light']), theme: propTypes.oneOf(['dark', 'light']),
}, },
setup() { setup() {
const { prefixCls } = useDesign('header-user-dropdown'); const { prefixCls } = useDesign('header-user-dropdown');
const { t } = useI18n(); const { t } = useI18n();
const { getShowDoc, getUseLockPage } = useHeaderSetting(); const { getShowDoc, getUseLockPage } = useHeaderSetting();
const userStore = useUserStore(); const userStore = useUserStore();
const go = useGo(); const go = useGo();
const passwordVisible = ref(false); const passwordVisible = ref(false);
const lockActionVisible = ref(false); const lockActionVisible = ref(false);
const lockActionRef = ref(null); const lockActionRef = ref(null);
const getUserInfo = computed(() => { const getUserInfo = computed(() => {
const { realname = '', avatar, desc } = userStore.getUserInfo || {}; const { realname = '', avatar, desc } = userStore.getUserInfo || {};
return { realname, avatar: avatar || headerImg, desc }; return { realname, avatar: avatar || headerImg, desc };
}); });
const getAvatarUrl = computed(() => { const getAvatarUrl = computed(() => {
let { avatar } = getUserInfo.value; let { avatar } = getUserInfo.value;
if (avatar == headerImg) { if (avatar == headerImg) {
return avatar; return avatar;
} else { } else {
return getFileAccessHttpUrl(avatar); return getFileAccessHttpUrl(avatar);
}
});
const [register, { openModal }] = useModal();
/**
* 多部门弹窗逻辑
*/
const loginSelectRef = ref();
// update-begin--author:liaozhiyang---date:20230901---forQQYUN-6333访
async function handleLock() {
await getRefPromise(lockActionRef);
openModal(true);
}
// update-end--author:liaozhiyang---date:20230901---forQQYUN-6333访
// login out
function handleLoginOut() {
userStore.confirmLoginOut();
} }
});
// open doc const [register, { openModal }] = useModal();
function openDoc() { /**
openWindow(SITE_URL); * 多部门弹窗逻辑
} */
const loginSelectRef = ref();
// update-begin--author:liaozhiyang---date:20230901---forQQYUN-6333访
async function handleLock() {
await getRefPromise(lockActionRef);
openModal(true);
}
// update-end--author:liaozhiyang---date:20230901---forQQYUN-6333访
// login out
function handleLoginOut() {
userStore.confirmLoginOut();
}
// // open doc
async function clearCache() { function openDoc() {
const result = await refreshCache(); openWindow(SITE_URL);
if (result.success) { }
const res = await queryAllDictItems();
removeAuthCache(DB_DICT_DATA_KEY);
setAuthCache(DB_DICT_DATA_KEY, res.result);
// update-begin--author:liaozhiyang---date:20240124---forQQYUN-7970
createMessage.success(t('layout.header.refreshCacheComplete'));
// update-end--author:liaozhiyang---date:20240124---forQQYUN-7970
} else {
// update-begin--author:liaozhiyang---date:20240124---forQQYUN-7970
createMessage.error(t('layout.header.refreshCacheFailure'));
// update-end--author:liaozhiyang---date:20240124---forQQYUN-7970
}
}
//
function updateCurrentDepart() {
loginSelectRef.value.show();
}
//
const updatePasswordRef = ref();
// update-begin--author:liaozhiyang---date:20230901---forQQYUN-6333访
async function updatePassword() {
passwordVisible.value = true;
await getRefPromise(updatePasswordRef);
updatePasswordRef.value.show(userStore.getUserInfo.username);
}
// update-end--author:liaozhiyang---date:20230901---forQQYUN-6333访
function handleMenuClick(e: { key: MenuEvent }) {
switch (e.key) {
case 'logout':
handleLoginOut();
break;
case 'doc':
openDoc();
break;
case 'lock':
handleLock();
break;
case 'cache':
clearCache();
break;
case 'depart':
updateCurrentDepart();
break;
case 'password':
updatePassword();
break;
case 'account':
//update-begin---author:wangshuai ---date:20221125 for------------
go(`/system/usersetting`);
//update-end---author:wangshuai ---date:20221125 for--------------
break;
}
}
return { //
prefixCls, async function clearCache() {
t, const result = await refreshCache();
getUserInfo, if (result.success) {
getAvatarUrl, const res = await queryAllDictItems();
handleMenuClick, removeAuthCache(DB_DICT_DATA_KEY);
getShowDoc, setAuthCache(DB_DICT_DATA_KEY, res.result);
register, // update-begin--author:liaozhiyang---date:20240124---forQQYUN-7970
getUseLockPage, createMessage.success(t('layout.header.refreshCacheComplete'));
loginSelectRef, // update-end--author:liaozhiyang---date:20240124---forQQYUN-7970
updatePasswordRef, } else {
passwordVisible, // update-begin--author:liaozhiyang---date:20240124---forQQYUN-7970
lockActionVisible, createMessage.error(t('layout.header.refreshCacheFailure'));
}; // update-end--author:liaozhiyang---date:20240124---forQQYUN-7970
}, }
}); }
//
function updateCurrentDepart() {
loginSelectRef.value.show();
}
//
const updatePasswordRef = ref();
// update-begin--author:liaozhiyang---date:20230901---forQQYUN-6333访
async function updatePassword() {
passwordVisible.value = true;
await getRefPromise(updatePasswordRef);
updatePasswordRef.value.show(userStore.getUserInfo.username);
}
// update-end--author:liaozhiyang---date:20230901---forQQYUN-6333访
function handleMenuClick(e: { key: MenuEvent }) {
switch (e.key) {
case 'logout':
handleLoginOut();
break;
case 'doc':
openDoc();
break;
case 'lock':
handleLock();
break;
case 'cache':
clearCache();
break;
case 'depart':
updateCurrentDepart();
break;
case 'password':
updatePassword();
break;
case 'account':
//update-begin---author:wangshuai ---date:20221125 for------------
go(`/system/usersetting`);
//update-end---author:wangshuai ---date:20221125 for--------------
break;
}
}
return {
prefixCls,
t,
getUserInfo,
getAvatarUrl,
handleMenuClick,
getShowDoc,
register,
getUseLockPage,
loginSelectRef,
updatePasswordRef,
passwordVisible,
lockActionVisible,
};
},
});
</script> </script>
<style lang="less"> <style lang="less">
@prefix-cls: ~'@{namespace}-header-user-dropdown'; @prefix-cls: ~'@{namespace}-header-user-dropdown';
.@{prefix-cls} { .@{prefix-cls} {
height: @header-height; height: @header-height;
padding: 0 0 0 10px; padding: 0 0 0 10px;
padding-right: 10px; padding-right: 10px;
overflow: hidden; overflow: hidden;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
img { img {
width: 24px; width: 24px;
height: 24px; height: 24px;
margin-right: 12px; margin-right: 12px;
} }
&__header { &__header {
border-radius: 50%; border-radius: 50%;
} }
&__name { &__name {
font-size: 14px; font-size: 14px;
} }
&--dark { &--dark {
&:hover { &:hover {
background-color: @header-dark-bg-hover-color; background-color: @header-dark-bg-hover-color;
}
}
&--light {
&:hover {
background-color: @header-light-bg-hover-color;
}
.@{prefix-cls}__name {
color: @text-color-base;
}
.@{prefix-cls}__desc {
color: @header-light-desc-color;
}
}
&-dropdown-overlay {
// update-begin--author:liaozhiyang---date:20231226---forQQYUN-7512
width: 160px;
// update-end--author:liaozhiyang---date:20231226---forQQYUN-7512
.ant-dropdown-menu-item {
min-width: 160px;
}
} }
} }
&--light {
&:hover {
background-color: @header-light-bg-hover-color;
}
.@{prefix-cls}__name {
color: @text-color-base;
}
.@{prefix-cls}__desc {
color: @header-light-desc-color;
}
}
&-dropdown-overlay {
// update-begin--author:liaozhiyang---date:20231226---forQQYUN-7512
width: 160px;
// update-end--author:liaozhiyang---date:20231226---forQQYUN-7512
.ant-dropdown-menu-item {
min-width: 160px;
}
}
}
</style> </style>

View File

@ -3,15 +3,11 @@
<!-- left start --> <!-- left start -->
<div :class="`${prefixCls}-left`"> <div :class="`${prefixCls}-left`">
<!-- logo --> <!-- logo -->
<AppLogo v-if="getShowHeaderLogo || getIsMobile" :class="`${prefixCls}-logo`" :theme="getHeaderTheme" :style="getLogoWidth" /> <AppLogo v-if="getShowHeaderLogo || getIsMobile" :class="`${prefixCls}-logo`" :theme="getHeaderTheme"
<LayoutTrigger :style="getLogoWidth" />
v-if="(getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile" <LayoutTrigger v-if="(getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile"
:theme="getHeaderTheme" :theme="getHeaderTheme" :sider="false" />
:sider="false"
/>
<LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" /> <LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
<!-- 欢迎语 -->
<span v-if="getShowContent && getShowBreadTitle && !getIsMobile" :class="[prefixCls, `${prefixCls}--${getHeaderTheme}`,'headerIntroductionClass']"> {{t('layout.header.welcomeIn')}} {{ title }} </span>
</div> </div>
<!-- left end --> <!-- left end -->
@ -23,236 +19,228 @@
<!-- action --> <!-- action -->
<div :class="`${prefixCls}-action`"> <div :class="`${prefixCls}-action`">
<AppSearch :class="`${prefixCls}-action__item `" v-if="getShowSearch" />
<ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" /> <ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />
<Notify v-if="getShowNotice" :class="`${prefixCls}-action__item notify-item`" />
<FullScreen v-if="getShowFullScreen" :class="`${prefixCls}-action__item fullscreen-item`" /> <FullScreen v-if="getShowFullScreen" :class="`${prefixCls}-action__item fullscreen-item`" />
<LockScreen v-if="getUseLockPage" />
<AppLocalePicker v-if="getShowLocalePicker" :reload="true" :showText="false" :class="`${prefixCls}-action__item`" />
<UserDropDown :theme="getHeaderTheme" /> <UserDropDown :theme="getHeaderTheme" />
<SettingDrawer v-if="getShowSetting" :class="`${prefixCls}-action__item`" /> <SettingDrawer v-if="getShowSetting" :class="`${prefixCls}-action__item`" />
<!-- ai助手 -->
<Aide></Aide>
</div> </div>
</Header> </Header>
<LoginSelect ref="loginSelectRef" @success="loginSelectOk"></LoginSelect> <LoginSelect ref="loginSelectRef" @success="loginSelectOk"></LoginSelect>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, unref, computed, ref, onMounted, toRaw } from 'vue'; import { defineComponent, unref, computed, ref, onMounted, toRaw } from 'vue';
import { useGlobSetting } from '/@/hooks/setting'; import { useGlobSetting } from '/@/hooks/setting';
import { propTypes } from '/@/utils/propTypes'; import { propTypes } from '/@/utils/propTypes';
import { Layout } from 'ant-design-vue'; import { Layout } from 'ant-design-vue';
import { AppLogo } from '/@/components/Application'; import { AppLogo } from '/@/components/Application';
import LayoutMenu from '../menu/index.vue'; import LayoutMenu from '../menu/index.vue';
import LayoutTrigger from '../trigger/index.vue'; import LayoutTrigger from '../trigger/index.vue';
import { AppSearch } from '/@/components/Application'; import { AppSearch } from '/@/components/Application';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useRootSetting } from '/@/hooks/setting/useRootSetting'; import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
import { SettingButtonPositionEnum } from '/@/enums/appEnum'; import { SettingButtonPositionEnum } from '/@/enums/appEnum';
import { AppLocalePicker } from '/@/components/Application'; import { AppLocalePicker } from '/@/components/Application';
import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction, LockScreen } from './components'; import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction, LockScreen } from './components';
import { useAppInject } from '/@/hooks/web/useAppInject'; import { useAppInject } from '/@/hooks/web/useAppInject';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
import { useLocale } from '/@/locales/useLocale'; import { useLocale } from '/@/locales/useLocale';
import LoginSelect from '/@/views/sys/login/LoginSelect.vue'; import LoginSelect from '/@/views/sys/login/LoginSelect.vue';
import { useUserStore } from '/@/store/modules/user'; import { useUserStore } from '/@/store/modules/user';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import Aide from "@/views/dashboard/ai/components/aide/index.vue" import Aide from "@/views/dashboard/ai/components/aide/index.vue"
const { t } = useI18n(); const { t } = useI18n();
export default defineComponent({ export default defineComponent({
name: 'LayoutHeader', name: 'LayoutHeader',
components: { components: {
Header: Layout.Header, Header: Layout.Header,
AppLogo, AppLogo,
LayoutTrigger, LayoutTrigger,
LayoutBreadcrumb, LayoutBreadcrumb,
LayoutMenu, LayoutMenu,
UserDropDown, UserDropDown,
AppLocalePicker, AppLocalePicker,
FullScreen, FullScreen,
Notify, Notify,
AppSearch, AppSearch,
ErrorAction, ErrorAction,
LockScreen, LockScreen,
LoginSelect, LoginSelect,
SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue'), { SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue'), {
loading: true, loading: true,
}), }),
Aide Aide
}, },
props: { props: {
fixed: propTypes.bool, fixed: propTypes.bool,
}, },
setup(props) { setup(props) {
const { prefixCls } = useDesign('layout-header'); const { prefixCls } = useDesign('layout-header');
const userStore = useUserStore(); const userStore = useUserStore();
const { getShowTopMenu, getShowHeaderTrigger, getSplit, getIsMixMode, getMenuWidth, getIsMixSidebar } = useMenuSetting(); const { getShowTopMenu, getShowHeaderTrigger, getSplit, getIsMixMode, getMenuWidth, getIsMixSidebar } = useMenuSetting();
const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting(); const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting();
const { title } = useGlobSetting(); const { title } = useGlobSetting();
const { const {
getHeaderTheme, getHeaderTheme,
getShowFullScreen, getShowFullScreen,
getShowNotice, getShowNotice,
getShowContent, getShowContent,
getShowBread, getShowBread,
getShowHeaderLogo, getShowHeaderLogo,
getShowHeader, getShowHeader,
getShowSearch, getShowSearch,
getUseLockPage, getUseLockPage,
getShowBreadTitle, getShowBreadTitle,
} = useHeaderSetting(); } = useHeaderSetting();
const { getShowLocalePicker } = useLocale(); const { getShowLocalePicker } = useLocale();
const { getIsMobile } = useAppInject(); const { getIsMobile } = useAppInject();
const getHeaderClass = computed(() => { const getHeaderClass = computed(() => {
const theme = unref(getHeaderTheme); const theme = unref(getHeaderTheme);
return [ return [
prefixCls,
{
[`${prefixCls}--fixed`]: props.fixed,
[`${prefixCls}--mobile`]: unref(getIsMobile),
[`${prefixCls}--${theme}`]: theme,
},
];
});
const getShowSetting = computed(() => {
if (!unref(getShowSettingButton)) {
return false;
}
const settingButtonPosition = unref(getSettingButtonPosition);
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
return unref(getShowHeader);
}
return settingButtonPosition === SettingButtonPositionEnum.HEADER;
});
const getLogoWidth = computed(() => {
if (!unref(getIsMixMode) || unref(getIsMobile)) {
return {};
}
const width = unref(getMenuWidth) < 180 ? 180 : unref(getMenuWidth);
return { width: `${width}px` };
});
const getSplitType = computed(() => {
return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE;
});
const getMenuMode = computed(() => {
return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null;
});
/**
* 首页多租户部门弹窗逻辑
*/
const loginSelectRef = ref();
function showLoginSelect() {
//update-begin---author:liusq Date:20220101 for----
//
const loginInfo = toRaw(userStore.getLoginInfo) || {};
if (!!loginInfo.isLogin) {
loginSelectRef.value.show(loginInfo);
}
//update-end---author:liusq Date:20220101 for----
}
function loginSelectOk() {
console.log('成功。。。。。');
}
onMounted(() => {
showLoginSelect();
});
return {
prefixCls, prefixCls,
getHeaderClass, {
getShowHeaderLogo, [`${prefixCls}--fixed`]: props.fixed,
getHeaderTheme, [`${prefixCls}--mobile`]: unref(getIsMobile),
getShowHeaderTrigger, [`${prefixCls}--${theme}`]: theme,
getIsMobile, },
getShowBreadTitle, ];
getShowBread, });
getShowContent,
getSplitType, const getShowSetting = computed(() => {
getSplit, if (!unref(getShowSettingButton)) {
getMenuMode, return false;
getShowTopMenu, }
getShowLocalePicker, const settingButtonPosition = unref(getSettingButtonPosition);
getShowFullScreen,
getShowNotice, if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
getUseErrorHandle, return unref(getShowHeader);
getLogoWidth, }
getIsMixSidebar, return settingButtonPosition === SettingButtonPositionEnum.HEADER;
getShowSettingButton, });
getShowSetting,
getShowSearch, const getLogoWidth = computed(() => {
getUseLockPage, if (!unref(getIsMixMode) || unref(getIsMobile)) {
loginSelectOk, return {};
loginSelectRef, }
title, const width = unref(getMenuWidth) < 180 ? 180 : unref(getMenuWidth);
t return { width: `${width}px` };
}; });
},
}); const getSplitType = computed(() => {
return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE;
});
const getMenuMode = computed(() => {
return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null;
});
/**
* 首页多租户部门弹窗逻辑
*/
const loginSelectRef = ref();
function showLoginSelect() {
//update-begin---author:liusq Date:20220101 for----
//
const loginInfo = toRaw(userStore.getLoginInfo) || {};
if (!!loginInfo.isLogin) {
loginSelectRef.value.show(loginInfo);
}
//update-end---author:liusq Date:20220101 for----
}
function loginSelectOk() {
console.log('成功。。。。。');
}
onMounted(() => {
showLoginSelect();
});
return {
prefixCls,
getHeaderClass,
getShowHeaderLogo,
getHeaderTheme,
getShowHeaderTrigger,
getIsMobile,
getShowBreadTitle,
getShowBread,
getShowContent,
getSplitType,
getSplit,
getMenuMode,
getShowTopMenu,
getShowLocalePicker,
getShowFullScreen,
getShowNotice,
getUseErrorHandle,
getLogoWidth,
getIsMixSidebar,
getShowSettingButton,
getShowSetting,
getShowSearch,
getUseLockPage,
loginSelectOk,
loginSelectRef,
title,
t
};
},
});
</script> </script>
<style lang="less"> <style lang="less">
@import './index.less'; @import './index.less';
//update-begin---author:scott ---date:2022-09-30 for----------- //update-begin---author:scott ---date:2022-09-30 for-----------
// //
@prefix-cls: ~'@{namespace}-layout-header'; @prefix-cls: ~'@{namespace}-layout-header';
.ant-layout .@{prefix-cls} { .ant-layout .@{prefix-cls} {
display: flex; display: flex;
padding: 0 8px; padding: 0 8px;
height: 48px; height: 48px;
align-items: center; align-items: center;
.headerIntroductionClass { .headerIntroductionClass {
margin-right: 4px; margin-right: 4px;
margin-bottom: 2px; margin-bottom: 2px;
border-bottom: 0px; border-bottom: 0px;
border-left: 0px; border-left: 0px;
}
&--light {
.headerIntroductionClass {
color: @breadcrumb-item-normal-color;
}
}
&--dark {
.headerIntroductionClass {
color: rgba(255, 255, 255, 0.6);
}
.anticon, .truncate {
color: rgba(255, 255, 255, 0.8);
}
}
//update-end---author:scott ---date::2022-09-30 for--------------
} }
&--light {
.headerIntroductionClass {
color: @breadcrumb-item-normal-color;
}
}
&--dark {
.headerIntroductionClass {
color: rgba(255, 255, 255, 0.6);
}
.anticon,
.truncate {
color: rgba(255, 255, 255, 0.8);
}
}
//update-end---author:scott ---date::2022-09-30 for--------------
}
</style> </style>

View File

@ -65,13 +65,13 @@ const setting: ProjectConfig = {
// 头部配置 // 头部配置
headerSetting: { headerSetting: {
// 背景色 // 背景色
bgColor: HEADER_PRESET_BG_COLOR_LIST[0], bgColor: HEADER_PRESET_BG_COLOR_LIST[5],
// 固定头部 // 固定头部
fixed: true, fixed: true,
// 是否显示顶部 // 是否显示顶部
show: true, show: true,
// 主题 // 主题
theme: ThemeEnum.LIGHT, theme: ThemeEnum.DARK,
// 开启锁屏功能 // 开启锁屏功能
useLockPage: true, useLockPage: true,
// 显示全屏按钮 // 显示全屏按钮
@ -87,7 +87,7 @@ const setting: ProjectConfig = {
// 菜单配置 // 菜单配置
menuSetting: { menuSetting: {
// 背景色 // 背景色
bgColor: SIDE_BAR_BG_COLOR_LIST[0], bgColor: SIDE_BAR_BG_COLOR_LIST[3],
// 是否固定住左侧菜单 // 是否固定住左侧菜单
fixed: true, fixed: true,
// 菜单折叠 // 菜单折叠

View File

@ -1,13 +0,0 @@
<template>
<div>
<h1>学生信息</h1>
</div>
</template>
<script>
export default {
}
</script>
<style></style>

View File

@ -1,5 +1,8 @@
<template> <template>
<IndexDef v-if="indexStyle === 0"></IndexDef> <div class="mod-home">
<h3>欢迎使用评阅人员管理系统</h3>
</div>
<!--<IndexDef v-if="indexStyle === 0"></IndexDef>
<IndexChart v-if="indexStyle === 1"></IndexChart> <IndexChart v-if="indexStyle === 1"></IndexChart>
<IndexBdc v-if="indexStyle == 2"></IndexBdc> <IndexBdc v-if="indexStyle == 2"></IndexBdc>
<IndexTask v-if="indexStyle == 3"></IndexTask> <IndexTask v-if="indexStyle == 3"></IndexTask>
@ -11,14 +14,20 @@
<a-radio :value="2">业务统计</a-radio> <a-radio :value="2">业务统计</a-radio>
<a-radio :value="3">我的任务</a-radio> <a-radio :value="3">我的任务</a-radio>
</a-radio-group> </a-radio-group>
</div> </div>-->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; //import { ref } from 'vue';
import IndexDef from './homePage/IndexDef.vue'; //import IndexDef from './homePage/IndexDef.vue';
import IndexChart from './homePage/IndexChart.vue'; //import IndexChart from './homePage/IndexChart.vue';
import IndexBdc from './homePage/IndexBdc.vue'; //import IndexBdc from './homePage/IndexBdc.vue';
import IndexTask from './homePage/IndexTask.vue'; //import IndexTask from './homePage/IndexTask.vue';
const indexStyle = ref(0); //const indexStyle = ref(0);
</script> </script>
<style>
.mod-home {
line-height: 2.5;
text-align: center;
}
</style>

View File

@ -1,29 +1,30 @@
<template> <template>
<LoginFormTitle v-show="getShow" class="enter-x" /> <LoginFormTitle v-show="getShow" class="enter-x" />
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin"> <Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow"
@keypress.enter="handleLogin">
<FormItem name="account" class="enter-x"> <FormItem name="account" class="enter-x">
<Input size="large" v-model:value="formData.account" :placeholder="t('sys.login.userName')" class="fix-auto-fill" /> <Input size="large" v-model:value="formData.account" :placeholder="t('sys.login.userName')"
class="fix-auto-fill" />
</FormItem> </FormItem>
<FormItem name="password" class="enter-x"> <FormItem name="password" class="enter-x">
<InputPassword size="large" visibilityToggle v-model:value="formData.password" :placeholder="t('sys.login.password')" /> <InputPassword size="large" visibilityToggle v-model:value="formData.password"
:placeholder="t('sys.login.password')" />
</FormItem> </FormItem>
<!--验证码--> <!--验证码-->
<ARow class="enter-x"> <ARow class="enter-x">
<ACol :span="12"> <ACol :span="12">
<FormItem name="inputCode" class="enter-x"> <FormItem name="inputCode" class="enter-x">
<Input size="large" v-model:value="formData.inputCode" :placeholder="t('sys.login.inputCode')" style="min-width: 100px" /> <Input size="large" v-model:value="formData.inputCode" :placeholder="t('sys.login.inputCode')"
style="min-width: 100px" />
</FormItem> </FormItem>
</ACol> </ACol>
<ACol :span="8"> <ACol :span="8">
<FormItem :style="{ 'text-align': 'right', 'margin-left': '20px' }" class="enter-x"> <FormItem :style="{ 'text-align': 'right', 'margin-left': '20px' }" class="enter-x">
<img <img v-if="randCodeData.requestCodeSuccess" style="margin-top: 2px; max-width: initial"
v-if="randCodeData.requestCodeSuccess" :src="randCodeData.randCodeImage" @click="handleChangeCheckCode" />
style="margin-top: 2px; max-width: initial" <img v-else style="margin-top: 2px; max-width: initial" src="../../../assets/images/checkcode.png"
:src="randCodeData.randCodeImage" @click="handleChangeCheckCode" />
@click="handleChangeCheckCode"
/>
<img v-else style="margin-top: 2px; max-width: initial" src="../../../assets/images/checkcode.png" @click="handleChangeCheckCode" />
</FormItem> </FormItem>
</ACol> </ACol>
</ARow> </ARow>
@ -76,121 +77,128 @@
<Divider class="enter-x">{{ t('sys.login.otherSignIn') }}</Divider> <Divider class="enter-x">{{ t('sys.login.otherSignIn') }}</Divider>
<div class="flex justify-evenly enter-x" :class="`${prefixCls}-sign-in-way`"> <div class="flex justify-evenly enter-x" :class="`${prefixCls}-sign-in-way`">
<a @click="onThirdLogin('github')" title="github"><GithubFilled /></a> <a @click="onThirdLogin('github')" title="github">
<a @click="onThirdLogin('wechat_enterprise')" title="企业微信"> <icon-font class="item-icon" type="icon-qiyeweixin3" /></a> <GithubFilled />
<a @click="onThirdLogin('dingtalk')" title="钉钉"><DingtalkCircleFilled /></a> </a>
<a @click="onThirdLogin('wechat_open')" title="微信"><WechatFilled /></a> <a @click="onThirdLogin('wechat_enterprise')" title="企业微信"> <icon-font class="item-icon"
type="icon-qiyeweixin3" /></a>
<a @click="onThirdLogin('dingtalk')" title="钉钉">
<DingtalkCircleFilled />
</a>
<a @click="onThirdLogin('wechat_open')" title="微信">
<WechatFilled />
</a>
</div> </div>
</Form> </Form>
<!-- 第三方登录相关弹框 --> <!-- 第三方登录相关弹框 -->
<ThirdModal ref="thirdModalRef"></ThirdModal> <ThirdModal ref="thirdModalRef"></ThirdModal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref, toRaw, unref, computed, onMounted } from 'vue'; import { reactive, ref, toRaw, unref, computed, onMounted } from 'vue';
import { Checkbox, Form, Input, Row, Col, Button, Divider } from 'ant-design-vue'; import { Checkbox, Form, Input, Row, Col, Button, Divider } from 'ant-design-vue';
import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue'; import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue';
import LoginFormTitle from './LoginFormTitle.vue'; import LoginFormTitle from './LoginFormTitle.vue';
import ThirdModal from './ThirdModal.vue'; import ThirdModal from './ThirdModal.vue';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user'; import { useUserStore } from '/@/store/modules/user';
import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin'; import { LoginStateEnum, useLoginState, useFormRules, useFormValid } from './useLogin';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { getCodeInfo } from '/@/api/sys/user'; import { getCodeInfo } from '/@/api/sys/user';
//import { onKeyStroke } from '@vueuse/core'; //import { onKeyStroke } from '@vueuse/core';
const ACol = Col; const ACol = Col;
const ARow = Row; const ARow = Row;
const FormItem = Form.Item; const FormItem = Form.Item;
const InputPassword = Input.Password; const InputPassword = Input.Password;
const IconFont = createFromIconfontCN({ const IconFont = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js', scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
}); });
const { t } = useI18n(); const { t } = useI18n();
const { notification, createErrorModal } = useMessage(); const { notification, createErrorModal } = useMessage();
const { prefixCls } = useDesign('login'); const { prefixCls } = useDesign('login');
const userStore = useUserStore(); const userStore = useUserStore();
const { setLoginState, getLoginState } = useLoginState(); const { setLoginState, getLoginState } = useLoginState();
const { getFormRules } = useFormRules(); const { getFormRules } = useFormRules();
const formRef = ref(); const formRef = ref();
const thirdModalRef = ref(); const thirdModalRef = ref();
const loading = ref(false); const loading = ref(false);
const rememberMe = ref(false); const rememberMe = ref(false);
const formData = reactive({ const formData = reactive({
account: 'admin', account: 'admin',
password: '123456', password: '123456',
inputCode: '', inputCode: '',
}); });
const randCodeData = reactive({ const randCodeData = reactive({
randCodeImage: '', randCodeImage: '',
requestCodeSuccess: false, requestCodeSuccess: false,
checkKey: null, checkKey: null,
}); });
const { validForm } = useFormValid(formRef); const { validForm } = useFormValid(formRef);
//onKeyStroke('Enter', handleLogin); //onKeyStroke('Enter', handleLogin);
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN); const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN);
async function handleLogin() { async function handleLogin() {
const data = await validForm(); const data = await validForm();
if (!data) return; if (!data) return;
try { try {
loading.value = true; loading.value = true;
const { userInfo } = await userStore.login( const { userInfo } = await userStore.login(
toRaw({ toRaw({
password: data.password, password: data.password,
username: data.account, username: data.account,
captcha: data.inputCode, captcha: data.inputCode,
checkKey: randCodeData.checkKey, checkKey: randCodeData.checkKey,
mode: 'none', // mode: 'none', //
}) })
); );
if (userInfo) { if (userInfo) {
notification.success({ notification.success({
message: t('sys.login.loginSuccessTitle'), message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`, description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
duration: 3,
});
}
} catch (error) {
notification.error({
message: t('sys.api.errorTip'),
description: error.message || t('sys.api.networkExceptionMsg'),
duration: 3, duration: 3,
}); });
loading.value = false;
//update-begin-author:taoyan date:2022-5-3 for: issues/41
handleChangeCheckCode();
//update-end-author:taoyan date:2022-5-3 for: issues/41
} }
} } catch (error) {
function handleChangeCheckCode() { notification.error({
formData.inputCode = ''; message: t('sys.api.errorTip'),
//TODO mock description: error.message || t('sys.api.networkExceptionMsg'),
randCodeData.checkKey = 1629428467008; //new Date().getTime(); duration: 3,
getCodeInfo(randCodeData.checkKey).then((res) => {
randCodeData.randCodeImage = res;
randCodeData.requestCodeSuccess = true;
}); });
} loading.value = false;
/** //update-begin-author:taoyan date:2022-5-3 for: issues/41
* 第三方登录
* @param type
*/
function onThirdLogin(type) {
thirdModalRef.value.onThirdLogin(type);
}
//
onMounted(() => {
handleChangeCheckCode(); handleChangeCheckCode();
//update-end-author:taoyan date:2022-5-3 for: issues/41
}
}
function handleChangeCheckCode() {
formData.inputCode = '';
//TODO mock
randCodeData.checkKey = 1629428467008; //new Date().getTime();
getCodeInfo(randCodeData.checkKey).then((res) => {
randCodeData.randCodeImage = res;
randCodeData.requestCodeSuccess = true;
}); });
}
/**
* 第三方登录
* @param type
*/
function onThirdLogin(type) {
thirdModalRef.value.onThirdLogin(type);
}
//
onMounted(() => {
handleChangeCheckCode();
});
</script> </script>

View File

@ -1,218 +1,221 @@
<template> <template>
<div class="app-loading"> <div class="app-loading">
<div class="app-loading-wrap"> <div class="app-loading-wrap">
<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo"> <!--<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo">-->
<div class="app-loading-dots"> <div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span> <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div> </div>
<div class="app-loading-title">JeecgBoot 企业级低代码平台</div> <div class="app-loading-title">哈尔滨师范大学</div>
</div> <div class="app-loading-title">评阅人员管理系统</div>
</div> </div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
/** /**
* 地址中携带token跳转至此页面进行登录操作 * 地址中携带token跳转至此页面进行登录操作
*/ */
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user'; import { useUserStore } from '/@/store/modules/user';
import { useI18n } from '/@/hooks/web/useI18n'; import { useI18n } from '/@/hooks/web/useI18n';
export default { export default {
name: "TokenLogin", name: "TokenLogin",
setup(){ setup() {
const route = useRoute(); const route = useRoute();
let router = useRouter(); let router = useRouter();
const {createMessage, notification} = useMessage() const { createMessage, notification } = useMessage()
const {t} = useI18n(); const { t } = useI18n();
const routeQuery:any = route.query; const routeQuery: any = route.query;
if(!routeQuery){ if (!routeQuery) {
createMessage.warning('参数无效') createMessage.warning('参数无效')
} }
const token = routeQuery['loginToken']; const token = routeQuery['loginToken'];
if(!token){ if (!token) {
createMessage.warning('token无效') createMessage.warning('token无效')
}
const userStore = useUserStore();
userStore.ThirdLogin({ token, thirdType: 'email', goHome: false }).then(res => {
console.log("res====>doThirdLogin", res)
if (res && res.userInfo) {
requestSuccess(res)
} else {
requestFailed(res)
} }
const userStore = useUserStore(); });
userStore.ThirdLogin({ token, thirdType:'email', goHome: false }).then(res => {
console.log("res====>doThirdLogin",res) function requestFailed(err) {
if(res && res.userInfo){ notification.error({
requestSuccess(res) message: '登录失败',
}else{ description: ((err.response || {}).data || {}).message || err.message || "请求出现错误,请稍后再试",
requestFailed(res) duration: 4,
}
}); });
}
function requestFailed (err) { function requestSuccess(res) {
let info = routeQuery.info;
if (info) {
let query = JSON.parse(info);
//update-begin-author:taoyan date:2023-4-27 for: QQYUN-4882
let path = '';
if (query.isLowApp === 1) {
path = '/myapps/personalOffice/myTodo'
} else {
let taskId = query.taskId;
path = '/task/handle/' + taskId
}
//update-end-author:taoyan date:2023-4-27 for: QQYUN-4882
router.replace({ path, query });
notification.success({
message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${res.userInfo.realname}`,
duration: 3,
});
} else {
notification.error({ notification.error({
message: '登录失败', message: '参数失效',
description: ((err.response || {}).data || {}).message || err.message || "请求出现错误,请稍后再试", description: "页面跳转参数丢失,请查看日志",
duration: 4, duration: 4,
}); });
} }
function requestSuccess(res){
let info = routeQuery.info;
if(info){
let query = JSON.parse(info);
//update-begin-author:taoyan date:2023-4-27 for: QQYUN-4882
let path = '';
if(query.isLowApp === 1){
path = '/myapps/personalOffice/myTodo'
}else{
let taskId = query.taskId;
path = '/task/handle/' + taskId
}
//update-end-author:taoyan date:2023-4-27 for: QQYUN-4882
router.replace({ path, query });
notification.success({
message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${res.userInfo.realname}`,
duration: 3,
});
}else{
notification.error({
message: '参数失效',
description: "页面跳转参数丢失,请查看日志",
duration: 4,
});
}
}
} }
} }
}
</script> </script>
<style scoped> <style scoped>
html[data-theme='dark'] .app-loading {
background-color: #2c344a;
}
html[data-theme='dark'] .app-loading { html[data-theme='dark'] .app-loading .app-loading-title {
background-color: #2c344a; color: rgba(255, 255, 255, 0.85);
} }
html[data-theme='dark'] .app-loading .app-loading-title { .app-loading {
color: rgba(255, 255, 255, 0.85); display: flex;
} width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: #f4f7f9;
}
.app-loading { .app-loading .app-loading-wrap {
display: flex; position: absolute;
width: 100%; top: 50%;
height: 100%; left: 50%;
justify-content: center; display: flex;
align-items: center; -webkit-transform: translate3d(-50%, -50%, 0);
flex-direction: column; transform: translate3d(-50%, -50%, 0);
background-color: #f4f7f9; justify-content: center;
} align-items: center;
flex-direction: column;
}
.app-loading .app-loading-wrap { .app-loading .dots {
position: absolute; display: flex;
top: 50%; padding: 98px;
left: 50%; justify-content: center;
display: flex; align-items: center;
-webkit-transform: translate3d(-50%, -50%, 0); }
transform: translate3d(-50%, -50%, 0);
justify-content: center;
align-items: center;
flex-direction: column;
}
.app-loading .dots { .app-loading .app-loading-title {
display: flex; display: flex;
padding: 98px; margin-top: 30px;
justify-content: center; font-size: 30px;
align-items: center; color: rgba(0, 0, 0, 0.85);
} justify-content: center;
align-items: center;
}
.app-loading .app-loading-title { .app-loading .app-loading-logo {
display: flex; display: block;
margin-top: 30px; width: 90px;
font-size: 30px; margin: 0 auto;
color: rgba(0, 0, 0, 0.85); margin-bottom: 20px;
justify-content: center; }
align-items: center;
}
.app-loading .app-loading-logo { .dot {
display: block; position: relative;
width: 90px; display: inline-block;
margin: 0 auto; width: 48px;
margin-bottom: 20px; height: 48px;
} margin-top: 30px;
font-size: 32px;
transform: rotate(45deg);
box-sizing: border-box;
animation: antRotate 1.2s infinite linear;
}
.dot { .dot i {
position: relative; position: absolute;
display: inline-block; display: block;
width: 48px; width: 20px;
height: 48px; height: 20px;
margin-top: 30px; background-color: #0065cc;
font-size: 32px; border-radius: 100%;
transform: rotate(45deg); opacity: 0.3;
box-sizing: border-box; transform: scale(0.75);
animation: antRotate 1.2s infinite linear; animation: antSpinMove 1s infinite linear alternate;
} transform-origin: 50% 50%;
}
.dot i { .dot i:nth-child(1) {
position: absolute; top: 0;
display: block; left: 0;
width: 20px; }
height: 20px;
background-color: #0065cc;
border-radius: 100%;
opacity: 0.3;
transform: scale(0.75);
animation: antSpinMove 1s infinite linear alternate;
transform-origin: 50% 50%;
}
.dot i:nth-child(1) { .dot i:nth-child(2) {
top: 0; top: 0;
left: 0; right: 0;
} -webkit-animation-delay: 0.4s;
animation-delay: 0.4s;
}
.dot i:nth-child(2) { .dot i:nth-child(3) {
top: 0; right: 0;
right: 0; bottom: 0;
-webkit-animation-delay: 0.4s; -webkit-animation-delay: 0.8s;
animation-delay: 0.4s; animation-delay: 0.8s;
} }
.dot i:nth-child(3) { .dot i:nth-child(4) {
right: 0; bottom: 0;
bottom: 0; left: 0;
-webkit-animation-delay: 0.8s; -webkit-animation-delay: 1.2s;
animation-delay: 0.8s; animation-delay: 1.2s;
} }
.dot i:nth-child(4) { @keyframes antRotate {
bottom: 0; to {
left: 0; -webkit-transform: rotate(405deg);
-webkit-animation-delay: 1.2s; transform: rotate(405deg);
animation-delay: 1.2s; }
} }
@keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@-webkit-keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@keyframes antSpinMove {
to {
opacity: 1;
}
}
@-webkit-keyframes antSpinMove {
to {
opacity: 1;
}
}
</style> </style>

View File

@ -1,86 +1,65 @@
<template> <template>
<div :class="prefixCls" class="login-background-img"> <div :class="prefixCls" class="login-background-img">
<AppLocalePicker class="absolute top-4 right-4 enter-x xl:text-gray-600" :showText="false"/> <AppLocalePicker class="absolute top-4 right-4 enter-x xl:text-gray-600" :showText="false" />
<AppDarkModeToggle class="absolute top-3 right-7 enter-x" /> <AppDarkModeToggle class="absolute top-3 right-7 enter-x" />
<div class="aui-logo" v-if="!getIsMobile">
<div>
<h3>
<img :src="logoImg" alt="jeecg" />
</h3>
</div>
</div>
<div v-else class="aui-phone-logo">
<img :src="logoImg" alt="jeecg" />
</div>
<div v-show="type === 'login'"> <div v-show="type === 'login'">
<div class="aui-content"> <div class="aui-content">
<div class="aui-container"> <div class="aui-container">
<div class="aui-form"> <div class="aui-form">
<div class="aui-image"> <div class="aui-image">
<div class="aui-image-text"> <div class="aui-image-text">
<img :src="adTextImg" /> <div>
<span class="introduce-text1">哈尔滨师范大学</span>
<br>
<span class="introduce-text">评阅人员管理系统</span>
<br>
<br>
<!--<span class="introduce-text" style="font-size: 18px;">深入分析 多维展示</span>-->
</div>
</div> </div>
</div> </div>
<div class="aui-formBox"> <div class="aui-formBox">
<div class="aui-formWell"> <div class="aui-formWell">
<div class="aui-flex aui-form-nav investment_title"> <div class="aui-flex aui-form-nav investment_title">
<div class="aui-flex-box" :class="activeIndex === 'accountLogin' ? 'activeNav on' : ''" @click="loginClick('accountLogin')" <div class="aui-flex-box" :class="activeIndex === 'accountLogin' ? 'activeNav on' : ''"
>{{ t('sys.login.signInFormTitle') }} @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> </div>
<div class="aui-form-box" style="height: 180px"> <div class="aui-form-box" style="height: 140px">
<a-form ref="loginRef" :model="formData" v-if="activeIndex === 'accountLogin'" @keyup.enter.native="loginHandleClick"> <a-form ref="loginRef" :model="formData" v-if="activeIndex === 'accountLogin'"
@keyup.enter.native="loginHandleClick">
<div class="aui-account"> <div class="aui-account">
<div class="aui-inputClear"> <div class="aui-inputClear">
<i class="icon icon-code"></i> <i class="icon icon-code"></i>
<a-form-item> <a-form-item>
<a-input class="fix-auto-fill" :placeholder="t('sys.login.userName')" v-model:value="formData.username" /> <a-input class="fix-auto-fill" :placeholder="t('sys.login.userName')"
v-model:value="formData.username" />
</a-form-item> </a-form-item>
</div> </div>
<div class="aui-inputClear"> <div class="aui-inputClear">
<i class="icon icon-password"></i> <i class="icon icon-password"></i>
<a-form-item> <a-form-item>
<a-input class="fix-auto-fill" type="password" :placeholder="t('sys.login.password')" v-model:value="formData.password" /> <a-input class="fix-auto-fill" type="password" :placeholder="t('sys.login.password')"
v-model:value="formData.password" />
</a-form-item> </a-form-item>
</div> </div>
<div class="aui-inputClear">
<i class="icon icon-code"></i>
<a-form-item>
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.inputCode')" v-model:value="formData.inputCode" />
</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="codeImg" @click="handleChangeCheckCode" />
</div>
</div>
<div class="aui-flex">
<div class="aui-flex-box">
<div class="aui-choice">
<a-input class="fix-auto-fill" type="checkbox" v-model:value="rememberMe" />
<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> </div>
</a-form> </a-form>
<a-form v-else ref="phoneFormRef" :model="phoneFormData" @keyup.enter.native="loginHandleClick"> <a-form v-else ref="phoneFormRef" :model="phoneFormData" @keyup.enter.native="loginHandleClick">
<div class="aui-account phone"> <div class="aui-account phone">
<div class="aui-inputClear phoneClear"> <div class="aui-inputClear phoneClear">
<a-input class="fix-auto-fill" :placeholder="t('sys.login.mobile')" v-model:value="phoneFormData.mobile" /> <a-input class="fix-auto-fill" :placeholder="t('sys.login.mobile')"
v-model:value="phoneFormData.mobile" />
</div> </div>
<div class="aui-inputClear"> <div class="aui-inputClear">
<a-input class="fix-auto-fill" :maxlength="6" :placeholder="t('sys.login.smsCode')" v-model:value="phoneFormData.smscode" /> <a-input class="fix-auto-fill" :maxlength="6" :placeholder="t('sys.login.smsCode')"
v-model:value="phoneFormData.smscode" />
<div v-if="showInterval" class="aui-code" @click="getLoginCode"> <div v-if="showInterval" class="aui-code" @click="getLoginCode">
<a>{{ t('component.countdown.normalText') }}</a> <a>{{ t('component.countdown.normalText') }}</a>
</div> </div>
<div v-else class="aui-code"> <div v-else class="aui-code">
<span class="aui-get-code code-shape">{{ t('component.countdown.sendText', [unref(timeRuning)]) }}</span> <span class="aui-get-code code-shape">{{ t('component.countdown.sendText',
[unref(timeRuning)]) }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -92,42 +71,11 @@
{{ t('sys.login.loginButton') }}</a-button> {{ t('sys.login.loginButton') }}</a-button>
</div> </div>
<div class="aui-flex"> <div class="aui-flex">
<a class="aui-linek-code aui-flex-box" @click="codeHandleClick">{{ t('sys.login.qrSignInFormTitle') }}</a> <a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton')
</div> }}</a>
<div class="aui-flex">
<a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton') }}</a>
</div> </div>
</div> </div>
</div> </div>
<a-form @keyup.enter.native="loginHandleClick">
<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('wechat_enterprise')"><icon-font class="item-icon" type="icon-qiyeweixin3" /></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>
@ -147,331 +95,310 @@
</div> </div>
</template> </template>
<script lang="ts" setup name="login-mini"> <script lang="ts" setup name="login-mini">
import { getCaptcha, getCodeInfo } from '/@/api/sys/user'; import { getCaptcha, getCodeInfo } from '/@/api/sys/user';
import { computed, onMounted, reactive, ref, toRaw, unref } from 'vue'; import { onMounted, reactive, ref, toRaw, unref } from 'vue';
import codeImg from '/@/assets/images/checkcode.png'; import { useUserStore } from '/@/store/modules/user';
import { Rule } from '/@/components/Form'; import { useMessage } from '/@/hooks/web/useMessage';
import { useUserStore } from '/@/store/modules/user'; import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage'; import { SmsEnum } from '/@/views/sys/login/useLogin';
import { useI18n } from '/@/hooks/web/useI18n'; import ThirdModal from '/@/views/sys/login/ThirdModal.vue';
import { SmsEnum } from '/@/views/sys/login/useLogin'; import MiniForgotpad from './MiniForgotpad.vue';
import ThirdModal from '/@/views/sys/login/ThirdModal.vue'; import MiniRegister from './MiniRegister.vue';
import MiniForgotpad from './MiniForgotpad.vue'; import MiniCodelogin from './MiniCodelogin.vue';
import MiniRegister from './MiniRegister.vue'; import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png';
import MiniCodelogin from './MiniCodelogin.vue'; import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application';
import logoImg from '/@/assets/loginmini/icon/jeecg_logo.png'; import { useLocaleStore } from '/@/store/modules/locale';
import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png'; import { useDesign } from "/@/hooks/web/useDesign";
import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application'; import { useAppInject } from "/@/hooks/web/useAppInject";
import { useLocaleStore } from '/@/store/modules/locale';
import { useDesign } from "/@/hooks/web/useDesign";
import { useAppInject } from "/@/hooks/web/useAppInject";
import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue';
const IconFont = createFromIconfontCN({ const { prefixCls } = useDesign('mini-login');
scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js', const { notification, createMessage } = useMessage();
}); const userStore = useUserStore();
const { prefixCls } = useDesign('mini-login'); const { t } = useI18n();
const { notification, createMessage } = useMessage(); const localeStore = useLocaleStore();
const userStore = useUserStore(); const randCodeData = reactive<any>({
const { t } = useI18n(); randCodeImage: '',
const localeStore = useLocaleStore(); requestCodeSuccess: false,
const showLocale = localeStore.getShowPicker; checkKey: null,
const randCodeData = reactive<any>({ });
randCodeImage: '', //
requestCodeSuccess: false, const activeIndex = ref<string>('accountLogin');
checkKey: null, const type = ref<string>('login');
}); //
const rememberMe = ref<string>('0'); const formData = reactive<any>({
// inputCode: '',
const activeIndex = ref<string>('accountLogin'); username: 'admin',
const type = ref<string>('login'); password: '123456',
// });
const formData = reactive<any>({ //
inputCode: '', const phoneFormData = reactive<any>({
username: 'admin', mobile: '',
password: '123456', smscode: '',
}); });
// const loginRef = ref();
const phoneFormData = reactive<any>({ //
mobile: '', const thirdModalRef = ref();
smscode: '', //
}); const codeRef = ref();
const loginRef = ref(); //
// const showInterval = ref<boolean>(true);
const thirdModalRef = ref(); //60s
// const timeRuning = ref<number>(60);
const codeRef = ref(); //
// const timer = ref<any>(null);
const showInterval = ref<boolean>(true); //
//60s const forgotRef = ref();
const timeRuning = ref<number>(60); //
// const registerRef = ref();
const timer = ref<any>(null); const loginLoading = ref<boolean>(false);
// const { getIsMobile } = useAppInject();
const forgotRef = ref();
//
const registerRef = ref();
const loginLoading = ref<boolean>(false);
const { getIsMobile } = useAppInject();
defineProps({
sessionTimeout: { /**
type: Boolean, * 获取验证码
}, */
function handleChangeCheckCode() {
formData.inputCode = '';
randCodeData.checkKey = 1629428467008;
getCodeInfo(randCodeData.checkKey).then((res) => {
randCodeData.randCodeImage = res;
randCodeData.requestCodeSuccess = true;
}); });
}
/** /**
* 获取验证码 * 切换登录方式
*/ */
function handleChangeCheckCode() { function loginClick(type) {
formData.inputCode = ''; activeIndex.value = type;
}
randCodeData.checkKey = 1629428467008; /**
getCodeInfo(randCodeData.checkKey).then((res) => { * 账号或者手机登录
randCodeData.randCodeImage = res; */
randCodeData.requestCodeSuccess = true; async function loginHandleClick() {
}); if (unref(activeIndex) === 'accountLogin') {
accountLogin();
} else {
//
phoneLogin();
} }
}
/** async function accountLogin() {
* 切换登录方式 if (!formData.username) {
*/ createMessage.warn(t('sys.login.accountPlaceholder'));
function loginClick(type) { return;
activeIndex.value = type;
} }
if (!formData.password) {
/** createMessage.warn(t('sys.login.passwordPlaceholder'));
* 账号或者手机登录 return;
*/
async function loginHandleClick() {
if (unref(activeIndex) === 'accountLogin') {
accountLogin();
} else {
//
phoneLogin();
}
} }
try {
async function accountLogin() { loginLoading.value = true;
if (!formData.username) { const { userInfo } = await userStore.login(
createMessage.warn(t('sys.login.accountPlaceholder')); toRaw({
return; password: formData.password,
} username: formData.username,
if (!formData.password) { captcha: formData.inputCode,
createMessage.warn(t('sys.login.passwordPlaceholder')); checkKey: randCodeData.checkKey,
return;
}
try {
loginLoading.value = true;
const { userInfo } = await userStore.login(
toRaw({
password: formData.password,
username: formData.username,
captcha: formData.inputCode,
checkKey: randCodeData.checkKey,
mode: 'none', //
})
);
if (userInfo) {
notification.success({
message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
duration: 3,
});
}
} catch (error) {
notification.error({
message: t('sys.api.errorTip'),
description: error.message || t('sys.login.networkExceptionMsg'),
duration: 3,
});
handleChangeCheckCode();
} finally {
loginLoading.value = false;
}
}
/**
* 手机号登录
*/
async function phoneLogin() {
if (!phoneFormData.mobile) {
createMessage.warn(t('sys.login.mobilePlaceholder'));
return;
}
if (!phoneFormData.smscode) {
createMessage.warn(t('sys.login.smsPlaceholder'));
return;
}
try {
loginLoading.value = true;
const { userInfo }: any = await userStore.phoneLogin({
mobile: phoneFormData.mobile,
captcha: phoneFormData.smscode,
mode: 'none', // mode: 'none', //
}); })
if (userInfo) { );
notification.success({ if (userInfo) {
message: t('sys.login.loginSuccessTitle'), notification.success({
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`, message: t('sys.login.loginSuccessTitle'),
duration: 3, description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
});
}
} catch (error) {
notification.error({
message: t('sys.api.errorTip'),
description: error.message || t('sys.login.networkExceptionMsg'),
duration: 3, duration: 3,
}); });
} finally {
loginLoading.value = false;
} }
} } catch (error) {
notification.error({
/** message: t('sys.api.errorTip'),
* 获取手机验证码 description: error.message || t('sys.login.networkExceptionMsg'),
*/ duration: 3,
async function getLoginCode() { });
if (!phoneFormData.mobile) {
createMessage.warn(t('sys.login.mobilePlaceholder'));
return;
}
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD });
if (result) {
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) {
thirdModalRef.value.onThirdLogin(type);
}
/**
* 忘记密码
*/
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(); handleChangeCheckCode();
} finally {
loginLoading.value = false;
} }
}
/** /**
* 注册 * 手机号登录
*/ */
function registerHandleClick() { async function phoneLogin() {
type.value = 'register'; if (!phoneFormData.mobile) {
setTimeout(() => { createMessage.warn(t('sys.login.mobilePlaceholder'));
registerRef.value.initForm(); return;
}, 300);
} }
if (!phoneFormData.smscode) {
/** createMessage.warn(t('sys.login.smsPlaceholder'));
* 注册 return;
*/
function codeHandleClick() {
type.value = 'codeLogin';
setTimeout(() => {
codeRef.value.initFrom();
}, 300);
} }
try {
loginLoading.value = true;
const { userInfo }: any = await userStore.phoneLogin({
mobile: phoneFormData.mobile,
captcha: phoneFormData.smscode,
mode: 'none', //
});
if (userInfo) {
notification.success({
message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
duration: 3,
});
}
} catch (error) {
notification.error({
message: t('sys.api.errorTip'),
description: error.message || t('sys.login.networkExceptionMsg'),
duration: 3,
});
} finally {
loginLoading.value = false;
}
}
onMounted(() => { /**
// * 获取手机验证码
handleChangeCheckCode(); */
}); async function getLoginCode() {
if (!phoneFormData.mobile) {
createMessage.warn(t('sys.login.mobilePlaceholder'));
return;
}
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD });
if (result) {
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);
}
}
}
/**
* 返回登录页面
*/
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);
}
onMounted(() => {
//
handleChangeCheckCode();
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import '/@/assets/loginmini/style/home.less'; @import '/@/assets/loginmini/style/home.less';
@import '/@/assets/loginmini/style/base.less'; @import '/@/assets/loginmini/style/base.less';
:deep(.ant-input:focus) { //
box-shadow: none; .introduce-text1 {
} font-size: 30px;
.aui-get-code { color: #fff;
float: right; font-weight: bold;
position: relative; transform: translate(-50%, -50%);
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 { .introduce-text {
color: #1573e9; font-size: 40px;
} color: #fff;
font-weight: bold;
transform: translate(-50%, -50%);
}
.code-shape { :deep(.ant-input:focus) {
border-color: #dadada !important; box-shadow: none;
color: #aaa !important; }
}
:deep(.jeecg-dark-switch){ .aui-get-code {
position:absolute; float: right;
margin-right: 10px; position: relative;
} z-index: 3;
.aui-link-login{ background: #ffffff;
height: 42px; color: #1573e9;
padding: 10px 15px; border-radius: 100px;
font-size: 14px; padding: 5px 16px;
border-radius: 8px; margin: 7px;
margin-top: 15px; border: 1px solid #1573e9;
margin-bottom: 8px; top: 12px;
flex: 1; }
color: #fff;
} .aui-get-code:hover {
.aui-phone-logo{ color: #1573e9;
position: absolute; }
margin-left: 10px;
width: 60px; .code-shape {
top:2px; border-color: #dadada !important;
z-index: 4; color: #aaa !important;
} }
.top-3{
top: 0.45rem; :deep(.jeecg-dark-switch) {
} position: absolute;
margin-right: 10px;
}
.aui-link-login {
height: 42px;
padding: 10px 15px;
font-size: 14px;
border-radius: 8px;
margin-top: 15px;
margin-bottom: 8px;
flex: 1;
color: #fff;
}
.aui-phone-logo {
position: absolute;
margin-left: 10px;
width: 60px;
top: 2px;
z-index: 4;
}
.top-3 {
top: 0.45rem;
}
</style> </style>
<style lang="less"> <style lang="less">
@ -486,9 +413,11 @@ html[data-theme='dark'] {
&::before { &::before {
background-image: url(/@/assets/svg/login-bg-dark.svg); background-image: url(/@/assets/svg/login-bg-dark.svg);
} }
.aui-inputClear{
.aui-inputClear {
background-color: #232a3b !important; background-color: #232a3b !important;
} }
.ant-input, .ant-input,
.ant-input-password { .ant-input-password {
background-color: #232a3b !important; background-color: #232a3b !important;
@ -505,30 +434,39 @@ html[data-theme='dark'] {
.app-iconify { .app-iconify {
color: #fff !important; color: #fff !important;
} }
.aui-inputClear input,.aui-input-line input,.aui-choice{
.aui-inputClear input,
.aui-input-line input,
.aui-choice {
color: #c9d1d9 !important; color: #c9d1d9 !important;
} }
.aui-formBox{ .aui-formBox {
background-color: @dark-bg !important; background-color: @dark-bg !important;
} }
.aui-third-text span{
.aui-third-text span {
background-color: @dark-bg !important; background-color: @dark-bg !important;
} }
.aui-form-nav .aui-flex-box{
.aui-form-nav .aui-flex-box {
color: #c9d1d9 !important; color: #c9d1d9 !important;
} }
.aui-formButton .aui-linek-code{ .aui-formButton .aui-linek-code {
background: @dark-bg !important; background: @dark-bg !important;
color: white !important; color: white !important;
} }
.aui-code-line{
.aui-code-line {
border-left: none !important; border-left: none !important;
} }
.ant-checkbox-inner,.aui-success h3{
.ant-checkbox-inner,
.aui-success h3 {
border-color: #c9d1d9; border-color: #c9d1d9;
} }
//update-begin---author:wangshuai ---date:20230828 forQQYUN-6363------------ //update-begin---author:wangshuai ---date:20230828 forQQYUN-6363------------
&-sign-in-way { &-sign-in-way {
.anticon { .anticon {
@ -541,6 +479,7 @@ html[data-theme='dark'] {
} }
} }
} }
//update-end---author:wangshuai ---date:20230828 forQQYUN-6363------------ //update-end---author:wangshuai ---date:20230828 forQQYUN-6363------------
} }
@ -554,7 +493,8 @@ html[data-theme='dark'] {
font-size: 12px !important; font-size: 12px !important;
color: @text-color-secondary !important; color: @text-color-secondary !important;
} }
.aui-third-login a{
.aui-third-login a {
background: transparent; background: transparent;
} }
} }