This commit is contained in:
dap
2024-11-09 16:45:50 +08:00
58 changed files with 1512 additions and 111 deletions

View File

@@ -31,7 +31,7 @@
#app,
body,
html {
@apply size-full overscroll-none;
@apply size-full;
/* scrollbar-gutter: stable; */
}

View File

@@ -3,19 +3,5 @@ import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
declaration: true,
entries: [
{
builder: 'mkdist',
input: './src',
loaders: ['vue'],
pattern: ['**/*.vue'],
},
{
builder: 'mkdist',
format: 'esm',
input: './src',
loaders: ['js'],
pattern: ['**/*.ts'],
},
],
entries: ['src/index'],
});

View File

@@ -1,27 +0,0 @@
<template>
<svg
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="none" fill-rule="evenodd" transform="translate(0 1)">
<ellipse
cx="32"
cy="33"
fill="hsl(var(--background-deep))"
rx="32"
ry="7"
/>
<g fill-rule="nonzero" stroke="hsl(var(--heavy))">
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
fill="hsl(var(--accent))"
/>
</g>
</g>
</svg>
</template>

View File

@@ -1,10 +1,14 @@
export { default as EmptyIcon } from './components/empty.vue';
export * from './create-icon';
export * from './lucide';
export type { IconifyIcon as IconifyIconStructure } from '@iconify/vue';
export { addCollection, addIcon, Icon as IconifyIcon } from '@iconify/vue';
export {
addCollection,
addIcon,
Icon as IconifyIcon,
listIcons,
} from '@iconify/vue';
/**
* 从@iconify/vue/dist/offline'导出的组件为离线ICON 不支持在线

View File

@@ -27,6 +27,7 @@ export {
FoldHorizontal,
Fullscreen,
Github,
Grip,
Info,
InspectionPanel,
Languages,

View File

@@ -84,6 +84,7 @@
"@types/lodash.get": "catalog:",
"@vue/shared": "catalog:",
"clsx": "catalog:",
"dayjs": "^1.11.13",
"defu": "catalog:",
"lodash.clonedeep": "catalog:",
"lodash.get": "catalog:",

View File

@@ -0,0 +1,18 @@
import dayjs from 'dayjs';
export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
try {
const date = dayjs(time);
if (!date.isValid()) {
throw new Error('Invalid date');
}
return date.format(format);
} catch (error) {
console.error(`Error formatting date: ${error}`);
return time;
}
}
export function formatDateTime(time: number | string) {
return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
}

View File

@@ -1,4 +1,5 @@
export * from './cn';
export * from './date';
export * from './diff';
export * from './dom';
export * from './inference';

View File

@@ -34,4 +34,6 @@ interface BasicUserInfo {
username: string;
}
export type { BasicOption, BasicUserInfo, SelectOption, TabOption };
type ClassType = Array<object | string> | object | string;
export type { BasicOption, BasicUserInfo, ClassType, SelectOption, TabOption };

View File

@@ -40,6 +40,7 @@
"@vben-core/composables": "workspace:*",
"@vben-core/shadcn-ui": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vben-core/typings": "workspace:*",
"@vee-validate/zod": "catalog:",
"@vueuse/core": "catalog:",
"vee-validate": "catalog:",

View File

@@ -3,7 +3,12 @@ import { computed, toRaw, unref, watch } from 'vue';
import { useSimpleLocale } from '@vben-core/composables';
import { VbenExpandableArrow } from '@vben-core/shadcn-ui';
import { cn, isFunction, triggerWindowResize } from '@vben-core/shared/utils';
import {
cn,
formatDate,
isFunction,
triggerWindowResize,
} from '@vben-core/shared/utils';
import { COMPONENT_MAP } from '../config';
import { injectFormProps } from '../use-form-context';
@@ -52,20 +57,64 @@ async function handleSubmit(e: Event) {
if (!valid) {
return;
}
await unref(rootProps).handleSubmit?.(toRaw(form.values));
const values = handleRangeTimeValue(toRaw(form.values));
await unref(rootProps).handleSubmit?.(values);
}
async function handleReset(e: Event) {
e?.preventDefault();
e?.stopPropagation();
const props = unref(rootProps);
const values = toRaw(form.values);
// 清理时间字段
props.fieldMappingTime &&
props.fieldMappingTime.forEach(([_, [startTimeKey, endTimeKey]]) => {
delete values[startTimeKey];
delete values[endTimeKey];
});
if (isFunction(props.handleReset)) {
await props.handleReset?.(form.values);
await props.handleReset?.(values);
} else {
form.resetForm();
}
}
function handleRangeTimeValue(values: Record<string, any>) {
const fieldMappingTime = unref(rootProps).fieldMappingTime;
if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
return values;
}
fieldMappingTime.forEach(
([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => {
if (!values[field]) {
delete values[field];
return;
}
const [startTime, endTime] = values[field];
const [startTimeFormat, endTimeFormat] = Array.isArray(format)
? format
: [format, format];
values[startTimeKey] = startTime
? formatDate(startTime, startTimeFormat)
: undefined;
values[endTimeKey] = endTime
? formatDate(endTime, endTimeFormat)
: undefined;
delete values[field];
},
);
return values;
}
watch(
() => collapsed.value,
() => {

View File

@@ -303,4 +303,13 @@ export class FormApi {
}
return validateResult;
}
async validateAndSubmitForm() {
const form = await this.getForm();
const { valid } = await form.validate();
if (!valid) {
return;
}
return await this.submitForm();
}
}

View File

@@ -1,4 +1,5 @@
import type { VbenButtonProps } from '@vben-core/shadcn-ui';
import type { ClassType } from '@vben-core/typings';
import type { FieldOptions, FormContext, GenericObject } from 'vee-validate';
import type { ZodTypeAny } from 'zod';
@@ -205,6 +206,12 @@ export type HandleResetFn = (
values: Record<string, any>,
) => Promise<void> | void;
export type FieldMappingTime = [
string,
[string, string],
([string, string] | string)?,
][];
export interface FormSchema<
T extends BaseFormComponentType = BaseFormComponentType,
> extends FormCommonConfig {
@@ -303,7 +310,11 @@ export interface VbenFormProps<
/**
* 表单操作区域class
*/
actionWrapperClass?: any;
actionWrapperClass?: ClassType;
/**
* 表单字段映射成时间格式
*/
fieldMappingTime?: FieldMappingTime;
/**
* 表单重置回调
*/

