This commit is contained in:
dap
2025-04-28 13:19:57 +08:00
90 changed files with 380 additions and 260 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/design",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/icons",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/shared",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line vue/prefer-import-from-vue
import { isFunction, isObject, isString } from '@vue/shared';
/**

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/typings",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/composables",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/preferences",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/form-ui",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/layout-ui",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/menu-ui",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -10,7 +10,7 @@ import { VbenIcon } from '@vben-core/shadcn-ui';
import { useMenuContext } from '../hooks';
interface Props extends MenuItemProps {
isMenuMore: boolean;
isMenuMore?: boolean;
isTopLevelMenuSubmenu: boolean;
level?: number;
}

View File

@@ -47,6 +47,10 @@ function onAlertClosed() {
isConfirm.value = false;
}
function onEscapeKeyDown() {
isConfirm.value = false;
}
const getIconRender = computed(() => {
let iconRender: Component | null = null;
if (props.icon) {
@@ -116,13 +120,11 @@ function handleCancel() {
const loading = ref(false);
async function handleOpenChange(val: boolean) {
const confirmState = isConfirm.value;
isConfirm.value = false;
await nextTick();
await nextTick(); // 等待标记isConfirm状态
if (!val && props.beforeClose) {
loading.value = true;
try {
const res = await props.beforeClose({ isConfirm: confirmState });
const res = await props.beforeClose({ isConfirm: isConfirm.value });
if (res !== false) {
open.value = false;
}
@@ -142,6 +144,7 @@ async function handleOpenChange(val: boolean) {
:overlay-blur="overlayBlur"
@opened="emits('opened')"
@closed="onAlertClosed"
@escape-key-down="onEscapeKeyDown"
:class="
cn(
containerClass,

View File

@@ -52,6 +52,10 @@ export interface DrawerProps {
* 弹窗描述
*/
description?: string;
/**
* 在关闭时销毁抽屉
*/
destroyOnClose?: boolean;
/**
* 是否显示底部
* @default true
@@ -143,10 +147,6 @@ export interface DrawerApiOptions extends DrawerState {
* 独立的抽屉组件
*/
connectedComponent?: Component;
/**
* 在关闭时销毁抽屉。仅在使用 connectedComponent 时有效
*/
destroyOnClose?: boolean;
/**
* 关闭前的回调,返回 false 可以阻止关闭
* @returns

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup>
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
import { computed, provide, ref, useId, watch } from 'vue';
import { computed, provide, ref, unref, useId, watch } from 'vue';
import {
useIsMobile,
@@ -35,6 +35,7 @@ interface Props extends DrawerProps {
const props = withDefaults(defineProps<Props>(), {
appendToMain: false,
closeIconPlacement: 'right',
destroyOnClose: true,
drawerApi: undefined,
submitting: false,
zIndex: 1000,
@@ -63,6 +64,7 @@ const {
confirmText,
contentClass,
description,
destroyOnClose,
footer: showFooter,
footerClass,
header: showHeader,
@@ -131,6 +133,29 @@ const getAppendTo = computed(() => {
? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`
: undefined;
});
/**
* destroyOnClose功能完善
*/
// 是否打开过
const hasOpened = ref(false);
const isClosed = ref(true);
watch(
() => state?.value?.isOpen,
(value) => {
isClosed.value = false;
if (value && !unref(hasOpened)) {
hasOpened.value = true;
}
},
);
function handleClosed() {
isClosed.value = true;
props.drawerApi?.onClosed();
}
const getForceMount = computed(() => {
return !unref(destroyOnClose) && unref(hasOpened);
});
</script>
<template>
<Sheet
@@ -144,15 +169,17 @@ const getAppendTo = computed(() => {
cn('flex w-[520px] flex-col', drawerClass, {
'!w-full': isMobile || placement === 'bottom' || placement === 'top',
'max-h-[100vh]': placement === 'bottom' || placement === 'top',
hidden: isClosed,
})
"
:modal="modal"
:open="state?.isOpen"
:side="placement"
:z-index="zIndex"
:force-mount="getForceMount"
:overlay-blur="overlayBlur"
@close-auto-focus="handleFocusOutside"
@closed="() => drawerApi?.onClosed()"
@closed="handleClosed"
@escape-key-down="escapeKeyDown"
@focus-outside="handleFocusOutside"
@interact-outside="interactOutside"

View File

@@ -21,7 +21,9 @@ import VbenDrawer from './drawer.vue';
const USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');
const DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {};
const DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {
destroyOnClose: true,
};
export function setDefaultDrawerProps(props: Partial<DrawerProps>) {
Object.assign(DEFAULT_DRAWER_PROPS, props);

View File

@@ -17,7 +17,9 @@ import VbenModal from './modal.vue';
const USER_MODAL_INJECT_KEY = Symbol('VBEN_MODAL_INJECT');
const DEFAULT_MODAL_PROPS: Partial<ModalProps> = {};
const DEFAULT_MODAL_PROPS: Partial<ModalProps> = {
destroyOnClose: true,
};
export function setDefaultModalProps(props: Partial<ModalProps>) {
Object.assign(DEFAULT_MODAL_PROPS, props);
@@ -86,7 +88,7 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
mergedOptions.onClosed = () => {
options.onClosed?.();
if (options.destroyOnClose) {
if (mergedOptions.destroyOnClose) {
injectData.reCreateModal?.();
}
};

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/shadcn-ui",
"version": "5.5.4",
"version": "5.5.5",
"#main": "./dist/index.mjs",
"#module": "./dist/index.mjs",
"homepage": "https://github.com/vbenjs/vue-vben-admin",

View File

@@ -41,7 +41,6 @@ watch(
innerValue.value.length > 0 ? innerValue.value[0] : undefined;
}
},
{ immediate: true },
);
watch(
@@ -60,7 +59,7 @@ watch(
innerValue.value = val === undefined ? [] : [val as ValueType];
}
},
{ deep: true },
{ deep: true, immediate: true },
);
async function onBtnClick(value: ValueType) {

View File

@@ -10,7 +10,7 @@ import TabsIndicator from './tabs-indicator.vue';
interface Props {
defaultValue?: string;
tabs: SegmentedItem[];
tabs?: SegmentedItem[];
}
const props = withDefaults(defineProps<Props>(), {

View File

@@ -1,4 +1,6 @@
<script lang="ts" setup>
import { CircleX } from '@vben-core/icons';
import {
Select,
SelectContent,
@@ -8,6 +10,7 @@ import {
} from '../../ui';
interface Props {
allowClear?: boolean;
class?: any;
// 弹出层的类名
contentClass?: any;
@@ -15,12 +18,27 @@ interface Props {
placeholder?: string;
}
const props = defineProps<Props>();
const props = withDefaults(defineProps<Props>(), {
allowClear: false,
});
const modelValue = defineModel<string>();
function handleClear() {
modelValue.value = undefined;
}
</script>
<template>
<Select>
<SelectTrigger :class="props.class">
<SelectValue :placeholder="placeholder" />
<Select v-model="modelValue">
<SelectTrigger :class="props.class" class="flex w-full items-center">
<SelectValue class="flex-auto text-left" :placeholder="placeholder" />
<CircleX
@pointerdown.stop
@click.stop.prevent="handleClear"
v-if="allowClear && modelValue"
data-clear-button
class="mr-1 size-4 cursor-pointer opacity-50 hover:opacity-100"
/>
</SelectTrigger>
<SelectContent :class="props.contentClass">
<template v-for="item in options" :key="item.value">

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/tabs-ui",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/constants",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/access",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/common-ui",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -9,7 +9,7 @@ export function useCaptchaPoints() {
}
function clearPoints() {
points.splice(0, points.length);
points.splice(0);
}
return {
addPoint,

View File

@@ -65,7 +65,7 @@
&.jv-string {
color: hsl(var(--primary));
word-break: break-word;
overflow-wrap: break-word;
white-space: normal;
}
}

View File

@@ -3,18 +3,20 @@ import type { VbenFormSchema } from '@vben-core/form-ui';
import type { AuthenticationProps, LoginAndRegisterParams } from './types';
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import { $t } from '@vben/locales';
import { useVbenForm } from '@vben-core/form-ui';
import { VbenButton, VbenCheckbox } from '@vben-core/shadcn-ui';
import { cloneDeep } from '@vben-core/shared/utils';
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import Title from './auth-title.vue';
import ThirdPartyLogin from './third-party-login.vue';
interface Props extends AuthenticationProps {
formSchema: VbenFormSchema[];
formSchema?: VbenFormSchema[];
}
defineOptions({

View File

@@ -1,17 +1,20 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import type { VbenFormSchema } from '@vben-core/form-ui';
import { $t } from '@vben/locales';
import { useVbenForm } from '@vben-core/form-ui';
import { VbenButton } from '@vben-core/shadcn-ui';
import { computed, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { $t } from '@vben/locales';
import { useVbenForm } from '@vben-core/form-ui';
import { VbenButton } from '@vben-core/shadcn-ui';
import Title from './auth-title.vue';
interface Props {
formSchema: VbenFormSchema[];
formSchema?: VbenFormSchema[];
/**
* @zh_CN 是否处于加载处理状态
*/

View File

@@ -6,7 +6,7 @@ import { computed } from 'vue';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@vben-core/shadcn-ui';
interface Props {
tabs: TabOption[];
tabs?: TabOption[];
}
defineOptions({

View File

@@ -12,7 +12,7 @@ import {
} from '@vben-core/shadcn-ui';
interface Props {
items: AnalysisOverviewItem[];
items?: AnalysisOverviewItem[];
}
defineOptions({

View File

@@ -10,7 +10,7 @@ import {
} from '@vben-core/shadcn-ui';
interface Props {
items: WorkbenchProjectItem[];
items?: WorkbenchProjectItem[];
title: string;
}
@@ -37,6 +37,8 @@ defineEmits(['click']);
'border-r-0': index % 3 === 2,
'border-b-0': index < 3,
'pb-4': index > 2,
'rounded-bl-xl': index === items.length - 3,
'rounded-br-xl': index === items.length - 1,
}"
class="border-border group w-full cursor-pointer border-r border-t p-4 transition-all hover:shadow-xl md:w-1/2 lg:w-1/3"
>

View File

@@ -10,7 +10,7 @@ import {
} from '@vben-core/shadcn-ui';
interface Props {
items: WorkbenchQuickNavItem[];
items?: WorkbenchQuickNavItem[];
title: string;
}
@@ -35,8 +35,10 @@ defineEmits(['click']);
<div
:class="{
'border-r-0': index % 3 === 2,
'pb-4': index > 2,
'border-b-0': index < 3,
'pb-4': index > 2,
'rounded-bl-xl': index === items.length - 3,
'rounded-br-xl': index === items.length - 1,
}"
class="flex-col-center border-border group w-1/3 cursor-pointer border-r border-t py-8 hover:shadow-xl"
@click="$emit('click', item)"

View File

@@ -10,7 +10,7 @@ import {
} from '@vben-core/shadcn-ui';
interface Props {
items: WorkbenchTodoItem[];
items?: WorkbenchTodoItem[];
title: string;
}

View File

@@ -10,7 +10,7 @@ import {
} from '@vben-core/shadcn-ui';
interface Props {
items: WorkbenchTrendItem[];
items?: WorkbenchTrendItem[];
title: string;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/hooks",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/layouts",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup>
interface Props {
companyName: string;
companyName?: string;
companySiteLink?: string;
date: string;
date?: string;
icp?: string;
icpLink?: string;
}

View File

@@ -12,7 +12,7 @@ import {
updatePreferences,
usePreferences,
} from '@vben/preferences';
import { useLockStore } from '@vben/stores';
import { useAccessStore } from '@vben/stores';
import { cloneDeep, mapTree } from '@vben/utils';
import { VbenAdminLayout } from '@vben-core/layout-ui';
@@ -49,7 +49,7 @@ const {
sidebarCollapsed,
theme,
} = usePreferences();
const lockStore = useLockStore();
const accessStore = useAccessStore();
const { refresh } = useRefresh();
const sidebarTheme = computed(() => {
@@ -356,7 +356,7 @@ const headerSlots = computed(() => {
/>
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
<slot v-if="accessStore.isLockScreen" name="lock-screen"></slot>
</Transition>
<template v-if="preferencesButtonPosition.fixed">

View File

@@ -1,15 +1,17 @@
<script lang="ts" setup>
import type { MenuRecordRaw } from '@vben/types';
import type { MenuProps } from '@vben-core/menu-ui';
import { Menu } from '@vben-core/menu-ui';
import { useRoute } from 'vue-router';
import { Menu } from '@vben-core/menu-ui';
import { useNavigation } from './use-navigation';
interface Props extends MenuProps {
collapse?: boolean;
menus: MenuRecordRaw[];
menus?: MenuRecordRaw[];
}
withDefaults(defineProps<Props>(), {

View File

@@ -1,11 +1,12 @@
<script lang="ts" setup>
import type { MenuRecordRaw } from '@vben/types';
import type { MenuProps } from '@vben-core/menu-ui';
import { Menu } from '@vben-core/menu-ui';
interface Props extends MenuProps {
menus: MenuRecordRaw[];
menus?: MenuRecordRaw[];
}
const props = withDefaults(defineProps<Props>(), {

View File

@@ -1,6 +1,8 @@
<script setup lang="ts">
import type { MenuRecordRaw } from '@vben/types';
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import {
ArrowDown,
ArrowUp,
@@ -10,9 +12,10 @@ import {
} from '@vben/icons';
import { $t } from '@vben/locales';
import { isWindowsOs } from '@vben/utils';
import { useVbenModal } from '@vben-core/popup-ui';
import { useMagicKeys, whenever } from '@vueuse/core';
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import SearchPanel from './search-panel.vue';
@@ -21,7 +24,7 @@ defineOptions({
});
const props = withDefaults(
defineProps<{ enableShortcutKey?: boolean; menus: MenuRecordRaw[] }>(),
defineProps<{ enableShortcutKey?: boolean; menus?: MenuRecordRaw[] }>(),
{
enableShortcutKey: true,
menus: () => [],

View File

@@ -1,21 +1,24 @@
<script setup lang="ts">
import type { MenuRecordRaw } from '@vben/types';
import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
import { useRouter } from 'vue-router';
import { SearchX, X } from '@vben/icons';
import { $t } from '@vben/locales';
import { mapTree, traverseTreeValues, uniqueByField } from '@vben/utils';
import { VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
import { isHttpUrl } from '@vben-core/shared/utils';
import { onKeyStroke, useLocalStorage, useThrottleFn } from '@vueuse/core';
import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
import { useRouter } from 'vue-router';
defineOptions({
name: 'SearchPanel',
});
const props = withDefaults(
defineProps<{ keyword: string; menus: MenuRecordRaw[] }>(),
defineProps<{ keyword?: string; menus?: MenuRecordRaw[] }>(),
{
keyword: '',
menus: () => [],

View File

@@ -1,12 +1,15 @@
<script setup lang="ts">
import { computed, reactive, ref } from 'vue';
import { LockKeyhole } from '@vben/icons';
import { $t, useI18n } from '@vben/locales';
import { storeToRefs, useLockStore } from '@vben/stores';
import { storeToRefs, useAccessStore } from '@vben/stores';
import { useScrollLock } from '@vben-core/composables';
import { useVbenForm, z } from '@vben-core/form-ui';
import { VbenAvatar, VbenButton } from '@vben-core/shadcn-ui';
import { useDateFormat, useNow } from '@vueuse/core';
import { computed, reactive, ref } from 'vue';
interface Props {
avatar?: string;
@@ -23,7 +26,7 @@ withDefaults(defineProps<Props>(), {
defineEmits<{ toLogin: [] }>();
const { locale } = useI18n();
const lockStore = useLockStore();
const accessStore = useAccessStore();
const now = useNow();
const meridiem = useDateFormat(now, 'A');
@@ -32,7 +35,7 @@ const minute = useDateFormat(now, 'mm');
const date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: locale.value });
const showUnlockForm = ref(false);
const { lockScreenPassword } = storeToRefs(lockStore);
const { lockScreenPassword } = storeToRefs(accessStore);
const [Form, { form, validate }] = useVbenForm(
reactive({
@@ -63,7 +66,7 @@ async function handleSubmit() {
const { valid } = await validate();
if (valid) {
if (validPass.value) {
lockStore.unlockScreen();
accessStore.unlockScreen();
} else {
form.setFieldError('password', $t('authentication.passwordErrorTip'));
}

View File

@@ -14,7 +14,7 @@ defineOptions({
withDefaults(
defineProps<{
disabled?: boolean;
items: SelectOption[];
items?: SelectOption[];
multiple?: boolean;
onBtnClick?: (value: string) => void;
placeholder?: string;

View File

@@ -7,7 +7,7 @@ defineOptions({
name: 'PreferenceToggleItem',
});
withDefaults(defineProps<{ disabled?: boolean; items: SelectOption[] }>(), {
withDefaults(defineProps<{ disabled?: boolean; items?: SelectOption[] }>(), {
disabled: false,
items: () => [],
});

View File

@@ -1,13 +1,17 @@
<script setup lang="ts">
import type { AnyFunction } from '@vben/types';
import type { Component } from 'vue';
import type { AnyFunction } from '@vben/types';
import { computed, useTemplateRef, watch } from 'vue';
import { useHoverToggle } from '@vben/hooks';
import { LockKeyhole, LogOut } from '@vben/icons';
import { $t } from '@vben/locales';
import { preferences, usePreferences } from '@vben/preferences';
import { useLockStore } from '@vben/stores';
import { useAccessStore } from '@vben/stores';
import { isWindowsOs } from '@vben/utils';
import { useVbenModal } from '@vben-core/popup-ui';
import {
Badge,
@@ -21,8 +25,8 @@ import {
VbenAvatar,
VbenIcon,
} from '@vben-core/shadcn-ui';
import { useMagicKeys, whenever } from '@vueuse/core';
import { computed, useTemplateRef, watch } from 'vue';
import { LockScreenModal } from '../lock-screen';
@@ -78,7 +82,7 @@ const emit = defineEmits<{ logout: [] }>();
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } =
usePreferences();
const lockStore = useLockStore();
const accessStore = useAccessStore();
const [LockModal, lockModalApi] = useVbenModal({
connectedComponent: LockScreenModal,
});
@@ -129,7 +133,7 @@ function handleOpenLock() {
function handleSubmitLock(lockScreenPassword: string) {
lockModalApi.close();
lockStore.lockScreen(lockScreenPassword);
accessStore.lockScreen(lockScreenPassword);
}
function handleLogout() {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/plugins",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -24,8 +24,8 @@ export function useVbenVxeGrid(options: VxeGridProps) {
return () => h(VxeGrid, { ...props, ...attrs, api: extendedApi }, slots);
},
{
inheritAttrs: false,
name: 'VbenVxeGrid',
inheritAttrs: false,
},
);
// Add reactivity support

View File

@@ -150,7 +150,9 @@ const toolbarOptions = computed(() => {
icon: 'vxe-icon-search',
circle: true,
status: showSearchForm.value ? 'primary' : undefined,
title: $t('common.search'),
title: showSearchForm.value
? $t('common.hideSearchPanel')
: $t('common.showSearchPanel'),
};
// 将搜索按钮合并到用户配置的toolbarConfig.tools中
const toolbarConfig: VxeGridPropTypes.ToolbarConfig = {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/request",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/icons",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/locales",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -18,5 +18,7 @@
"delete": "Delete",
"create": "Create",
"yes": "Yes",
"no": "No"
"no": "No",
"showSearchPanel": "Show search panel",
"hideSearchPanel": "Hide search panel"
}

View File

@@ -18,5 +18,7 @@
"delete": "删除",
"create": "新增",
"yes": "是",
"no": "否"
"no": "否",
"showSearchPanel": "显示搜索面板",
"hideSearchPanel": "隐藏搜索面板"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/preferences",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/stores",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {
@@ -25,6 +25,7 @@
"@vben-core/typings": "workspace:*",
"pinia": "catalog:",
"pinia-plugin-persistedstate": "catalog:",
"secure-ls": "catalog:",
"vue": "catalog:",
"vue-router": "catalog:"
}

View File

@@ -1,6 +1,7 @@
import type { MenuRecordRaw } from '@vben-core/typings';
import type { RouteRecordRaw } from 'vue-router';
import type { MenuRecordRaw } from '@vben-core/typings';
import { acceptHMRUpdate, defineStore } from 'pinia';
type AccessToken = null | string;
@@ -26,6 +27,14 @@ interface AccessState {
* 是否已经检查过权限
*/
isAccessChecked: boolean;
/**
* 是否锁屏状态
*/
isLockScreen: boolean;
/**
* 锁屏密码
*/
lockScreenPassword?: string;
/**
* 登录是否过期
*/
@@ -60,6 +69,10 @@ export const useAccessStore = defineStore('core-access', {
}
return findMenu(this.accessMenus, path);
},
lockScreen(password: string) {
this.isLockScreen = true;
this.lockScreenPassword = password;
},
setAccessCodes(codes: string[]) {
this.accessCodes = codes;
},
@@ -81,10 +94,20 @@ export const useAccessStore = defineStore('core-access', {
setRefreshToken(token: AccessToken) {
this.refreshToken = token;
},
unlockScreen() {
this.isLockScreen = false;
this.lockScreenPassword = undefined;
},
},
persist: {
// 持久化
pick: ['accessToken', 'refreshToken', 'accessCodes'],
pick: [
'accessToken',
'refreshToken',
'accessCodes',
'isLockScreen',
'lockScreenPassword',
],
},
state: (): AccessState => ({
accessCodes: [],
@@ -92,6 +115,8 @@ export const useAccessStore = defineStore('core-access', {
accessRoutes: [],
accessToken: null,
isAccessChecked: false,
isLockScreen: false,
lockScreenPassword: undefined,
loginExpired: false,
refreshToken: null,
}),

View File

@@ -1,4 +1,3 @@
export * from './access';
export * from './lock';
export * from './tabbar';
export * from './user';

View File

@@ -1,31 +0,0 @@
import { createPinia, setActivePinia } from 'pinia';
import { beforeEach, describe, expect, it } from 'vitest';
import { useLockStore } from './lock';
describe('useLockStore', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('should initialize with correct default state', () => {
const store = useLockStore();
expect(store.isLockScreen).toBe(false);
expect(store.lockScreenPassword).toBeUndefined();
});
it('should lock screen with a password', () => {
const store = useLockStore();
store.lockScreen('1234');
expect(store.isLockScreen).toBe(true);
expect(store.lockScreenPassword).toBe('1234');
});
it('should unlock screen and clear password', () => {
const store = useLockStore();
store.lockScreen('1234');
store.unlockScreen();
expect(store.isLockScreen).toBe(false);
expect(store.lockScreenPassword).toBeUndefined();
});
});

View File

@@ -1,33 +0,0 @@
import { defineStore } from 'pinia';
interface AppState {
/**
* 是否锁屏状态
*/
isLockScreen: boolean;
/**
* 锁屏密码
*/
lockScreenPassword?: string;
}
export const useLockStore = defineStore('core-lock', {
actions: {
lockScreen(password: string) {
this.isLockScreen = true;
this.lockScreenPassword = password;
},
unlockScreen() {
this.isLockScreen = false;
this.lockScreenPassword = undefined;
},
},
persist: {
pick: ['isLockScreen', 'lockScreenPassword'],
},
state: (): AppState => ({
isLockScreen: false,
lockScreenPassword: undefined,
}),
});

View File

@@ -3,6 +3,7 @@ import type { Pinia } from 'pinia';
import type { App } from 'vue';
import { createPinia } from 'pinia';
import SecureLS from 'secure-ls';
let pinia: Pinia;
@@ -20,11 +21,27 @@ export async function initStores(app: App, options: InitStoreOptions) {
const { createPersistedState } = await import('pinia-plugin-persistedstate');
pinia = createPinia();
const { namespace } = options;
const ls = new SecureLS({
encodingType: 'aes',
encryptionSecret: import.meta.env.VITE_APP_STORE_SECURE_KEY,
isCompression: true,
// @ts-ignore secure-ls does not have a type definition for this
metaKey: `${namespace}-secure-meta`,
});
pinia.use(
createPersistedState({
// key $appName-$store.id
key: (storeKey) => `${namespace}-${storeKey}`,
storage: localStorage,
storage: import.meta.env.DEV
? localStorage
: {
getItem(key) {
return ls.get(key);
},
setItem(key, value) {
ls.set(key, value);
},
},
}),
);
app.use(pinia);

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/styles",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/types",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -1,6 +1,6 @@
{
"name": "@vben/utils",
"version": "5.5.4",
"version": "5.5.5",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {