This commit is contained in:
dap
2025-04-09 09:34:17 +08:00
20 changed files with 483 additions and 154 deletions

View File

@@ -17,6 +17,14 @@
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
},
"./es/tippy": {
"types": "./src/components/tippy/index.ts",
"default": "./src/components/tippy/index.ts"
},
"./es/loading": {
"types": "./src/components/loading/index.ts",
"default": "./src/components/loading/index.ts"
}
},
"dependencies": {

View File

@@ -5,9 +5,11 @@ import type {
RouteLocationNormalizedLoadedGeneric,
} from 'vue-router';
import { computed } from 'vue';
import { RouterView } from 'vue-router';
import { preferences, usePreferences } from '@vben/preferences';
import { storeToRefs, useTabbarStore } from '@vben/stores';
import { RouterView } from 'vue-router';
import { IFrameRouterView } from '../../iframe';
@@ -19,6 +21,15 @@ const { keepAlive } = usePreferences();
const { getCachedTabs, getExcludeCachedTabs, renderRouteView } =
storeToRefs(tabbarStore);
/**
* 是否使用动画
*/
const getEnabledTransition = computed(() => {
const { transition } = preferences;
const transitionName = transition.name;
return transitionName && transition.enable;
});
// 页面切换动画
function getTransitionName(_route: RouteLocationNormalizedLoaded) {
// 如果偏好设置未设置,则不使用动画
@@ -89,7 +100,12 @@ function transformComponent(
<div class="relative h-full">
<IFrameRouterView />
<RouterView v-slot="{ Component, route }">
<Transition :name="getTransitionName(route)" appear mode="out-in">
<Transition
v-if="getEnabledTransition"
:name="getTransitionName(route)"
appear
mode="out-in"
>
<KeepAlive
v-if="keepAlive"
:exclude="getExcludeCachedTabs"
@@ -108,6 +124,25 @@ function transformComponent(
:key="route.fullPath"
/>
</Transition>
<template v-else>
<KeepAlive
v-if="keepAlive"
:exclude="getExcludeCachedTabs"
:include="getCachedTabs"
>
<component
:is="transformComponent(Component, route)"
v-if="renderRouteView"
v-show="!route.meta.iframeSrc"
:key="route.fullPath"
/>
</KeepAlive>
<component
:is="Component"
v-else-if="renderRouteView"
:key="route.fullPath"
/>
</template>
</RouterView>
</div>
</template>

View File

@@ -1,6 +1,3 @@
import type { ClassType, DeepPartial } from '@vben/types';
import type { VbenFormProps } from '@vben-core/form-ui';
import type { Ref } from 'vue';
import type {
VxeGridListeners,
VxeGridPropTypes,
@@ -8,6 +5,12 @@ import type {
VxeUIExport,
} from 'vxe-table';
import type { Ref } from 'vue';
import type { ClassType, DeepPartial } from '@vben/types';
import type { VbenFormProps } from '@vben-core/form-ui';
import type { VxeGridApi } from './api';
import { useVbenForm } from '@vben-core/form-ui';
@@ -28,6 +31,10 @@ export interface VxeTableGridOptions<T = any> extends VxeTableGridProps<T> {
toolbarConfig?: ToolbarConfigOptions;
}
export interface SeparatorOptions {
show?: boolean;
backgroundColor?: string;
}
export interface VxeGridProps {
/**
* 标题
@@ -61,13 +68,17 @@ export interface VxeGridProps {
* 显示搜索表单
*/
showSearchForm?: boolean;
/**
* 搜索表单与表格主体之间的分隔条
*/
separator?: boolean | SeparatorOptions;
}
export type ExtendedVxeGridApi = {
export type ExtendedVxeGridApi = VxeGridApi & {
useStore: <T = NoInfer<VxeGridProps>>(
selector?: (state: NoInfer<VxeGridProps>) => T,
) => Readonly<Ref<T>>;
} & VxeGridApi;
};
export interface SetupVxeTable {
configVxeTable: (ui: VxeUIExport) => void;

View File

@@ -29,7 +29,13 @@ import { usePriorityValues } from '@vben/hooks';
import { EmptyIcon } from '@vben/icons';
import { $t } from '@vben/locales';
import { usePreferences } from '@vben/preferences';
import { cloneDeep, cn, isEqual, mergeWithArrayOverride } from '@vben/utils';
import {
cloneDeep,
cn,
isBoolean,
isEqual,
mergeWithArrayOverride,
} from '@vben/utils';
import { VbenHelpTooltip, VbenLoading } from '@vben-core/shadcn-ui';
@@ -67,10 +73,30 @@ const {
tableTitle,
tableTitleHelp,
showSearchForm,
separator,
} = usePriorityValues(props, state);
const { isMobile } = usePreferences();
const isSeparator = computed(() => {
if (
!formOptions.value ||
showSearchForm.value === false ||
separator.value === false
) {
return false;
}
if (separator.value === true || separator.value === undefined) {
return true;
}
return separator.value.show !== false;
});
const separatorBg = computed(() => {
return !separator.value ||
isBoolean(separator.value) ||
!separator.value.backgroundColor
? undefined
: separator.value.backgroundColor;
});
const slots: SetupContext['slots'] = useSlots();
const [Form, formApi] = useTableForm({
@@ -380,7 +406,18 @@ onUnmounted(() => {
<div
v-if="formOptions"
v-show="showSearchForm !== false"
:class="cn('relative rounded py-3', isCompactForm ? 'pb-8' : 'pb-4')"
:class="
cn(
'relative rounded py-3',
isCompactForm
? isSeparator
? 'pb-8'
: 'pb-4'
: isSeparator
? 'pb-4'
: 'pb-0',
)
"
>
<slot name="form">
<Form>
@@ -409,6 +446,10 @@ onUnmounted(() => {
</Form>
</slot>
<div
v-if="isSeparator"
:style="{
...(separatorBg ? { backgroundColor: separatorBg } : undefined),
}"
class="bg-background-deep z-100 absolute -left-2 bottom-1 h-2 w-[calc(100%+1rem)] overflow-hidden md:bottom-2 md:h-3"
></div>
</div>