style: lint格式化文件
This commit is contained in:
@ -1,51 +1,51 @@
|
||||
<template>
|
||||
<div :class="[prefixCls, getLayoutContentMode]" v-loading="getOpenPageLoading && getPageLoading">
|
||||
<PageLayout />
|
||||
</div>
|
||||
<div :class="[prefixCls, getLayoutContentMode]" v-loading="getOpenPageLoading && getPageLoading">
|
||||
<PageLayout />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import PageLayout from '/@/layouts/page/index.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||
import { useContentViewHeight } from './useContentViewHeight';
|
||||
import { defineComponent } from 'vue';
|
||||
import PageLayout from '/@/layouts/page/index.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
|
||||
import { useContentViewHeight } from './useContentViewHeight';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutContent',
|
||||
components: { PageLayout },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('layout-content');
|
||||
const { getOpenPageLoading } = useTransitionSetting();
|
||||
const { getLayoutContentMode, getPageLoading } = useRootSetting();
|
||||
export default defineComponent({
|
||||
name: 'LayoutContent',
|
||||
components: { PageLayout },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('layout-content');
|
||||
const { getOpenPageLoading } = useTransitionSetting();
|
||||
const { getLayoutContentMode, getPageLoading } = useRootSetting();
|
||||
|
||||
useContentViewHeight();
|
||||
return {
|
||||
prefixCls,
|
||||
getOpenPageLoading,
|
||||
getLayoutContentMode,
|
||||
getPageLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
useContentViewHeight();
|
||||
return {
|
||||
prefixCls,
|
||||
getOpenPageLoading,
|
||||
getLayoutContentMode,
|
||||
getPageLoading
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-layout-content';
|
||||
@prefix-cls: ~'@{namespace}-layout-content';
|
||||
|
||||
.@{prefix-cls} {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
.@{prefix-cls} {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
|
||||
&.fixed {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
&.fixed {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&-loading {
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
z-index: @page-loading-z-index;
|
||||
}
|
||||
}
|
||||
|
||||
&-loading {
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
z-index: @page-loading-z-index;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,83 +1,82 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { BackTop } from 'ant-design-vue';
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { BackTop } from 'ant-design-vue';
|
||||
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useUserStoreWithOut } from '/@/store/modules/user';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useUserStoreWithOut } from '/@/store/modules/user';
|
||||
|
||||
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { SettingButtonPositionEnum } from '/@/enums/appEnum';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
|
||||
import SessionTimeoutLogin from '/@/views/sys/login/SessionTimeoutLogin.vue';
|
||||
export default defineComponent({
|
||||
name: 'LayoutFeatures',
|
||||
components: {
|
||||
BackTop,
|
||||
LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/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-feature');
|
||||
const { getShowHeader } = useHeaderSetting();
|
||||
import SessionTimeoutLogin from '/@/views/sys/login/SessionTimeoutLogin.vue';
|
||||
export default defineComponent({
|
||||
name: 'LayoutFeatures',
|
||||
components: {
|
||||
BackTop,
|
||||
LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/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-feature');
|
||||
const { getShowHeader } = useHeaderSetting();
|
||||
|
||||
const getIsSessionTimeout = computed(() => userStore.getSessionTimeout);
|
||||
const getIsSessionTimeout = computed(() => userStore.getSessionTimeout);
|
||||
|
||||
const getIsFixedSettingDrawer = computed(() => {
|
||||
if (!unref(getShowSettingButton)) {
|
||||
return false;
|
||||
const getIsFixedSettingDrawer = computed(() => {
|
||||
if (!unref(getShowSettingButton)) {
|
||||
return false;
|
||||
}
|
||||
const settingButtonPosition = unref(getSettingButtonPosition);
|
||||
|
||||
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
|
||||
return !unref(getShowHeader) || unref(getFullContent);
|
||||
}
|
||||
return settingButtonPosition === SettingButtonPositionEnum.FIXED;
|
||||
});
|
||||
|
||||
return {
|
||||
getTarget: () => document.body,
|
||||
getUseOpenBackTop,
|
||||
getIsFixedSettingDrawer,
|
||||
prefixCls,
|
||||
getIsSessionTimeout
|
||||
};
|
||||
}
|
||||
const settingButtonPosition = unref(getSettingButtonPosition);
|
||||
|
||||
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
|
||||
return !unref(getShowHeader) || unref(getFullContent);
|
||||
}
|
||||
return settingButtonPosition === SettingButtonPositionEnum.FIXED;
|
||||
});
|
||||
|
||||
return {
|
||||
getTarget: () => document.body,
|
||||
getUseOpenBackTop,
|
||||
getIsFixedSettingDrawer,
|
||||
prefixCls,
|
||||
getIsSessionTimeout,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutLockPage />
|
||||
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
|
||||
<SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" />
|
||||
<SessionTimeoutLogin v-if="getIsSessionTimeout" />
|
||||
<LayoutLockPage />
|
||||
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
|
||||
<SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" />
|
||||
<SessionTimeoutLogin v-if="getIsSessionTimeout" />
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-setting-drawer-feature';
|
||||
@prefix-cls: ~'@{namespace}-setting-drawer-feature';
|
||||
|
||||
.@{prefix-cls} {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
color: @white;
|
||||
cursor: pointer;
|
||||
background-color: @primary-color;
|
||||
border-radius: 6px 0 0 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.@{prefix-cls} {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
color: @white;
|
||||
cursor: pointer;
|
||||
background-color: @primary-color;
|
||||
border-radius: 6px 0 0 6px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,95 +1,95 @@
|
||||
<template>
|
||||
<AFooter :class="prefixCls" v-if="getShowLayoutFooter" ref="footerRef">
|
||||
<div :class="`${prefixCls}__links`">
|
||||
<a @click="openWindow(SITE_URL)">{{ t('官网地址') }}</a>
|
||||
<AFooter :class="prefixCls" v-if="getShowLayoutFooter" ref="footerRef">
|
||||
<div :class="`${prefixCls}__links`">
|
||||
<a @click="openWindow(SITE_URL)">{{ t('官网地址') }}</a>
|
||||
|
||||
<GithubFilled @click="openWindow(GITHUB_URL)" :class="`${prefixCls}__github`" />
|
||||
<GithubFilled @click="openWindow(GITHUB_URL)" :class="`${prefixCls}__github`" />
|
||||
|
||||
<a @click="openWindow(DOC_URL)">{{ t('文档地址') }}</a>
|
||||
</div>
|
||||
<div>Copyright ©2024 ITC-FRAMEWORK</div>
|
||||
</AFooter>
|
||||
<a @click="openWindow(DOC_URL)">{{ t('文档地址') }}</a>
|
||||
</div>
|
||||
<div>Copyright ©2024 ITC-FRAMEWORK</div>
|
||||
</AFooter>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, unref, ref } from 'vue';
|
||||
import { Layout } from 'ant-design-vue';
|
||||
import { computed, defineComponent, unref, ref } from 'vue';
|
||||
import { Layout } from 'ant-design-vue';
|
||||
|
||||
import { GithubFilled } from '@ant-design/icons-vue';
|
||||
import { GithubFilled } from '@ant-design/icons-vue';
|
||||
|
||||
import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
|
||||
import { openWindow } from '/@/utils';
|
||||
import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
|
||||
import { openWindow } from '/@/utils';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '../content/useContentViewHeight';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '../content/useContentViewHeight';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutFooter',
|
||||
components: { AFooter: Layout.Footer, GithubFilled },
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { getShowFooter } = useRootSetting();
|
||||
const { currentRoute } = useRouter();
|
||||
const { prefixCls } = useDesign('layout-footer');
|
||||
export default defineComponent({
|
||||
name: 'LayoutFooter',
|
||||
components: { AFooter: Layout.Footer, GithubFilled },
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { getShowFooter } = useRootSetting();
|
||||
const { currentRoute } = useRouter();
|
||||
const { prefixCls } = useDesign('layout-footer');
|
||||
|
||||
const footerRef = ref<ComponentRef>(null);
|
||||
const { setFooterHeight } = useLayoutHeight();
|
||||
const footerRef = ref<ComponentRef>(null);
|
||||
const { setFooterHeight } = useLayoutHeight();
|
||||
|
||||
const getShowLayoutFooter = computed(() => {
|
||||
if (unref(getShowFooter)) {
|
||||
const footerEl = unref(footerRef)?.$el;
|
||||
setFooterHeight(footerEl?.offsetHeight || 0);
|
||||
} else {
|
||||
setFooterHeight(0);
|
||||
const getShowLayoutFooter = computed(() => {
|
||||
if (unref(getShowFooter)) {
|
||||
const footerEl = unref(footerRef)?.$el;
|
||||
setFooterHeight(footerEl?.offsetHeight || 0);
|
||||
} else {
|
||||
setFooterHeight(0);
|
||||
}
|
||||
return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter;
|
||||
});
|
||||
|
||||
return {
|
||||
getShowLayoutFooter,
|
||||
prefixCls,
|
||||
t,
|
||||
DOC_URL,
|
||||
GITHUB_URL,
|
||||
SITE_URL,
|
||||
openWindow,
|
||||
footerRef
|
||||
};
|
||||
}
|
||||
return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter;
|
||||
});
|
||||
|
||||
return {
|
||||
getShowLayoutFooter,
|
||||
prefixCls,
|
||||
t,
|
||||
DOC_URL,
|
||||
GITHUB_URL,
|
||||
SITE_URL,
|
||||
openWindow,
|
||||
footerRef,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-layout-footer';
|
||||
@prefix-cls: ~'@{namespace}-layout-footer';
|
||||
|
||||
@normal-color: rgba(0, 0, 0, 0.45);
|
||||
@normal-color: rgba(0, 0, 0, 0.45);
|
||||
|
||||
@hover-color: rgba(0, 0, 0, 0.85);
|
||||
@hover-color: rgba(0, 0, 0, 0.85);
|
||||
|
||||
.@{prefix-cls} {
|
||||
color: @normal-color;
|
||||
text-align: center;
|
||||
|
||||
&__links {
|
||||
margin-bottom: 8px;
|
||||
|
||||
a {
|
||||
.@{prefix-cls} {
|
||||
color: @normal-color;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
color: @hover-color;
|
||||
&__links {
|
||||
margin-bottom: 8px;
|
||||
|
||||
a {
|
||||
color: @normal-color;
|
||||
|
||||
&:hover {
|
||||
color: @hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__github {
|
||||
margin: 0 30px;
|
||||
&__github {
|
||||
margin: 0 30px;
|
||||
|
||||
&:hover {
|
||||
color: @hover-color;
|
||||
}
|
||||
&:hover {
|
||||
color: @hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -7,130 +7,116 @@
|
||||
</div>
|
||||
</template>
|
||||
<template>
|
||||
<MultipleTabs v-if="getShowTabs" style="display:none"/>
|
||||
<MultipleTabs v-if="getShowTabs" style="display: none" />
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, unref, computed, CSSProperties } from 'vue';
|
||||
import { defineComponent, unref, computed, CSSProperties } from 'vue';
|
||||
|
||||
import LayoutHeader from './index.vue';
|
||||
import MultipleTabs from '../tabs/index.vue';
|
||||
import LayoutHeader from './index.vue';
|
||||
import MultipleTabs from '../tabs/index.vue';
|
||||
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useFullContent } from '/@/hooks/web/useFullContent';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '../content/useContentViewHeight';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useFullContent } from '/@/hooks/web/useFullContent';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLayoutHeight } from '../content/useContentViewHeight';
|
||||
|
||||
const HEADER_HEIGHT = 60;
|
||||
const HEADER_HEIGHT = 60;
|
||||
|
||||
const TABS_HEIGHT = 42;
|
||||
export default defineComponent({
|
||||
name: 'LayoutMultipleHeader',
|
||||
components: { LayoutHeader, MultipleTabs },
|
||||
setup() {
|
||||
const { setHeaderHeight } = useLayoutHeight();
|
||||
const { prefixCls } = useDesign('layout-multiple-header');
|
||||
const TABS_HEIGHT = 42;
|
||||
export default defineComponent({
|
||||
name: 'LayoutMultipleHeader',
|
||||
components: { LayoutHeader, MultipleTabs },
|
||||
setup() {
|
||||
const { setHeaderHeight } = useLayoutHeight();
|
||||
const { prefixCls } = useDesign('layout-multiple-header');
|
||||
|
||||
const { getCalcContentWidth, getSplit } = useMenuSetting();
|
||||
const { getIsMobile } = useAppInject();
|
||||
const {
|
||||
getFixed,
|
||||
getShowInsetHeaderRef,
|
||||
getShowFullHeaderRef,
|
||||
getHeaderTheme,
|
||||
getShowHeader,
|
||||
} = useHeaderSetting();
|
||||
const { getCalcContentWidth, getSplit } = useMenuSetting();
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { getFixed, getShowInsetHeaderRef, getShowFullHeaderRef, getHeaderTheme, getShowHeader } = useHeaderSetting();
|
||||
|
||||
const { getFullContent } = useFullContent();
|
||||
const { getFullContent } = useFullContent();
|
||||
|
||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||
const { getShowMultipleTab } = useMultipleTabSetting();
|
||||
|
||||
const getShowTabs = computed(() => {
|
||||
return unref(getShowMultipleTab) && !unref(getFullContent);
|
||||
});
|
||||
const getShowTabs = computed(() => {
|
||||
return unref(getShowMultipleTab) && !unref(getFullContent);
|
||||
});
|
||||
|
||||
const getIsShowPlaceholderDom = computed(() => {
|
||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||
});
|
||||
const getIsShowPlaceholderDom = computed(() => {
|
||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||
});
|
||||
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
const style: CSSProperties = {};
|
||||
if (unref(getFixed)) {
|
||||
style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
|
||||
const getWrapStyle = computed((): CSSProperties => {
|
||||
const style: CSSProperties = {};
|
||||
if (unref(getFixed)) {
|
||||
style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
|
||||
}
|
||||
if (unref(getShowFullHeaderRef)) {
|
||||
style.top = `${HEADER_HEIGHT}px`;
|
||||
}
|
||||
return style;
|
||||
});
|
||||
|
||||
const getIsFixed = computed(() => {
|
||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||
});
|
||||
|
||||
const getPlaceholderDomStyle = computed((): CSSProperties => {
|
||||
let height = 0;
|
||||
if ((unref(getShowFullHeaderRef) || !unref(getSplit)) && unref(getShowHeader) && !unref(getFullContent)) {
|
||||
height += HEADER_HEIGHT;
|
||||
}
|
||||
if (unref(getShowMultipleTab) && !unref(getFullContent)) {
|
||||
height += TABS_HEIGHT;
|
||||
}
|
||||
setHeaderHeight(height);
|
||||
return {
|
||||
height: `${height - 10}px`
|
||||
};
|
||||
});
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [prefixCls, `${prefixCls}--${unref(getHeaderTheme)}`, { [`${prefixCls}--fixed`]: unref(getIsFixed) }];
|
||||
});
|
||||
|
||||
const isOnlyShowContent = computed(() => {
|
||||
return window.isOnlyShowContent == 'Y';
|
||||
});
|
||||
|
||||
return {
|
||||
getClass,
|
||||
prefixCls,
|
||||
getPlaceholderDomStyle,
|
||||
getIsFixed,
|
||||
getWrapStyle,
|
||||
getIsShowPlaceholderDom,
|
||||
getShowTabs,
|
||||
getShowInsetHeaderRef,
|
||||
isOnlyShowContent
|
||||
};
|
||||
}
|
||||
if (unref(getShowFullHeaderRef)) {
|
||||
style.top = `${HEADER_HEIGHT}px`;
|
||||
}
|
||||
return style;
|
||||
});
|
||||
|
||||
const getIsFixed = computed(() => {
|
||||
return unref(getFixed) || unref(getShowFullHeaderRef);
|
||||
});
|
||||
|
||||
const getPlaceholderDomStyle = computed((): CSSProperties => {
|
||||
let height = 0;
|
||||
if (
|
||||
(unref(getShowFullHeaderRef) || !unref(getSplit)) &&
|
||||
unref(getShowHeader) &&
|
||||
!unref(getFullContent)
|
||||
) {
|
||||
height += HEADER_HEIGHT;
|
||||
}
|
||||
if (unref(getShowMultipleTab) && !unref(getFullContent)) {
|
||||
height += TABS_HEIGHT;
|
||||
}
|
||||
setHeaderHeight(height);
|
||||
return {
|
||||
height: `${height - 10}px`,
|
||||
};
|
||||
});
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
`${prefixCls}--${unref(getHeaderTheme)}`,
|
||||
{ [`${prefixCls}--fixed`]: unref(getIsFixed) },
|
||||
];
|
||||
});
|
||||
|
||||
const isOnlyShowContent = computed(() => {
|
||||
return window.isOnlyShowContent=='Y';
|
||||
});
|
||||
|
||||
return {
|
||||
getClass,
|
||||
prefixCls,
|
||||
getPlaceholderDomStyle,
|
||||
getIsFixed,
|
||||
getWrapStyle,
|
||||
getIsShowPlaceholderDom,
|
||||
getShowTabs,
|
||||
getShowInsetHeaderRef,
|
||||
isOnlyShowContent
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-layout-multiple-header';
|
||||
@prefix-cls: ~'@{namespace}-layout-multiple-header';
|
||||
|
||||
.@{prefix-cls} {
|
||||
transition: width 0.2s;
|
||||
flex: 0 0 auto;
|
||||
.@{prefix-cls} {
|
||||
transition: width 0.2s;
|
||||
flex: 0 0 auto;
|
||||
|
||||
&--dark {
|
||||
margin-left: -1px;
|
||||
&--dark {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: @multiple-tab-fixed-z-index;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: @multiple-tab-fixed-z-index;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,204 +1,204 @@
|
||||
<template>
|
||||
<div :class="[prefixCls, `${prefixCls}--${theme}`]">
|
||||
<a-breadcrumb :routes="routes">
|
||||
<template #itemRender="{ route, routes: routesMatched, paths }">
|
||||
<Icon :icon="getIcon(route)" v-if="getShowBreadCrumbIcon && getIcon(route)" />
|
||||
<span v-if="!hasRedirect(routesMatched, route)">
|
||||
{{ t(route.name || route.meta.title) }}
|
||||
</span>
|
||||
<router-link v-else to="" @click="handleClick(route, paths, $event)">
|
||||
{{ t(route.name || route.meta.title) }}
|
||||
</router-link>
|
||||
</template>
|
||||
</a-breadcrumb>
|
||||
</div>
|
||||
<div :class="[prefixCls, `${prefixCls}--${theme}`]">
|
||||
<a-breadcrumb :routes="routes">
|
||||
<template #itemRender="{ route, routes: routesMatched, paths }">
|
||||
<Icon :icon="getIcon(route)" v-if="getShowBreadCrumbIcon && getIcon(route)" />
|
||||
<span v-if="!hasRedirect(routesMatched, route)">
|
||||
{{ t(route.name || route.meta.title) }}
|
||||
</span>
|
||||
<router-link v-else to="" @click="handleClick(route, paths, $event)">
|
||||
{{ t(route.name || route.meta.title) }}
|
||||
</router-link>
|
||||
</template>
|
||||
</a-breadcrumb>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { RouteLocationMatched } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
import type { Menu } from '/@/router/types';
|
||||
import type { RouteLocationMatched } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
import type { Menu } from '/@/router/types';
|
||||
|
||||
import { defineComponent, ref, watchEffect } from 'vue';
|
||||
import { defineComponent, ref, watchEffect } from 'vue';
|
||||
|
||||
import { Breadcrumb } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { Breadcrumb } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isString } from '/@/utils/is';
|
||||
import { filter } from '/@/utils/helper/treeHelper';
|
||||
import { getMenus } from '/@/router/menus';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isString } from '/@/utils/is';
|
||||
import { filter } from '/@/utils/helper/treeHelper';
|
||||
import { getMenus } from '/@/router/menus';
|
||||
|
||||
import { REDIRECT_NAME } from '/@/router/constant';
|
||||
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||
import { REDIRECT_NAME } from '/@/router/constant';
|
||||
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutBreadcrumb',
|
||||
components: { Icon, [Breadcrumb.name]: Breadcrumb },
|
||||
props: {
|
||||
theme: propTypes.oneOf(['dark', 'light']),
|
||||
},
|
||||
setup() {
|
||||
const routes = ref<RouteLocationMatched[]>([]);
|
||||
const { currentRoute } = useRouter();
|
||||
const { prefixCls } = useDesign('layout-breadcrumb');
|
||||
const { getShowBreadCrumbIcon } = useRootSetting();
|
||||
const go = useGo();
|
||||
export default defineComponent({
|
||||
name: 'LayoutBreadcrumb',
|
||||
components: { Icon, [Breadcrumb.name]: Breadcrumb },
|
||||
props: {
|
||||
theme: propTypes.oneOf(['dark', 'light'])
|
||||
},
|
||||
setup() {
|
||||
const routes = ref<RouteLocationMatched[]>([]);
|
||||
const { currentRoute } = useRouter();
|
||||
const { prefixCls } = useDesign('layout-breadcrumb');
|
||||
const { getShowBreadCrumbIcon } = useRootSetting();
|
||||
const go = useGo();
|
||||
|
||||
const { t } = useI18n();
|
||||
watchEffect(async () => {
|
||||
if (currentRoute.value.name === REDIRECT_NAME) return;
|
||||
const menus = await getMenus();
|
||||
const { t } = useI18n();
|
||||
watchEffect(async () => {
|
||||
if (currentRoute.value.name === REDIRECT_NAME) return;
|
||||
const menus = await getMenus();
|
||||
|
||||
const routeMatched = currentRoute.value.matched;
|
||||
const cur = routeMatched?.[routeMatched.length - 1];
|
||||
let path = currentRoute.value.path;
|
||||
const routeMatched = currentRoute.value.matched;
|
||||
const cur = routeMatched?.[routeMatched.length - 1];
|
||||
let path = currentRoute.value.path;
|
||||
|
||||
if (cur && cur?.meta?.currentActiveMenu) {
|
||||
path = cur.meta.currentActiveMenu as string;
|
||||
}
|
||||
if (cur && cur?.meta?.currentActiveMenu) {
|
||||
path = cur.meta.currentActiveMenu as string;
|
||||
}
|
||||
|
||||
const parent = getAllParentPath(menus, path);
|
||||
const filterMenus = menus.filter((item) => item.path === parent[0]);
|
||||
const matched = getMatched(filterMenus, parent) as any;
|
||||
const parent = getAllParentPath(menus, path);
|
||||
const filterMenus = menus.filter((item) => item.path === parent[0]);
|
||||
const matched = getMatched(filterMenus, parent) as any;
|
||||
|
||||
if (!matched || matched.length === 0) return;
|
||||
if (!matched || matched.length === 0) return;
|
||||
|
||||
const breadcrumbList = filterItem(matched);
|
||||
const breadcrumbList = filterItem(matched);
|
||||
|
||||
if (currentRoute.value.meta?.currentActiveMenu) {
|
||||
breadcrumbList.push({
|
||||
...currentRoute.value,
|
||||
name: currentRoute.value.meta?.title || currentRoute.value.name,
|
||||
} as unknown as RouteLocationMatched);
|
||||
}
|
||||
routes.value = breadcrumbList;
|
||||
});
|
||||
|
||||
function getMatched(menus: Menu[], parent: string[]) {
|
||||
const metched: Menu[] = [];
|
||||
menus.forEach((item) => {
|
||||
if (parent.includes(item.path)) {
|
||||
metched.push({
|
||||
...item,
|
||||
name: item.meta?.title || item.name,
|
||||
if (currentRoute.value.meta?.currentActiveMenu) {
|
||||
breadcrumbList.push({
|
||||
...currentRoute.value,
|
||||
name: currentRoute.value.meta?.title || currentRoute.value.name
|
||||
} as unknown as RouteLocationMatched);
|
||||
}
|
||||
routes.value = breadcrumbList;
|
||||
});
|
||||
}
|
||||
if (item.children?.length) {
|
||||
metched.push(...getMatched(item.children, parent));
|
||||
}
|
||||
});
|
||||
return metched;
|
||||
}
|
||||
|
||||
function filterItem(list: RouteLocationMatched[]) {
|
||||
return filter(list, (item) => {
|
||||
const { meta, name } = item;
|
||||
if (!meta) {
|
||||
return !!name;
|
||||
}
|
||||
const { title, hideBreadcrumb, hideMenu } = meta;
|
||||
if (!title || hideBreadcrumb || hideMenu) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).filter((item) => !item.meta?.hideBreadcrumb);
|
||||
}
|
||||
function getMatched(menus: Menu[], parent: string[]) {
|
||||
const metched: Menu[] = [];
|
||||
menus.forEach((item) => {
|
||||
if (parent.includes(item.path)) {
|
||||
metched.push({
|
||||
...item,
|
||||
name: item.meta?.title || item.name
|
||||
});
|
||||
}
|
||||
if (item.children?.length) {
|
||||
metched.push(...getMatched(item.children, parent));
|
||||
}
|
||||
});
|
||||
return metched;
|
||||
}
|
||||
|
||||
function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
|
||||
e?.preventDefault();
|
||||
const { children, redirect, meta } = route;
|
||||
function filterItem(list: RouteLocationMatched[]) {
|
||||
return filter(list, (item) => {
|
||||
const { meta, name } = item;
|
||||
if (!meta) {
|
||||
return !!name;
|
||||
}
|
||||
const { title, hideBreadcrumb, hideMenu } = meta;
|
||||
if (!title || hideBreadcrumb || hideMenu) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).filter((item) => !item.meta?.hideBreadcrumb);
|
||||
}
|
||||
|
||||
if (children?.length && !redirect) {
|
||||
e?.stopPropagation();
|
||||
return;
|
||||
function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
|
||||
e?.preventDefault();
|
||||
const { children, redirect, meta } = route;
|
||||
|
||||
if (children?.length && !redirect) {
|
||||
e?.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (meta?.carryParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (redirect && isString(redirect)) {
|
||||
go(redirect);
|
||||
} else {
|
||||
let goPath = '';
|
||||
if (paths.length === 1) {
|
||||
goPath = paths[0];
|
||||
} else {
|
||||
const ps = paths.slice(1);
|
||||
const lastPath = ps.pop() || '';
|
||||
goPath = `${lastPath}`;
|
||||
}
|
||||
goPath = /^\//.test(goPath) ? goPath : `/${goPath}`;
|
||||
go(goPath);
|
||||
}
|
||||
}
|
||||
|
||||
function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
|
||||
return routes.indexOf(route) !== routes.length - 1;
|
||||
}
|
||||
|
||||
function getIcon(route) {
|
||||
return route.icon || route.meta?.icon;
|
||||
}
|
||||
|
||||
return { routes, t, prefixCls, getIcon, getShowBreadCrumbIcon, handleClick, hasRedirect };
|
||||
}
|
||||
if (meta?.carryParam) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (redirect && isString(redirect)) {
|
||||
go(redirect);
|
||||
} else {
|
||||
let goPath = '';
|
||||
if (paths.length === 1) {
|
||||
goPath = paths[0];
|
||||
} else {
|
||||
const ps = paths.slice(1);
|
||||
const lastPath = ps.pop() || '';
|
||||
goPath = `${lastPath}`;
|
||||
}
|
||||
goPath = /^\//.test(goPath) ? goPath : `/${goPath}`;
|
||||
go(goPath);
|
||||
}
|
||||
}
|
||||
|
||||
function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
|
||||
return routes.indexOf(route) !== routes.length - 1;
|
||||
}
|
||||
|
||||
function getIcon(route) {
|
||||
return route.icon || route.meta?.icon;
|
||||
}
|
||||
|
||||
return { routes, t, prefixCls, getIcon, getShowBreadCrumbIcon, handleClick, hasRedirect };
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-layout-breadcrumb';
|
||||
@prefix-cls: ~'@{namespace}-layout-breadcrumb';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
padding: 0 8px;
|
||||
align-items: center;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
padding: 0 8px;
|
||||
align-items: center;
|
||||
|
||||
.ant-breadcrumb-link {
|
||||
.anticon {
|
||||
margin-right: 4px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&--light {
|
||||
.ant-breadcrumb-link {
|
||||
color: @breadcrumb-item-normal-color;
|
||||
|
||||
a {
|
||||
color: rgb(0 0 0 / 65%);
|
||||
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
.ant-breadcrumb-link {
|
||||
.anticon {
|
||||
margin-right: 4px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-breadcrumb-separator {
|
||||
color: @breadcrumb-item-normal-color;
|
||||
}
|
||||
}
|
||||
&--light {
|
||||
.ant-breadcrumb-link {
|
||||
color: @breadcrumb-item-normal-color;
|
||||
|
||||
&--dark {
|
||||
.ant-breadcrumb-link {
|
||||
color: rgb(255 255 255 / 60%);
|
||||
a {
|
||||
color: rgb(0 0 0 / 65%);
|
||||
|
||||
a {
|
||||
color: rgb(255 255 255 / 80%);
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @white;
|
||||
}
|
||||
.ant-breadcrumb-separator {
|
||||
color: @breadcrumb-item-normal-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-breadcrumb-separator,
|
||||
.anticon {
|
||||
color: rgb(255 255 255 / 80%);
|
||||
}
|
||||
&--dark {
|
||||
.ant-breadcrumb-link {
|
||||
color: rgb(255 255 255 / 60%);
|
||||
|
||||
a {
|
||||
color: rgb(255 255 255 / 80%);
|
||||
|
||||
&:hover {
|
||||
color: @white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-breadcrumb-separator,
|
||||
.anticon {
|
||||
color: rgb(255 255 255 / 80%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,48 +1,43 @@
|
||||
<template>
|
||||
<Tooltip
|
||||
:title="t('layout.header.tooltipErrorLog')"
|
||||
placement="bottom"
|
||||
:mouseEnterDelay="0.5"
|
||||
@click="handleToErrorList"
|
||||
>
|
||||
<Badge :count="getCount" :offset="[0, 10]" :overflowCount="99">
|
||||
<Icon icon="ion:bug-outline" />
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('layout.header.tooltipErrorLog')" placement="bottom" :mouseEnterDelay="0.5" @click="handleToErrorList">
|
||||
<Badge :count="getCount" :offset="[0, 10]" :overflowCount="99">
|
||||
<Icon icon="ion:bug-outline" />
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { Tooltip, Badge } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { Tooltip, Badge } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useErrorLogStore } from '/@/store/modules/errorLog';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useErrorLogStore } from '/@/store/modules/errorLog';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ErrorAction',
|
||||
components: { Icon, Tooltip, Badge },
|
||||
export default defineComponent({
|
||||
name: 'ErrorAction',
|
||||
components: { Icon, Tooltip, Badge },
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { push } = useRouter();
|
||||
const errorLogStore = useErrorLogStore();
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { push } = useRouter();
|
||||
const errorLogStore = useErrorLogStore();
|
||||
|
||||
const getCount = computed(() => errorLogStore.getErrorLogListCount);
|
||||
const getCount = computed(() => errorLogStore.getErrorLogListCount);
|
||||
|
||||
function handleToErrorList() {
|
||||
push(PageEnum.ERROR_LOG_PAGE).then(() => {
|
||||
errorLogStore.setErrorLogListCount(0);
|
||||
});
|
||||
}
|
||||
function handleToErrorList() {
|
||||
push(PageEnum.ERROR_LOG_PAGE).then(() => {
|
||||
errorLogStore.setErrorLogListCount(0);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
getCount,
|
||||
handleToErrorList,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
t,
|
||||
getCount,
|
||||
handleToErrorList
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
<template>
|
||||
<Tooltip :title="getTitle" placement="bottom" :mouseEnterDelay="0.5">
|
||||
<span @click="toggle">
|
||||
<Icon icon="material-symbols:fit-screen-rounded" size="26" v-if="!isFullscreen" />
|
||||
<Icon icon="mingcute:fullscreen-exit-fill" size="24" v-else />
|
||||
</span>
|
||||
</Tooltip>
|
||||
<Tooltip :title="getTitle" placement="bottom" :mouseEnterDelay="0.5">
|
||||
<span @click="toggle">
|
||||
<Icon icon="material-symbols:fit-screen-rounded" size="26" v-if="!isFullscreen" />
|
||||
<Icon icon="mingcute:fullscreen-exit-fill" size="24" v-else />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FullScreen',
|
||||
components: { Icon, Tooltip },
|
||||
export default defineComponent({
|
||||
name: 'FullScreen',
|
||||
components: { Icon, Tooltip },
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { toggle, isFullscreen } = useFullscreen();
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { toggle, isFullscreen } = useFullscreen();
|
||||
|
||||
const getTitle = computed(() => {
|
||||
return unref(isFullscreen) ? t('退出全屏') : t('全屏');
|
||||
});
|
||||
const getTitle = computed(() => {
|
||||
return unref(isFullscreen) ? t('退出全屏') : t('全屏');
|
||||
});
|
||||
|
||||
return {
|
||||
getTitle,
|
||||
isFullscreen,
|
||||
toggle,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
getTitle,
|
||||
isFullscreen,
|
||||
toggle
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,166 +1,148 @@
|
||||
<template>
|
||||
<AMenu
|
||||
v-if="getShowContent && getShowBread"
|
||||
:selectedKeys="cur"
|
||||
mode="horizontal"
|
||||
:class="[prefixCls, `${prefixCls}--${theme}`]"
|
||||
>
|
||||
<MenuItem v-for="item in system" @click="changeSystem(item.id)" :key="item.id" class="item-system">
|
||||
{{ item.name }}
|
||||
</MenuItem>
|
||||
</AMenu>
|
||||
<Tooltip title="子系统" :mouseEnterDelay="0.5">
|
||||
<Dropdown
|
||||
v-if="getShowTopMenu && !getIsMobile"
|
||||
placement="bottom"
|
||||
:trigger="['click']"
|
||||
:dropMenuList="system"
|
||||
:selectedKeys="cur"
|
||||
@menu-event="handleMenuEvent"
|
||||
overlayClassName="app-locale-picker-overlay"
|
||||
>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item :key="item.event" v-for="item in system">
|
||||
<Icon
|
||||
:icon="item.icon || 'ant-design:appstore-outlined'"
|
||||
color="#DEDFFF"
|
||||
size="26"
|
||||
style="vertical-align: -7px"
|
||||
/>
|
||||
{{ item.text }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<span class="cursor-pointer flex items-center p-2">
|
||||
<Icon icon="icon-park-outline:system" size="22" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
</Tooltip>
|
||||
<AMenu v-if="getShowContent && getShowBread" :selectedKeys="cur" mode="horizontal" :class="[prefixCls, `${prefixCls}--${theme}`]">
|
||||
<MenuItem v-for="item in system" @click="changeSystem(item.id)" :key="item.id" class="item-system">
|
||||
{{ item.name }}
|
||||
</MenuItem>
|
||||
</AMenu>
|
||||
<Tooltip title="子系统" :mouseEnterDelay="0.5">
|
||||
<Dropdown v-if="getShowTopMenu && !getIsMobile" placement="bottom" :trigger="['click']" :dropMenuList="system" :selectedKeys="cur" @menu-event="handleMenuEvent" overlayClassName="app-locale-picker-overlay">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item :key="item.event" v-for="item in system">
|
||||
<Icon :icon="item.icon || 'ant-design:appstore-outlined'" color="#DEDFFF" size="26" style="vertical-align: -7px" />
|
||||
{{ item.text }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<span class="cursor-pointer flex items-center p-2">
|
||||
<Icon icon="icon-park-outline:system" size="22" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, watch } from 'vue';
|
||||
import type { MenuTheme } from 'ant-design-vue';
|
||||
import { Breadcrumb, Tooltip, Menu } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
import type { DropMenu } from '/@/components/Dropdown';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { usePermissionStore } from '/@/store/modules/permission';
|
||||
export default defineComponent({
|
||||
name: 'LayoutBreadcrumb',
|
||||
components: {
|
||||
Icon,
|
||||
[Breadcrumb.name]: Breadcrumb,
|
||||
Tooltip,
|
||||
AMenu: Menu,
|
||||
MenuItem: Menu.Item,
|
||||
Dropdown,
|
||||
},
|
||||
props: {
|
||||
theme: propTypes.oneOf(['dark', 'light']),
|
||||
},
|
||||
setup() {
|
||||
const permissionStore = usePermissionStore();
|
||||
const { subSystemList } = storeToRefs(permissionStore);
|
||||
const Mtheme = ref<MenuTheme>('dark');
|
||||
const cur = ref<string[]>([permissionStore.getSubSystem]);
|
||||
|
||||
const { prefixCls } = useDesign('layout-breadcrumb');
|
||||
const { getIsMobile } = useAppInject();
|
||||
const system = ref<any[]>([]);
|
||||
const { t } = useI18n();
|
||||
const { getShowTopMenu } = useMenuSetting();
|
||||
const { getShowContent, getShowBread } = useHeaderSetting();
|
||||
watch(
|
||||
() => subSystemList.value,
|
||||
(v) => {
|
||||
system.value = v;
|
||||
import { defineComponent, onMounted, ref, watch } from 'vue';
|
||||
import type { MenuTheme } from 'ant-design-vue';
|
||||
import { Breadcrumb, Tooltip, Menu } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
import type { DropMenu } from '/@/components/Dropdown';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { usePermissionStore } from '/@/store/modules/permission';
|
||||
export default defineComponent({
|
||||
name: 'LayoutBreadcrumb',
|
||||
components: {
|
||||
Icon,
|
||||
[Breadcrumb.name]: Breadcrumb,
|
||||
Tooltip,
|
||||
AMenu: Menu,
|
||||
MenuItem: Menu.Item,
|
||||
Dropdown
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
onMounted(async () => {
|
||||
await permissionStore.changeSubsystem(getShowTopMenu.value, getIsMobile.value);
|
||||
system.value = permissionStore.getSubSysList;
|
||||
if(system.value.length>0){
|
||||
changeSystem(system.value[0].id);
|
||||
}
|
||||
});
|
||||
props: {
|
||||
theme: propTypes.oneOf(['dark', 'light'])
|
||||
},
|
||||
setup() {
|
||||
const permissionStore = usePermissionStore();
|
||||
const { subSystemList } = storeToRefs(permissionStore);
|
||||
const Mtheme = ref<MenuTheme>('dark');
|
||||
const cur = ref<string[]>([permissionStore.getSubSystem]);
|
||||
|
||||
//切换系统
|
||||
function changeSystem(systemId: string) {
|
||||
permissionStore.setSubSystem(systemId);
|
||||
cur.value = [systemId];
|
||||
}
|
||||
const { prefixCls } = useDesign('layout-breadcrumb');
|
||||
const { getIsMobile } = useAppInject();
|
||||
const system = ref<any[]>([]);
|
||||
const { t } = useI18n();
|
||||
const { getShowTopMenu } = useMenuSetting();
|
||||
const { getShowContent, getShowBread } = useHeaderSetting();
|
||||
watch(
|
||||
() => subSystemList.value,
|
||||
(v) => {
|
||||
system.value = v;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
onMounted(async () => {
|
||||
await permissionStore.changeSubsystem(getShowTopMenu.value, getIsMobile.value);
|
||||
system.value = permissionStore.getSubSysList;
|
||||
if (system.value.length > 0) {
|
||||
changeSystem(system.value[0].id);
|
||||
}
|
||||
});
|
||||
|
||||
function handleMenuEvent(menu: DropMenu) {
|
||||
if (cur.value[0] === menu.event) {
|
||||
return;
|
||||
//切换系统
|
||||
function changeSystem(systemId: string) {
|
||||
permissionStore.setSubSystem(systemId);
|
||||
cur.value = [systemId];
|
||||
}
|
||||
|
||||
function handleMenuEvent(menu: DropMenu) {
|
||||
if (cur.value[0] === menu.event) {
|
||||
return;
|
||||
}
|
||||
cur.value = [menu.event as string];
|
||||
|
||||
permissionStore.setSubSystem(menu.event as string);
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
cur,
|
||||
changeSystem,
|
||||
system,
|
||||
Mtheme,
|
||||
getShowContent,
|
||||
getShowTopMenu,
|
||||
getShowBread,
|
||||
getIsMobile,
|
||||
handleMenuEvent
|
||||
};
|
||||
}
|
||||
cur.value = [menu.event as string];
|
||||
|
||||
permissionStore.setSubSystem(menu.event as string);
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
cur,
|
||||
changeSystem,
|
||||
system,
|
||||
Mtheme,
|
||||
getShowContent,
|
||||
getShowTopMenu,
|
||||
getShowBread,
|
||||
getIsMobile,
|
||||
handleMenuEvent,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-layout-breadcrumb';
|
||||
@prefix-cls: ~'@{namespace}-layout-breadcrumb';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&.ant-menu {
|
||||
background: none;
|
||||
border: 0;
|
||||
.@{prefix-cls} {
|
||||
&.ant-menu {
|
||||
background: none;
|
||||
border: 0;
|
||||
|
||||
.ant-menu-item {
|
||||
padding: 0 10px;
|
||||
.ant-menu-item {
|
||||
padding: 0 10px;
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ant-menu-item-icon {
|
||||
background: rgb(171 170 205 / 30%);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgb(171 170 205 / 30%);
|
||||
margin: 0 5px;
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
background: none;
|
||||
|
||||
.ant-menu-item-icon {
|
||||
border: 1px solid rgb(222 223 255);
|
||||
}
|
||||
|
||||
&::after {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-icon {
|
||||
background: rgb(171 170 205 / 30%);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgb(171 170 205 / 30%);
|
||||
margin: 0 5px;
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
background: none;
|
||||
|
||||
.ant-menu-item-icon {
|
||||
border: 1px solid rgb(222 223 255);
|
||||
}
|
||||
|
||||
&::after {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,125 +1,119 @@
|
||||
<template>
|
||||
<BasicModal
|
||||
:footer="null"
|
||||
:title="t('锁定屏幕')"
|
||||
v-bind="$attrs"
|
||||
:class="prefixCls"
|
||||
@register="register"
|
||||
>
|
||||
<div :class="`${prefixCls}__entry`">
|
||||
<div :class="`${prefixCls}__header`">
|
||||
<img :src="avatar" :class="`${prefixCls}__header-img`" />
|
||||
<p :class="`${prefixCls}__header-name`">
|
||||
{{ getRealName }}
|
||||
</p>
|
||||
</div>
|
||||
<BasicModal :footer="null" :title="t('锁定屏幕')" v-bind="$attrs" :class="prefixCls" @register="register">
|
||||
<div :class="`${prefixCls}__entry`">
|
||||
<div :class="`${prefixCls}__header`">
|
||||
<img :src="avatar" :class="`${prefixCls}__header-img`" />
|
||||
<p :class="`${prefixCls}__header-name`">
|
||||
{{ getRealName }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- <BasicForm @register="registerForm" /> -->
|
||||
<!-- <BasicForm @register="registerForm" /> -->
|
||||
|
||||
<div :class="`${prefixCls}__footer`">
|
||||
<a-button type="primary" block class="mt-2" @click="handleLock">
|
||||
{{ t('锁定') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</BasicModal>
|
||||
<div :class="`${prefixCls}__footer`">
|
||||
<a-button type="primary" block class="mt-2" @click="handleLock">
|
||||
{{ t('锁定') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal/index';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal/index';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useLockStore } from '/@/store/modules/lock';
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
export default defineComponent({
|
||||
name: 'LockModal',
|
||||
components: { BasicModal, BasicForm },
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useLockStore } from '/@/store/modules/lock';
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
export default defineComponent({
|
||||
name: 'LockModal',
|
||||
components: { BasicModal, BasicForm },
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign('header-lock-modal');
|
||||
const userStore = useUserStore();
|
||||
const lockStore = useLockStore();
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign('header-lock-modal');
|
||||
const userStore = useUserStore();
|
||||
const lockStore = useLockStore();
|
||||
|
||||
const getRealName = computed(() => userStore.getUserInfo?.name);
|
||||
const [register, { closeModal }] = useModalInner();
|
||||
const getRealName = computed(() => userStore.getUserInfo?.name);
|
||||
const [register, { closeModal }] = useModalInner();
|
||||
|
||||
const [registerForm, { validateFields, resetFields }] = useForm({
|
||||
showActionButtonGroup: false,
|
||||
schemas: [
|
||||
{
|
||||
field: 'password',
|
||||
label: t('锁屏密码'),
|
||||
colProps: {
|
||||
span: 24,
|
||||
},
|
||||
component: 'InputPassword',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const [registerForm, { validateFields, resetFields }] = useForm({
|
||||
showActionButtonGroup: false,
|
||||
schemas: [
|
||||
{
|
||||
field: 'password',
|
||||
label: t('锁屏密码'),
|
||||
colProps: {
|
||||
span: 24
|
||||
},
|
||||
component: 'InputPassword',
|
||||
required: true
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
async function handleLock() {
|
||||
// const values = (await validateFields()) as any;
|
||||
// const password: string | undefined = values.password;
|
||||
closeModal();
|
||||
async function handleLock() {
|
||||
// const values = (await validateFields()) as any;
|
||||
// const password: string | undefined = values.password;
|
||||
closeModal();
|
||||
|
||||
lockStore.setLockInfo({
|
||||
isLock: true,
|
||||
});
|
||||
// await resetFields();
|
||||
}
|
||||
lockStore.setLockInfo({
|
||||
isLock: true
|
||||
});
|
||||
// await resetFields();
|
||||
}
|
||||
|
||||
const avatar = computed(() => {
|
||||
const { avatar } = userStore.getUserInfo;
|
||||
return avatar || headerImg;
|
||||
});
|
||||
const avatar = computed(() => {
|
||||
const { avatar } = userStore.getUserInfo;
|
||||
return avatar || headerImg;
|
||||
});
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
getRealName,
|
||||
register,
|
||||
registerForm,
|
||||
handleLock,
|
||||
avatar,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
getRealName,
|
||||
register,
|
||||
registerForm,
|
||||
handleLock,
|
||||
avatar
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-header-lock-modal';
|
||||
@prefix-cls: ~'@{namespace}-header-lock-modal';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&__entry {
|
||||
position: relative;
|
||||
//height: 240px;
|
||||
padding: 130px 30px 30px;
|
||||
border-radius: 10px;
|
||||
.@{prefix-cls} {
|
||||
&__entry {
|
||||
position: relative;
|
||||
//height: 240px;
|
||||
padding: 130px 30px 30px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - 45px);
|
||||
width: auto;
|
||||
text-align: center;
|
||||
|
||||
&-img {
|
||||
width: 70px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&-name {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(50% - 45px);
|
||||
width: auto;
|
||||
text-align: center;
|
||||
|
||||
&-img {
|
||||
width: 70px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&-name {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,189 +1,181 @@
|
||||
<template>
|
||||
<a-list :class="prefixCls" bordered :pagination="getPagination">
|
||||
<template v-for="item in getData" :key="item.id">
|
||||
<a-list-item class="list-item">
|
||||
<a-list-item-meta>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
<a-typography-paragraph
|
||||
@click="handleTitleClick(item)"
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:style="{ cursor: isTitleClickable ? 'pointer' : '' }"
|
||||
:delete="!!item.titleDelete"
|
||||
:ellipsis="
|
||||
$props.titleRows && $props.titleRows > 0
|
||||
? { rows: $props.titleRows, tooltip: !!item.title }
|
||||
: false
|
||||
"
|
||||
:content="item.title"
|
||||
/>
|
||||
<div class="extra" v-if="item.extra">
|
||||
<a-tag class="tag" :color="item.color">
|
||||
{{ item.extra }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-list :class="prefixCls" bordered :pagination="getPagination">
|
||||
<template v-for="item in getData" :key="item.id">
|
||||
<a-list-item class="list-item">
|
||||
<a-list-item-meta>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
<a-typography-paragraph
|
||||
@click="handleTitleClick(item)"
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:style="{ cursor: isTitleClickable ? 'pointer' : '' }"
|
||||
:delete="!!item.titleDelete"
|
||||
:ellipsis="$props.titleRows && $props.titleRows > 0 ? { rows: $props.titleRows, tooltip: !!item.title } : false"
|
||||
:content="item.title"
|
||||
/>
|
||||
<div class="extra" v-if="item.extra">
|
||||
<a-tag class="tag" :color="item.color">
|
||||
{{ item.extra }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #avatar>
|
||||
<a-avatar v-if="item.avatar" class="avatar" :src="item.avatar" />
|
||||
<span v-else> {{ item.avatar }}</span>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<a-avatar v-if="item.avatar" class="avatar" :src="item.avatar" />
|
||||
<span v-else> {{ item.avatar }}</span>
|
||||
</template>
|
||||
|
||||
<template #description>
|
||||
<div>
|
||||
<div class="description" v-if="item.description">
|
||||
<a-typography-paragraph
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:ellipsis="
|
||||
$props.descRows && $props.descRows > 0
|
||||
? { rows: $props.descRows, tooltip: !!item.description }
|
||||
: false
|
||||
"
|
||||
:content="item.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="datetime">
|
||||
{{ item.datetime }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
<template #description>
|
||||
<div>
|
||||
<div class="description" v-if="item.description">
|
||||
<a-typography-paragraph
|
||||
style="width: 100%; margin-bottom: 0 !important"
|
||||
:ellipsis="$props.descRows && $props.descRows > 0 ? { rows: $props.descRows, tooltip: !!item.description } : false"
|
||||
:content="item.description"
|
||||
/>
|
||||
</div>
|
||||
<div class="datetime">
|
||||
{{ item.datetime }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType, ref, watch, unref } from 'vue';
|
||||
import { ListItem } from './data';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { List, Avatar, Tag, Typography } from 'ant-design-vue';
|
||||
import { isNumber } from '/@/utils/is';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
[Avatar.name]: Avatar,
|
||||
[List.name]: List,
|
||||
[List.Item.name]: List.Item,
|
||||
AListItemMeta: List.Item.Meta,
|
||||
ATypographyParagraph: Typography.Paragraph,
|
||||
[Tag.name]: Tag,
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array as PropType<ListItem[]>,
|
||||
default: () => [],
|
||||
},
|
||||
pageSize: {
|
||||
type: [Boolean, Number] as PropType<Boolean | Number>,
|
||||
default: 5,
|
||||
},
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
titleRows: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
descRows: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
onTitleClick: {
|
||||
type: Function as PropType<(Recordable) => void>,
|
||||
},
|
||||
},
|
||||
emits: ['update:currentPage'],
|
||||
setup(props, { emit }) {
|
||||
const { prefixCls } = useDesign('header-notify-list');
|
||||
const current = ref(props.currentPage || 1);
|
||||
const getData = computed(() => {
|
||||
const { pageSize, list } = props;
|
||||
if (pageSize === false) return [];
|
||||
let size = isNumber(pageSize) ? pageSize : 5;
|
||||
return list.slice(size * (unref(current) - 1), size * unref(current));
|
||||
});
|
||||
watch(
|
||||
() => props.currentPage,
|
||||
(v) => {
|
||||
current.value = v;
|
||||
import { computed, defineComponent, PropType, ref, watch, unref } from 'vue';
|
||||
import { ListItem } from './data';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { List, Avatar, Tag, Typography } from 'ant-design-vue';
|
||||
import { isNumber } from '/@/utils/is';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
[Avatar.name]: Avatar,
|
||||
[List.name]: List,
|
||||
[List.Item.name]: List.Item,
|
||||
AListItemMeta: List.Item.Meta,
|
||||
ATypographyParagraph: Typography.Paragraph,
|
||||
[Tag.name]: Tag
|
||||
},
|
||||
);
|
||||
const isTitleClickable = computed(() => !!props.onTitleClick);
|
||||
const getPagination = computed(() => {
|
||||
const { list, pageSize } = props;
|
||||
if (pageSize > 0 && list && list.length > pageSize) {
|
||||
return {
|
||||
total: list.length,
|
||||
pageSize,
|
||||
//size: 'small',
|
||||
current: unref(current),
|
||||
onChange(page) {
|
||||
current.value = page;
|
||||
emit('update:currentPage', page);
|
||||
props: {
|
||||
list: {
|
||||
type: Array as PropType<ListItem[]>,
|
||||
default: () => []
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
pageSize: {
|
||||
type: [Boolean, Number] as PropType<Boolean | Number>,
|
||||
default: 5
|
||||
},
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
titleRows: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
descRows: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
onTitleClick: {
|
||||
type: Function as PropType<(Recordable) => void>
|
||||
}
|
||||
},
|
||||
emits: ['update:currentPage'],
|
||||
setup(props, { emit }) {
|
||||
const { prefixCls } = useDesign('header-notify-list');
|
||||
const current = ref(props.currentPage || 1);
|
||||
const getData = computed(() => {
|
||||
const { pageSize, list } = props;
|
||||
if (pageSize === false) return [];
|
||||
let size = isNumber(pageSize) ? pageSize : 5;
|
||||
return list.slice(size * (unref(current) - 1), size * unref(current));
|
||||
});
|
||||
watch(
|
||||
() => props.currentPage,
|
||||
(v) => {
|
||||
current.value = v;
|
||||
}
|
||||
);
|
||||
const isTitleClickable = computed(() => !!props.onTitleClick);
|
||||
const getPagination = computed(() => {
|
||||
const { list, pageSize } = props;
|
||||
if (pageSize > 0 && list && list.length > pageSize) {
|
||||
return {
|
||||
total: list.length,
|
||||
pageSize,
|
||||
//size: 'small',
|
||||
current: unref(current),
|
||||
onChange(page) {
|
||||
current.value = page;
|
||||
emit('update:currentPage', page);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
function handleTitleClick(item: ListItem) {
|
||||
props.onTitleClick && props.onTitleClick(item);
|
||||
}
|
||||
|
||||
return { prefixCls, getPagination, getData, handleTitleClick, isTitleClickable };
|
||||
}
|
||||
});
|
||||
|
||||
function handleTitleClick(item: ListItem) {
|
||||
props.onTitleClick && props.onTitleClick(item);
|
||||
}
|
||||
|
||||
return { prefixCls, getPagination, getData, handleTitleClick, isTitleClickable };
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-header-notify-list';
|
||||
@prefix-cls: ~'@{namespace}-header-notify-list';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
.@{prefix-cls} {
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep(.ant-pagination-disabled) {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
&-item {
|
||||
padding: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
.title {
|
||||
margin-bottom: 8px;
|
||||
font-weight: normal;
|
||||
|
||||
.extra {
|
||||
float: right;
|
||||
margin-top: -1.5px;
|
||||
margin-right: 0;
|
||||
font-weight: normal;
|
||||
|
||||
.tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.datetime {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.ant-pagination-disabled) {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
&-item {
|
||||
padding: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
.title {
|
||||
margin-bottom: 8px;
|
||||
font-weight: normal;
|
||||
|
||||
.extra {
|
||||
float: right;
|
||||
margin-top: -1.5px;
|
||||
margin-right: 0;
|
||||
font-weight: normal;
|
||||
|
||||
.tag {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.datetime {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,519 +1,502 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<Popover title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`">
|
||||
<Badge :count="count" dot :numberStyle="numberStyle">
|
||||
<Icon icon="ion:notifcations" size="22" />
|
||||
</Badge>
|
||||
<template #content>
|
||||
<Tabs>
|
||||
<template v-for="item in listData" :key="item.key">
|
||||
<TabPane>
|
||||
<template #tab>
|
||||
{{ item.name }}
|
||||
<span v-if="item.unreadNum !== 0">({{ item.unreadNum }})</span>
|
||||
</template>
|
||||
<div :class="prefixCls">
|
||||
<Popover title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`">
|
||||
<Badge :count="count" dot :numberStyle="numberStyle">
|
||||
<Icon icon="ion:notifcations" size="22" />
|
||||
</Badge>
|
||||
<template #content>
|
||||
<Tabs>
|
||||
<template v-for="item in listData" :key="item.key">
|
||||
<TabPane>
|
||||
<template #tab>
|
||||
{{ item.name }}
|
||||
<span v-if="item.unreadNum !== 0">({{ item.unreadNum }})</span>
|
||||
</template>
|
||||
|
||||
<div v-if="item.key === '4'" class="min-h-88">
|
||||
<div>
|
||||
<div class="list-item">
|
||||
<span class="header-title">{{ t('流程审批') }}</span>
|
||||
<router-link
|
||||
class="opr"
|
||||
:to="{
|
||||
path: '/task/processtasks',
|
||||
query: {},
|
||||
}"
|
||||
>
|
||||
{{ t('查看更多') }} 》
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="item.list.length > 0">
|
||||
<div class="readed-mark" v-for="it in item.list" :key="it.id">
|
||||
<div
|
||||
class="list-data-item"
|
||||
:class="it.read ? 'readed' : ''"
|
||||
@click="ApprovalHandle(it, item.key, 1)"
|
||||
>
|
||||
<span class="list-item-title">{{ it.title }}</span>
|
||||
<span class="list-item-time">{{ it.timeFormat }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
<div>
|
||||
<div class="list-item">
|
||||
<span class="header-title">{{ t('流程传阅') }}</span>
|
||||
<router-link
|
||||
class="opr"
|
||||
:to="{
|
||||
path: '/task/processtasks',
|
||||
query: { name: 'MyCirculation' },
|
||||
}"
|
||||
>
|
||||
{{ t('查看更多') }} 》
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="item.read!.length>0">
|
||||
<div class="list-item readed-mark" v-for="it in item.read" :key="it.id">
|
||||
<div
|
||||
class="list-data-item"
|
||||
:class="it.read ? 'readed' : ''"
|
||||
@click="ApprovalHandle(it, item.key, 2)"
|
||||
>
|
||||
<span class="list-item-title">{{ it.title }}</span>
|
||||
<span class="list-item-time">{{ it.timeFormat }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
<div class="notice-footer">
|
||||
<span @click="setReadAll(item.key)">{{ t('全部设置已读') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--系统通知消息-->
|
||||
<div v-else-if="item.key === '5'" class="h-88">
|
||||
<div v-if="item.list.length > 0" class="h-82">
|
||||
<div
|
||||
class="list-item readed-mark"
|
||||
v-for="it in item.list"
|
||||
:key="it.id"
|
||||
:class="it.isRead === 1 ? 'readed' : ''"
|
||||
@click="
|
||||
() => {
|
||||
it.isRead = 1;
|
||||
setReadSingle(it.id, item.key);
|
||||
goToRouter(it);
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="list-item-title" style="width: 220px;">
|
||||
<a-tooltip>
|
||||
<template #title>{{ it.title }}</template>
|
||||
{{ it.title }}
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<span class="list-item-time">{{ it.createDate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else/>
|
||||
</div>
|
||||
<div v-else class="h-88">
|
||||
<div v-if="item.list.length > 0" class="h-82">
|
||||
<div
|
||||
class="list-item readed-mark"
|
||||
v-for="it in item.list"
|
||||
:key="it.id"
|
||||
:class="it.read ? 'readed' : ''"
|
||||
@click="
|
||||
() => {
|
||||
it.read = 1;
|
||||
setReadSingle(it.id, item.key);
|
||||
}
|
||||
<div v-if="item.key === '4'" class="min-h-88">
|
||||
<div>
|
||||
<div class="list-item">
|
||||
<span class="header-title">{{ t('流程审批') }}</span>
|
||||
<router-link
|
||||
class="opr"
|
||||
:to="{
|
||||
path: '/task/processtasks',
|
||||
query: {}
|
||||
}"
|
||||
>
|
||||
{{ t('查看更多') }} 》
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="item.list.length > 0">
|
||||
<div class="readed-mark" v-for="it in item.list" :key="it.id">
|
||||
<div class="list-data-item" :class="it.read ? 'readed' : ''" @click="ApprovalHandle(it, item.key, 1)">
|
||||
<span class="list-item-title">{{ it.title }}</span>
|
||||
<span class="list-item-time">{{ it.timeFormat }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
<div>
|
||||
<div class="list-item">
|
||||
<span class="header-title">{{ t('流程传阅') }}</span>
|
||||
<router-link
|
||||
class="opr"
|
||||
:to="{
|
||||
path: '/task/processtasks',
|
||||
query: { name: 'MyCirculation' }
|
||||
}"
|
||||
>
|
||||
{{ t('查看更多') }} 》
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="item.read!.length>0">
|
||||
<div class="list-item readed-mark" v-for="it in item.read" :key="it.id">
|
||||
<div class="list-data-item" :class="it.read ? 'readed' : ''" @click="ApprovalHandle(it, item.key, 2)">
|
||||
<span class="list-item-title">{{ it.title }}</span>
|
||||
<span class="list-item-time">{{ it.timeFormat }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
<div class="notice-footer">
|
||||
<span @click="setReadAll(item.key)">{{ t('全部设置已读') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--系统通知消息-->
|
||||
<div v-else-if="item.key === '5'" class="h-88">
|
||||
<div v-if="item.list.length > 0" class="h-82">
|
||||
<div
|
||||
class="list-item readed-mark"
|
||||
v-for="it in item.list"
|
||||
:key="it.id"
|
||||
:class="it.isRead === 1 ? 'readed' : ''"
|
||||
@click="
|
||||
() => {
|
||||
it.isRead = 1;
|
||||
setReadSingle(it.id, item.key);
|
||||
goToRouter(it);
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="list-item-title" style="width: 220px">
|
||||
<a-tooltip>
|
||||
<template #title>{{ it.title }}</template>
|
||||
{{ it.title }}
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<span class="list-item-time">{{ it.createDate }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
<div v-else class="h-88">
|
||||
<div v-if="item.list.length > 0" class="h-82">
|
||||
<div
|
||||
class="list-item readed-mark"
|
||||
v-for="it in item.list"
|
||||
:key="it.id"
|
||||
:class="it.read ? 'readed' : ''"
|
||||
@click="
|
||||
() => {
|
||||
it.read = 1;
|
||||
setReadSingle(it.id, item.key);
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="list-item-title">
|
||||
<a-tooltip>
|
||||
<template #title>{{ it.title }}</template>
|
||||
{{ it.title }}
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<span class="list-item-time">{{ it.timeFormat }}</span>
|
||||
</div>
|
||||
<div class="notice-footer"
|
||||
><span @click="setReadAll(item.key)">{{ t('全部设置已读') }}</span
|
||||
><span>{{ t('查看更多') }} 》</span></div
|
||||
>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
</TabPane>
|
||||
</template>
|
||||
</Tabs>
|
||||
<ApprovalProcess
|
||||
v-if="Approval.visible"
|
||||
:taskId="Approval.taskId || ''"
|
||||
:processId="Approval.processId || ''"
|
||||
:schemaId="Approval.schemaId || ''"
|
||||
:visible="Approval.visible"
|
||||
@close="
|
||||
() => {
|
||||
Approval.visible = false;
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="list-item-title">
|
||||
<a-tooltip>
|
||||
<template #title>{{ it.title }}</template>
|
||||
{{ it.title }}
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<span class="list-item-time">{{ it.timeFormat }}</span>
|
||||
</div>
|
||||
<div class="notice-footer"
|
||||
><span @click="setReadAll(item.key)">{{ t('全部设置已读') }}</span
|
||||
><span>{{ t('查看更多') }} 》</span></div
|
||||
>
|
||||
</div>
|
||||
<a-empty :image="simpleImage" v-else />
|
||||
</div>
|
||||
</TabPane>
|
||||
</template>
|
||||
</Tabs>
|
||||
<ApprovalProcess
|
||||
v-if="Approval.visible"
|
||||
:taskId="Approval.taskId || ''"
|
||||
:processId="Approval.processId || ''"
|
||||
:schemaId="Approval.schemaId || ''"
|
||||
:visible="Approval.visible"
|
||||
@close="
|
||||
() => {
|
||||
Approval.visible = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
<LookProcess
|
||||
v-if="LookData.visible"
|
||||
:taskId="LookData.taskId || ''"
|
||||
:processId="LookData.processId || ''"
|
||||
:visible="LookData.visible"
|
||||
@close="
|
||||
() => {
|
||||
LookData.visible = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
/>
|
||||
<LookProcess
|
||||
v-if="LookData.visible"
|
||||
:taskId="LookData.taskId || ''"
|
||||
:processId="LookData.processId || ''"
|
||||
:visible="LookData.visible"
|
||||
@close="
|
||||
() => {
|
||||
LookData.visible = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, onUnmounted } from 'vue';
|
||||
import { Popover, Tabs, Badge } from 'ant-design-vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { tabListData } from './data';
|
||||
import { computed, defineComponent, ref, onUnmounted } from 'vue';
|
||||
import { Popover, Tabs, Badge } from 'ant-design-vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { tabListData } from './data';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { downloadByUrl } from '/@/utils/file/download';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { downloadByUrl } from '/@/utils/file/download';
|
||||
|
||||
import {
|
||||
getOaMessage,
|
||||
getOaNews,
|
||||
setOaRead,
|
||||
setSingleRead,
|
||||
setWorkReadAll,
|
||||
getScheduleMsg,
|
||||
setScheduleRead,
|
||||
setScheduleReadAll,
|
||||
} from '/@/api/system/login';
|
||||
import {queryLoginUserNotices, setSystemNoticeRead} from '/@/api/system/systemNotice/index'
|
||||
import { getInfoByDownloadUrl } from '/@/api/system/file';
|
||||
import { Empty } from 'ant-design-vue';
|
||||
import { getOaMessage, getOaNews, setOaRead, setSingleRead, setWorkReadAll, getScheduleMsg, setScheduleRead, setScheduleReadAll } from '/@/api/system/login';
|
||||
import { queryLoginUserNotices, setSystemNoticeRead } from '/@/api/system/systemNotice/index';
|
||||
import { getInfoByDownloadUrl } from '/@/api/system/file';
|
||||
import { Empty } from 'ant-design-vue';
|
||||
|
||||
import ApprovalProcess from '/@/views/workflow/task/components/ApprovalProcess.vue';
|
||||
import LookProcess from '/@/views/workflow/task/components/LookProcess.vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import {useRouter } from 'vue-router';
|
||||
const { t } = useI18n();
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Popover,
|
||||
Tabs,
|
||||
TabPane: Tabs.TabPane,
|
||||
Badge,
|
||||
Icon,
|
||||
ApprovalProcess,
|
||||
LookProcess,
|
||||
},
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const Approval = ref<{
|
||||
taskId?: string;
|
||||
processId?: string;
|
||||
schemaId?: string;
|
||||
visible: boolean;
|
||||
}>({
|
||||
visible: false,
|
||||
});
|
||||
const LookData = ref<{
|
||||
taskId?: string;
|
||||
processId?: string;
|
||||
visible: boolean;
|
||||
}>({
|
||||
visible: false,
|
||||
});
|
||||
const { prefixCls } = useDesign('header-notify');
|
||||
let times: any = ref();
|
||||
const listData = ref(tabListData);
|
||||
const simpleImage = ref(Empty.PRESENTED_IMAGE_SIMPLE);
|
||||
getDatas();
|
||||
times.value = setInterval(() => {
|
||||
getDatas();
|
||||
}, 10000);
|
||||
async function getDatas() {
|
||||
listData.value.forEach((o) => {
|
||||
o.list = [];
|
||||
o.unreadNum = 0;
|
||||
if (o.read) o.read = [];
|
||||
});
|
||||
try {
|
||||
if(import.meta.env.VITE_GLOB_DISABLE_NEWS !== 'true') {
|
||||
let res = await getOaNews(1);
|
||||
res.list.forEach((o) => {
|
||||
if (!o.readId) listData.value[0].unreadNum += 1;
|
||||
listData.value[0].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.briefHead,
|
||||
description: '',
|
||||
datetime: o.releaseTime,
|
||||
color: '',
|
||||
type: '3',
|
||||
read: o.isRead,
|
||||
});
|
||||
});
|
||||
let res1 = await getOaNews(2);
|
||||
res1.list.forEach((o) => {
|
||||
if (!o.readId) listData.value[1].unreadNum += 1;
|
||||
listData.value[1].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.briefHead,
|
||||
description: '',
|
||||
datetime: o.releaseTime,
|
||||
color: '',
|
||||
type: '3',
|
||||
read: o.isRead,
|
||||
});
|
||||
});
|
||||
let res2 = await getOaMessage();
|
||||
res2.forEach((o) => {
|
||||
if (o.messageType === 0) {
|
||||
if (!o.isRead) listData.value[2].unreadNum += 1;
|
||||
listData.value[2].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.messageContent,
|
||||
description: '',
|
||||
datetime: o.sendTime,
|
||||
timeFormat: o.timeFormat,
|
||||
color: '',
|
||||
type: '3',
|
||||
read: o.isRead,
|
||||
});
|
||||
} else if (o.messageType == 1) {
|
||||
if (!o.isRead) listData.value[3].unreadNum += 1;
|
||||
listData.value[3].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.messageContent,
|
||||
description: '',
|
||||
datetime: o.sendTime,
|
||||
timeFormat: o.timeFormat,
|
||||
color: '',
|
||||
type: '3',
|
||||
taskId: o.objectId,
|
||||
processId: o.processId,
|
||||
schemaId: o.schemaId,
|
||||
read: o.isRead,
|
||||
});
|
||||
} else if (o.messageType == 2) {
|
||||
if (!o.isRead) listData.value[3].unreadNum += 1;
|
||||
listData.value[3].read?.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.messageContent,
|
||||
description: '',
|
||||
datetime: o.sendTime,
|
||||
read: o.isRead,
|
||||
timeFormat: o.timeFormat,
|
||||
color: '',
|
||||
type: '3',
|
||||
taskId: o.objectId,
|
||||
processId: o.processId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//系统消息
|
||||
let res4 = import.meta.env.VITE_DISABLE_NOTE === 'true' ? {list:[]} : await queryLoginUserNotices({limit: 1, size: 10});
|
||||
listData.value[4].list = res4.list;
|
||||
listData.value[4].unreadNum = res4.list.filter((item) => item.isRead == 0).length;
|
||||
}
|
||||
|
||||
let res3 = await getScheduleMsg();
|
||||
res3.list.forEach((item) => (item.read = item.isRead));
|
||||
listData.value[2].unreadNum = res3.list.filter((x) => !x.isRead).length;
|
||||
listData.value[2].list.push(...res3.list);
|
||||
console.log('message', listData.value);
|
||||
} catch (error) {
|
||||
console.error('message error', error)
|
||||
clearInterval(times.value);
|
||||
}
|
||||
}
|
||||
|
||||
const count = computed(() => {
|
||||
let count = 0;
|
||||
for (let i = 0; i < listData.value.length; i++) {
|
||||
count += listData.value[i].unreadNum;
|
||||
}
|
||||
return count;
|
||||
});
|
||||
|
||||
async function setReadAll(type) {
|
||||
if (type == 1 || type == 2) {
|
||||
let ids: string[] = [];
|
||||
|
||||
listData.value[type - 1].list.forEach((o) => {
|
||||
o.read = 1;
|
||||
ids.push(o.id);
|
||||
});
|
||||
|
||||
await setOaRead(ids);
|
||||
} else if (type == 3) {
|
||||
await setScheduleReadAll();
|
||||
listData.value[type - 1].list.forEach((o) => {
|
||||
o.read = 1;
|
||||
});
|
||||
} else if (type == 4) {
|
||||
listData.value[type - 1].list.forEach((o) => {
|
||||
o.read = 1;
|
||||
});
|
||||
await setWorkReadAll();
|
||||
}
|
||||
listData.value[type - 1].unreadNum = 0;
|
||||
}
|
||||
async function setReadSingle(ids, num) {
|
||||
if (num == 3) {
|
||||
await setScheduleRead([ids]);
|
||||
} else if (num == 4) {
|
||||
await setSingleRead(ids);
|
||||
} else if (num == 5) {
|
||||
await setSystemNoticeRead([ids]);
|
||||
} else {
|
||||
await setOaRead([ids]);
|
||||
}
|
||||
if (listData.value[num - 1].unreadNum > 0) listData.value[num - 1].unreadNum -= 1;
|
||||
}
|
||||
function goToRouter(record){
|
||||
if(record.type === '99') {
|
||||
//异步打包下载
|
||||
record.paramsJson = record.paramsJson ? JSON.parse(record.paramsJson) : {};
|
||||
let fileId = record.paramsJson.id || [];
|
||||
getInfoByDownloadUrl({id: fileId}).then((res)=>{
|
||||
let fileUrl = res.fileUrlFixed || res.fileUrl;
|
||||
downloadByUrl({ url: fileUrl, fileName: (res.fileName+res.fileType) || 'files.zip' });
|
||||
});
|
||||
return;
|
||||
}
|
||||
router.push(record.path)
|
||||
}
|
||||
onUnmounted(() => {
|
||||
clearInterval(times.value);
|
||||
});
|
||||
function ApprovalHandle(it, key, type) {
|
||||
if (type == 1) {
|
||||
Approval.value = {
|
||||
taskId: it.taskId,
|
||||
processId: it.processId,
|
||||
schemaId: it.schemaId,
|
||||
visible: true,
|
||||
};
|
||||
} else {
|
||||
LookData.value = {
|
||||
taskId: it.taskId,
|
||||
processId: it.processId,
|
||||
visible: true,
|
||||
};
|
||||
}
|
||||
it.read = 1;
|
||||
setReadSingle(it.id, key);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
listData,
|
||||
count,
|
||||
setReadAll,
|
||||
simpleImage,
|
||||
numberStyle: {
|
||||
top: '18px',
|
||||
right: '8px',
|
||||
import ApprovalProcess from '/@/views/workflow/task/components/ApprovalProcess.vue';
|
||||
import LookProcess from '/@/views/workflow/task/components/LookProcess.vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
const { t } = useI18n();
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Popover,
|
||||
Tabs,
|
||||
TabPane: Tabs.TabPane,
|
||||
Badge,
|
||||
Icon,
|
||||
ApprovalProcess,
|
||||
LookProcess
|
||||
},
|
||||
setReadSingle,
|
||||
ApprovalHandle,
|
||||
Approval,
|
||||
LookData,
|
||||
t,
|
||||
goToRouter,
|
||||
};
|
||||
},
|
||||
});
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const Approval = ref<{
|
||||
taskId?: string;
|
||||
processId?: string;
|
||||
schemaId?: string;
|
||||
visible: boolean;
|
||||
}>({
|
||||
visible: false
|
||||
});
|
||||
const LookData = ref<{
|
||||
taskId?: string;
|
||||
processId?: string;
|
||||
visible: boolean;
|
||||
}>({
|
||||
visible: false
|
||||
});
|
||||
const { prefixCls } = useDesign('header-notify');
|
||||
let times: any = ref();
|
||||
const listData = ref(tabListData);
|
||||
const simpleImage = ref(Empty.PRESENTED_IMAGE_SIMPLE);
|
||||
getDatas();
|
||||
times.value = setInterval(() => {
|
||||
getDatas();
|
||||
}, 10000);
|
||||
async function getDatas() {
|
||||
listData.value.forEach((o) => {
|
||||
o.list = [];
|
||||
o.unreadNum = 0;
|
||||
if (o.read) o.read = [];
|
||||
});
|
||||
try {
|
||||
if (import.meta.env.VITE_GLOB_DISABLE_NEWS !== 'true') {
|
||||
let res = await getOaNews(1);
|
||||
res.list.forEach((o) => {
|
||||
if (!o.readId) listData.value[0].unreadNum += 1;
|
||||
listData.value[0].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.briefHead,
|
||||
description: '',
|
||||
datetime: o.releaseTime,
|
||||
color: '',
|
||||
type: '3',
|
||||
read: o.isRead
|
||||
});
|
||||
});
|
||||
let res1 = await getOaNews(2);
|
||||
res1.list.forEach((o) => {
|
||||
if (!o.readId) listData.value[1].unreadNum += 1;
|
||||
listData.value[1].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.briefHead,
|
||||
description: '',
|
||||
datetime: o.releaseTime,
|
||||
color: '',
|
||||
type: '3',
|
||||
read: o.isRead
|
||||
});
|
||||
});
|
||||
let res2 = await getOaMessage();
|
||||
res2.forEach((o) => {
|
||||
if (o.messageType === 0) {
|
||||
if (!o.isRead) listData.value[2].unreadNum += 1;
|
||||
listData.value[2].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.messageContent,
|
||||
description: '',
|
||||
datetime: o.sendTime,
|
||||
timeFormat: o.timeFormat,
|
||||
color: '',
|
||||
type: '3',
|
||||
read: o.isRead
|
||||
});
|
||||
} else if (o.messageType == 1) {
|
||||
if (!o.isRead) listData.value[3].unreadNum += 1;
|
||||
listData.value[3].list.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.messageContent,
|
||||
description: '',
|
||||
datetime: o.sendTime,
|
||||
timeFormat: o.timeFormat,
|
||||
color: '',
|
||||
type: '3',
|
||||
taskId: o.objectId,
|
||||
processId: o.processId,
|
||||
schemaId: o.schemaId,
|
||||
read: o.isRead
|
||||
});
|
||||
} else if (o.messageType == 2) {
|
||||
if (!o.isRead) listData.value[3].unreadNum += 1;
|
||||
listData.value[3].read?.push({
|
||||
id: o.id,
|
||||
avatar: '',
|
||||
title: o.messageContent,
|
||||
description: '',
|
||||
datetime: o.sendTime,
|
||||
read: o.isRead,
|
||||
timeFormat: o.timeFormat,
|
||||
color: '',
|
||||
type: '3',
|
||||
taskId: o.objectId,
|
||||
processId: o.processId
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//系统消息
|
||||
let res4 = import.meta.env.VITE_DISABLE_NOTE === 'true' ? { list: [] } : await queryLoginUserNotices({ limit: 1, size: 10 });
|
||||
listData.value[4].list = res4.list;
|
||||
listData.value[4].unreadNum = res4.list.filter((item) => item.isRead == 0).length;
|
||||
}
|
||||
|
||||
let res3 = await getScheduleMsg();
|
||||
res3.list.forEach((item) => (item.read = item.isRead));
|
||||
listData.value[2].unreadNum = res3.list.filter((x) => !x.isRead).length;
|
||||
listData.value[2].list.push(...res3.list);
|
||||
console.log('message', listData.value);
|
||||
} catch (error) {
|
||||
console.error('message error', error);
|
||||
clearInterval(times.value);
|
||||
}
|
||||
}
|
||||
|
||||
const count = computed(() => {
|
||||
let count = 0;
|
||||
for (let i = 0; i < listData.value.length; i++) {
|
||||
count += listData.value[i].unreadNum;
|
||||
}
|
||||
return count;
|
||||
});
|
||||
|
||||
async function setReadAll(type) {
|
||||
if (type == 1 || type == 2) {
|
||||
let ids: string[] = [];
|
||||
|
||||
listData.value[type - 1].list.forEach((o) => {
|
||||
o.read = 1;
|
||||
ids.push(o.id);
|
||||
});
|
||||
|
||||
await setOaRead(ids);
|
||||
} else if (type == 3) {
|
||||
await setScheduleReadAll();
|
||||
listData.value[type - 1].list.forEach((o) => {
|
||||
o.read = 1;
|
||||
});
|
||||
} else if (type == 4) {
|
||||
listData.value[type - 1].list.forEach((o) => {
|
||||
o.read = 1;
|
||||
});
|
||||
await setWorkReadAll();
|
||||
}
|
||||
listData.value[type - 1].unreadNum = 0;
|
||||
}
|
||||
async function setReadSingle(ids, num) {
|
||||
if (num == 3) {
|
||||
await setScheduleRead([ids]);
|
||||
} else if (num == 4) {
|
||||
await setSingleRead(ids);
|
||||
} else if (num == 5) {
|
||||
await setSystemNoticeRead([ids]);
|
||||
} else {
|
||||
await setOaRead([ids]);
|
||||
}
|
||||
if (listData.value[num - 1].unreadNum > 0) listData.value[num - 1].unreadNum -= 1;
|
||||
}
|
||||
function goToRouter(record) {
|
||||
if (record.type === '99') {
|
||||
//异步打包下载
|
||||
record.paramsJson = record.paramsJson ? JSON.parse(record.paramsJson) : {};
|
||||
let fileId = record.paramsJson.id || [];
|
||||
getInfoByDownloadUrl({ id: fileId }).then((res) => {
|
||||
let fileUrl = res.fileUrlFixed || res.fileUrl;
|
||||
downloadByUrl({ url: fileUrl, fileName: res.fileName + res.fileType || 'files.zip' });
|
||||
});
|
||||
return;
|
||||
}
|
||||
router.push(record.path);
|
||||
}
|
||||
onUnmounted(() => {
|
||||
clearInterval(times.value);
|
||||
});
|
||||
function ApprovalHandle(it, key, type) {
|
||||
if (type == 1) {
|
||||
Approval.value = {
|
||||
taskId: it.taskId,
|
||||
processId: it.processId,
|
||||
schemaId: it.schemaId,
|
||||
visible: true
|
||||
};
|
||||
} else {
|
||||
LookData.value = {
|
||||
taskId: it.taskId,
|
||||
processId: it.processId,
|
||||
visible: true
|
||||
};
|
||||
}
|
||||
it.read = 1;
|
||||
setReadSingle(it.id, key);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
listData,
|
||||
count,
|
||||
setReadAll,
|
||||
simpleImage,
|
||||
numberStyle: {
|
||||
top: '18px',
|
||||
right: '8px'
|
||||
},
|
||||
setReadSingle,
|
||||
ApprovalHandle,
|
||||
Approval,
|
||||
LookData,
|
||||
t,
|
||||
goToRouter
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-header-notify';
|
||||
@prefix-cls: ~'@{namespace}-header-notify';
|
||||
|
||||
.@{prefix-cls} {
|
||||
padding-top: 2px;
|
||||
.@{prefix-cls} {
|
||||
padding-top: 2px;
|
||||
|
||||
&__overlay {
|
||||
width: 380px;
|
||||
&__overlay {
|
||||
width: 380px;
|
||||
}
|
||||
|
||||
.ant-tabs-content {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.ant-badge {
|
||||
font-size: 18px;
|
||||
|
||||
.ant-badge-multiple-words {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-content {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.ant-badge {
|
||||
font-size: 18px;
|
||||
|
||||
.ant-badge-multiple-words {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="less">
|
||||
.list-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
.list-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
|
||||
.header-title {
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
.header-title {
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.opr {
|
||||
color: #02a7f0;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&.readed {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.opr {
|
||||
color: #02a7f0;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
.list-data-item {
|
||||
display: flex;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&.readed {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
&.readed {
|
||||
color: gray;
|
||||
.list-item-title {
|
||||
width: 280px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.list-data-item {
|
||||
display: flex;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&.readed {
|
||||
color: gray;
|
||||
.list-item-time {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.list-item-title {
|
||||
width: 280px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.readed-mark {
|
||||
color: #02a7f0;
|
||||
}
|
||||
|
||||
.list-item-time {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.readed-mark {
|
||||
color: #02a7f0;
|
||||
}
|
||||
|
||||
.notice-footer {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
font-size: 12px;
|
||||
color: #02a7f0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.notice-footer {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
font-size: 12px;
|
||||
color: #02a7f0;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,32 +1,32 @@
|
||||
<template>
|
||||
<MenuItem :key="itemKey">
|
||||
<span class="flex items-center">
|
||||
<Icon :icon="icon" class="mr-1" />
|
||||
<span>{{ text }}</span>
|
||||
</span>
|
||||
</MenuItem>
|
||||
<MenuItem :key="itemKey">
|
||||
<span class="flex items-center">
|
||||
<Icon :icon="icon" class="mr-1" />
|
||||
<span>{{ text }}</span>
|
||||
</span>
|
||||
</MenuItem>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Menu } from 'ant-design-vue';
|
||||
import { Menu } from 'ant-design-vue';
|
||||
|
||||
import { computed, defineComponent, getCurrentInstance } from 'vue';
|
||||
import { computed, defineComponent, getCurrentInstance } from 'vue';
|
||||
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DropdownMenuItem',
|
||||
components: { MenuItem: Menu.Item, Icon },
|
||||
props: {
|
||||
// eslint-disable-next-line
|
||||
key: propTypes.string,
|
||||
text: propTypes.string,
|
||||
icon: propTypes.string,
|
||||
},
|
||||
setup(props) {
|
||||
const instance = getCurrentInstance();
|
||||
const itemKey = computed(() => props.key || instance?.vnode?.props?.key);
|
||||
return { itemKey };
|
||||
},
|
||||
});
|
||||
export default defineComponent({
|
||||
name: 'DropdownMenuItem',
|
||||
components: { MenuItem: Menu.Item, Icon },
|
||||
props: {
|
||||
// eslint-disable-next-line
|
||||
key: propTypes.string,
|
||||
text: propTypes.string,
|
||||
icon: propTypes.string
|
||||
},
|
||||
setup(props) {
|
||||
const instance = getCurrentInstance();
|
||||
const itemKey = computed(() => props.key || instance?.vnode?.props?.key);
|
||||
return { itemKey };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,179 +1,167 @@
|
||||
<template>
|
||||
<Dropdown placement="bottomRight" :overlayClassName="`${prefixCls}-dropdown-overlay`">
|
||||
<span :class="[prefixCls, `${prefixCls}--${theme}`]" class="flex">
|
||||
<span
|
||||
style="border-left: 1px solid rgb(255 255 255 / 30%); height: 30px; padding-right: 15px"
|
||||
></span>
|
||||
<div style="margin-right: 12px; height: 30px; margin-top: -12px">
|
||||
<a-image
|
||||
:width="24"
|
||||
:height="24"
|
||||
:src="getUserInfo.avatar"
|
||||
:fallback="headerImg"
|
||||
/>
|
||||
</div>
|
||||
<span :class="`${prefixCls}__info hidden md:block`">
|
||||
<span :class="`${prefixCls}__name `" class="truncate">
|
||||
{{ getUserInfo.name }}
|
||||
<Dropdown placement="bottomRight" :overlayClassName="`${prefixCls}-dropdown-overlay`">
|
||||
<span :class="[prefixCls, `${prefixCls}--${theme}`]" class="flex">
|
||||
<span style="border-left: 1px solid rgb(255 255 255 / 30%); height: 30px; padding-right: 15px"></span>
|
||||
<div style="margin-right: 12px; height: 30px; margin-top: -12px">
|
||||
<a-image :width="24" :height="24" :src="getUserInfo.avatar" :fallback="headerImg" />
|
||||
</div>
|
||||
<span :class="`${prefixCls}__info hidden md:block`">
|
||||
<span :class="`${prefixCls}__name `" class="truncate">
|
||||
{{ getUserInfo.name }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<template #overlay>
|
||||
<AMenu @click="handleMenuClick">
|
||||
<MenuItem key="usercenter" :text="t('用户中心')" icon="ant-design:user-switch-outlined" />
|
||||
<MenuItem key="doc" :text="t('文档')" icon="ion:document-text-outline" v-if="getShowDoc" />
|
||||
<MenuDivider v-if="getShowDoc" />
|
||||
<MenuItem
|
||||
v-if="getUseLockPage"
|
||||
key="lock"
|
||||
:text="t('锁定屏幕')"
|
||||
icon="ion:lock-closed-outline"
|
||||
/>
|
||||
<MenuItem key="logout" :text="t('退出系统')" icon="ion:power-outline" />
|
||||
</AMenu>
|
||||
</template>
|
||||
</Dropdown>
|
||||
<LockAction @register="register" />
|
||||
<template #overlay>
|
||||
<AMenu @click="handleMenuClick">
|
||||
<MenuItem key="usercenter" :text="t('用户中心')" icon="ant-design:user-switch-outlined" />
|
||||
<MenuItem key="doc" :text="t('文档')" icon="ion:document-text-outline" v-if="getShowDoc" />
|
||||
<MenuDivider v-if="getShowDoc" />
|
||||
<MenuItem v-if="getUseLockPage" key="lock" :text="t('锁定屏幕')" icon="ion:lock-closed-outline" />
|
||||
<MenuItem key="logout" :text="t('退出系统')" icon="ion:power-outline" />
|
||||
</AMenu>
|
||||
</template>
|
||||
</Dropdown>
|
||||
<LockAction @register="register" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// components
|
||||
import { Dropdown, Menu } from 'ant-design-vue';
|
||||
// components
|
||||
import { Dropdown, Menu } from 'ant-design-vue';
|
||||
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
|
||||
import { DOC_URL } from '/@/settings/siteSetting';
|
||||
import { DOC_URL } from '/@/settings/siteSetting';
|
||||
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { openWindow } from '/@/utils';
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { openWindow } from '/@/utils';
|
||||
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
|
||||
// type MenuEvent = 'logout' | 'doc' | 'lock' | 'usercenter';
|
||||
// type MenuEvent = 'logout' | 'doc' | 'lock' | 'usercenter';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UserDropdown',
|
||||
components: {
|
||||
Dropdown,
|
||||
AMenu: Menu,
|
||||
MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
|
||||
MenuDivider: Menu.Divider,
|
||||
LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
|
||||
},
|
||||
props: {
|
||||
theme: propTypes.oneOf(['dark', 'light']),
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('header-user-dropdown');
|
||||
const { t } = useI18n();
|
||||
const { getShowDoc, getUseLockPage } = useHeaderSetting();
|
||||
const userStore = useUserStore();
|
||||
const go = useGo();
|
||||
export default defineComponent({
|
||||
name: 'UserDropdown',
|
||||
components: {
|
||||
Dropdown,
|
||||
AMenu: Menu,
|
||||
MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
|
||||
MenuDivider: Menu.Divider,
|
||||
LockAction: createAsyncComponent(() => import('../lock/LockModal.vue'))
|
||||
},
|
||||
props: {
|
||||
theme: propTypes.oneOf(['dark', 'light'])
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('header-user-dropdown');
|
||||
const { t } = useI18n();
|
||||
const { getShowDoc, getUseLockPage } = useHeaderSetting();
|
||||
const userStore = useUserStore();
|
||||
const go = useGo();
|
||||
|
||||
const getUserInfo = computed(() => {
|
||||
const { name = '', avatar, desc } = userStore.getUserInfo || {};
|
||||
return { name, avatar: avatar || headerImg, desc };
|
||||
});
|
||||
const getUserInfo = computed(() => {
|
||||
const { name = '', avatar, desc } = userStore.getUserInfo || {};
|
||||
return { name, avatar: avatar || headerImg, desc };
|
||||
});
|
||||
|
||||
const [register, { openModal }] = useModal();
|
||||
const [register, { openModal }] = useModal();
|
||||
|
||||
function handleLock() {
|
||||
openModal(true);
|
||||
}
|
||||
function handleLock() {
|
||||
openModal(true);
|
||||
}
|
||||
|
||||
// login out
|
||||
function handleLoginOut() {
|
||||
userStore.confirmLoginOut();
|
||||
}
|
||||
// login out
|
||||
function handleLoginOut() {
|
||||
userStore.confirmLoginOut();
|
||||
}
|
||||
|
||||
// open doc
|
||||
function openDoc() {
|
||||
openWindow(DOC_URL);
|
||||
}
|
||||
// open doc
|
||||
function openDoc() {
|
||||
openWindow(DOC_URL);
|
||||
}
|
||||
|
||||
// updatePwd
|
||||
function openUserCenter() {
|
||||
go(PageEnum.USER_CENTER);
|
||||
}
|
||||
// updatePwd
|
||||
function openUserCenter() {
|
||||
go(PageEnum.USER_CENTER);
|
||||
}
|
||||
|
||||
function handleMenuClick(e) {
|
||||
switch (e.key) {
|
||||
case 'logout':
|
||||
handleLoginOut();
|
||||
break;
|
||||
case 'doc':
|
||||
openDoc();
|
||||
break;
|
||||
case 'lock':
|
||||
handleLock();
|
||||
break;
|
||||
case 'usercenter':
|
||||
openUserCenter();
|
||||
break;
|
||||
function handleMenuClick(e) {
|
||||
switch (e.key) {
|
||||
case 'logout':
|
||||
handleLoginOut();
|
||||
break;
|
||||
case 'doc':
|
||||
openDoc();
|
||||
break;
|
||||
case 'lock':
|
||||
handleLock();
|
||||
break;
|
||||
case 'usercenter':
|
||||
openUserCenter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
t,
|
||||
getUserInfo,
|
||||
handleMenuClick,
|
||||
getShowDoc,
|
||||
register,
|
||||
getUseLockPage
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
t,
|
||||
getUserInfo,
|
||||
handleMenuClick,
|
||||
getShowDoc,
|
||||
register,
|
||||
getUseLockPage,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-header-user-dropdown';
|
||||
@prefix-cls: ~'@{namespace}-header-user-dropdown';
|
||||
|
||||
.@{prefix-cls} {
|
||||
height: @header-height;
|
||||
padding: 0 0 0 10px;
|
||||
padding-right: 10px;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
.@{prefix-cls} {
|
||||
height: @header-height;
|
||||
padding: 0 0 0 10px;
|
||||
padding-right: 10px;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
&__name {
|
||||
font-size: 14px;
|
||||
&__name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
// &--dark {
|
||||
// &:hover {
|
||||
// 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 {
|
||||
.ant-dropdown-menu-item {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// &--dark {
|
||||
// &:hover {
|
||||
// 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 {
|
||||
.ant-dropdown-menu-item {
|
||||
min-width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -4,193 +4,193 @@
|
||||
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||
|
||||
.@{header-prefix-cls} {
|
||||
display: flex;
|
||||
height: @header-height;
|
||||
padding: 0;
|
||||
margin-left: -1px;
|
||||
line-height: @header-height;
|
||||
color: @white;
|
||||
background-color: @white;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&--mobile {
|
||||
.@{breadcrumb-prefix-cls},
|
||||
.error-action,
|
||||
.notify-item,
|
||||
.fullscreen-item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.@{logo-prefix-cls} {
|
||||
min-width: unset;
|
||||
padding-right: 0;
|
||||
|
||||
&__title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.@{header-trigger-prefix-cls} {
|
||||
padding: 0 4px 0 8px !important;
|
||||
}
|
||||
.@{header-prefix-cls}-action {
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: @layout-header-fixed-z-index;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-logo {
|
||||
display: flex;
|
||||
height: @header-height;
|
||||
min-width: 192px;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
padding: 0;
|
||||
margin-left: -1px;
|
||||
line-height: @header-height;
|
||||
color: @white;
|
||||
background-color: @white;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
img {
|
||||
width: @logo-width;
|
||||
height: @logo-width;
|
||||
margin-right: 2px;
|
||||
&--mobile {
|
||||
.@{breadcrumb-prefix-cls},
|
||||
.error-action,
|
||||
.notify-item,
|
||||
.fullscreen-item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.@{logo-prefix-cls} {
|
||||
min-width: unset;
|
||||
padding-right: 0;
|
||||
|
||||
&__title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.@{header-trigger-prefix-cls} {
|
||||
padding: 0 4px 0 8px !important;
|
||||
}
|
||||
.@{header-prefix-cls}-action {
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-left {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
|
||||
.@{header-trigger-prefix-cls} {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 1px 10px 0 1px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
.anticon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&.light {
|
||||
&:hover {
|
||||
background-color: @header-light-bg-hover-color;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #000;
|
||||
}
|
||||
}
|
||||
|
||||
&.dark {
|
||||
&:hover {
|
||||
background-color: @header-dark-bg-hover-color;
|
||||
}
|
||||
}
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: @layout-header-fixed-z-index;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-action {
|
||||
display: flex;
|
||||
min-width: 180px;
|
||||
// padding-right: 12px;
|
||||
align-items: center;
|
||||
|
||||
&__item {
|
||||
display: flex !important;
|
||||
height: @header-height;
|
||||
padding: 0 2px;
|
||||
font-size: 1.2em;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
.ant-badge {
|
||||
&-logo {
|
||||
height: @header-height;
|
||||
line-height: @header-height;
|
||||
}
|
||||
min-width: 192px;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
|
||||
.ant-badge-dot {
|
||||
top: 10px;
|
||||
right: 2px;
|
||||
}
|
||||
img {
|
||||
width: @logo-width;
|
||||
height: @logo-width;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
span[role='img'] {
|
||||
padding: 0 2px;
|
||||
}
|
||||
}
|
||||
&-left {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
|
||||
&--light {
|
||||
background-color: @white !important;
|
||||
border-bottom: 1px solid @header-light-bottom-border-color;
|
||||
border-left: 1px solid @header-light-bottom-border-color;
|
||||
.@{header-trigger-prefix-cls} {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 1px 10px 0 1px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
.@{header-prefix-cls}-logo {
|
||||
color: @text-color-base;
|
||||
.anticon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @header-light-bg-hover-color;
|
||||
}
|
||||
&.light {
|
||||
&:hover {
|
||||
background-color: @header-light-bg-hover-color;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: #000;
|
||||
}
|
||||
}
|
||||
|
||||
&.dark {
|
||||
&:hover {
|
||||
background-color: @header-dark-bg-hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{header-prefix-cls}-action {
|
||||
&__item {
|
||||
color: @text-color-base;
|
||||
&-menu {
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.app-iconify {
|
||||
padding: 0 10px;
|
||||
font-size: 16px !important;
|
||||
&-action {
|
||||
display: flex;
|
||||
min-width: 180px;
|
||||
// padding-right: 12px;
|
||||
align-items: center;
|
||||
|
||||
&__item {
|
||||
display: flex !important;
|
||||
height: @header-height;
|
||||
padding: 0 2px;
|
||||
font-size: 1.2em;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
.ant-badge {
|
||||
height: @header-height;
|
||||
line-height: @header-height;
|
||||
}
|
||||
|
||||
.ant-badge-dot {
|
||||
top: 10px;
|
||||
right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @header-light-bg-hover-color;
|
||||
span[role='img'] {
|
||||
padding: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon,
|
||||
span[role='img'] {
|
||||
color: @text-color-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--dark {
|
||||
background-color: @header-dark-bg-color !important;
|
||||
// border-bottom: 1px solid @border-color-base;
|
||||
border-left: 1px solid @border-color-base;
|
||||
.@{header-prefix-cls}-logo {
|
||||
&:hover {
|
||||
background-color: @header-dark-bg-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{header-prefix-cls}-action {
|
||||
&__item {
|
||||
.app-iconify {
|
||||
padding: 0 10px;
|
||||
// font-size: 16px !important;
|
||||
&--light {
|
||||
background-color: @white !important;
|
||||
border-bottom: 1px solid @header-light-bottom-border-color;
|
||||
border-left: 1px solid @header-light-bottom-border-color;
|
||||
|
||||
.@{header-prefix-cls}-logo {
|
||||
color: @text-color-base;
|
||||
|
||||
&:hover {
|
||||
background-color: @header-light-bg-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-badge {
|
||||
span {
|
||||
color: @white;
|
||||
}
|
||||
}
|
||||
.@{header-prefix-cls}-action {
|
||||
&__item {
|
||||
color: @text-color-base;
|
||||
|
||||
&:hover {
|
||||
background-color: @header-dark-bg-hover-color;
|
||||
.app-iconify {
|
||||
padding: 0 10px;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @header-light-bg-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-icon,
|
||||
span[role='img'] {
|
||||
color: @text-color-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--dark {
|
||||
background-color: @header-dark-bg-color !important;
|
||||
// border-bottom: 1px solid @border-color-base;
|
||||
border-left: 1px solid @border-color-base;
|
||||
.@{header-prefix-cls}-logo {
|
||||
&:hover {
|
||||
background-color: @header-dark-bg-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{header-prefix-cls}-action {
|
||||
&__item {
|
||||
.app-iconify {
|
||||
padding: 0 10px;
|
||||
// font-size: 16px !important;
|
||||
}
|
||||
|
||||
.ant-badge {
|
||||
span {
|
||||
color: @white;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @header-dark-bg-hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,11 +58,11 @@
|
||||
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { useLocale } from '/@/locales/useLocale';
|
||||
import {getAppEnvConfig} from "/@/utils/env";
|
||||
import { getAppEnvConfig } from '/@/utils/env';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutHeader',
|
||||
methods: {getAppEnvConfig},
|
||||
methods: { getAppEnvConfig },
|
||||
components: {
|
||||
LayHeader: Layout.Header,
|
||||
AppLogo,
|
||||
|
||||
@ -1,107 +1,107 @@
|
||||
<template>
|
||||
<Layout :class="prefixCls" v-bind="lockEvents">
|
||||
<LayoutFeatures v-if="showSide"/>
|
||||
<LayoutHeader fixed v-if="getShowFullHeaderRef && showSide"/>
|
||||
<Layout :class="[layoutClass]">
|
||||
<LayoutSideBar v-if="(getShowSidebar || getIsMobile) && showSide"/>
|
||||
<Layout :class="`${prefixCls}-main`">
|
||||
<LayoutMultipleHeader v-if="showSide"/>
|
||||
<LayoutContent />
|
||||
<LayoutFooter />
|
||||
</Layout>
|
||||
<Layout :class="prefixCls" v-bind="lockEvents">
|
||||
<LayoutFeatures v-if="showSide" />
|
||||
<LayoutHeader fixed v-if="getShowFullHeaderRef && showSide" />
|
||||
<Layout :class="[layoutClass]">
|
||||
<LayoutSideBar v-if="(getShowSidebar || getIsMobile) && showSide" />
|
||||
<Layout :class="`${prefixCls}-main`">
|
||||
<LayoutMultipleHeader v-if="showSide" />
|
||||
<LayoutContent />
|
||||
<LayoutFooter />
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, unref, ref } from 'vue';
|
||||
import { Layout } from 'ant-design-vue';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { defineComponent, computed, unref, ref } from 'vue';
|
||||
import { Layout } from 'ant-design-vue';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
|
||||
import LayoutHeader from './header/index.vue';
|
||||
import LayoutContent from './content/index.vue';
|
||||
import LayoutSideBar from './sider/index.vue';
|
||||
import LayoutMultipleHeader from './header/MultipleHeader.vue';
|
||||
import LayoutHeader from './header/index.vue';
|
||||
import LayoutContent from './content/index.vue';
|
||||
import LayoutSideBar from './sider/index.vue';
|
||||
import LayoutMultipleHeader from './header/MultipleHeader.vue';
|
||||
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLockPage } from '/@/hooks/web/useLockPage';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useLockPage } from '/@/hooks/web/useLockPage';
|
||||
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import useGlobalFlag from '/@/hooks/core/useGlobalFlag';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import useGlobalFlag from '/@/hooks/core/useGlobalFlag';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DefaultLayout',
|
||||
components: {
|
||||
LayoutFeatures: createAsyncComponent(() => import('/@/layouts/default/feature/index.vue')),
|
||||
LayoutFooter: createAsyncComponent(() => import('/@/layouts/default/footer/index.vue')),
|
||||
LayoutHeader,
|
||||
LayoutContent,
|
||||
LayoutSideBar,
|
||||
LayoutMultipleHeader,
|
||||
Layout,
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('default-layout');
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { getShowFullHeaderRef } = useHeaderSetting();
|
||||
const { getShowSidebar, getIsMixSidebar, getShowMenu } = useMenuSetting();
|
||||
const globalFlag = useGlobalFlag();
|
||||
const route = useRoute();
|
||||
let showSide = ref(true)
|
||||
const { isSingleLogin } = globalFlag;
|
||||
if (route.query.isSingleLogin) {
|
||||
isSingleLogin.value = true
|
||||
}
|
||||
if (isSingleLogin.value) {
|
||||
showSide.value = false
|
||||
}
|
||||
export default defineComponent({
|
||||
name: 'DefaultLayout',
|
||||
components: {
|
||||
LayoutFeatures: createAsyncComponent(() => import('/@/layouts/default/feature/index.vue')),
|
||||
LayoutFooter: createAsyncComponent(() => import('/@/layouts/default/footer/index.vue')),
|
||||
LayoutHeader,
|
||||
LayoutContent,
|
||||
LayoutSideBar,
|
||||
LayoutMultipleHeader,
|
||||
Layout
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('default-layout');
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { getShowFullHeaderRef } = useHeaderSetting();
|
||||
const { getShowSidebar, getIsMixSidebar, getShowMenu } = useMenuSetting();
|
||||
const globalFlag = useGlobalFlag();
|
||||
const route = useRoute();
|
||||
let showSide = ref(true);
|
||||
const { isSingleLogin } = globalFlag;
|
||||
if (route.query.isSingleLogin) {
|
||||
isSingleLogin.value = true;
|
||||
}
|
||||
if (isSingleLogin.value) {
|
||||
showSide.value = false;
|
||||
}
|
||||
|
||||
// Create a lock screen monitor
|
||||
const lockEvents = useLockPage();
|
||||
// Create a lock screen monitor
|
||||
const lockEvents = useLockPage();
|
||||
|
||||
const layoutClass = computed(() => {
|
||||
let cls: string[] = ['ant-layout'];
|
||||
if (unref(getIsMixSidebar) || unref(getShowMenu)) {
|
||||
cls.push('ant-layout-has-sider');
|
||||
const layoutClass = computed(() => {
|
||||
let cls: string[] = ['ant-layout'];
|
||||
if (unref(getIsMixSidebar) || unref(getShowMenu)) {
|
||||
cls.push('ant-layout-has-sider');
|
||||
}
|
||||
return cls;
|
||||
});
|
||||
|
||||
return {
|
||||
getShowFullHeaderRef,
|
||||
getShowSidebar,
|
||||
prefixCls,
|
||||
getIsMobile,
|
||||
getIsMixSidebar,
|
||||
layoutClass,
|
||||
lockEvents,
|
||||
showSide
|
||||
};
|
||||
}
|
||||
return cls;
|
||||
});
|
||||
|
||||
return {
|
||||
getShowFullHeaderRef,
|
||||
getShowSidebar,
|
||||
prefixCls,
|
||||
getIsMobile,
|
||||
getIsMixSidebar,
|
||||
layoutClass,
|
||||
lockEvents,
|
||||
showSide
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-default-layout';
|
||||
@prefix-cls: ~'@{namespace}-default-layout';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background-color: @content-bg;
|
||||
flex-direction: column;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
background-color: @content-bg;
|
||||
flex-direction: column;
|
||||
|
||||
> .ant-layout {
|
||||
min-height: 100%;
|
||||
overflow-x: auto;
|
||||
> .ant-layout {
|
||||
min-height: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
&-main {
|
||||
width: 100%;
|
||||
margin-left: 1px;
|
||||
min-width: 1000px;
|
||||
}
|
||||
}
|
||||
|
||||
&-main {
|
||||
width: 100%;
|
||||
margin-left: 1px;
|
||||
min-width: 1000px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,197 +1,163 @@
|
||||
<script lang="tsx">
|
||||
import type { PropType, CSSProperties } from 'vue';
|
||||
import type { PropType, CSSProperties } from 'vue';
|
||||
|
||||
import { computed, defineComponent, unref, toRef } from 'vue';
|
||||
import { BasicMenu } from '/@/components/Menu';
|
||||
import { SimpleMenu } from '/@/components/SimpleMenu';
|
||||
import { AppLogo } from '/@/components/Application';
|
||||
import { computed, defineComponent, unref, toRef } from 'vue';
|
||||
import { BasicMenu } from '/@/components/Menu';
|
||||
import { SimpleMenu } from '/@/components/SimpleMenu';
|
||||
import { AppLogo } from '/@/components/Application';
|
||||
|
||||
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
||||
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
||||
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { ScrollContainer } from '/@/components/Container';
|
||||
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { useSplitMenu } from './useLayoutMenu';
|
||||
import { openWindow } from '/@/utils';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isUrl } from '/@/utils/is';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { useSplitMenu } from './useLayoutMenu';
|
||||
import { openWindow } from '/@/utils';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isUrl } from '/@/utils/is';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutMenu',
|
||||
props: {
|
||||
theme: propTypes.oneOf(['light', 'dark']),
|
||||
export default defineComponent({
|
||||
name: 'LayoutMenu',
|
||||
props: {
|
||||
theme: propTypes.oneOf(['light', 'dark']),
|
||||
|
||||
splitType: {
|
||||
type: Number as PropType<MenuSplitTyeEnum>,
|
||||
default: MenuSplitTyeEnum.NONE,
|
||||
},
|
||||
splitType: {
|
||||
type: Number as PropType<MenuSplitTyeEnum>,
|
||||
default: MenuSplitTyeEnum.NONE
|
||||
},
|
||||
|
||||
isHorizontal: propTypes.bool,
|
||||
// menu Mode
|
||||
menuMode: {
|
||||
type: [String] as PropType<Nullable<MenuModeEnum>>,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const go = useGo();
|
||||
isHorizontal: propTypes.bool,
|
||||
// menu Mode
|
||||
menuMode: {
|
||||
type: [String] as PropType<Nullable<MenuModeEnum>>,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const go = useGo();
|
||||
|
||||
const {
|
||||
getMenuMode,
|
||||
getMenuType,
|
||||
getMenuTheme,
|
||||
getCollapsed,
|
||||
getCollapsedShowTitle,
|
||||
getAccordion,
|
||||
getIsHorizontal,
|
||||
getIsSidebarType,
|
||||
getSplit,
|
||||
} = useMenuSetting();
|
||||
const { getShowLogo } = useRootSetting();
|
||||
const { getMenuMode, getMenuType, getMenuTheme, getCollapsed, getCollapsedShowTitle, getAccordion, getIsHorizontal, getIsSidebarType, getSplit } = useMenuSetting();
|
||||
const { getShowLogo } = useRootSetting();
|
||||
|
||||
const { prefixCls } = useDesign('layout-menu');
|
||||
const { prefixCls } = useDesign('layout-menu');
|
||||
|
||||
const { menusRef } = useSplitMenu(toRef(props, 'splitType'));
|
||||
const { menusRef } = useSplitMenu(toRef(props, 'splitType'));
|
||||
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { getIsMobile } = useAppInject();
|
||||
|
||||
const getComputedMenuMode = computed(() =>
|
||||
unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode),
|
||||
);
|
||||
const getComputedMenuMode = computed(() => (unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode)));
|
||||
|
||||
const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
|
||||
const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
|
||||
|
||||
const getIsShowLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType));
|
||||
const getIsShowLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType));
|
||||
|
||||
const getUseScroll = computed(() => {
|
||||
return (
|
||||
!unref(getIsHorizontal) &&
|
||||
(unref(getIsSidebarType) ||
|
||||
props.splitType === MenuSplitTyeEnum.LEFT ||
|
||||
props.splitType === MenuSplitTyeEnum.NONE)
|
||||
);
|
||||
});
|
||||
const getUseScroll = computed(() => {
|
||||
return !unref(getIsHorizontal) && (unref(getIsSidebarType) || props.splitType === MenuSplitTyeEnum.LEFT || props.splitType === MenuSplitTyeEnum.NONE);
|
||||
});
|
||||
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: `calc(100% - ${unref(getIsShowLogo) ? '60px' : '0px'})`,
|
||||
};
|
||||
});
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: `calc(100% - ${unref(getIsShowLogo) ? '60px' : '0px'})`
|
||||
};
|
||||
});
|
||||
|
||||
const getLogoClass = computed(() => {
|
||||
return [
|
||||
`${prefixCls}-logo`,
|
||||
unref(getComputedMenuTheme),
|
||||
{
|
||||
[`${prefixCls}--mobile`]: unref(getIsMobile),
|
||||
},
|
||||
];
|
||||
});
|
||||
const getLogoClass = computed(() => {
|
||||
return [
|
||||
`${prefixCls}-logo`,
|
||||
unref(getComputedMenuTheme),
|
||||
{
|
||||
[`${prefixCls}--mobile`]: unref(getIsMobile)
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const getCommonProps = computed(() => {
|
||||
const menus = unref(menusRef);
|
||||
return {
|
||||
menus,
|
||||
beforeClickFn: beforeMenuClickFn,
|
||||
items: menus,
|
||||
theme: unref(getComputedMenuTheme),
|
||||
accordion: unref(getAccordion),
|
||||
collapse: unref(getCollapsed),
|
||||
collapsedShowTitle: unref(getCollapsedShowTitle),
|
||||
onMenuClick: handleMenuClick,
|
||||
};
|
||||
});
|
||||
/**
|
||||
* click menu
|
||||
* @param menu
|
||||
*/
|
||||
const getCommonProps = computed(() => {
|
||||
const menus = unref(menusRef);
|
||||
return {
|
||||
menus,
|
||||
beforeClickFn: beforeMenuClickFn,
|
||||
items: menus,
|
||||
theme: unref(getComputedMenuTheme),
|
||||
accordion: unref(getAccordion),
|
||||
collapse: unref(getCollapsed),
|
||||
collapsedShowTitle: unref(getCollapsedShowTitle),
|
||||
onMenuClick: handleMenuClick
|
||||
};
|
||||
});
|
||||
/**
|
||||
* click menu
|
||||
* @param menu
|
||||
*/
|
||||
|
||||
function handleMenuClick(path: string) {
|
||||
go(path);
|
||||
}
|
||||
function handleMenuClick(path: string) {
|
||||
go(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* before click menu
|
||||
* @param menu
|
||||
*/
|
||||
async function beforeMenuClickFn(path: string) {
|
||||
if (!isUrl(path)) {
|
||||
return true;
|
||||
/**
|
||||
* before click menu
|
||||
* @param menu
|
||||
*/
|
||||
async function beforeMenuClickFn(path: string) {
|
||||
if (!isUrl(path)) {
|
||||
return true;
|
||||
}
|
||||
openWindow(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderHeader() {
|
||||
if (!unref(getIsShowLogo) && !unref(getIsMobile)) return null;
|
||||
|
||||
return <AppLogo showTitle={!unref(getCollapsed)} class={unref(getLogoClass)} theme={unref(getComputedMenuTheme)} />;
|
||||
}
|
||||
|
||||
function renderMenu() {
|
||||
const { menus, ...menuProps } = unref(getCommonProps);
|
||||
// console.log(menus);
|
||||
if (!menus || !menus.length) return null;
|
||||
return !props.isHorizontal ? (
|
||||
<SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
|
||||
) : (
|
||||
<BasicMenu {...(menuProps as any)} isHorizontal={props.isHorizontal} type={unref(getMenuType)} showLogo={unref(getIsShowLogo)} mode={unref(getComputedMenuMode as any)} items={menus} />
|
||||
);
|
||||
}
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<>
|
||||
{renderHeader()}
|
||||
{unref(getUseScroll) ? <ScrollContainer style={unref(getWrapperStyle)}>{() => renderMenu()}</ScrollContainer> : renderMenu()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
openWindow(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderHeader() {
|
||||
if (!unref(getIsShowLogo) && !unref(getIsMobile)) return null;
|
||||
|
||||
return (
|
||||
<AppLogo
|
||||
showTitle={!unref(getCollapsed)}
|
||||
class={unref(getLogoClass)}
|
||||
theme={unref(getComputedMenuTheme)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function renderMenu() {
|
||||
const { menus, ...menuProps } = unref(getCommonProps);
|
||||
// console.log(menus);
|
||||
if (!menus || !menus.length) return null;
|
||||
return !props.isHorizontal ? (
|
||||
<SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
|
||||
) : (
|
||||
<BasicMenu
|
||||
{...(menuProps as any)}
|
||||
isHorizontal={props.isHorizontal}
|
||||
type={unref(getMenuType)}
|
||||
showLogo={unref(getIsShowLogo)}
|
||||
mode={unref(getComputedMenuMode as any)}
|
||||
items={menus}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<>
|
||||
{renderHeader()}
|
||||
{unref(getUseScroll) ? (
|
||||
<ScrollContainer style={unref(getWrapperStyle)}>{() => renderMenu()}</ScrollContainer>
|
||||
) : (
|
||||
renderMenu()
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-layout-menu';
|
||||
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||
@prefix-cls: ~'@{namespace}-layout-menu';
|
||||
@logo-prefix-cls: ~'@{namespace}-app-logo';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&-logo {
|
||||
height: @header-height;
|
||||
padding: 10px 4px 10px 10px;
|
||||
.@{prefix-cls} {
|
||||
&-logo {
|
||||
height: @header-height;
|
||||
padding: 10px 4px 10px 10px;
|
||||
|
||||
img {
|
||||
width: @logo-width;
|
||||
height: @logo-width;
|
||||
}
|
||||
}
|
||||
|
||||
&--mobile {
|
||||
.@{logo-prefix-cls} {
|
||||
&__title {
|
||||
opacity: 1;
|
||||
img {
|
||||
width: @logo-width;
|
||||
height: @logo-width;
|
||||
}
|
||||
}
|
||||
|
||||
&--mobile {
|
||||
.@{logo-prefix-cls} {
|
||||
&__title {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,14 +1,7 @@
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { BasicDrawer } from '/@/components/Drawer/index';
|
||||
import { Divider } from 'ant-design-vue';
|
||||
import {
|
||||
TypePicker,
|
||||
ThemeColorPicker,
|
||||
SettingFooter,
|
||||
SwitchItem,
|
||||
SelectItem,
|
||||
InputNumberItem,
|
||||
} from './components';
|
||||
import { TypePicker, ThemeColorPicker, SettingFooter, SwitchItem, SelectItem, InputNumberItem } from './components';
|
||||
|
||||
// import { AppDarkModeToggle } from '/@/components/Application';
|
||||
|
||||
@ -23,398 +16,204 @@ import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
import { baseHandler } from './handler';
|
||||
|
||||
import {
|
||||
HandlerEnum,
|
||||
contentModeOptions,
|
||||
topMenuAlignOptions,
|
||||
getMenuTriggerOptions,
|
||||
routerTransitionOptions,
|
||||
menuTypeList,
|
||||
mixSidebarTriggerOptions,
|
||||
} from './enum';
|
||||
import { HandlerEnum, contentModeOptions, topMenuAlignOptions, getMenuTriggerOptions, routerTransitionOptions, menuTypeList, mixSidebarTriggerOptions } from './enum';
|
||||
|
||||
import {
|
||||
HEADER_PRESET_BG_COLOR_LIST,
|
||||
SIDE_BAR_BG_COLOR_LIST,
|
||||
APP_PRESET_COLOR_LIST,
|
||||
} from '/@/settings/designSetting';
|
||||
import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST, APP_PRESET_COLOR_LIST } from '/@/settings/designSetting';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SettingDrawer',
|
||||
setup(_, { attrs }) {
|
||||
const {
|
||||
getContentMode,
|
||||
getShowFooter,
|
||||
getShowBreadCrumb,
|
||||
getShowBreadCrumbIcon,
|
||||
getShowLogo,
|
||||
getFullContent,
|
||||
getColorWeak,
|
||||
getGrayMode,
|
||||
getLockTime,
|
||||
//getShowDarkModeToggle,
|
||||
getThemeColor,
|
||||
} = useRootSetting();
|
||||
name: 'SettingDrawer',
|
||||
setup(_, { attrs }) {
|
||||
const {
|
||||
getContentMode,
|
||||
getShowFooter,
|
||||
getShowBreadCrumb,
|
||||
getShowBreadCrumbIcon,
|
||||
getShowLogo,
|
||||
getFullContent,
|
||||
getColorWeak,
|
||||
getGrayMode,
|
||||
getLockTime,
|
||||
//getShowDarkModeToggle,
|
||||
getThemeColor
|
||||
} = useRootSetting();
|
||||
|
||||
const { getOpenPageLoading, getBasicTransition, getEnableTransition, getOpenNProgress } =
|
||||
useTransitionSetting();
|
||||
const { getOpenPageLoading, getBasicTransition, getEnableTransition, getOpenNProgress } = useTransitionSetting();
|
||||
|
||||
const {
|
||||
getIsHorizontal,
|
||||
getShowMenu,
|
||||
getMenuType,
|
||||
getTrigger,
|
||||
getCollapsedShowTitle,
|
||||
getMenuFixed,
|
||||
getCollapsed,
|
||||
getCanDrag,
|
||||
getTopMenuAlign,
|
||||
getAccordion,
|
||||
getMenuWidth,
|
||||
getMenuBgColor,
|
||||
getIsTopMenu,
|
||||
getSplit,
|
||||
getIsMixSidebar,
|
||||
getCloseMixSidebarOnChange,
|
||||
getMixSideTrigger,
|
||||
getMixSideFixed,
|
||||
} = useMenuSetting();
|
||||
const {
|
||||
getIsHorizontal,
|
||||
getShowMenu,
|
||||
getMenuType,
|
||||
getTrigger,
|
||||
getCollapsedShowTitle,
|
||||
getMenuFixed,
|
||||
getCollapsed,
|
||||
getCanDrag,
|
||||
getTopMenuAlign,
|
||||
getAccordion,
|
||||
getMenuWidth,
|
||||
getMenuBgColor,
|
||||
getIsTopMenu,
|
||||
getSplit,
|
||||
getIsMixSidebar,
|
||||
getCloseMixSidebarOnChange,
|
||||
getMixSideTrigger,
|
||||
getMixSideFixed
|
||||
} = useMenuSetting();
|
||||
|
||||
const {
|
||||
getShowHeader,
|
||||
getFixed: getHeaderFixed,
|
||||
getHeaderBgColor,
|
||||
getShowSearch,
|
||||
} = useHeaderSetting();
|
||||
const { getShowHeader, getFixed: getHeaderFixed, getHeaderBgColor, getShowSearch } = useHeaderSetting();
|
||||
|
||||
const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
|
||||
const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
|
||||
|
||||
const getShowMenuRef = computed(() => {
|
||||
return unref(getShowMenu) && !unref(getIsHorizontal);
|
||||
});
|
||||
const getShowMenuRef = computed(() => {
|
||||
return unref(getShowMenu) && !unref(getIsHorizontal);
|
||||
});
|
||||
|
||||
function renderSidebar() {
|
||||
return (
|
||||
<>
|
||||
<TypePicker
|
||||
menuTypeList={menuTypeList}
|
||||
handler={(item: typeof menuTypeList[0]) => {
|
||||
baseHandler(HandlerEnum.CHANGE_LAYOUT, {
|
||||
mode: item.mode,
|
||||
type: item.type,
|
||||
split: unref(getIsHorizontal) ? false : undefined,
|
||||
});
|
||||
}}
|
||||
def={unref(getMenuType)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
function renderSidebar() {
|
||||
return (
|
||||
<>
|
||||
<TypePicker
|
||||
menuTypeList={menuTypeList}
|
||||
handler={(item: (typeof menuTypeList)[0]) => {
|
||||
baseHandler(HandlerEnum.CHANGE_LAYOUT, {
|
||||
mode: item.mode,
|
||||
type: item.type,
|
||||
split: unref(getIsHorizontal) ? false : undefined
|
||||
});
|
||||
}}
|
||||
def={unref(getMenuType)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderHeaderTheme() {
|
||||
return (
|
||||
<ThemeColorPicker
|
||||
colorList={HEADER_PRESET_BG_COLOR_LIST}
|
||||
def={unref(getHeaderBgColor)}
|
||||
event={HandlerEnum.HEADER_THEME}
|
||||
/>
|
||||
);
|
||||
}
|
||||
function renderHeaderTheme() {
|
||||
return <ThemeColorPicker colorList={HEADER_PRESET_BG_COLOR_LIST} def={unref(getHeaderBgColor)} event={HandlerEnum.HEADER_THEME} />;
|
||||
}
|
||||
|
||||
function renderSiderTheme() {
|
||||
return (
|
||||
<ThemeColorPicker
|
||||
colorList={SIDE_BAR_BG_COLOR_LIST}
|
||||
def={unref(getMenuBgColor)}
|
||||
event={HandlerEnum.MENU_THEME}
|
||||
/>
|
||||
);
|
||||
}
|
||||
function renderSiderTheme() {
|
||||
return <ThemeColorPicker colorList={SIDE_BAR_BG_COLOR_LIST} def={unref(getMenuBgColor)} event={HandlerEnum.MENU_THEME} />;
|
||||
}
|
||||
|
||||
function renderMainTheme() {
|
||||
return (
|
||||
<ThemeColorPicker
|
||||
colorList={APP_PRESET_COLOR_LIST}
|
||||
def={unref(getThemeColor)}
|
||||
event={HandlerEnum.CHANGE_THEME_COLOR}
|
||||
/>
|
||||
);
|
||||
}
|
||||
function renderMainTheme() {
|
||||
return <ThemeColorPicker colorList={APP_PRESET_COLOR_LIST} def={unref(getThemeColor)} event={HandlerEnum.CHANGE_THEME_COLOR} />;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description:
|
||||
*/
|
||||
function renderFeatures() {
|
||||
let triggerDef = unref(getTrigger);
|
||||
/**
|
||||
* @description:
|
||||
*/
|
||||
function renderFeatures() {
|
||||
let triggerDef = unref(getTrigger);
|
||||
|
||||
const triggerOptions = getMenuTriggerOptions(unref(getSplit));
|
||||
const some = triggerOptions.some((item) => item.value === triggerDef);
|
||||
if (!some) {
|
||||
triggerDef = TriggerEnum.FOOTER;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SwitchItem
|
||||
title={t('分割菜单')}
|
||||
event={HandlerEnum.MENU_SPLIT}
|
||||
def={unref(getSplit)}
|
||||
disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('固定展开菜单')}
|
||||
event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR}
|
||||
def={unref(getMixSideFixed)}
|
||||
disabled={!unref(getIsMixSidebar)}
|
||||
/>
|
||||
|
||||
<SwitchItem
|
||||
title={t('切换页面关闭菜单')}
|
||||
event={HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE}
|
||||
def={unref(getCloseMixSidebarOnChange)}
|
||||
disabled={!unref(getIsMixSidebar)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('折叠菜单')}
|
||||
event={HandlerEnum.MENU_COLLAPSED}
|
||||
def={unref(getCollapsed)}
|
||||
disabled={!unref(getShowMenuRef)}
|
||||
/>
|
||||
|
||||
<SwitchItem
|
||||
title={t('侧边菜单拖拽')}
|
||||
event={HandlerEnum.MENU_HAS_DRAG}
|
||||
def={unref(getCanDrag)}
|
||||
disabled={!unref(getShowMenuRef)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('菜单搜索')}
|
||||
event={HandlerEnum.HEADER_SEARCH}
|
||||
def={unref(getShowSearch)}
|
||||
disabled={!unref(getShowHeader)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('侧边菜单手风琴模式')}
|
||||
event={HandlerEnum.MENU_ACCORDION}
|
||||
def={unref(getAccordion)}
|
||||
disabled={!unref(getShowMenuRef)}
|
||||
/>
|
||||
|
||||
<SwitchItem
|
||||
title={t('折叠菜单显示名称')}
|
||||
event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE}
|
||||
def={unref(getCollapsedShowTitle)}
|
||||
disabled={!unref(getShowMenuRef) || !unref(getCollapsed) || unref(getIsMixSidebar)}
|
||||
/>
|
||||
|
||||
<SwitchItem
|
||||
title={t('固定header')}
|
||||
event={HandlerEnum.HEADER_FIXED}
|
||||
def={unref(getHeaderFixed)}
|
||||
disabled={!unref(getShowHeader)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('固定Sidebar')}
|
||||
event={HandlerEnum.MENU_FIXED}
|
||||
def={unref(getMenuFixed)}
|
||||
disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)}
|
||||
/>
|
||||
<SelectItem
|
||||
title={t('混合菜单触发方式')}
|
||||
event={HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR}
|
||||
def={unref(getMixSideTrigger)}
|
||||
options={mixSidebarTriggerOptions}
|
||||
disabled={!unref(getIsMixSidebar)}
|
||||
/>
|
||||
<SelectItem
|
||||
title={t('顶部菜单布局')}
|
||||
event={HandlerEnum.MENU_TOP_ALIGN}
|
||||
def={unref(getTopMenuAlign)}
|
||||
options={topMenuAlignOptions}
|
||||
disabled={
|
||||
!unref(getShowHeader) ||
|
||||
unref(getSplit) ||
|
||||
(!unref(getIsTopMenu) && !unref(getSplit)) ||
|
||||
unref(getIsMixSidebar)
|
||||
const triggerOptions = getMenuTriggerOptions(unref(getSplit));
|
||||
const some = triggerOptions.some((item) => item.value === triggerDef);
|
||||
if (!some) {
|
||||
triggerDef = TriggerEnum.FOOTER;
|
||||
}
|
||||
/>
|
||||
<SelectItem
|
||||
title={t('菜单折叠按钮')}
|
||||
event={HandlerEnum.MENU_TRIGGER}
|
||||
def={triggerDef}
|
||||
options={triggerOptions}
|
||||
disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)}
|
||||
/>
|
||||
<SelectItem
|
||||
title={t('内容区域宽度')}
|
||||
event={HandlerEnum.CONTENT_MODE}
|
||||
def={unref(getContentMode)}
|
||||
options={contentModeOptions}
|
||||
/>
|
||||
<InputNumberItem
|
||||
title={t('自动锁屏')}
|
||||
min={0}
|
||||
event={HandlerEnum.LOCK_TIME}
|
||||
defaultValue={unref(getLockTime)}
|
||||
formatter={(value: string) => {
|
||||
return parseInt(value) === 0 ? `0(${t('不自动锁屏')})` : `${value}${t('分钟')}`;
|
||||
}}
|
||||
/>
|
||||
<InputNumberItem
|
||||
title={t('菜单展开宽度')}
|
||||
max={600}
|
||||
min={100}
|
||||
step={10}
|
||||
event={HandlerEnum.MENU_WIDTH}
|
||||
disabled={!unref(getShowMenuRef)}
|
||||
defaultValue={unref(getMenuWidth)}
|
||||
formatter={(value: string) => `${parseInt(value)}px`}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderContent() {
|
||||
return (
|
||||
<>
|
||||
<SwitchItem
|
||||
title={t('面包屑')}
|
||||
event={HandlerEnum.SHOW_BREADCRUMB}
|
||||
def={unref(getShowBreadCrumb)}
|
||||
disabled={!unref(getShowHeader)}
|
||||
/>
|
||||
return (
|
||||
<>
|
||||
<SwitchItem title={t('分割菜单')} event={HandlerEnum.MENU_SPLIT} def={unref(getSplit)} disabled={!unref(getShowMenuRef) || unref(getMenuType) !== MenuTypeEnum.MIX} />
|
||||
<SwitchItem title={t('固定展开菜单')} event={HandlerEnum.MENU_FIXED_MIX_SIDEBAR} def={unref(getMixSideFixed)} disabled={!unref(getIsMixSidebar)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('面包屑图标')}
|
||||
event={HandlerEnum.SHOW_BREADCRUMB_ICON}
|
||||
def={unref(getShowBreadCrumbIcon)}
|
||||
disabled={!unref(getShowHeader)}
|
||||
/>
|
||||
<SwitchItem title={t('切换页面关闭菜单')} event={HandlerEnum.MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE} def={unref(getCloseMixSidebarOnChange)} disabled={!unref(getIsMixSidebar)} />
|
||||
<SwitchItem title={t('折叠菜单')} event={HandlerEnum.MENU_COLLAPSED} def={unref(getCollapsed)} disabled={!unref(getShowMenuRef)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('标签页')}
|
||||
event={HandlerEnum.TABS_SHOW}
|
||||
def={unref(getShowMultipleTab)}
|
||||
/>
|
||||
<SwitchItem title={t('侧边菜单拖拽')} event={HandlerEnum.MENU_HAS_DRAG} def={unref(getCanDrag)} disabled={!unref(getShowMenuRef)} />
|
||||
<SwitchItem title={t('菜单搜索')} event={HandlerEnum.HEADER_SEARCH} def={unref(getShowSearch)} disabled={!unref(getShowHeader)} />
|
||||
<SwitchItem title={t('侧边菜单手风琴模式')} event={HandlerEnum.MENU_ACCORDION} def={unref(getAccordion)} disabled={!unref(getShowMenuRef)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('标签页刷新按钮')}
|
||||
event={HandlerEnum.TABS_SHOW_REDO}
|
||||
def={unref(getShowRedo)}
|
||||
disabled={!unref(getShowMultipleTab)}
|
||||
/>
|
||||
<SwitchItem title={t('折叠菜单显示名称')} event={HandlerEnum.MENU_COLLAPSED_SHOW_TITLE} def={unref(getCollapsedShowTitle)} disabled={!unref(getShowMenuRef) || !unref(getCollapsed) || unref(getIsMixSidebar)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('标签页快捷按钮')}
|
||||
event={HandlerEnum.TABS_SHOW_QUICK}
|
||||
def={unref(getShowQuick)}
|
||||
disabled={!unref(getShowMultipleTab)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('标签页折叠按钮')}
|
||||
event={HandlerEnum.TABS_SHOW_FOLD}
|
||||
def={unref(getShowFold)}
|
||||
disabled={!unref(getShowMultipleTab)}
|
||||
/>
|
||||
<SwitchItem title={t('固定header')} event={HandlerEnum.HEADER_FIXED} def={unref(getHeaderFixed)} disabled={!unref(getShowHeader)} />
|
||||
<SwitchItem title={t('固定Sidebar')} event={HandlerEnum.MENU_FIXED} def={unref(getMenuFixed)} disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)} />
|
||||
<SelectItem title={t('混合菜单触发方式')} event={HandlerEnum.MENU_TRIGGER_MIX_SIDEBAR} def={unref(getMixSideTrigger)} options={mixSidebarTriggerOptions} disabled={!unref(getIsMixSidebar)} />
|
||||
<SelectItem
|
||||
title={t('顶部菜单布局')}
|
||||
event={HandlerEnum.MENU_TOP_ALIGN}
|
||||
def={unref(getTopMenuAlign)}
|
||||
options={topMenuAlignOptions}
|
||||
disabled={!unref(getShowHeader) || unref(getSplit) || (!unref(getIsTopMenu) && !unref(getSplit)) || unref(getIsMixSidebar)}
|
||||
/>
|
||||
<SelectItem title={t('菜单折叠按钮')} event={HandlerEnum.MENU_TRIGGER} def={triggerDef} options={triggerOptions} disabled={!unref(getShowMenuRef) || unref(getIsMixSidebar)} />
|
||||
<SelectItem title={t('内容区域宽度')} event={HandlerEnum.CONTENT_MODE} def={unref(getContentMode)} options={contentModeOptions} />
|
||||
<InputNumberItem
|
||||
title={t('自动锁屏')}
|
||||
min={0}
|
||||
event={HandlerEnum.LOCK_TIME}
|
||||
defaultValue={unref(getLockTime)}
|
||||
formatter={(value: string) => {
|
||||
return parseInt(value) === 0 ? `0(${t('不自动锁屏')})` : `${value}${t('分钟')}`;
|
||||
}}
|
||||
/>
|
||||
<InputNumberItem title={t('菜单展开宽度')} max={600} min={100} step={10} event={HandlerEnum.MENU_WIDTH} disabled={!unref(getShowMenuRef)} defaultValue={unref(getMenuWidth)} formatter={(value: string) => `${parseInt(value)}px`} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
<SwitchItem
|
||||
title={t('左侧菜单')}
|
||||
event={HandlerEnum.MENU_SHOW_SIDEBAR}
|
||||
def={unref(getShowMenu)}
|
||||
disabled={unref(getIsHorizontal)}
|
||||
/>
|
||||
function renderContent() {
|
||||
return (
|
||||
<>
|
||||
<SwitchItem title={t('面包屑')} event={HandlerEnum.SHOW_BREADCRUMB} def={unref(getShowBreadCrumb)} disabled={!unref(getShowHeader)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('顶栏')}
|
||||
event={HandlerEnum.HEADER_SHOW}
|
||||
def={unref(getShowHeader)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title="Logo"
|
||||
event={HandlerEnum.SHOW_LOGO}
|
||||
def={unref(getShowLogo)}
|
||||
disabled={unref(getIsMixSidebar)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('页脚')}
|
||||
event={HandlerEnum.SHOW_FOOTER}
|
||||
def={unref(getShowFooter)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('全屏内容')}
|
||||
event={HandlerEnum.FULL_CONTENT}
|
||||
def={unref(getFullContent)}
|
||||
/>
|
||||
<SwitchItem title={t('面包屑图标')} event={HandlerEnum.SHOW_BREADCRUMB_ICON} def={unref(getShowBreadCrumbIcon)} disabled={!unref(getShowHeader)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('灰色模式')}
|
||||
event={HandlerEnum.GRAY_MODE}
|
||||
def={unref(getGrayMode)}
|
||||
/>
|
||||
<SwitchItem title={t('标签页')} event={HandlerEnum.TABS_SHOW} def={unref(getShowMultipleTab)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('色弱模式')}
|
||||
event={HandlerEnum.COLOR_WEAK}
|
||||
def={unref(getColorWeak)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
<SwitchItem title={t('标签页刷新按钮')} event={HandlerEnum.TABS_SHOW_REDO} def={unref(getShowRedo)} disabled={!unref(getShowMultipleTab)} />
|
||||
|
||||
function renderTransition() {
|
||||
return (
|
||||
<>
|
||||
<SwitchItem
|
||||
title={t('顶部进度条')}
|
||||
event={HandlerEnum.OPEN_PROGRESS}
|
||||
def={unref(getOpenNProgress)}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={t('切换loading')}
|
||||
event={HandlerEnum.OPEN_PAGE_LOADING}
|
||||
def={unref(getOpenPageLoading)}
|
||||
/>
|
||||
<SwitchItem title={t('标签页快捷按钮')} event={HandlerEnum.TABS_SHOW_QUICK} def={unref(getShowQuick)} disabled={!unref(getShowMultipleTab)} />
|
||||
<SwitchItem title={t('标签页折叠按钮')} event={HandlerEnum.TABS_SHOW_FOLD} def={unref(getShowFold)} disabled={!unref(getShowMultipleTab)} />
|
||||
|
||||
<SwitchItem
|
||||
title={t('切换动画')}
|
||||
event={HandlerEnum.OPEN_ROUTE_TRANSITION}
|
||||
def={unref(getEnableTransition)}
|
||||
/>
|
||||
<SwitchItem title={t('左侧菜单')} event={HandlerEnum.MENU_SHOW_SIDEBAR} def={unref(getShowMenu)} disabled={unref(getIsHorizontal)} />
|
||||
|
||||
<SelectItem
|
||||
title={t('动画类型')}
|
||||
event={HandlerEnum.ROUTER_TRANSITION}
|
||||
def={unref(getBasicTransition)}
|
||||
options={routerTransitionOptions}
|
||||
disabled={!unref(getEnableTransition)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
<SwitchItem title={t('顶栏')} event={HandlerEnum.HEADER_SHOW} def={unref(getShowHeader)} />
|
||||
<SwitchItem title="Logo" event={HandlerEnum.SHOW_LOGO} def={unref(getShowLogo)} disabled={unref(getIsMixSidebar)} />
|
||||
<SwitchItem title={t('页脚')} event={HandlerEnum.SHOW_FOOTER} def={unref(getShowFooter)} />
|
||||
<SwitchItem title={t('全屏内容')} event={HandlerEnum.FULL_CONTENT} def={unref(getFullContent)} />
|
||||
|
||||
return () => (
|
||||
<BasicDrawer {...attrs} title={t('项目配置')} width={330} class="setting-drawer">
|
||||
{/* {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
|
||||
<SwitchItem title={t('灰色模式')} event={HandlerEnum.GRAY_MODE} def={unref(getGrayMode)} />
|
||||
|
||||
<SwitchItem title={t('色弱模式')} event={HandlerEnum.COLOR_WEAK} def={unref(getColorWeak)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderTransition() {
|
||||
return (
|
||||
<>
|
||||
<SwitchItem title={t('顶部进度条')} event={HandlerEnum.OPEN_PROGRESS} def={unref(getOpenNProgress)} />
|
||||
<SwitchItem title={t('切换loading')} event={HandlerEnum.OPEN_PAGE_LOADING} def={unref(getOpenPageLoading)} />
|
||||
|
||||
<SwitchItem title={t('切换动画')} event={HandlerEnum.OPEN_ROUTE_TRANSITION} def={unref(getEnableTransition)} />
|
||||
|
||||
<SelectItem title={t('动画类型')} event={HandlerEnum.ROUTER_TRANSITION} def={unref(getBasicTransition)} options={routerTransitionOptions} disabled={!unref(getEnableTransition)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return () => (
|
||||
<BasicDrawer {...attrs} title={t('项目配置')} width={330} class="setting-drawer">
|
||||
{/* {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
|
||||
{unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" />} */}
|
||||
<Divider>{() => t('导航栏模式')}</Divider>
|
||||
{renderSidebar()}
|
||||
<Divider>{() => t('系统主题')}</Divider>
|
||||
{renderMainTheme()}
|
||||
<Divider>{() => t('顶栏主题')}</Divider>
|
||||
{renderHeaderTheme()}
|
||||
<Divider>{() => t('菜单主题')}</Divider>
|
||||
{renderSiderTheme()}
|
||||
<Divider>{() => t('界面功能')}</Divider>
|
||||
{renderFeatures()}
|
||||
<Divider>{() => t('界面显示')}</Divider>
|
||||
{renderContent()}
|
||||
<Divider>{() => t('动画')}</Divider>
|
||||
{renderTransition()}
|
||||
<Divider />
|
||||
<SettingFooter />
|
||||
</BasicDrawer>
|
||||
);
|
||||
},
|
||||
<Divider>{() => t('导航栏模式')}</Divider>
|
||||
{renderSidebar()}
|
||||
<Divider>{() => t('系统主题')}</Divider>
|
||||
{renderMainTheme()}
|
||||
<Divider>{() => t('顶栏主题')}</Divider>
|
||||
{renderHeaderTheme()}
|
||||
<Divider>{() => t('菜单主题')}</Divider>
|
||||
{renderSiderTheme()}
|
||||
<Divider>{() => t('界面功能')}</Divider>
|
||||
{renderFeatures()}
|
||||
<Divider>{() => t('界面显示')}</Divider>
|
||||
{renderContent()}
|
||||
<Divider>{() => t('动画')}</Divider>
|
||||
{renderTransition()}
|
||||
<Divider />
|
||||
<SettingFooter />
|
||||
</BasicDrawer>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,56 +1,51 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<InputNumber
|
||||
v-bind="$attrs"
|
||||
size="small"
|
||||
:class="`${prefixCls}-input-number`"
|
||||
@change="handleChange"
|
||||
/>
|
||||
</div>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<InputNumber v-bind="$attrs" size="small" :class="`${prefixCls}-input-number`" @change="handleChange" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'InputNumberItem',
|
||||
components: { InputNumber },
|
||||
props: {
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-input-number-item');
|
||||
export default defineComponent({
|
||||
name: 'InputNumberItem',
|
||||
components: { InputNumber },
|
||||
props: {
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>
|
||||
},
|
||||
title: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-input-number-item');
|
||||
|
||||
function handleChange(e) {
|
||||
props.event && baseHandler(props.event, e);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
handleChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
function handleChange(e) {
|
||||
props.event && baseHandler(props.event, e);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
handleChange
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-input-number-item';
|
||||
@prefix-cls: ~'@{namespace}-setting-input-number-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
|
||||
&-input-number {
|
||||
width: 126px;
|
||||
&-input-number {
|
||||
width: 126px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,75 +1,68 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<Select
|
||||
v-bind="getBindValue"
|
||||
:class="`${prefixCls}-select`"
|
||||
@change="handleChange"
|
||||
:disabled="disabled"
|
||||
size="small"
|
||||
:options="options"
|
||||
/>
|
||||
</div>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<Select v-bind="getBindValue" :class="`${prefixCls}-select`" @change="handleChange" :disabled="disabled" size="small" :options="options" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
|
||||
import { Select } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
import { Select } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SelectItem',
|
||||
components: { Select },
|
||||
props: {
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
def: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
},
|
||||
initValue: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<LabelValueOptions>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-select-item');
|
||||
const getBindValue = computed(() => {
|
||||
return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
|
||||
});
|
||||
export default defineComponent({
|
||||
name: 'SelectItem',
|
||||
components: { Select },
|
||||
props: {
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean
|
||||
},
|
||||
title: {
|
||||
type: String
|
||||
},
|
||||
def: {
|
||||
type: [String, Number] as PropType<string | number>
|
||||
},
|
||||
initValue: {
|
||||
type: [String, Number] as PropType<string | number>
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<LabelValueOptions>,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-select-item');
|
||||
const getBindValue = computed(() => {
|
||||
return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
|
||||
});
|
||||
|
||||
function handleChange(e: ChangeEvent) {
|
||||
props.event && baseHandler(props.event, e);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
handleChange,
|
||||
getBindValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
function handleChange(e: ChangeEvent) {
|
||||
props.event && baseHandler(props.event, e);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
handleChange,
|
||||
getBindValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-select-item';
|
||||
@prefix-cls: ~'@{namespace}-setting-select-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
|
||||
&-select {
|
||||
width: 126px;
|
||||
&-select {
|
||||
width: 126px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,99 +1,97 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<a-button type="primary" block @click="handleCopy">
|
||||
<CopyOutlined class="mr-2" />
|
||||
{{ t('拷贝') }}
|
||||
</a-button>
|
||||
<div :class="prefixCls">
|
||||
<a-button type="primary" block @click="handleCopy">
|
||||
<CopyOutlined class="mr-2" />
|
||||
{{ t('拷贝') }}
|
||||
</a-button>
|
||||
|
||||
<a-button color="warning" block @click="handleResetSetting" class="my-3">
|
||||
<RedoOutlined class="mr-2" />
|
||||
{{ t('重置') }}
|
||||
</a-button>
|
||||
<a-button color="warning" block @click="handleResetSetting" class="my-3">
|
||||
<RedoOutlined class="mr-2" />
|
||||
{{ t('重置') }}
|
||||
</a-button>
|
||||
|
||||
<a-button color="error" block @click="handleClearAndRedo">
|
||||
<RedoOutlined class="mr-2" />
|
||||
{{ t('清空缓存并返回登录页') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<a-button color="error" block @click="handleClearAndRedo">
|
||||
<RedoOutlined class="mr-2" />
|
||||
{{ t('清空缓存并返回登录页') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, unref } from 'vue';
|
||||
import { defineComponent, unref } from 'vue';
|
||||
|
||||
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
|
||||
import { CopyOutlined, RedoOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import { usePermissionStore } from '/@/store/modules/permission';
|
||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import { usePermissionStore } from '/@/store/modules/permission';
|
||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
|
||||
|
||||
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
|
||||
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
|
||||
import defaultSetting from '/@/settings/projectSetting';
|
||||
import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
|
||||
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
|
||||
import defaultSetting from '/@/settings/projectSetting';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SettingFooter',
|
||||
components: { CopyOutlined, RedoOutlined },
|
||||
setup() {
|
||||
const permissionStore = usePermissionStore();
|
||||
const { prefixCls } = useDesign('setting-footer');
|
||||
const { t } = useI18n();
|
||||
const { createSuccessModal, createMessage } = useMessage();
|
||||
const tabStore = useMultipleTabStore();
|
||||
const userStore = useUserStore();
|
||||
const appStore = useAppStore();
|
||||
export default defineComponent({
|
||||
name: 'SettingFooter',
|
||||
components: { CopyOutlined, RedoOutlined },
|
||||
setup() {
|
||||
const permissionStore = usePermissionStore();
|
||||
const { prefixCls } = useDesign('setting-footer');
|
||||
const { t } = useI18n();
|
||||
const { createSuccessModal, createMessage } = useMessage();
|
||||
const tabStore = useMultipleTabStore();
|
||||
const userStore = useUserStore();
|
||||
const appStore = useAppStore();
|
||||
|
||||
function handleCopy() {
|
||||
const { isSuccessRef } = useCopyToClipboard(
|
||||
JSON.stringify(unref(appStore.getProjectConfig), null, 2),
|
||||
);
|
||||
unref(isSuccessRef) &&
|
||||
createSuccessModal({
|
||||
title: t('操作成功'),
|
||||
content: t('复制成功,请到 src/settings/projectSetting.ts 中修改配置!'),
|
||||
});
|
||||
}
|
||||
function handleResetSetting() {
|
||||
try {
|
||||
appStore.setProjectConfig(defaultSetting);
|
||||
const { colorWeak, grayMode } = defaultSetting;
|
||||
// updateTheme(themeColor);
|
||||
updateColorWeak(colorWeak);
|
||||
updateGrayMode(grayMode);
|
||||
createMessage.success(t('重置成功!'));
|
||||
} catch (error: any) {
|
||||
createMessage.error(error);
|
||||
function handleCopy() {
|
||||
const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(appStore.getProjectConfig), null, 2));
|
||||
unref(isSuccessRef) &&
|
||||
createSuccessModal({
|
||||
title: t('操作成功'),
|
||||
content: t('复制成功,请到 src/settings/projectSetting.ts 中修改配置!')
|
||||
});
|
||||
}
|
||||
function handleResetSetting() {
|
||||
try {
|
||||
appStore.setProjectConfig(defaultSetting);
|
||||
const { colorWeak, grayMode } = defaultSetting;
|
||||
// updateTheme(themeColor);
|
||||
updateColorWeak(colorWeak);
|
||||
updateGrayMode(grayMode);
|
||||
createMessage.success(t('重置成功!'));
|
||||
} catch (error: any) {
|
||||
createMessage.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function handleClearAndRedo() {
|
||||
localStorage.clear();
|
||||
appStore.resetAllState();
|
||||
permissionStore.resetState();
|
||||
tabStore.resetState();
|
||||
userStore.resetState();
|
||||
location.reload();
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
t,
|
||||
handleCopy,
|
||||
handleResetSetting,
|
||||
handleClearAndRedo
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function handleClearAndRedo() {
|
||||
localStorage.clear();
|
||||
appStore.resetAllState();
|
||||
permissionStore.resetState();
|
||||
tabStore.resetState();
|
||||
userStore.resetState();
|
||||
location.reload();
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
t,
|
||||
handleCopy,
|
||||
handleResetSetting,
|
||||
handleClearAndRedo,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-footer';
|
||||
@prefix-cls: ~'@{namespace}-setting-footer';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,66 +1,60 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<Switch
|
||||
v-bind="getBindValue"
|
||||
@change="handleChange"
|
||||
:disabled="disabled"
|
||||
:checkedChildren="t('开')"
|
||||
:unCheckedChildren="t('关')"
|
||||
/>
|
||||
</div>
|
||||
<div :class="prefixCls">
|
||||
<span> {{ title }}</span>
|
||||
<Switch v-bind="getBindValue" @change="handleChange" :disabled="disabled" :checkedChildren="t('开')" :unCheckedChildren="t('关')" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
|
||||
import { Switch } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
import { Switch } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SwitchItem',
|
||||
components: { Switch },
|
||||
props: {
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
def: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-switch-item');
|
||||
const { t } = useI18n();
|
||||
export default defineComponent({
|
||||
name: 'SwitchItem',
|
||||
components: { Switch },
|
||||
props: {
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean
|
||||
},
|
||||
title: {
|
||||
type: String
|
||||
},
|
||||
def: {
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-switch-item');
|
||||
const { t } = useI18n();
|
||||
|
||||
const getBindValue = computed(() => {
|
||||
return props.def ? { checked: props.def } : {};
|
||||
});
|
||||
function handleChange(e: ChangeEvent) {
|
||||
props.event && baseHandler(props.event, e);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
t,
|
||||
handleChange,
|
||||
getBindValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
const getBindValue = computed(() => {
|
||||
return props.def ? { checked: props.def } : {};
|
||||
});
|
||||
function handleChange(e: ChangeEvent) {
|
||||
props.event && baseHandler(props.event, e);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
t,
|
||||
handleChange,
|
||||
getBindValue
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-switch-item';
|
||||
@prefix-cls: ~'@{namespace}-setting-switch-item';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 16px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,88 +1,88 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<template v-for="color in colorList || []" :key="color">
|
||||
<span
|
||||
@click="handleClick(color)"
|
||||
:class="[
|
||||
`${prefixCls}__item`,
|
||||
{
|
||||
[`${prefixCls}__item--active`]: def === color,
|
||||
},
|
||||
]"
|
||||
:style="{ background: color }"
|
||||
>
|
||||
<CheckOutlined />
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
<div :class="prefixCls">
|
||||
<template v-for="color in colorList || []" :key="color">
|
||||
<span
|
||||
@click="handleClick(color)"
|
||||
:class="[
|
||||
`${prefixCls}__item`,
|
||||
{
|
||||
[`${prefixCls}__item--active`]: def === color
|
||||
}
|
||||
]"
|
||||
:style="{ background: color }"
|
||||
>
|
||||
<CheckOutlined />
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { CheckOutlined } from '@ant-design/icons-vue';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { CheckOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
import { baseHandler } from '../handler';
|
||||
import { HandlerEnum } from '../enum';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ThemeColorPicker',
|
||||
components: { CheckOutlined },
|
||||
props: {
|
||||
colorList: {
|
||||
type: Array as PropType<string[]>,
|
||||
defualt: [],
|
||||
},
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>,
|
||||
},
|
||||
def: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-theme-picker');
|
||||
export default defineComponent({
|
||||
name: 'ThemeColorPicker',
|
||||
components: { CheckOutlined },
|
||||
props: {
|
||||
colorList: {
|
||||
type: Array as PropType<string[]>,
|
||||
defualt: []
|
||||
},
|
||||
event: {
|
||||
type: Number as PropType<HandlerEnum>
|
||||
},
|
||||
def: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('setting-theme-picker');
|
||||
|
||||
function handleClick(color: string) {
|
||||
props.event && baseHandler(props.event, color);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
handleClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
function handleClick(color: string) {
|
||||
props.event && baseHandler(props.event, color);
|
||||
}
|
||||
return {
|
||||
prefixCls,
|
||||
handleClick
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-setting-theme-picker';
|
||||
@prefix-cls: ~'@{namespace}-setting-theme-picker';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 16px 0;
|
||||
justify-content: space-around;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 16px 0;
|
||||
justify-content: space-around;
|
||||
|
||||
&__item {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2px;
|
||||
&__item {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2px;
|
||||
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&--active {
|
||||
border: 1px solid lighten(@primary-color, 10%);
|
||||
&--active {
|
||||
border: 1px solid lighten(@primary-color, 10%);
|
||||
|
||||
svg {
|
||||
display: inline-block;
|
||||
margin: 0 0 3px 3px;
|
||||
font-size: 12px;
|
||||
fill: @white !important;
|
||||
svg {
|
||||
display: inline-block;
|
||||
margin: 0 0 3px 3px;
|
||||
font-size: 12px;
|
||||
fill: @white !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,178 +1,178 @@
|
||||
<template>
|
||||
<div :class="prefixCls">
|
||||
<template v-for="item in menuTypeList || []" :key="item.title">
|
||||
<Tooltip :title="item.title" placement="bottom">
|
||||
<div
|
||||
@click="handler(item)"
|
||||
:class="[
|
||||
`${prefixCls}__item`,
|
||||
`${prefixCls}__item--${item.type}`,
|
||||
{
|
||||
[`${prefixCls}__item--active`]: def === item.type,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div class="mix-sidebar"></div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</template>
|
||||
</div>
|
||||
<div :class="prefixCls">
|
||||
<template v-for="item in menuTypeList || []" :key="item.title">
|
||||
<Tooltip :title="item.title" placement="bottom">
|
||||
<div
|
||||
@click="handler(item)"
|
||||
:class="[
|
||||
`${prefixCls}__item`,
|
||||
`${prefixCls}__item--${item.type}`,
|
||||
{
|
||||
[`${prefixCls}__item--active`]: def === item.type
|
||||
}
|
||||
]"
|
||||
>
|
||||
<div class="mix-sidebar"></div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import { menuTypeList } from '../enum';
|
||||
export default defineComponent({
|
||||
name: 'MenuTypePicker',
|
||||
components: { Tooltip },
|
||||
props: {
|
||||
menuTypeList: {
|
||||
type: Array as PropType<typeof menuTypeList>,
|
||||
defualt: () => [],
|
||||
},
|
||||
handler: {
|
||||
type: Function as PropType<Fn>,
|
||||
default: () => ({}),
|
||||
},
|
||||
def: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('setting-menu-type-picker');
|
||||
import { menuTypeList } from '../enum';
|
||||
export default defineComponent({
|
||||
name: 'MenuTypePicker',
|
||||
components: { Tooltip },
|
||||
props: {
|
||||
menuTypeList: {
|
||||
type: Array as PropType<typeof menuTypeList>,
|
||||
defualt: () => []
|
||||
},
|
||||
handler: {
|
||||
type: Function as PropType<Fn>,
|
||||
default: () => ({})
|
||||
},
|
||||
def: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('setting-menu-type-picker');
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
prefixCls
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-setting-menu-type-picker';
|
||||
@prefix-cls: ~'@{namespace}-setting-menu-type-picker';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
|
||||
&__item {
|
||||
position: relative;
|
||||
width: 56px;
|
||||
height: 48px;
|
||||
margin-right: 16px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: #f0f2f5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
|
||||
&__item {
|
||||
position: relative;
|
||||
width: 56px;
|
||||
height: 48px;
|
||||
margin-right: 16px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
background-color: #f0f2f5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
}
|
||||
&::before,
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&--sidebar,
|
||||
&--light {
|
||||
&::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
background-color: #273352;
|
||||
border-radius: 4px 0 0 4px;
|
||||
&--sidebar,
|
||||
&--light {
|
||||
&::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
background-color: #273352;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&--mix {
|
||||
&::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #273352;
|
||||
}
|
||||
}
|
||||
|
||||
&--top-menu {
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #273352;
|
||||
}
|
||||
}
|
||||
|
||||
&--dark {
|
||||
background-color: #273352;
|
||||
}
|
||||
|
||||
&--mix-sidebar {
|
||||
&::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
background-color: #273352;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.mix-sidebar {
|
||||
position: absolute;
|
||||
left: 25%;
|
||||
width: 15%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&--active {
|
||||
padding: 12px;
|
||||
border: 2px solid @primary-color;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #fff;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&--mix {
|
||||
&::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #273352;
|
||||
}
|
||||
}
|
||||
|
||||
&--top-menu {
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #273352;
|
||||
}
|
||||
}
|
||||
|
||||
&--dark {
|
||||
background-color: #273352;
|
||||
}
|
||||
|
||||
&--mix-sidebar {
|
||||
&::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 25%;
|
||||
height: 100%;
|
||||
background-color: #273352;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 25%;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.mix-sidebar {
|
||||
position: absolute;
|
||||
left: 25%;
|
||||
width: 15%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&--active {
|
||||
padding: 12px;
|
||||
border: 2px solid @primary-color;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,66 +1,66 @@
|
||||
<template>
|
||||
<div :class="getClass" :style="getDragBarStyle"></div>
|
||||
<div :class="getClass" :style="getDragBarStyle"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DargBar',
|
||||
props: {
|
||||
mobile: Boolean,
|
||||
},
|
||||
setup(props) {
|
||||
const { getMiniWidthNumber, getCollapsed, getCanDrag } = useMenuSetting();
|
||||
export default defineComponent({
|
||||
name: 'DargBar',
|
||||
props: {
|
||||
mobile: Boolean
|
||||
},
|
||||
setup(props) {
|
||||
const { getMiniWidthNumber, getCollapsed, getCanDrag } = useMenuSetting();
|
||||
|
||||
const { prefixCls } = useDesign('darg-bar');
|
||||
const getDragBarStyle = computed(() => {
|
||||
if (unref(getCollapsed)) {
|
||||
return { left: `${unref(getMiniWidthNumber)}px` };
|
||||
const { prefixCls } = useDesign('darg-bar');
|
||||
const getDragBarStyle = computed(() => {
|
||||
if (unref(getCollapsed)) {
|
||||
return { left: `${unref(getMiniWidthNumber)}px` };
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--hide`]: !unref(getCanDrag) || props.mobile
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
getDragBarStyle,
|
||||
getClass
|
||||
};
|
||||
}
|
||||
return {};
|
||||
});
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--hide`]: !unref(getCanDrag) || props.mobile,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
getDragBarStyle,
|
||||
getClass,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-darg-bar';
|
||||
@prefix-cls: ~'@{namespace}-darg-bar';
|
||||
|
||||
.@{prefix-cls} {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -2px;
|
||||
z-index: @side-drag-z-index;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
.@{prefix-cls} {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -2px;
|
||||
z-index: @side-drag-z-index;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
|
||||
&--hide {
|
||||
display: none;
|
||||
&--hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @primary-color;
|
||||
box-shadow: 0 0 4px 0 rgb(28 36 56 / 15%);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @primary-color;
|
||||
box-shadow: 0 0 4px 0 rgb(28 36 56 / 15%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,185 +1,171 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="getMenuFixed && !getIsMobile"
|
||||
:style="getHiddenDomStyle"
|
||||
v-show="showClassSideBarRef"
|
||||
></div>
|
||||
<Sider
|
||||
v-show="showClassSideBarRef"
|
||||
ref="sideRef"
|
||||
breakpoint="lg"
|
||||
collapsible
|
||||
:class="getSiderClass"
|
||||
:width="getMenuWidth"
|
||||
:collapsed="getCollapsed"
|
||||
:collapsedWidth="getCollapsedWidth"
|
||||
:theme="getMenuTheme"
|
||||
@breakpoint="onBreakpointChange"
|
||||
:trigger="getTrigger"
|
||||
v-bind="getTriggerAttr"
|
||||
>
|
||||
<template #trigger v-if="getShowTrigger">
|
||||
<LayoutTrigger />
|
||||
</template>
|
||||
<LayoutMenu :theme="getMenuTheme" :menuMode="getMode" :splitType="getSplitType" />
|
||||
<DragBar ref="dragBarRef" />
|
||||
</Sider>
|
||||
<div v-if="getMenuFixed && !getIsMobile" :style="getHiddenDomStyle" v-show="showClassSideBarRef"></div>
|
||||
<Sider
|
||||
v-show="showClassSideBarRef"
|
||||
ref="sideRef"
|
||||
breakpoint="lg"
|
||||
collapsible
|
||||
:class="getSiderClass"
|
||||
:width="getMenuWidth"
|
||||
:collapsed="getCollapsed"
|
||||
:collapsedWidth="getCollapsedWidth"
|
||||
:theme="getMenuTheme"
|
||||
@breakpoint="onBreakpointChange"
|
||||
:trigger="getTrigger"
|
||||
v-bind="getTriggerAttr"
|
||||
>
|
||||
<template #trigger v-if="getShowTrigger">
|
||||
<LayoutTrigger />
|
||||
</template>
|
||||
<LayoutMenu :theme="getMenuTheme" :menuMode="getMode" :splitType="getSplitType" />
|
||||
<DragBar ref="dragBarRef" />
|
||||
</Sider>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, unref, CSSProperties, h } from 'vue';
|
||||
import { computed, defineComponent, ref, unref, CSSProperties, h } from 'vue';
|
||||
|
||||
import { Layout } from 'ant-design-vue';
|
||||
import LayoutMenu from '../menu/index.vue';
|
||||
import LayoutTrigger from '/@/layouts/default/trigger/index.vue';
|
||||
import { Layout } from 'ant-design-vue';
|
||||
import LayoutMenu from '../menu/index.vue';
|
||||
import LayoutTrigger from '/@/layouts/default/trigger/index.vue';
|
||||
|
||||
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
||||
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
|
||||
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider';
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
import DragBar from './DragBar.vue';
|
||||
export default defineComponent({
|
||||
name: 'LayoutSideBar',
|
||||
components: { Sider: Layout.Sider, LayoutMenu, DragBar, LayoutTrigger },
|
||||
setup() {
|
||||
const dragBarRef = ref<ElRef>(null);
|
||||
const sideRef = ref<ElRef>(null);
|
||||
import DragBar from './DragBar.vue';
|
||||
export default defineComponent({
|
||||
name: 'LayoutSideBar',
|
||||
components: { Sider: Layout.Sider, LayoutMenu, DragBar, LayoutTrigger },
|
||||
setup() {
|
||||
const dragBarRef = ref<ElRef>(null);
|
||||
const sideRef = ref<ElRef>(null);
|
||||
|
||||
const {
|
||||
getCollapsed,
|
||||
getMenuWidth,
|
||||
getSplit,
|
||||
getMenuTheme,
|
||||
getRealWidth,
|
||||
getMenuHidden,
|
||||
getMenuFixed,
|
||||
getIsMixMode,
|
||||
toggleCollapsed,
|
||||
} = useMenuSetting();
|
||||
const { getCollapsed, getMenuWidth, getSplit, getMenuTheme, getRealWidth, getMenuHidden, getMenuFixed, getIsMixMode, toggleCollapsed } = useMenuSetting();
|
||||
|
||||
const { prefixCls } = useDesign('layout-sideBar');
|
||||
const { prefixCls } = useDesign('layout-sideBar');
|
||||
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { getIsMobile } = useAppInject();
|
||||
|
||||
const { getTriggerAttr, getShowTrigger } = useTrigger(getIsMobile);
|
||||
const { getTriggerAttr, getShowTrigger } = useTrigger(getIsMobile);
|
||||
|
||||
useDragLine(sideRef, dragBarRef);
|
||||
useDragLine(sideRef, dragBarRef);
|
||||
|
||||
const { getCollapsedWidth, onBreakpointChange } = useSiderEvent();
|
||||
const { getCollapsedWidth, onBreakpointChange } = useSiderEvent();
|
||||
|
||||
const getMode = computed(() => {
|
||||
return unref(getSplit) ? MenuModeEnum.INLINE : null;
|
||||
});
|
||||
const getMode = computed(() => {
|
||||
return unref(getSplit) ? MenuModeEnum.INLINE : null;
|
||||
});
|
||||
|
||||
const getSplitType = computed(() => {
|
||||
return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE;
|
||||
});
|
||||
const getSplitType = computed(() => {
|
||||
return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE;
|
||||
});
|
||||
|
||||
const showClassSideBarRef = computed(() => {
|
||||
return unref(getSplit) ? !unref(getMenuHidden) : true;
|
||||
});
|
||||
const showClassSideBarRef = computed(() => {
|
||||
return unref(getSplit) ? !unref(getMenuHidden) : true;
|
||||
});
|
||||
|
||||
const getSiderClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--fixed`]: unref(getMenuFixed),
|
||||
[`${prefixCls}--mix`]: unref(getIsMixMode) && !unref(getIsMobile),
|
||||
},
|
||||
];
|
||||
});
|
||||
const getSiderClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--fixed`]: unref(getMenuFixed),
|
||||
[`${prefixCls}--mix`]: unref(getIsMixMode) && !unref(getIsMobile)
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const getHiddenDomStyle = computed((): CSSProperties => {
|
||||
const width = `${unref(getRealWidth)}px`;
|
||||
return {
|
||||
width: width,
|
||||
overflow: 'hidden',
|
||||
flex: `0 0 ${width}`,
|
||||
maxWidth: width,
|
||||
minWidth: width,
|
||||
transition: 'all 0.2s',
|
||||
};
|
||||
});
|
||||
const getHiddenDomStyle = computed((): CSSProperties => {
|
||||
const width = `${unref(getRealWidth)}px`;
|
||||
return {
|
||||
width: width,
|
||||
overflow: 'hidden',
|
||||
flex: `0 0 ${width}`,
|
||||
maxWidth: width,
|
||||
minWidth: width,
|
||||
transition: 'all 0.2s'
|
||||
};
|
||||
});
|
||||
|
||||
// 在此处使用计算量可能会导致sider异常
|
||||
// andv 更新后,如果trigger插槽可用,则此处代码可废弃
|
||||
const getTrigger = h(LayoutTrigger);
|
||||
// 在此处使用计算量可能会导致sider异常
|
||||
// andv 更新后,如果trigger插槽可用,则此处代码可废弃
|
||||
const getTrigger = h(LayoutTrigger);
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
sideRef,
|
||||
dragBarRef,
|
||||
getIsMobile,
|
||||
getHiddenDomStyle,
|
||||
getSiderClass,
|
||||
getTrigger,
|
||||
getTriggerAttr,
|
||||
getCollapsedWidth,
|
||||
getMenuFixed,
|
||||
showClassSideBarRef,
|
||||
getMenuWidth,
|
||||
getCollapsed,
|
||||
getMenuTheme,
|
||||
onBreakpointChange,
|
||||
getMode,
|
||||
getSplitType,
|
||||
getShowTrigger,
|
||||
toggleCollapsed,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
prefixCls,
|
||||
sideRef,
|
||||
dragBarRef,
|
||||
getIsMobile,
|
||||
getHiddenDomStyle,
|
||||
getSiderClass,
|
||||
getTrigger,
|
||||
getTriggerAttr,
|
||||
getCollapsedWidth,
|
||||
getMenuFixed,
|
||||
showClassSideBarRef,
|
||||
getMenuWidth,
|
||||
getCollapsed,
|
||||
getMenuTheme,
|
||||
onBreakpointChange,
|
||||
getMode,
|
||||
getSplitType,
|
||||
getShowTrigger,
|
||||
toggleCollapsed
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-layout-sideBar';
|
||||
@prefix-cls: ~'@{namespace}-layout-sideBar';
|
||||
|
||||
.@{prefix-cls} {
|
||||
z-index: @layout-sider-fixed-z-index;
|
||||
.@{prefix-cls} {
|
||||
z-index: @layout-sider-fixed-z-index;
|
||||
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&--mix {
|
||||
top: @header-height;
|
||||
height: calc(100% - @header-height);
|
||||
}
|
||||
|
||||
&.ant-layout-sider-dark {
|
||||
background-color: @sider-dark-bg-color;
|
||||
|
||||
.ant-layout-sider-trigger {
|
||||
color: darken(@white, 25%);
|
||||
background-color: @trigger-dark-bg-color;
|
||||
|
||||
&:hover {
|
||||
color: @white;
|
||||
background-color: @trigger-dark-hover-bg-color;
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.ant-layout-sider-dark) {
|
||||
// box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
|
||||
&--mix {
|
||||
top: @header-height;
|
||||
height: calc(100% - @header-height);
|
||||
}
|
||||
|
||||
.ant-layout-sider-trigger {
|
||||
color: @text-color-base;
|
||||
border-top: 1px solid @border-color-light;
|
||||
}
|
||||
}
|
||||
&.ant-layout-sider-dark {
|
||||
background-color: @sider-dark-bg-color;
|
||||
|
||||
.ant-layout-sider-zero-width-trigger {
|
||||
top: 40%;
|
||||
z-index: 10;
|
||||
}
|
||||
.ant-layout-sider-trigger {
|
||||
color: darken(@white, 25%);
|
||||
background-color: @trigger-dark-bg-color;
|
||||
|
||||
& .ant-layout-sider-trigger {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
&:hover {
|
||||
color: @white;
|
||||
background-color: @trigger-dark-hover-bg-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.ant-layout-sider-dark) {
|
||||
// box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
|
||||
|
||||
.ant-layout-sider-trigger {
|
||||
color: @text-color-base;
|
||||
border-top: 1px solid @border-color-light;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-layout-sider-zero-width-trigger {
|
||||
top: 40%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
& .ant-layout-sider-trigger {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,6 @@
|
||||
<template>
|
||||
<template v-if="!isOnlyShowContent">
|
||||
<Drawer
|
||||
v-if="getIsMobile"
|
||||
placement="left"
|
||||
:class="prefixCls"
|
||||
:width="getMenuWidth"
|
||||
:getContainer="null"
|
||||
:visible="!getCollapsed"
|
||||
@close="handleClose"
|
||||
>
|
||||
<Drawer v-if="getIsMobile" placement="left" :class="prefixCls" :width="getMenuWidth" :getContainer="null" :visible="!getCollapsed" @close="handleClose">
|
||||
<Sider />
|
||||
</Drawer>
|
||||
<MixSider v-else-if="getIsMixSidebar" />
|
||||
@ -16,48 +8,48 @@
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent,computed } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
|
||||
import Sider from './LayoutSider.vue';
|
||||
import MixSider from './MixSider.vue';
|
||||
import { Drawer } from 'ant-design-vue';
|
||||
import Sider from './LayoutSider.vue';
|
||||
import MixSider from './MixSider.vue';
|
||||
import { Drawer } from 'ant-design-vue';
|
||||
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
export default defineComponent({
|
||||
name: 'SiderWrapper',
|
||||
components: { Sider, Drawer, MixSider },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('layout-sider-wrapper');
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { setMenuSetting, getCollapsed, getMenuWidth, getIsMixSidebar } = useMenuSetting();
|
||||
import { useAppInject } from '/@/hooks/web/useAppInject';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
export default defineComponent({
|
||||
name: 'SiderWrapper',
|
||||
components: { Sider, Drawer, MixSider },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('layout-sider-wrapper');
|
||||
const { getIsMobile } = useAppInject();
|
||||
const { setMenuSetting, getCollapsed, getMenuWidth, getIsMixSidebar } = useMenuSetting();
|
||||
|
||||
function handleClose() {
|
||||
setMenuSetting({
|
||||
collapsed: true,
|
||||
});
|
||||
}
|
||||
function handleClose() {
|
||||
setMenuSetting({
|
||||
collapsed: true
|
||||
});
|
||||
}
|
||||
|
||||
const isOnlyShowContent = computed(() => {
|
||||
return window.isOnlyShowContent=='Y';
|
||||
});
|
||||
const isOnlyShowContent = computed(() => {
|
||||
return window.isOnlyShowContent == 'Y';
|
||||
});
|
||||
|
||||
return { prefixCls, getIsMobile, getCollapsed, handleClose, getMenuWidth, getIsMixSidebar,isOnlyShowContent };
|
||||
},
|
||||
});
|
||||
return { prefixCls, getIsMobile, getCollapsed, handleClose, getMenuWidth, getIsMixSidebar, isOnlyShowContent };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-layout-sider-wrapper';
|
||||
@prefix-cls: ~'@{namespace}-layout-sider-wrapper';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-drawer-body {
|
||||
height: 100vh;
|
||||
padding: 0;
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
.ant-drawer-body {
|
||||
height: 100vh;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ant-drawer-header-no-title {
|
||||
display: none;
|
||||
.ant-drawer-header-no-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,42 +1,40 @@
|
||||
<template>
|
||||
<span :class="`${prefixCls}__extra-fold`" @click="handleFold">
|
||||
<Icon :icon="getIcon" />
|
||||
</span>
|
||||
<span :class="`${prefixCls}__extra-fold`" @click="handleFold">
|
||||
<Icon :icon="getIcon" />
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, unref, computed } from 'vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { defineComponent, unref, computed } from 'vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { triggerWindowResize } from '/@/utils/event';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { triggerWindowResize } from '/@/utils/event';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FoldButton',
|
||||
components: { Icon },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||
const { getShowMenu, setMenuSetting } = useMenuSetting();
|
||||
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
|
||||
export default defineComponent({
|
||||
name: 'FoldButton',
|
||||
components: { Icon },
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||
const { getShowMenu, setMenuSetting } = useMenuSetting();
|
||||
const { getShowHeader, setHeaderSetting } = useHeaderSetting();
|
||||
|
||||
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
||||
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader));
|
||||
|
||||
const getIcon = computed(() =>
|
||||
unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full',
|
||||
);
|
||||
const getIcon = computed(() => (unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full'));
|
||||
|
||||
function handleFold() {
|
||||
const isUnFold = unref(getIsUnFold);
|
||||
setMenuSetting({
|
||||
show: isUnFold,
|
||||
hidden: !isUnFold,
|
||||
});
|
||||
setHeaderSetting({ show: isUnFold });
|
||||
triggerWindowResize();
|
||||
}
|
||||
function handleFold() {
|
||||
const isUnFold = unref(getIsUnFold);
|
||||
setMenuSetting({
|
||||
show: isUnFold,
|
||||
hidden: !isUnFold
|
||||
});
|
||||
setHeaderSetting({ show: isUnFold });
|
||||
triggerWindowResize();
|
||||
}
|
||||
|
||||
return { prefixCls, getIcon, handleFold };
|
||||
},
|
||||
});
|
||||
return { prefixCls, getIcon, handleFold };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,78 +1,67 @@
|
||||
<template>
|
||||
<Dropdown
|
||||
:dropMenuList="getDropMenuList"
|
||||
:trigger="getTrigger"
|
||||
placement="bottom"
|
||||
overlayClassName="multiple-tabs__dropdown"
|
||||
@menu-event="handleMenuEvent"
|
||||
>
|
||||
<div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs">
|
||||
<span class="ml-1">{{ getTitle }}</span>
|
||||
</div>
|
||||
<span :class="`${prefixCls}__extra-quick`" v-else @click="handleContext">
|
||||
<Icon icon="ion:chevron-down" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
<Dropdown :dropMenuList="getDropMenuList" :trigger="getTrigger" placement="bottom" overlayClassName="multiple-tabs__dropdown" @menu-event="handleMenuEvent">
|
||||
<div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs">
|
||||
<span class="ml-1">{{ getTitle }}</span>
|
||||
</div>
|
||||
<span :class="`${prefixCls}__extra-quick`" v-else @click="handleContext">
|
||||
<Icon icon="ion:chevron-down" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
import type { PropType } from 'vue';
|
||||
import type { RouteLocationNormalized } from 'vue-router';
|
||||
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { Dropdown } from '/@/components/Dropdown/index';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { defineComponent, computed, unref } from 'vue';
|
||||
import { Dropdown } from '/@/components/Dropdown/index';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
import { TabContentProps } from '../types';
|
||||
import { TabContentProps } from '../types';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTabDropdown } from '../useTabDropdown';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useTabDropdown } from '../useTabDropdown';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabContent',
|
||||
components: { Dropdown, Icon },
|
||||
props: {
|
||||
tabItem: {
|
||||
type: Object as PropType<RouteLocationNormalized>,
|
||||
default: null,
|
||||
},
|
||||
isExtra: Boolean,
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||
const { t } = useI18n();
|
||||
export default defineComponent({
|
||||
name: 'TabContent',
|
||||
components: { Dropdown, Icon },
|
||||
props: {
|
||||
tabItem: {
|
||||
type: Object as PropType<RouteLocationNormalized>,
|
||||
default: null
|
||||
},
|
||||
isExtra: Boolean
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||
const { t } = useI18n();
|
||||
|
||||
const getTitle = computed(() => {
|
||||
const tabItem = props.tabItem as any;
|
||||
const meta = tabItem.meta || {};
|
||||
const metaTitle=typeof meta?.title=='function'?meta.title(tabItem):meta?.title;
|
||||
return tabItem.tabTitle || (meta && t(metaTitle as string));
|
||||
});
|
||||
const getTitle = computed(() => {
|
||||
const tabItem = props.tabItem as any;
|
||||
const meta = tabItem.meta || {};
|
||||
const metaTitle = typeof meta?.title == 'function' ? meta.title(tabItem) : meta?.title;
|
||||
return tabItem.tabTitle || (meta && t(metaTitle as string));
|
||||
});
|
||||
|
||||
const getIsTabs = computed(() => !props.isExtra);
|
||||
const getIsTabs = computed(() => !props.isExtra);
|
||||
|
||||
const getTrigger = computed((): ('contextmenu' | 'click' | 'hover')[] =>
|
||||
unref(getIsTabs) ? ['contextmenu'] : ['click'],
|
||||
);
|
||||
const getTrigger = computed((): ('contextmenu' | 'click' | 'hover')[] => (unref(getIsTabs) ? ['contextmenu'] : ['click']));
|
||||
|
||||
const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(
|
||||
props as TabContentProps,
|
||||
getIsTabs,
|
||||
);
|
||||
const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(props as TabContentProps, getIsTabs);
|
||||
|
||||
function handleContext(e) {
|
||||
props.tabItem && handleContextMenu(props.tabItem)(e);
|
||||
}
|
||||
function handleContext(e) {
|
||||
props.tabItem && handleContextMenu(props.tabItem)(e);
|
||||
}
|
||||
|
||||
return {
|
||||
prefixCls,
|
||||
getDropMenuList,
|
||||
handleMenuEvent,
|
||||
handleContext,
|
||||
getTrigger,
|
||||
getIsTabs,
|
||||
getTitle,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
prefixCls,
|
||||
getDropMenuList,
|
||||
handleMenuEvent,
|
||||
handleContext,
|
||||
getTrigger,
|
||||
getIsTabs,
|
||||
getTitle
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
<template>
|
||||
<span :class="`${prefixCls}__extra-redo`" @click="handleRedo">
|
||||
<RedoOutlined :spin="loading" />
|
||||
</span>
|
||||
<span :class="`${prefixCls}__extra-redo`" @click="handleRedo">
|
||||
<RedoOutlined :spin="loading" />
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { RedoOutlined } from '@ant-design/icons-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { RedoOutlined } from '@ant-design/icons-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabRedo',
|
||||
components: { RedoOutlined },
|
||||
export default defineComponent({
|
||||
name: 'TabRedo',
|
||||
components: { RedoOutlined },
|
||||
|
||||
setup() {
|
||||
const loading = ref(false);
|
||||
setup() {
|
||||
const loading = ref(false);
|
||||
|
||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||
const { refreshPage } = useTabs();
|
||||
const { prefixCls } = useDesign('multiple-tabs-content');
|
||||
const { refreshPage } = useTabs();
|
||||
|
||||
async function handleRedo() {
|
||||
loading.value = true;
|
||||
await refreshPage();
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
// Animation execution time
|
||||
}, 1200);
|
||||
}
|
||||
return { prefixCls, handleRedo, loading };
|
||||
},
|
||||
});
|
||||
async function handleRedo() {
|
||||
loading.value = true;
|
||||
await refreshPage();
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
// Animation execution time
|
||||
}, 1200);
|
||||
}
|
||||
return { prefixCls, handleRedo, loading };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,214 +1,214 @@
|
||||
@prefix-cls: ~'@{namespace}-multiple-tabs';
|
||||
|
||||
html[data-theme='dark'] {
|
||||
.@{prefix-cls} {
|
||||
.ant-tabs-tab {
|
||||
border-bottom: 1px solid @border-color-base;
|
||||
.@{prefix-cls} {
|
||||
.ant-tabs-tab {
|
||||
border-bottom: 1px solid @border-color-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='light'] {
|
||||
.@{prefix-cls} {
|
||||
.ant-tabs-tab:not(.ant-tabs-tab-active) {
|
||||
border: 0;
|
||||
.@{prefix-cls} {
|
||||
.ant-tabs-tab:not(.ant-tabs-tab-active) {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefix-cls} {
|
||||
z-index: 10;
|
||||
height: @multiple-height + 2;
|
||||
line-height: @multiple-height + 2;
|
||||
background-color: @component-background;
|
||||
border-bottom: 1px solid @border-color-base;
|
||||
z-index: 10;
|
||||
height: @multiple-height + 2;
|
||||
line-height: @multiple-height + 2;
|
||||
background-color: @component-background;
|
||||
border-bottom: 1px solid @border-color-base;
|
||||
|
||||
.ant-tabs-small {
|
||||
height: @multiple-height;
|
||||
}
|
||||
|
||||
.ant-tabs.ant-tabs-card {
|
||||
.ant-tabs-nav {
|
||||
padding-top: 2px;
|
||||
height: @multiple-height;
|
||||
margin: 0;
|
||||
background-color: @component-background;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
|
||||
.ant-tabs-nav-container {
|
||||
.ant-tabs-small {
|
||||
height: @multiple-height;
|
||||
padding-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab {
|
||||
height: calc(@multiple-height - 2px);
|
||||
padding-right: 12px;
|
||||
line-height: calc(@multiple-height - 2px);
|
||||
color: @text-color-base;
|
||||
background-color: @component-background;
|
||||
transition: none;
|
||||
.ant-tabs.ant-tabs-card {
|
||||
.ant-tabs-nav {
|
||||
padding-top: 2px;
|
||||
height: @multiple-height;
|
||||
margin: 0;
|
||||
background-color: @component-background;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
|
||||
&:hover {
|
||||
.ant-tabs-tab-remove {
|
||||
opacity: 1;
|
||||
.ant-tabs-nav-container {
|
||||
height: @multiple-height;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.ant-tabs-tab {
|
||||
height: calc(@multiple-height - 2px);
|
||||
padding-right: 12px;
|
||||
line-height: calc(@multiple-height - 2px);
|
||||
color: @text-color-base;
|
||||
background-color: @component-background;
|
||||
transition: none;
|
||||
|
||||
&:hover {
|
||||
.ant-tabs-tab-remove {
|
||||
opacity: 1;
|
||||
|
||||
svg {
|
||||
fill: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab-remove {
|
||||
width: 8px;
|
||||
height: 38px;
|
||||
font-size: 12px;
|
||||
color: inherit;
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
margin-left: 2px;
|
||||
margin-right: -4px;
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
width: 0.8em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// > div {
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// }
|
||||
|
||||
svg {
|
||||
fill: @text-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab:not(.ant-tabs-tab-active) {
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab-active {
|
||||
position: relative;
|
||||
padding-left: 7px;
|
||||
border: 0;
|
||||
border-bottom: 2px solid @primary-color;
|
||||
transition: none;
|
||||
|
||||
&:nth-child(1) {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: @primary-color !important;
|
||||
}
|
||||
|
||||
.ant-tabs-tab-remove {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.7em;
|
||||
fill: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-nav > div:nth-child(1) {
|
||||
padding: 0 6px;
|
||||
|
||||
.ant-tabs-tab {
|
||||
margin-right: 3px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab:not(.ant-tabs-tab-active) {
|
||||
.anticon-close {
|
||||
font-size: 12px;
|
||||
|
||||
svg {
|
||||
fill: @primary-color;
|
||||
width: 0.6em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-dropdown-trigger {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
&--hide-close {
|
||||
.ant-tabs-tab-remove {
|
||||
width: 8px;
|
||||
height: 38px;
|
||||
font-size: 12px;
|
||||
color: inherit;
|
||||
opacity: 0;
|
||||
transition: none;
|
||||
margin-left: 2px;
|
||||
margin-right: -4px;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
width: 0.8em;
|
||||
&-content {
|
||||
&__extra-quick,
|
||||
&__extra-redo,
|
||||
&__extra-fold {
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: calc(@multiple-height - 16px);
|
||||
line-height: calc(@multiple-height - 16px);
|
||||
color: @text-color-secondary;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-left: 1px solid @border-color-base;
|
||||
|
||||
&:hover {
|
||||
color: @text-color-base;
|
||||
}
|
||||
|
||||
span[role='img'] {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// > div {
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// }
|
||||
|
||||
svg {
|
||||
fill: @text-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab:not(.ant-tabs-tab-active) {
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab-active {
|
||||
position: relative;
|
||||
padding-left: 7px;
|
||||
border: 0;
|
||||
border-bottom: 2px solid @primary-color;
|
||||
transition: none;
|
||||
|
||||
&:nth-child(1) {
|
||||
padding-left: 12px;
|
||||
&__extra-redo {
|
||||
span[role='img'] {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
color: @primary-color !important;
|
||||
&__info {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: @multiple-height - 2;
|
||||
padding-left: 0;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ant-tabs-tab-remove {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 0.7em;
|
||||
fill: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-nav > div:nth-child(1) {
|
||||
padding: 0 6px;
|
||||
|
||||
.ant-tabs-tab {
|
||||
margin-right: 3px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-tab:not(.ant-tabs-tab-active) {
|
||||
.anticon-close {
|
||||
font-size: 12px;
|
||||
|
||||
svg {
|
||||
width: 0.6em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-dropdown-trigger {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
&--hide-close {
|
||||
.ant-tabs-tab-remove {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
&__extra-quick,
|
||||
&__extra-redo,
|
||||
&__extra-fold {
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: calc(@multiple-height - 16px);
|
||||
line-height: calc(@multiple-height - 16px);
|
||||
color: @text-color-secondary;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-left: 1px solid @border-color-base;
|
||||
|
||||
&:hover {
|
||||
color: @text-color-base;
|
||||
}
|
||||
|
||||
span[role='img'] {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
&__extra-redo {
|
||||
span[role='img'] {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: @multiple-height - 2;
|
||||
padding-left: 0;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tabs-dropdown-menu {
|
||||
&-title-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&-title-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.@{prefix-cls} {
|
||||
&-content__info {
|
||||
width: auto;
|
||||
margin-left: 0;
|
||||
line-height: 28px;
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
&-content__info {
|
||||
width: auto;
|
||||
margin-left: 0;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-item-remove {
|
||||
margin-left: auto;
|
||||
}
|
||||
&-item-remove {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.multiple-tabs__dropdown {
|
||||
.ant-dropdown-content {
|
||||
width: 172px;
|
||||
}
|
||||
.ant-dropdown-content {
|
||||
width: 172px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,146 +1,135 @@
|
||||
<template>
|
||||
<div :class="getWrapClass">
|
||||
<Tabs
|
||||
type="editable-card"
|
||||
size="small"
|
||||
:animated="false"
|
||||
:hideAdd="true"
|
||||
:tabBarGutter="3"
|
||||
:activeKey="activeKeyRef"
|
||||
@change="handleChange"
|
||||
@edit="handleEdit"
|
||||
>
|
||||
<template v-for="item in getTabsState" :key="item.query ? item.fullPath : item.path">
|
||||
<TabPane :closable="!(item && item.meta && item.meta.affix)">
|
||||
<template #tab>
|
||||
<TabContent :tabItem="item" />
|
||||
</template>
|
||||
</TabPane>
|
||||
</template>
|
||||
<div :class="getWrapClass">
|
||||
<Tabs type="editable-card" size="small" :animated="false" :hideAdd="true" :tabBarGutter="3" :activeKey="activeKeyRef" @change="handleChange" @edit="handleEdit">
|
||||
<template v-for="item in getTabsState" :key="item.query ? item.fullPath : item.path">
|
||||
<TabPane :closable="!(item && item.meta && item.meta.affix)">
|
||||
<template #tab>
|
||||
<TabContent :tabItem="item" />
|
||||
</template>
|
||||
</TabPane>
|
||||
</template>
|
||||
|
||||
<template #rightExtra v-if="getShowRedo || getShowQuick">
|
||||
<TabRedo v-if="getShowRedo" />
|
||||
<TabContent isExtra :tabItem="$route" v-if="getShowQuick" />
|
||||
<FoldButton v-if="getShowFold" />
|
||||
</template>
|
||||
</Tabs>
|
||||
</div>
|
||||
<template #rightExtra v-if="getShowRedo || getShowQuick">
|
||||
<TabRedo v-if="getShowRedo" />
|
||||
<TabContent isExtra :tabItem="$route" v-if="getShowQuick" />
|
||||
<FoldButton v-if="getShowFold" />
|
||||
</template>
|
||||
</Tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { RouteLocationNormalized, RouteMeta } from 'vue-router';
|
||||
import type { RouteLocationNormalized, RouteMeta } from 'vue-router';
|
||||
|
||||
import { defineComponent, computed, unref, ref } from 'vue';
|
||||
import { defineComponent, computed, unref, ref } from 'vue';
|
||||
|
||||
import { Tabs } from 'ant-design-vue';
|
||||
import TabContent from './components/TabContent.vue';
|
||||
import FoldButton from './components/FoldButton.vue';
|
||||
import TabRedo from './components/TabRedo.vue';
|
||||
import { Tabs } from 'ant-design-vue';
|
||||
import TabContent from './components/TabContent.vue';
|
||||
import FoldButton from './components/FoldButton.vue';
|
||||
import TabRedo from './components/TabRedo.vue';
|
||||
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
import { useGo } from '/@/hooks/web/usePage';
|
||||
|
||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
|
||||
import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
|
||||
import { REDIRECT_NAME } from '/@/router/constant';
|
||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
||||
import { REDIRECT_NAME } from '/@/router/constant';
|
||||
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
|
||||
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MultipleTabs',
|
||||
components: {
|
||||
TabRedo,
|
||||
FoldButton,
|
||||
Tabs,
|
||||
TabPane: Tabs.TabPane,
|
||||
TabContent,
|
||||
},
|
||||
setup() {
|
||||
const affixTextList = initAffixTabs();
|
||||
const activeKeyRef = ref('');
|
||||
export default defineComponent({
|
||||
name: 'MultipleTabs',
|
||||
components: {
|
||||
TabRedo,
|
||||
FoldButton,
|
||||
Tabs,
|
||||
TabPane: Tabs.TabPane,
|
||||
TabContent
|
||||
},
|
||||
setup() {
|
||||
const affixTextList = initAffixTabs();
|
||||
const activeKeyRef = ref('');
|
||||
|
||||
useTabsDrag(affixTextList);
|
||||
const tabStore = useMultipleTabStore();
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
useTabsDrag(affixTextList);
|
||||
const tabStore = useMultipleTabStore();
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
|
||||
const { prefixCls } = useDesign('multiple-tabs');
|
||||
const go = useGo();
|
||||
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
|
||||
const { prefixCls } = useDesign('multiple-tabs');
|
||||
const go = useGo();
|
||||
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
|
||||
|
||||
const getTabsState = computed(() => {
|
||||
return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
|
||||
});
|
||||
const getTabsState = computed(() => {
|
||||
return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
|
||||
});
|
||||
|
||||
const unClose = computed(() => unref(getTabsState).length === 1);
|
||||
const unClose = computed(() => unref(getTabsState).length === 1);
|
||||
|
||||
const getWrapClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--hide-close`]: unref(unClose),
|
||||
},
|
||||
];
|
||||
});
|
||||
const getWrapClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--hide-close`]: unref(unClose)
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
listenerRouteChange((route) => {
|
||||
const { name } = route;
|
||||
if (name === REDIRECT_NAME || !route || !userStore.getToken) {
|
||||
return;
|
||||
listenerRouteChange((route) => {
|
||||
const { name } = route;
|
||||
if (name === REDIRECT_NAME || !route || !userStore.getToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { path, fullPath, meta = {} } = route;
|
||||
const { currentActiveMenu, hideTab } = meta as RouteMeta;
|
||||
const isHide = !hideTab ? null : currentActiveMenu;
|
||||
const p = isHide || fullPath || path;
|
||||
if (activeKeyRef.value !== p) {
|
||||
activeKeyRef.value = p as string;
|
||||
}
|
||||
|
||||
if (isHide) {
|
||||
const findParentRoute = router.getRoutes().find((item) => item.path === currentActiveMenu);
|
||||
|
||||
findParentRoute && tabStore.addTab(findParentRoute as unknown as RouteLocationNormalized);
|
||||
} else {
|
||||
tabStore.addTab(unref(route));
|
||||
}
|
||||
});
|
||||
|
||||
function handleChange(activeKey: any) {
|
||||
console.log('handleChange');
|
||||
|
||||
activeKeyRef.value = activeKey;
|
||||
go(activeKey, false);
|
||||
}
|
||||
|
||||
// Close the current tab
|
||||
function handleEdit(targetKey: string) {
|
||||
// Added operation to hide, currently only use delete operation
|
||||
if (unref(unClose)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabStore.closeTabByKey(targetKey, router);
|
||||
}
|
||||
return {
|
||||
getWrapClass,
|
||||
handleEdit,
|
||||
handleChange,
|
||||
activeKeyRef,
|
||||
getTabsState,
|
||||
getShowQuick,
|
||||
getShowRedo,
|
||||
getShowFold
|
||||
};
|
||||
}
|
||||
|
||||
const { path, fullPath, meta = {} } = route;
|
||||
const { currentActiveMenu, hideTab } = meta as RouteMeta;
|
||||
const isHide = !hideTab ? null : currentActiveMenu;
|
||||
const p = isHide || fullPath || path;
|
||||
if (activeKeyRef.value !== p) {
|
||||
activeKeyRef.value = p as string;
|
||||
}
|
||||
|
||||
if (isHide) {
|
||||
const findParentRoute = router
|
||||
.getRoutes()
|
||||
.find((item) => item.path === currentActiveMenu);
|
||||
|
||||
findParentRoute && tabStore.addTab(findParentRoute as unknown as RouteLocationNormalized);
|
||||
} else {
|
||||
tabStore.addTab(unref(route));
|
||||
}
|
||||
});
|
||||
|
||||
function handleChange(activeKey: any) {
|
||||
console.log('handleChange');
|
||||
|
||||
activeKeyRef.value = activeKey;
|
||||
go(activeKey, false);
|
||||
}
|
||||
|
||||
// Close the current tab
|
||||
function handleEdit(targetKey: string) {
|
||||
// Added operation to hide, currently only use delete operation
|
||||
if (unref(unClose)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabStore.closeTabByKey(targetKey, router);
|
||||
}
|
||||
return {
|
||||
getWrapClass,
|
||||
handleEdit,
|
||||
handleChange,
|
||||
activeKeyRef,
|
||||
getTabsState,
|
||||
getShowQuick,
|
||||
getShowRedo,
|
||||
getShowFold,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import url('./index.less');
|
||||
@import url('./index.less');
|
||||
</style>
|
||||
|
||||
@ -1,28 +1,26 @@
|
||||
<template>
|
||||
<span :class="[prefixCls, theme]" @click="toggleCollapsed">
|
||||
<span
|
||||
style="border-left: 1px solid rgb(255, 255, 255, 0.3); height: 30px; padding-right: 15px"
|
||||
></span>
|
||||
<MenuUnfoldOutlined v-if="getCollapsed" /> <MenuFoldOutlined v-else />
|
||||
</span>
|
||||
<span :class="[prefixCls, theme]" @click="toggleCollapsed">
|
||||
<span style="border-left: 1px solid rgb(255, 255, 255, 0.3); height: 30px; padding-right: 15px"></span>
|
||||
<MenuUnfoldOutlined v-if="getCollapsed" /> <MenuFoldOutlined v-else />
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { defineComponent } from 'vue';
|
||||
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'HeaderTrigger',
|
||||
components: { MenuUnfoldOutlined, MenuFoldOutlined },
|
||||
props: {
|
||||
theme: propTypes.oneOf(['light', 'dark']),
|
||||
},
|
||||
setup() {
|
||||
const { getCollapsed, toggleCollapsed } = useMenuSetting();
|
||||
const { prefixCls } = useDesign('layout-header-trigger');
|
||||
return { getCollapsed, toggleCollapsed, prefixCls };
|
||||
},
|
||||
});
|
||||
export default defineComponent({
|
||||
name: 'HeaderTrigger',
|
||||
components: { MenuUnfoldOutlined, MenuFoldOutlined },
|
||||
props: {
|
||||
theme: propTypes.oneOf(['light', 'dark'])
|
||||
},
|
||||
setup() {
|
||||
const { getCollapsed, toggleCollapsed } = useMenuSetting();
|
||||
const { prefixCls } = useDesign('layout-header-trigger');
|
||||
return { getCollapsed, toggleCollapsed, prefixCls };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<div @click.stop="toggleCollapsed">
|
||||
<DoubleRightOutlined v-if="getCollapsed" />
|
||||
<DoubleLeftOutlined v-else />
|
||||
</div>
|
||||
<div @click.stop="toggleCollapsed">
|
||||
<DoubleRightOutlined v-if="getCollapsed" />
|
||||
<DoubleLeftOutlined v-else />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { DoubleRightOutlined, DoubleLeftOutlined } from '@ant-design/icons-vue';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
import { defineComponent } from 'vue';
|
||||
import { DoubleRightOutlined, DoubleLeftOutlined } from '@ant-design/icons-vue';
|
||||
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SiderTrigger',
|
||||
components: { DoubleRightOutlined, DoubleLeftOutlined },
|
||||
setup() {
|
||||
const { getCollapsed, toggleCollapsed } = useMenuSetting();
|
||||
export default defineComponent({
|
||||
name: 'SiderTrigger',
|
||||
components: { DoubleRightOutlined, DoubleLeftOutlined },
|
||||
setup() {
|
||||
const { getCollapsed, toggleCollapsed } = useMenuSetting();
|
||||
|
||||
return { getCollapsed, toggleCollapsed };
|
||||
},
|
||||
});
|
||||
return { getCollapsed, toggleCollapsed };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<SiderTrigger v-if="sider" />
|
||||
<HeaderTrigger v-else :theme="theme" />
|
||||
<SiderTrigger v-if="sider" />
|
||||
<HeaderTrigger v-else :theme="theme" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import HeaderTrigger from './HeaderTrigger.vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import HeaderTrigger from './HeaderTrigger.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LayoutTrigger',
|
||||
components: {
|
||||
SiderTrigger: createAsyncComponent(() => import('./SiderTrigger.vue')),
|
||||
HeaderTrigger: HeaderTrigger,
|
||||
},
|
||||
props: {
|
||||
sider: propTypes.bool.def(true),
|
||||
theme: propTypes.oneOf(['light', 'dark']),
|
||||
},
|
||||
});
|
||||
export default defineComponent({
|
||||
name: 'LayoutTrigger',
|
||||
components: {
|
||||
SiderTrigger: createAsyncComponent(() => import('./SiderTrigger.vue')),
|
||||
HeaderTrigger: HeaderTrigger
|
||||
},
|
||||
props: {
|
||||
sider: propTypes.bool.def(true),
|
||||
theme: propTypes.oneOf(['light', 'dark'])
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user