View File

@@ -41,6 +41,7 @@
"@vben-core/icons": "workspace:*",
"@vben-core/shadcn-ui": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vben-core/typings": "workspace:*",
"@vueuse/core": "catalog:",
"vue": "catalog:"
}

View File

@@ -1,3 +1,5 @@
import type { ClassType } from '@vben-core/typings';
import type { DrawerApi } from './drawer-api';
import type { Component, Ref } from 'vue';
@@ -7,7 +9,7 @@ export interface DrawerProps {
* 取消按钮文字
*/
cancelText?: string;
class?: string;
class?: ClassType;
/**
* 是否显示右上角的关闭按钮
* @default true
@@ -42,6 +44,20 @@ export interface DrawerProps {
* @default true
*/
footer?: boolean;
/**
* 弹窗底部样式
*/
footerClass?: ClassType;
/**
* 是否显示顶栏
* @default true
*/
header?: boolean;
/**
* 弹窗头部样式
*/
headerClass?: ClassType;
/**
* 弹窗是否显示
* @default false

View File

@@ -56,6 +56,9 @@ const {
contentClass,
description,
footer: showFooter,
footerClass,
header: showHeader,
headerClass,
loading: showLoading,
modal,
openAutoFocus,
@@ -129,10 +132,15 @@ function handleFocusOutside(e: Event) {
@pointer-down-outside="pointerDownOutside"
>
<SheetHeader
v-if="showHeader"
:class="
cn('!flex flex-row items-center justify-between border-b px-6 py-5', {
'px-4 py-3': closable,
})
cn(
'!flex flex-row items-center justify-between border-b px-6 py-5',
headerClass,
{
'px-4 py-3': closable,
},
)
"
>
<div>
@@ -171,6 +179,12 @@ function handleFocusOutside(e: Event) {
</div>
</SheetHeader>
<template v-else>
<VisuallyHidden>
<SheetTitle />
<SheetDescription />
</VisuallyHidden>
</template>
<div
ref="wrapperRef"
:class="
@@ -186,7 +200,12 @@ function handleFocusOutside(e: Event) {
<SheetFooter
v-if="showFooter"
class="w-full flex-row items-center justify-end border-t p-2 px-3"
:class="
cn(
'w-full flex-row items-center justify-end border-t p-2 px-3',
footerClass,
)
"
>
<slot name="prepend-footer"></slot>
<slot name="footer">

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import type {
AvatarFallbackProps,
AvatarImageProps,
@@ -11,9 +12,9 @@ import { Avatar, AvatarFallback, AvatarImage } from '../../ui';
interface Props extends AvatarRootProps, AvatarFallbackProps, AvatarImageProps {
alt?: string;
class?: any;
class?: ClassType;
dot?: boolean;
dotClass?: any;
dotClass?: ClassType;
}
defineOptions({

View File

@@ -14,6 +14,7 @@ interface Props extends VbenButtonProps {
disabled?: boolean;
onClick?: () => void;
tooltip?: string;
tooltipDelayDuration?: number;
tooltipSide?: 'bottom' | 'left' | 'right' | 'top';
variant?: ButtonVariants;
}
@@ -21,6 +22,7 @@ interface Props extends VbenButtonProps {
const props = withDefaults(defineProps<Props>(), {
disabled: false,
onClick: () => {},
tooltipDelayDuration: 200,
tooltipSide: 'bottom',
variant: 'icon',
});
@@ -42,7 +44,11 @@ const showTooltip = computed(() => !!slots.tooltip || !!props.tooltip);
<slot></slot>
</VbenButton>
<VbenTooltip v-else :side="tooltipSide">
<VbenTooltip
v-else
:delay-duration="tooltipDelayDuration"
:side="tooltipSide"
>
<template #trigger>
<VbenButton
:class="cn('rounded-full', props.class)"

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import type {
ContextMenuContentProps,
ContextMenuRootEmits,
@@ -22,11 +23,11 @@ import {
const props = defineProps<
{
class?: any;
contentClass?: any;
class?: ClassType;
contentClass?: ClassType;
contentProps?: ContextMenuContentProps;
handlerData?: Record<string, any>;
itemClass?: any;
itemClass?: ClassType;
menus: (data: any) => IContextMenuItem[];
} & ContextMenuRootProps
>();

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import type {
HoverCardContentProps,
HoverCardRootEmits,
@@ -12,8 +13,8 @@ import { useForwardPropsEmits } from 'radix-vue';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '../../ui';
interface Props extends HoverCardRootProps {
class?: any;
contentClass?: any;
class?: ClassType;
contentClass?: ClassType;
contentProps?: HoverCardContentProps;
}

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import type {
PopoverContentProps,
PopoverRootEmits,
@@ -16,8 +17,8 @@ import {
} from '../../ui';
interface Props extends PopoverRootProps {
class?: any;
contentClass?: any;
class?: ClassType;
contentClass?: ClassType;
contentProps?: PopoverContentProps;
}

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import { computed, ref } from 'vue';
import { cn } from '@vben-core/shared/utils';
@@ -6,9 +8,9 @@ import { cn } from '@vben-core/shared/utils';
import { ScrollArea, ScrollBar } from '../../ui';
interface Props {
class?: any;
class?: ClassType;
horizontal?: boolean;
scrollBarClass?: any;
scrollBarClass?: ClassType;
shadow?: boolean;
shadowBorder?: boolean;
shadowBottom?: boolean;

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import type { TooltipContentProps } from 'radix-vue';
import type { StyleValue } from 'vue';
@@ -11,7 +12,7 @@ import {
} from '../../ui';
interface Props {
contentClass?: any;
contentClass?: ClassType;
contentStyle?: StyleValue;
delayDuration?: number;
side?: TooltipContentProps['side'];

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import type { ClassType } from '@vben-core/typings';
import { computed, ref } from 'vue';
import { cn } from '@vben-core/shared/utils';
@@ -18,8 +20,8 @@ import DialogOverlay from './DialogOverlay.vue';
const props = withDefaults(
defineProps<
{
class?: any;
closeClass?: any;
class?: ClassType;
closeClass?: ClassType;
modal?: boolean;
open?: boolean;
showClose?: boolean;