;
export interface FormItemDependencies {
@@ -145,6 +148,11 @@ type ComponentProps =
| MaybeComponentProps;
export interface FormCommonConfig {
+ /**
+ * 是否可折叠的
+ * @default false
+ */
+ collapsible?: boolean;
/**
* 在Label后显示一个冒号
*/
@@ -157,6 +165,11 @@ export interface FormCommonConfig {
* 所有表单项的控件样式
*/
controlClass?: string;
+ /**
+ * 默认折叠
+ * @default false
+ */
+ defaultCollapsed?: boolean;
/**
* 所有表单项的禁用状态
* @default false
@@ -228,6 +241,19 @@ type MappedComponentProps =
) => P & Record)
| (P & Record);
+/**
+ * 格式化 `getValues()` 输出中的当前字段值。
+ * - 返回 `undefined`:保留当前字段已被移除的状态,通常配合 `setValue(key, nextValue)`
+ * 把一个字段拆分写入到其他字段,例如 `startTime` / `endTime`
+ * - 返回其他值:会将当前字段恢复/写回为该返回值
+ * - `setValue` 回调签名为 `(key, nextValue) => void`
+ */
+export type FormValueFormat = (
+ value: any,
+ setValue: (fieldName: string, value: any) => void,
+ values: Record,
+) => any;
+
interface FormSchemaBody extends Omit {
/** 默认值 */
defaultValue?: any;
@@ -249,6 +275,12 @@ interface FormSchemaBody extends Omit {
rules?: FormSchemaRuleType;
/** 后缀 */
suffix?: CustomRenderType;
+ /**
+ * 获取表单值时格式化当前字段。
+ * - 返回值不为 `undefined` 时,会回写到当前 fieldName
+ * - 返回值为 `undefined` 时,可通过 setValue 写入一个或多个目标字段
+ */
+ valueFormat?: FormValueFormat;
}
type FormSchemaDiscriminated<
diff --git a/packages/@core/ui-kit/layout-ui/package.json b/packages/@core/ui-kit/layout-ui/package.json
index efeba2269..e579303d9 100644
--- a/packages/@core/ui-kit/layout-ui/package.json
+++ b/packages/@core/ui-kit/layout-ui/package.json
@@ -47,5 +47,8 @@
"@vben-core/typings": "workspace:*",
"@vueuse/core": "catalog:",
"vue": "catalog:"
+ },
+ "devDependencies": {
+ "unplugin-vue": "catalog:"
}
}
diff --git a/packages/@core/ui-kit/menu-ui/package.json b/packages/@core/ui-kit/menu-ui/package.json
index a1dbc1b2a..5290fb1a8 100644
--- a/packages/@core/ui-kit/menu-ui/package.json
+++ b/packages/@core/ui-kit/menu-ui/package.json
@@ -51,6 +51,7 @@
"vue": "catalog:"
},
"devDependencies": {
- "@types/qs": "catalog:"
+ "@types/qs": "catalog:",
+ "unplugin-vue": "catalog:"
}
}
diff --git a/packages/@core/ui-kit/popup-ui/package.json b/packages/@core/ui-kit/popup-ui/package.json
index 0e384cbf3..865a83c07 100644
--- a/packages/@core/ui-kit/popup-ui/package.json
+++ b/packages/@core/ui-kit/popup-ui/package.json
@@ -47,5 +47,8 @@
"@vben-core/typings": "workspace:*",
"@vueuse/core": "catalog:",
"vue": "catalog:"
+ },
+ "devDependencies": {
+ "unplugin-vue": "catalog:"
}
}
diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts
index 5d8523b4d..85f02e27d 100644
--- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts
+++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts
@@ -79,7 +79,7 @@ export interface DrawerProps {
*/
headerClass?: ClassType;
/**
- * 弹窗是否显示
+ * 抽屉加载状态
* @default false
*/
loading?: boolean;
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
index 74758913d..c83d7095f 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
+++ b/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
@@ -46,6 +46,7 @@ export class ModalApi {
contentClass: '',
destroyOnClose: true,
draggable: false,
+ overflow: false,
footer: true,
footerClass: '',
fullscreen: false,
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
index 4debaff4b..5a7a50286 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
+++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
@@ -97,7 +97,7 @@ export interface ModalProps {
header?: boolean;
headerClass?: ClassType;
/**
- * 弹窗是否显示
+ * 弹窗加载状态
* @default false
*/
loading?: boolean;
@@ -110,6 +110,11 @@ export interface ModalProps {
* 是否自动聚焦
*/
openAutoFocus?: boolean;
+ /**
+ * 拖动范围是否可以超出可视区
+ * @default false
+ */
+ overflow?: boolean;
/**
* 弹窗遮罩模糊效果
*/
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
index f63d86018..1947b2254 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
+++ b/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
@@ -81,6 +81,7 @@ const {
description,
destroyOnClose,
draggable,
+ overflow,
footer: showFooter,
footerClass,
fullscreen,
@@ -122,6 +123,7 @@ const { dragging, transform } = useModalDraggable(
shouldDraggable,
getAppendTo,
shouldCentered,
+ overflow,
);
const firstOpened = ref(false);
@@ -246,7 +248,8 @@ function handleClosed() {
{
'border border-border': bordered,
'shadow-3xl': !bordered,
- 'top-0 left-0 size-full max-h-full translate-0!': shouldFullscreen,
+ 'top-0 left-0 size-full max-h-full transform-[translate(0,0)]!':
+ shouldFullscreen,
'top-1/2': centered && !shouldFullscreen,
'duration-300': !dragging,
hidden: isClosed,
diff --git a/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts b/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts
index 84910b744..a7bcba555 100644
--- a/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts
+++ b/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts
@@ -15,6 +15,7 @@ export function useModalDraggable(
draggable: ComputedRef,
containerSelector?: ComputedRef,
centered?: ComputedRef,
+ overflow?: ComputedRef,
) {
const transform = reactive({
offsetX: 0,
@@ -67,8 +68,10 @@ export function useModalDraggable(
let moveX = offsetX + e.clientX - downX;
let moveY = offsetY + e.clientY - downY;
- moveX = Math.min(Math.max(moveX, minLeft), maxLeft);
- moveY = Math.min(Math.max(moveY, minTop), maxTop);
+ if (!overflow?.value) {
+ moveX = Math.min(Math.max(moveX, minLeft), maxLeft);
+ moveY = Math.min(Math.max(moveY, minTop), maxTop);
+ }
transform.offsetX = moveX;
transform.offsetY = moveY;
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
new file mode 100644
index 000000000..85b019718
--- /dev/null
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params-item.vue
@@ -0,0 +1,123 @@
+
+
+
+
+
+ {{ data.key }}
+
+
+
+
+
+
+
+ {{ limitDisplay }}
+
+
+ step:{{ data.option.step }}
+
+
+
+
+
+ {{ data.description }}
+
+
+
+
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
new file mode 100644
index 000000000..8c0accac4
--- /dev/null
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible-params.vue
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+ onParamValueChange(v, row.key)"
+ />
+
+ onParamValueChange(v, row.key)"
+ />
+
+
+
+
+
+
+
+
+ {{ open ? 'Fold' : 'Unfold' }}
+
+
+
+
+
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue
new file mode 100755
index 000000000..f76dbf13e
--- /dev/null
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/collapsible.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts
new file mode 100755
index 000000000..8563a7e59
--- /dev/null
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/index.ts
@@ -0,0 +1,4 @@
+export { default as VbenCollapsibleParams } from './collapsible-params.vue';
+export { default as VbenCollapsible } from './collapsible.vue';
+
+export * from './type';
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts
new file mode 100644
index 000000000..f2fcffdf3
--- /dev/null
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/collapsible/type.ts
@@ -0,0 +1,22 @@
+export interface CollapsibleParamsProps {
+ defaultOpen?: boolean;
+ maxHeight?: number | string;
+ params: CollapsibleParamSchema[];
+ visibleCount?: number;
+}
+
+export interface CollapsibleParamOption {
+ [key: string]: any;
+ max?: number;
+ min?: number;
+ precision?: number;
+ step?: number;
+ type?: 'exponential' | 'number' | 'select' | 'string';
+}
+
+export interface CollapsibleParamSchema {
+ defaultValue?: number | number[] | string | string[];
+ description: string;
+ key: string;
+ option: CollapsibleParamOption;
+}
diff --git a/packages/@core/ui-kit/shadcn-ui/src/components/index.ts b/packages/@core/ui-kit/shadcn-ui/src/components/index.ts
index 034bbbca7..ebbdbcc19 100644
--- a/packages/@core/ui-kit/shadcn-ui/src/components/index.ts
+++ b/packages/@core/ui-kit/shadcn-ui/src/components/index.ts
@@ -3,6 +3,7 @@ export * from './back-top';
export * from './breadcrumb';
export * from './button';
export * from './checkbox';
+export * from './collapsible';
export * from './context-menu';
export * from './count-to-animator';
export * from './dropdown-menu';
diff --git a/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts b/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts
index d02877518..0213f2ff8 100644
--- a/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts
+++ b/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts
@@ -1,7 +1,7 @@
import { cva } from 'class-variance-authority';
export const buttonVariants = cva(
- 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
{
defaultVariants: {
size: 'default',
diff --git a/packages/@core/ui-kit/tabs-ui/package.json b/packages/@core/ui-kit/tabs-ui/package.json
index 23e37f0a4..75d0fd854 100644
--- a/packages/@core/ui-kit/tabs-ui/package.json
+++ b/packages/@core/ui-kit/tabs-ui/package.json
@@ -47,5 +47,8 @@
"@vben-core/typings": "workspace:*",
"@vueuse/core": "catalog:",
"vue": "catalog:"
+ },
+ "devDependencies": {
+ "unplugin-vue": "catalog:"
}
}
diff --git a/packages/effects/common-ui/package.json b/packages/effects/common-ui/package.json
index 4dae68c62..fcb893034 100644
--- a/packages/effects/common-ui/package.json
+++ b/packages/effects/common-ui/package.json
@@ -63,6 +63,7 @@
},
"devDependencies": {
"@types/json-bigint": "catalog:",
- "@types/qrcode": "catalog:"
+ "@types/qrcode": "catalog:",
+ "@vue/test-utils": "catalog:"
}
}
diff --git a/packages/effects/common-ui/src/components/api-component/api-component.vue b/packages/effects/common-ui/src/components/api-component/api-component.vue
index 45ec260f4..2c6d69317 100644
--- a/packages/effects/common-ui/src/components/api-component/api-component.vue
+++ b/packages/effects/common-ui/src/components/api-component/api-component.vue
@@ -17,6 +17,7 @@ defineOptions({ name: 'ApiComponent', inheritAttrs: false });
const props = withDefaults(defineProps(), {
labelField: 'label',
valueField: 'value',
+ labelFn: undefined,
disabledField: 'disabled',
childrenField: '',
optionsPropName: 'options',
@@ -54,33 +55,37 @@ const hasPendingRequest = ref(false);
const getOptions = computed(() => {
const {
labelField,
+ labelFn,
valueField,
disabledField,
childrenField,
numberToString,
} = props;
- const refOptionsData = unref(refOptions);
-
- function transformData(data: OptionsItem[]): OptionsItem[] {
+ function transformData(data: OptionsItem[] = []): OptionsItem[] {
return data.map((item) => {
const value = get(item, valueField);
- const disabled = get(item, disabledField);
+ const children = childrenField ? get(item, childrenField) : item.children;
return {
- ...objectOmit(item, [labelField, valueField, disabled, childrenField]),
- label: get(item, labelField),
+ ...objectOmit(item, [
+ labelField,
+ valueField,
+ disabledField,
+ ...(childrenField ? [childrenField] : []),
+ ]),
+ label: labelFn ? labelFn(item) : get(item, labelField),
value: numberToString ? `${value}` : value,
disabled: get(item, disabledField),
- ...(childrenField && item[childrenField]
- ? { children: transformData(item[childrenField]) }
+ ...(Array.isArray(children) && children.length > 0
+ ? { children: transformData(children) }
: {}),
};
});
}
- const data: OptionsItem[] = transformData(refOptionsData);
+ const data = transformData(unref(refOptions));
- return data.length > 0 ? data : props.options;
+ return data.length > 0 ? data : transformData(props.options);
});
const bindProps = computed(() => {
diff --git a/packages/effects/common-ui/src/components/api-component/index.ts b/packages/effects/common-ui/src/components/api-component/index.ts
index 097858698..173b30d1c 100644
--- a/packages/effects/common-ui/src/components/api-component/index.ts
+++ b/packages/effects/common-ui/src/components/api-component/index.ts
@@ -1,5 +1,6 @@
export { default as ApiComponent } from './api-component.vue';
export type {
+ ApiComponentLabelFn,
ApiComponentOptionsItem,
ApiComponentProps,
ApiComponentSharedProps,
diff --git a/packages/effects/common-ui/src/components/api-component/types.ts b/packages/effects/common-ui/src/components/api-component/types.ts
index 000636a7f..a771f78a5 100644
--- a/packages/effects/common-ui/src/components/api-component/types.ts
+++ b/packages/effects/common-ui/src/components/api-component/types.ts
@@ -10,6 +10,8 @@ export type ApiComponentOptionsItem = {
value?: number | string;
};
+export type ApiComponentLabelFn = (item: ApiComponentOptionsItem) => string;
+
export interface ApiComponentProps {
/** 组件 */
component: Component;
@@ -23,6 +25,8 @@ export interface ApiComponentProps {
resultField?: string;
/** label字段名 */
labelField?: string;
+ /** 通过选项数据自定义label */
+ labelFn?: ApiComponentLabelFn;
/** children字段名,需要层级数据的组件可用 */
childrenField?: string;
/** value字段名 */
diff --git a/packages/effects/common-ui/src/components/index.ts b/packages/effects/common-ui/src/components/index.ts
index 13fc3c7a7..774f21891 100644
--- a/packages/effects/common-ui/src/components/index.ts
+++ b/packages/effects/common-ui/src/components/index.ts
@@ -27,6 +27,7 @@ export {
VbenContextMenu,
VbenCountToAnimator,
VbenFullScreen,
+ VbenIconButton,
VbenInputPassword,
VbenLoading,
VbenLogo,
diff --git a/packages/effects/layouts/src/widgets/notification/notification.vue b/packages/effects/layouts/src/widgets/notification/notification.vue
index a399932ff..372b1f586 100644
--- a/packages/effects/layouts/src/widgets/notification/notification.vue
+++ b/packages/effects/layouts/src/widgets/notification/notification.vue
@@ -1,67 +1,69 @@
-
+
@@ -83,29 +85,60 @@ function handleClick(item: NotificationItem) {
-
+
+
-
-
-
-
-
{{ item.title }}
-
- {{ item.message }}
-
-
- {{ item.date }}
-
-
+
+
+
+
+
{{ item.title }}
+
+ {{ item.message }}
+
+
+ {{ item.date }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -117,7 +150,9 @@ function handleClick(item: NotificationItem) {