diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fb33f60..ebb9d8ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.3.2 + +**REFACTOR** + +- 所有表格操作列宽度调整为'auto', 这样会根据子元素宽度适配(比如没有分配权限的情况) + # 1.3.1 **REFACTOR** diff --git a/apps/web-antd/src/adapter/component/index.ts b/apps/web-antd/src/adapter/component/index.ts index ca59e2e5..3cde8257 100644 --- a/apps/web-antd/src/adapter/component/index.ts +++ b/apps/web-antd/src/adapter/component/index.ts @@ -9,7 +9,6 @@ import type { BaseFormComponentType } from '@vben/common-ui'; import type { Recordable } from '@vben/types'; import { - computed, defineAsyncComponent, defineComponent, getCurrentInstance, @@ -91,15 +90,10 @@ const withDefaultPlaceholder = ( inheritAttrs: false, name: component.name, setup: (props: any, { attrs, expose, slots }) => { - /** - * 需要使用computed 否则后续updateSchema更新的placeholder无法显示(响应式问题) - */ - const placeholder = computed( - () => - props?.placeholder || - attrs?.placeholder || - $t(`ui.placeholder.${type}`), - ); + const placeholder = + props?.placeholder || + attrs?.placeholder || + $t(`ui.placeholder.${type}`); // 透传组件暴露的方法 const innerRef = ref(); @@ -118,7 +112,7 @@ const withDefaultPlaceholder = ( component, { ...componentProps, - placeholder: placeholder.value, + placeholder, ...props, ...attrs, ref: innerRef, diff --git a/apps/web-antd/src/views/demo/demo/data.ts b/apps/web-antd/src/views/demo/demo/data.ts index 81c90c39..241d855f 100755 --- a/apps/web-antd/src/views/demo/demo/data.ts +++ b/apps/web-antd/src/views/demo/demo/data.ts @@ -51,7 +51,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/demo/tree/data.ts b/apps/web-antd/src/views/demo/tree/data.ts index a6984f67..ae15288e 100755 --- a/apps/web-antd/src/views/demo/tree/data.ts +++ b/apps/web-antd/src/views/demo/tree/data.ts @@ -60,7 +60,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/monitor/online/data.ts b/apps/web-antd/src/views/monitor/online/data.ts index 8a42aaf6..15944dc4 100644 --- a/apps/web-antd/src/views/monitor/online/data.ts +++ b/apps/web-antd/src/views/monitor/online/data.ts @@ -79,6 +79,7 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 120, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/monitor/operlog/data.tsx b/apps/web-antd/src/views/monitor/operlog/data.tsx index ee1bacea..d42b3709 100644 --- a/apps/web-antd/src/views/monitor/operlog/data.tsx +++ b/apps/web-antd/src/views/monitor/operlog/data.tsx @@ -86,6 +86,7 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 120, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/client/data.tsx b/apps/web-antd/src/views/system/client/data.tsx index 2b852f0b..1cf85720 100644 --- a/apps/web-antd/src/views/system/client/data.tsx +++ b/apps/web-antd/src/views/system/client/data.tsx @@ -95,7 +95,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/config/data.ts b/apps/web-antd/src/views/system/config/data.ts index 9cb45ffa..0b462e4f 100644 --- a/apps/web-antd/src/views/system/config/data.ts +++ b/apps/web-antd/src/views/system/config/data.ts @@ -71,7 +71,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/dept/data.ts b/apps/web-antd/src/views/system/dept/data.ts index e5f9a669..8ae8a96d 100644 --- a/apps/web-antd/src/views/system/dept/data.ts +++ b/apps/web-antd/src/views/system/dept/data.ts @@ -39,11 +39,13 @@ export const columns: VxeGridProps['columns'] = [ { field: 'orderNum', title: '排序', - width: 180, + resizable: false, + width: 'auto', }, { field: 'status', - width: 180, + resizable: false, + width: 'auto', title: '状态', slots: { default: ({ row }) => { diff --git a/apps/web-antd/src/views/system/dict/data/data.ts b/apps/web-antd/src/views/system/dict/data/data.ts index 81887463..087e96b2 100644 --- a/apps/web-antd/src/views/system/dict/data/data.ts +++ b/apps/web-antd/src/views/system/dict/data/data.ts @@ -45,7 +45,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/dict/type/data.ts b/apps/web-antd/src/views/system/dict/type/data.ts index 2d08365b..cfd584a7 100644 --- a/apps/web-antd/src/views/system/dict/type/data.ts +++ b/apps/web-antd/src/views/system/dict/type/data.ts @@ -39,7 +39,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/menu/data.tsx b/apps/web-antd/src/views/system/menu/data.tsx index a416c429..f29cc4f3 100644 --- a/apps/web-antd/src/views/system/menu/data.tsx +++ b/apps/web-antd/src/views/system/menu/data.tsx @@ -145,7 +145,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 200, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/notice/data.ts b/apps/web-antd/src/views/system/notice/data.ts index 4e463e9a..8e052c19 100644 --- a/apps/web-antd/src/views/system/notice/data.ts +++ b/apps/web-antd/src/views/system/notice/data.ts @@ -69,7 +69,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/oss-config/data.tsx b/apps/web-antd/src/views/system/oss-config/data.tsx index 7b394def..2d086210 100644 --- a/apps/web-antd/src/views/system/oss-config/data.tsx +++ b/apps/web-antd/src/views/system/oss-config/data.tsx @@ -81,7 +81,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/oss/data.tsx b/apps/web-antd/src/views/system/oss/data.tsx index 06d1bc67..ec834796 100644 --- a/apps/web-antd/src/views/system/oss/data.tsx +++ b/apps/web-antd/src/views/system/oss/data.tsx @@ -69,7 +69,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/post/data.ts b/apps/web-antd/src/views/system/post/data.ts index 3a7da9d2..e8595553 100644 --- a/apps/web-antd/src/views/system/post/data.ts +++ b/apps/web-antd/src/views/system/post/data.ts @@ -65,7 +65,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/role-assign/data.tsx b/apps/web-antd/src/views/system/role-assign/data.tsx index 75f8bfe9..a26bd164 100644 --- a/apps/web-antd/src/views/system/role-assign/data.tsx +++ b/apps/web-antd/src/views/system/role-assign/data.tsx @@ -37,6 +37,7 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/tenant/data.tsx b/apps/web-antd/src/views/system/tenant/data.tsx index c86ec835..69af062b 100644 --- a/apps/web-antd/src/views/system/tenant/data.tsx +++ b/apps/web-antd/src/views/system/tenant/data.tsx @@ -68,7 +68,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 200, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/system/tenantPackage/data.ts b/apps/web-antd/src/views/system/tenantPackage/data.ts index 4015f432..a80de6a5 100644 --- a/apps/web-antd/src/views/system/tenantPackage/data.ts +++ b/apps/web-antd/src/views/system/tenantPackage/data.ts @@ -29,7 +29,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 180, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/workflow/category/data.ts b/apps/web-antd/src/views/workflow/category/data.ts index 41a0a884..9dfe1940 100644 --- a/apps/web-antd/src/views/workflow/category/data.ts +++ b/apps/web-antd/src/views/workflow/category/data.ts @@ -33,7 +33,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 200, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/workflow/leave/data.tsx b/apps/web-antd/src/views/workflow/leave/data.tsx index 7afdb898..7eb3441b 100644 --- a/apps/web-antd/src/views/workflow/leave/data.tsx +++ b/apps/web-antd/src/views/workflow/leave/data.tsx @@ -91,7 +91,8 @@ export const columns: VxeGridProps['columns'] = [ fixed: 'right', slots: { default: 'action' }, title: '操作', - width: 210, + resizable: false, + width: 'auto', }, ]; diff --git a/apps/web-antd/src/views/workflow/processDefinition/category-tree.vue b/apps/web-antd/src/views/workflow/processDefinition/category-tree.vue index 6912c256..901038c8 100644 --- a/apps/web-antd/src/views/workflow/processDefinition/category-tree.vue +++ b/apps/web-antd/src/views/workflow/processDefinition/category-tree.vue @@ -1,7 +1,9 @@ diff --git a/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue b/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue index 17bc1215..7a82e724 100644 --- a/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue +++ b/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue @@ -208,6 +208,8 @@ onBeforeUnmount(() => { nsMenu.e('popup-container'), is(rootMenu.theme, true), opened ? '' : 'hidden', + 'overflow-auto', + 'max-h-[calc(var(--radix-hover-card-content-available-height)-20px)]', ]" :content-props="contentProps" :open="true" diff --git a/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts b/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts index 20e4254c..521a9647 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts +++ b/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts @@ -7,7 +7,7 @@ import type { AlertProps, BeforeCloseScope, PromptProps } from './alert'; import { h, nextTick, ref, render } from 'vue'; import { useSimpleLocale } from '@vben-core/composables'; -import { Input } from '@vben-core/shadcn-ui'; +import { Input, VbenRenderContent } from '@vben-core/shadcn-ui'; import { isFunction, isString } from '@vben-core/shared/utils'; import Alert from './alert.vue'; @@ -146,11 +146,7 @@ export async function vbenPrompt( const inputComponentRef = ref(null); const staticContents: Component[] = []; - if (isString(content)) { - staticContents.push(h('span', content)); - } else if (content) { - staticContents.push(content as Component); - } + staticContents.push(h(VbenRenderContent, { content, renderBr: true })); const modelPropName = _modelPropName || 'modelValue'; const componentProps = { ..._componentProps }; diff --git a/packages/@core/ui-kit/popup-ui/src/alert/alert.ts b/packages/@core/ui-kit/popup-ui/src/alert/alert.ts index 49d65ed5..5a214fa2 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/alert.ts +++ b/packages/@core/ui-kit/popup-ui/src/alert/alert.ts @@ -2,6 +2,8 @@ import type { Component, VNode, VNodeArrayChildren } from 'vue'; import type { Recordable } from '@vben-core/typings'; +import { createContext } from '@vben-core/shadcn-ui'; + export type IconType = 'error' | 'info' | 'question' | 'success' | 'warning'; export type BeforeCloseScope = { @@ -34,8 +36,14 @@ export type AlertProps = { contentClass?: string; /** 执行beforeClose回调期间,在内容区域显示一个loading遮罩*/ contentMasking?: boolean; + /** 弹窗底部内容(与按钮在同一个容器中) */ + footer?: Component | string; /** 弹窗的图标(在标题的前面) */ icon?: Component | IconType; + /** + * 弹窗遮罩模糊效果 + */ + overlayBlur?: number; /** 是否显示取消按钮 */ showCancel?: boolean; /** 弹窗标题 */ @@ -64,3 +72,28 @@ export type PromptProps = { /** 输入组件的值属性名 */ modelPropName?: string; } & Omit; + +/** + * Alert上下文 + */ +export type AlertContext = { + /** 执行取消操作 */ + doCancel: () => void; + /** 执行确认操作 */ + doConfirm: () => void; +}; + +export const [injectAlertContext, provideAlertContext] = + createContext('VbenAlertContext'); + +/** + * 获取Alert上下文 + * @returns AlertContext + */ +export function useAlertContext() { + const context = injectAlertContext(); + if (!context) { + throw new Error('useAlertContext must be used within an AlertProvider'); + } + return context; +} diff --git a/packages/@core/ui-kit/popup-ui/src/alert/alert.vue b/packages/@core/ui-kit/popup-ui/src/alert/alert.vue index 5c02ed2a..a5b4d0da 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/alert.vue +++ b/packages/@core/ui-kit/popup-ui/src/alert/alert.vue @@ -3,7 +3,7 @@ import type { Component } from 'vue'; import type { AlertProps } from './alert'; -import { computed, h, nextTick, ref, watch } from 'vue'; +import { computed, h, nextTick, ref } from 'vue'; import { useSimpleLocale } from '@vben-core/composables'; import { @@ -28,6 +28,8 @@ import { import { globalShareState } from '@vben-core/shared/global-state'; import { cn } from '@vben-core/shared/utils'; +import { provideAlertContext } from './alert'; + const props = withDefaults(defineProps(), { bordered: true, buttonAlign: 'end', @@ -39,14 +41,12 @@ const open = defineModel('open', { default: false }); const { $t } = useSimpleLocale(); const components = globalShareState.getComponents(); const isConfirm = ref(false); -watch(open, async (val) => { - await nextTick(); - if (val) { - isConfirm.value = false; - } else { - emits('closed', isConfirm.value); - } -}); + +function onAlertClosed() { + emits('closed', isConfirm.value); + isConfirm.value = false; +} + const getIconRender = computed(() => { let iconRender: Component | null = null; if (props.icon) { @@ -89,6 +89,23 @@ const getIconRender = computed(() => { } return iconRender; }); + +function doCancel() { + isConfirm.value = false; + handleOpenChange(false); +} + +function doConfirm() { + isConfirm.value = true; + handleOpenChange(false); + emits('confirm'); +} + +provideAlertContext({ + doCancel, + doConfirm, +}); + function handleConfirm() { isConfirm.value = true; emits('confirm'); @@ -100,6 +117,7 @@ function handleCancel() { const loading = ref(false); async function handleOpenChange(val: boolean) { + await nextTick(); if (!val && props.beforeClose) { loading.value = true; try { @@ -120,15 +138,16 @@ async function handleOpenChange(val: boolean) { -
+
-
+
+ { return { isFunction: (fn: any) => typeof fn === 'function', Store: class { + get state() { + return this._state; + } private _state: DrawerState; + private options: any; constructor(initialState: DrawerState, options: any) { @@ -25,10 +29,6 @@ vi.mock('@vben-core/shared/store', () => { this._state = fn(this._state); this.options.onUpdate(); } - - get state() { - return this._state; - } }, }; }); @@ -54,7 +54,6 @@ describe('drawerApi', () => { }); it('should close the drawer if onBeforeClose allows it', () => { - drawerApi.open(); drawerApi.close(); expect(drawerApi.store.state.isOpen).toBe(false); }); diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts b/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts index d2e7d690..a19a1717 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts @@ -86,7 +86,8 @@ export class DrawerApi { } /** - * 关闭弹窗 + * 关闭抽屉 + * @description 关闭抽屉时会调用 onBeforeClose 钩子函数,如果 onBeforeClose 返回 false,则不关闭弹窗 */ async close() { // 通过 onBeforeClose 钩子函数来判断是否允许关闭弹窗 diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue index 410c3ffe..b5535ba4 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue @@ -274,7 +274,7 @@ const getAppendTo = computed(() => { {{ cancelText || $t('cancel') }} - + import type { ExtendedModalApi, ModalProps } from './modal'; -import { computed, nextTick, provide, ref, useId, watch } from 'vue'; +import { computed, nextTick, provide, ref, unref, useId, watch } from 'vue'; import { useIsMobile, @@ -34,6 +34,7 @@ interface Props extends ModalProps { const props = withDefaults(defineProps(), { appendToMain: false, + destroyOnClose: true, modalApi: undefined, }); @@ -67,6 +68,7 @@ const { confirmText, contentClass, description, + destroyOnClose, draggable, footer: showFooter, footerClass, @@ -100,10 +102,15 @@ const { dragging, transform } = useModalDraggable( shouldDraggable, ); +const firstOpened = ref(false); +const isClosed = ref(true); + watch( () => state?.value?.isOpen, async (v) => { if (v) { + isClosed.value = false; + if (!firstOpened.value) firstOpened.value = true; await nextTick(); if (!contentRef.value) return; const innerContentRef = contentRef.value.getContentRef(); @@ -113,6 +120,7 @@ watch( dialogRef.value.style.transform = `translate(${offsetX}px, ${offsetY}px)`; } }, + { immediate: true }, ); watch( @@ -176,6 +184,15 @@ const getAppendTo = computed(() => { ? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div` : undefined; }); + +const getForceMount = computed(() => { + return !unref(destroyOnClose) && unref(firstOpened); +}); + +function handleClosed() { + isClosed.value = true; + props.modalApi?.onClosed(); +} diff --git a/playground/src/views/examples/modal/in-content-demo.vue b/playground/src/views/examples/modal/in-content-demo.vue index b51d363f..7ffe7b77 100644 --- a/playground/src/views/examples/modal/in-content-demo.vue +++ b/playground/src/views/examples/modal/in-content-demo.vue @@ -24,7 +24,7 @@ const value = ref(); title="基础弹窗示例" title-tooltip="标题提示内容" > - 此弹窗指定在内容区域打开 - + 此弹窗指定在内容区域打开,并且在关闭之后弹窗内容不会被销毁 + diff --git a/playground/src/views/examples/modal/index.vue b/playground/src/views/examples/modal/index.vue index 2137227b..3ed6cdea 100644 --- a/playground/src/views/examples/modal/index.vue +++ b/playground/src/views/examples/modal/index.vue @@ -138,6 +138,7 @@ function openConfirm() { }, 1000); }); }, + centered: false, content: '这是一个确认弹窗', icon: 'question', }) @@ -160,6 +161,7 @@ async function openPrompt() { componentProps: { placeholder: '不能吃芝士...' }, content: '中午吃了什么?', icon: 'question', + overlayBlur: 3, }) .then((res) => { message.success(`用户输入了:${res}`); @@ -196,7 +198,7 @@ async function openPrompt() { - +

在内容区域打开弹窗的示例