diff --git a/.vscode/settings.json b/.vscode/settings.json index b074051d..bb2590be 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -224,10 +224,20 @@ "commentTranslate.multiLineMerge": true, "vue.server.hybridMode": true, "vitest.disableWorkspaceWarning": true, - "cSpell.words": ["tinymce", "vditor"], "typescript.tsdk": "node_modules/typescript/lib", "editor.linkedEditing": true, // 自动同步更改html标签, "vscodeCustomCodeColor.highlightValue": "v-access", // v-access显示的颜色 "vscodeCustomCodeColor.highlightValueColor": "#CCFFFF", - "oxc.enable": false + "oxc.enable": false, + "cSpell.words": [ + "archiver", + "axios", + "dotenv", + "isequal", + "jspm", + "napi", + "nolebase", + "rollup", + "vitest" + ] } diff --git a/apps/web-antd/src/adapter/component/index.ts b/apps/web-antd/src/adapter/component/index.ts index 628f1a62..15e07448 100644 --- a/apps/web-antd/src/adapter/component/index.ts +++ b/apps/web-antd/src/adapter/component/index.ts @@ -8,40 +8,70 @@ import type { Component } from 'vue'; import type { BaseFormComponentType } from '@vben/common-ui'; import type { Recordable } from '@vben/types'; -import { computed, defineComponent, getCurrentInstance, h, ref } from 'vue'; +import { + computed, + defineAsyncComponent, + defineComponent, + getCurrentInstance, + h, + ref, +} from 'vue'; import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import { $t } from '@vben/locales'; -import { - AutoComplete, - Button, - Checkbox, - CheckboxGroup, - DatePicker, - Divider, - Input, - InputNumber, - InputPassword, - Mentions, - notification, - Radio, - RadioGroup, - RangePicker, - Rate, - Select, - Space, - Switch, - Textarea, - TimePicker, - TreeSelect, - Upload, -} from 'ant-design-vue'; +import { notification } from 'ant-design-vue'; import { Tinymce as RichTextarea } from '#/components/tinymce'; import { FileUpload, ImageUpload } from '#/components/upload'; import { FileUploadOld, ImageUploadOld } from '#/components/upload-old'; +const AutoComplete = defineAsyncComponent( + () => import('ant-design-vue/es/auto-complete'), +); +const Button = defineAsyncComponent(() => import('ant-design-vue/es/button')); +const Checkbox = defineAsyncComponent( + () => import('ant-design-vue/es/checkbox'), +); +const CheckboxGroup = defineAsyncComponent(() => + import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup), +); +const DatePicker = defineAsyncComponent( + () => import('ant-design-vue/es/date-picker'), +); +const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider')); +const Input = defineAsyncComponent(() => import('ant-design-vue/es/input')); +const InputNumber = defineAsyncComponent( + () => import('ant-design-vue/es/input-number'), +); +const InputPassword = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.InputPassword), +); +const Mentions = defineAsyncComponent( + () => import('ant-design-vue/es/mentions'), +); +const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio')); +const RadioGroup = defineAsyncComponent(() => + import('ant-design-vue/es/radio').then((res) => res.RadioGroup), +); +const RangePicker = defineAsyncComponent(() => + import('ant-design-vue/es/date-picker').then((res) => res.RangePicker), +); +const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate')); +const Select = defineAsyncComponent(() => import('ant-design-vue/es/select')); +const Space = defineAsyncComponent(() => import('ant-design-vue/es/space')); +const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch')); +const Textarea = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.Textarea), +); +const TimePicker = defineAsyncComponent( + () => import('ant-design-vue/es/time-picker'), +); +const TreeSelect = defineAsyncComponent( + () => import('ant-design-vue/es/tree-select'), +); +const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload')); + const withDefaultPlaceholder = ( component: T, type: 'input' | 'select', diff --git a/apps/web-antd/src/bootstrap.ts b/apps/web-antd/src/bootstrap.ts index 35b9924b..885e1e32 100644 --- a/apps/web-antd/src/bootstrap.ts +++ b/apps/web-antd/src/bootstrap.ts @@ -1,8 +1,7 @@ import { createApp, watchEffect } from 'vue'; import { registerAccessDirective } from '@vben/access'; -import { initTippy, registerLoadingDirective } from '@vben/common-ui'; -import { MotionPlugin } from '@vben/plugins/motion'; +import { registerLoadingDirective } from '@vben/common-ui/es/loading'; import { preferences } from '@vben/preferences'; import { initStores } from '@vben/stores'; import '@vben/styles'; @@ -50,12 +49,14 @@ async function bootstrap(namespace: string) { registerAccessDirective(app); // 初始化 tippy + const { initTippy } = await import('@vben/common-ui/es/tippy'); initTippy(app); // 配置路由及路由守卫 app.use(router); // 配置Motion插件 + const { MotionPlugin } = await import('@vben/plugins/motion'); app.use(MotionPlugin); // 动态更新标题 diff --git a/apps/web-antd/src/router/routes/core.ts b/apps/web-antd/src/router/routes/core.ts index 4ecb68f8..2666cc68 100644 --- a/apps/web-antd/src/router/routes/core.ts +++ b/apps/web-antd/src/router/routes/core.ts @@ -2,10 +2,10 @@ import type { RouteRecordRaw } from 'vue-router'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; -import { AuthPageLayout, BasicLayout } from '#/layouts'; import { $t } from '#/locales'; -import Login from '#/views/_core/authentication/login.vue'; +const BasicLayout = () => import('#/layouts/basic.vue'); +const AuthPageLayout = () => import('#/layouts/auth.vue'); /** 全局404页面 */ const fallbackNotFoundRoute: RouteRecordRaw = { component: () => import('#/views/_core/fallback/not-found.vue'), @@ -58,7 +58,7 @@ const coreRoutes: RouteRecordRaw[] = [ { name: 'Login', path: 'login', - component: Login, + component: () => import('#/views/_core/authentication/login.vue'), meta: { title: $t('page.auth.login'), }, diff --git a/docs/src/components/common-ui/vben-alert.md b/docs/src/components/common-ui/vben-alert.md index 6a477e31..61caac6d 100644 --- a/docs/src/components/common-ui/vben-alert.md +++ b/docs/src/components/common-ui/vben-alert.md @@ -43,6 +43,9 @@ export type BeforeCloseScope = { isConfirm: boolean; }; +/** + * alert 属性 + */ export type AlertProps = { /** 关闭前的回调,如果返回false,则终止关闭 */ beforeClose?: ( @@ -50,6 +53,8 @@ export type AlertProps = { ) => boolean | Promise | undefined; /** 边框 */ bordered?: boolean; + /** 按钮对齐方式 */ + buttonAlign?: 'center' | 'end' | 'start'; /** 取消按钮的标题 */ cancelText?: string; /** 是否居中显示 */ @@ -62,6 +67,8 @@ export type AlertProps = { content: Component | string; /** 弹窗内容的额外样式 */ contentClass?: string; + /** 执行beforeClose回调期间,在内容区域显示一个loading遮罩*/ + contentMasking?: boolean; /** 弹窗的图标(在标题的前面) */ icon?: Component | IconType; /** 是否显示取消按钮 */ @@ -70,6 +77,25 @@ export type AlertProps = { title?: string; }; +/** prompt 属性 */ +export type PromptProps = { + /** 关闭前的回调,如果返回false,则终止关闭 */ + beforeClose?: (scope: { + isConfirm: boolean; + value: T | undefined; + }) => boolean | Promise | undefined; + /** 用于接受用户输入的组件 */ + component?: Component; + /** 输入组件的属性 */ + componentProps?: Recordable; + /** 输入组件的插槽 */ + componentSlots?: Recordable; + /** 默认值 */ + defaultValue?: T; + /** 输入组件的值属性名 */ + modelPropName?: string; +} & Omit; + /** * 函数签名 * alert和confirm的函数签名相同。 diff --git a/docs/src/components/common-ui/vben-vxe-table.md b/docs/src/components/common-ui/vben-vxe-table.md index 011f4f5d..344ecae1 100644 --- a/docs/src/components/common-ui/vben-vxe-table.md +++ b/docs/src/components/common-ui/vben-vxe-table.md @@ -167,6 +167,23 @@ vxeUI.renderer.add('CellLink', { 当启用了表单搜索时,可以在toolbarConfig中配置`search`为`true`来让表格在工具栏区域显示一个搜索表单控制按钮。表格的所有以`form-`开头的命名插槽都会被传递给搜索表单。 +### 定制分隔条 + +当你启用表单搜索时,在表单和表格之间会显示一个分隔条。这个分隔条使用了默认的组件背景色,并且横向贯穿整个Vben Vxe Table在视觉上融入了页面的默认背景中。如果你在Vben Vxe Table的外层包裹了一个不同背景色的容器(如将其放在一个Card内),默认的表单和表格之间的分隔条可能就显得格格不入了,下面的代码演示了如何定制这个分隔条。 + +```ts +const [Grid] = useVbenVxeGrid({ + formOptions: {}, + gridOptions: {}, + // 完全移除分隔条 + separator: false, + // 你也可以使用下面的代码来移除分隔条 + // separator: { show: false }, + // 或者使用下面的代码来改变分隔条的颜色 + // separator: { backgroundColor: 'rgba(100,100,0,0.5)' }, +}); +``` + ## 单元格编辑 @@ -231,15 +248,16 @@ useVbenVxeGrid 返回的第二个参数,是一个对象,包含了一些表 所有属性都可以传入 `useVbenVxeGrid` 的第一个参数中。 -| 属性名 | 描述 | 类型 | -| -------------- | -------------------- | ------------------- | -| tableTitle | 表格标题 | `string` | -| tableTitleHelp | 表格标题帮助信息 | `string` | -| gridClass | grid组件的class | `string` | -| gridOptions | grid组件的参数 | `VxeTableGridProps` | -| gridEvents | grid组件的触发的事件 | `VxeGridListeners` | -| formOptions | 表单参数 | `VbenFormProps` | -| showSearchForm | 是否显示搜索表单 | `boolean` | +| 属性名 | 描述 | 类型 | 版本要求 | +| --- | --- | --- | --- | +| tableTitle | 表格标题 | `string` | - | +| tableTitleHelp | 表格标题帮助信息 | `string` | - | +| gridClass | grid组件的class | `string` | - | +| gridOptions | grid组件的参数 | `VxeTableGridProps` | - | +| gridEvents | grid组件的触发的事件 | `VxeGridListeners` | - | +| formOptions | 表单参数 | `VbenFormProps` | - | +| showSearchForm | 是否显示搜索表单 | `boolean` | - | +| separator | 搜索表单与表格主体之间的分隔条 | `boolean\|SeparatorOptions` | >5.5.4 | ## Slots diff --git a/docs/src/demos/vben-alert/alert/index.vue b/docs/src/demos/vben-alert/alert/index.vue index 103ce64f..9ba18a4d 100644 --- a/docs/src/demos/vben-alert/alert/index.vue +++ b/docs/src/demos/vben-alert/alert/index.vue @@ -3,7 +3,7 @@ import { h } from 'vue'; import { alert, VbenButton } from '@vben/common-ui'; -import { Empty } from 'ant-design-vue'; +import { Result } from 'ant-design-vue'; function showAlert() { alert('This is an alert message'); @@ -18,7 +18,12 @@ function showIconAlert() { function showCustomAlert() { alert({ - content: h(Empty, { description: '什么都没有' }), + buttonAlign: 'center', + content: h(Result, { + status: 'success', + subTitle: '已成功创建订单。订单ID:2017182818828182881', + title: '操作成功', + }), }); } diff --git a/docs/src/demos/vben-alert/prompt/index.vue b/docs/src/demos/vben-alert/prompt/index.vue index 423124e7..c9cf5c3e 100644 --- a/docs/src/demos/vben-alert/prompt/index.vue +++ b/docs/src/demos/vben-alert/prompt/index.vue @@ -1,7 +1,10 @@ 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 d022d1cd..20e4254c 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts +++ b/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts @@ -1,10 +1,10 @@ -import type { Component } from 'vue'; +import type { Component, VNode } from 'vue'; import type { Recordable } from '@vben-core/typings'; -import type { AlertProps, BeforeCloseScope } from './alert'; +import type { AlertProps, BeforeCloseScope, PromptProps } from './alert'; -import { h, ref, render } from 'vue'; +import { h, nextTick, ref, render } from 'vue'; import { useSimpleLocale } from '@vben-core/composables'; import { Input } from '@vben-core/shadcn-ui'; @@ -130,40 +130,58 @@ export function vbenConfirm( } export async function vbenPrompt( - options: Omit & { - beforeClose?: (scope: { - isConfirm: boolean; - value: T | undefined; - }) => boolean | Promise | undefined; - component?: Component; - componentProps?: Recordable; - defaultValue?: T; - modelPropName?: string; - }, + options: PromptProps, ): Promise { const { component: _component, componentProps: _componentProps, + componentSlots, content, defaultValue, modelPropName: _modelPropName, ...delegated } = options; - const contents: Component[] = []; + const modelValue = ref(defaultValue); + const inputComponentRef = ref(null); + const staticContents: Component[] = []; + if (isString(content)) { - contents.push(h('span', content)); - } else { - contents.push(content); + staticContents.push(h('span', content)); + } else if (content) { + staticContents.push(content as Component); } - const componentProps = _componentProps || {}; + const modelPropName = _modelPropName || 'modelValue'; - componentProps[modelPropName] = modelValue.value; - componentProps[`onUpdate:${modelPropName}`] = (val: any) => { - modelValue.value = val; + const componentProps = { ..._componentProps }; + + // 每次渲染时都会重新计算的内容函数 + const contentRenderer = () => { + const currentProps = { ...componentProps }; + + // 设置当前值 + currentProps[modelPropName] = modelValue.value; + + // 设置更新处理函数 + currentProps[`onUpdate:${modelPropName}`] = (val: T) => { + modelValue.value = val; + }; + + // 创建输入组件 + inputComponentRef.value = h( + _component || Input, + currentProps, + componentSlots, + ); + + // 返回包含静态内容和输入组件的数组 + return h( + 'div', + { class: 'flex flex-col gap-2' }, + { default: () => [...staticContents, inputComponentRef.value] }, + ); }; - const componentRef = h(_component || Input, componentProps); - contents.push(componentRef); + const props: AlertProps & Recordable = { ...delegated, async beforeClose(scope: BeforeCloseScope) { @@ -174,23 +192,46 @@ export async function vbenPrompt( }); } }, - content: h( - 'div', - { class: 'flex flex-col gap-2' }, - { default: () => contents }, - ), - onOpened() { - // 组件挂载完成后,自动聚焦到输入组件 - if ( - componentRef.component?.exposed && - isFunction(componentRef.component.exposed.focus) - ) { - componentRef.component.exposed.focus(); - } else if (componentRef.el && isFunction(componentRef.el.focus)) { - componentRef.el.focus(); + // 使用函数形式,每次渲染都会重新计算内容 + content: contentRenderer, + contentMasking: true, + async onOpened() { + await nextTick(); + const componentRef: null | VNode = inputComponentRef.value; + if (componentRef) { + if ( + componentRef.component?.exposed && + isFunction(componentRef.component.exposed.focus) + ) { + componentRef.component.exposed.focus(); + } else { + if (componentRef.el) { + if ( + isFunction(componentRef.el.focus) && + ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes( + componentRef.el.tagName, + ) + ) { + componentRef.el.focus(); + } else if (isFunction(componentRef.el.querySelector)) { + const focusableElement = componentRef.el.querySelector( + 'input, select, textarea, button', + ); + if (focusableElement && isFunction(focusableElement.focus)) { + focusableElement.focus(); + } + } else if ( + componentRef.el.nextElementSibling && + isFunction(componentRef.el.nextElementSibling.focus) + ) { + componentRef.el.nextElementSibling.focus(); + } + } + } } }, }; + await vbenConfirm(props); return modelValue.value; } 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 6a574daa..49d65ed5 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/alert.ts +++ b/packages/@core/ui-kit/popup-ui/src/alert/alert.ts @@ -1,4 +1,6 @@ -import type { Component } from 'vue'; +import type { Component, VNode, VNodeArrayChildren } from 'vue'; + +import type { Recordable } from '@vben-core/typings'; export type IconType = 'error' | 'info' | 'question' | 'success' | 'warning'; @@ -13,6 +15,11 @@ export type AlertProps = { ) => boolean | Promise | undefined; /** 边框 */ bordered?: boolean; + /** + * 按钮对齐方式 + * @default 'end' + */ + buttonAlign?: 'center' | 'end' | 'start'; /** 取消按钮的标题 */ cancelText?: string; /** 是否居中显示 */ @@ -25,6 +32,8 @@ export type AlertProps = { content: Component | string; /** 弹窗内容的额外样式 */ contentClass?: string; + /** 执行beforeClose回调期间,在内容区域显示一个loading遮罩*/ + contentMasking?: boolean; /** 弹窗的图标(在标题的前面) */ icon?: Component | IconType; /** 是否显示取消按钮 */ @@ -32,3 +41,26 @@ export type AlertProps = { /** 弹窗标题 */ title?: string; }; + +/** Prompt属性 */ +export type PromptProps = { + /** 关闭前的回调,如果返回false,则终止关闭 */ + beforeClose?: (scope: { + isConfirm: boolean; + value: T | undefined; + }) => boolean | Promise | undefined; + /** 用于接受用户输入的组件 */ + component?: Component; + /** 输入组件的属性 */ + componentProps?: Recordable; + /** 输入组件的插槽 */ + componentSlots?: + | (() => any) + | Recordable + | VNode + | VNodeArrayChildren; + /** 默认值 */ + defaultValue?: T; + /** 输入组件的值属性名 */ + modelPropName?: string; +} & Omit; 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 2cd334b7..8c7c4541 100644 --- a/packages/@core/ui-kit/popup-ui/src/alert/alert.vue +++ b/packages/@core/ui-kit/popup-ui/src/alert/alert.vue @@ -30,6 +30,7 @@ import { cn } from '@vben-core/shared/utils'; const props = withDefaults(defineProps(), { bordered: true, + buttonAlign: 'end', centered: true, containerClass: 'w-[520px]', }); @@ -154,9 +155,9 @@ async function handleOpenChange(val: boolean) {
- + -
+
{ + const { transition } = preferences; + const transitionName = transition.name; + return transitionName && transition.enable; +}); + // 页面切换动画 function getTransitionName(_route: RouteLocationNormalizedLoaded) { // 如果偏好设置未设置,则不使用动画 @@ -89,7 +100,12 @@ function transformComponent(
- + +
diff --git a/packages/effects/plugins/src/vxe-table/types.ts b/packages/effects/plugins/src/vxe-table/types.ts index cac73ed3..09c2a8ee 100644 --- a/packages/effects/plugins/src/vxe-table/types.ts +++ b/packages/effects/plugins/src/vxe-table/types.ts @@ -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 extends VxeTableGridProps { 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: >( selector?: (state: NoInfer) => T, ) => Readonly>; -} & VxeGridApi; +}; export interface SetupVxeTable { configVxeTable: (ui: VxeUIExport) => void; diff --git a/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue b/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue index 1536e2a3..2213c956 100644 --- a/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue +++ b/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue @@ -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(() => {
@@ -409,6 +446,10 @@ onUnmounted(() => {
diff --git a/playground/src/adapter/component/index.ts b/playground/src/adapter/component/index.ts index 9b847dfc..88cfbf24 100644 --- a/playground/src/adapter/component/index.ts +++ b/playground/src/adapter/component/index.ts @@ -8,35 +8,64 @@ import type { Component } from 'vue'; import type { BaseFormComponentType } from '@vben/common-ui'; import type { Recordable } from '@vben/types'; -import { defineComponent, getCurrentInstance, h, ref } from 'vue'; +import { + defineAsyncComponent, + defineComponent, + getCurrentInstance, + h, + ref, +} from 'vue'; import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import { $t } from '@vben/locales'; -import { - AutoComplete, - Button, - Checkbox, - CheckboxGroup, - DatePicker, - Divider, - Input, - InputNumber, - InputPassword, - Mentions, - notification, - Radio, - RadioGroup, - RangePicker, - Rate, - Select, - Space, - Switch, - Textarea, - TimePicker, - TreeSelect, - Upload, -} from 'ant-design-vue'; +import { notification } from 'ant-design-vue'; + +const AutoComplete = defineAsyncComponent( + () => import('ant-design-vue/es/auto-complete'), +); +const Button = defineAsyncComponent(() => import('ant-design-vue/es/button')); +const Checkbox = defineAsyncComponent( + () => import('ant-design-vue/es/checkbox'), +); +const CheckboxGroup = defineAsyncComponent(() => + import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup), +); +const DatePicker = defineAsyncComponent( + () => import('ant-design-vue/es/date-picker'), +); +const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider')); +const Input = defineAsyncComponent(() => import('ant-design-vue/es/input')); +const InputNumber = defineAsyncComponent( + () => import('ant-design-vue/es/input-number'), +); +const InputPassword = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.InputPassword), +); +const Mentions = defineAsyncComponent( + () => import('ant-design-vue/es/mentions'), +); +const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio')); +const RadioGroup = defineAsyncComponent(() => + import('ant-design-vue/es/radio').then((res) => res.RadioGroup), +); +const RangePicker = defineAsyncComponent(() => + import('ant-design-vue/es/date-picker').then((res) => res.RangePicker), +); +const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate')); +const Select = defineAsyncComponent(() => import('ant-design-vue/es/select')); +const Space = defineAsyncComponent(() => import('ant-design-vue/es/space')); +const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch')); +const Textarea = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.Textarea), +); +const TimePicker = defineAsyncComponent( + () => import('ant-design-vue/es/time-picker'), +); +const TreeSelect = defineAsyncComponent( + () => import('ant-design-vue/es/tree-select'), +); +const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload')); const withDefaultPlaceholder = ( component: T, diff --git a/playground/src/bootstrap.ts b/playground/src/bootstrap.ts index cecb3cf6..6df3bd52 100644 --- a/playground/src/bootstrap.ts +++ b/playground/src/bootstrap.ts @@ -1,14 +1,12 @@ import { createApp, watchEffect } from 'vue'; import { registerAccessDirective } from '@vben/access'; -import { initTippy, registerLoadingDirective } from '@vben/common-ui'; -import { MotionPlugin } from '@vben/plugins/motion'; +import { registerLoadingDirective } from '@vben/common-ui'; import { preferences } from '@vben/preferences'; import { initStores } from '@vben/stores'; import '@vben/styles'; import '@vben/styles/antd'; -import { VueQueryPlugin } from '@tanstack/vue-query'; import { useTitle } from '@vueuse/core'; import { $t, setupI18n } from '#/locales'; @@ -21,13 +19,13 @@ async function bootstrap(namespace: string) { // 初始化组件适配器 await initComponentAdapter(); - // // 设置弹窗的默认配置 + // 设置弹窗的默认配置 // setDefaultModalProps({ // fullscreenButton: false, // }); - // // 设置抽屉的默认配置 + // 设置抽屉的默认配置 // setDefaultDrawerProps({ - // // zIndex: 1020, + // zIndex: 1020, // }); const app = createApp(App); @@ -48,15 +46,18 @@ async function bootstrap(namespace: string) { registerAccessDirective(app); // 初始化 tippy + const { initTippy } = await import('@vben/common-ui/es/tippy'); initTippy(app); // 配置路由及路由守卫 app.use(router); // 配置@tanstack/vue-query + const { VueQueryPlugin } = await import('@tanstack/vue-query'); app.use(VueQueryPlugin); // 配置Motion插件 + const { MotionPlugin } = await import('@vben/plugins/motion'); app.use(MotionPlugin); // 动态更新标题 diff --git a/playground/src/router/routes/core.ts b/playground/src/router/routes/core.ts index 7218da22..4a527a31 100644 --- a/playground/src/router/routes/core.ts +++ b/playground/src/router/routes/core.ts @@ -2,10 +2,10 @@ import type { RouteRecordRaw } from 'vue-router'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; -import { AuthPageLayout, BasicLayout } from '#/layouts'; import { $t } from '#/locales'; -import Login from '#/views/_core/authentication/login.vue'; +const BasicLayout = () => import('#/layouts/basic.vue'); +const AuthPageLayout = () => import('#/layouts/auth.vue'); /** 全局404页面 */ const fallbackNotFoundRoute: RouteRecordRaw = { component: () => import('#/views/_core/fallback/not-found.vue'), @@ -50,7 +50,7 @@ const coreRoutes: RouteRecordRaw[] = [ { name: 'Login', path: 'login', - component: Login, + component: () => import('#/views/_core/authentication/login.vue'), meta: { title: $t('page.auth.login'), }, diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 16e4457b..70b08357 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -21,22 +21,22 @@ catalog: '@commitlint/cli': ^19.8.0 '@commitlint/config-conventional': ^19.8.0 '@ctrl/tinycolor': ^4.1.0 - '@eslint/js': ^9.23.0 + '@eslint/js': ^9.24.0 '@faker-js/faker': ^9.6.0 - '@iconify/json': ^2.2.323 + '@iconify/json': ^2.2.324 '@iconify/tailwind': ^1.2.0 '@iconify/vue': ^4.3.0 - '@intlify/core-base': ^11.1.2 + '@intlify/core-base': ^11.1.3 '@intlify/unplugin-vue-i18n': ^6.0.5 '@jspm/generator': ^2.5.1 '@manypkg/get-packages': ^2.2.2 - '@nolebase/vitepress-plugin-git-changelog': ^2.15.1 + '@nolebase/vitepress-plugin-git-changelog': ^2.16.0 '@playwright/test': ^1.51.1 - '@pnpm/workspace.read-manifest': ^1000.1.2 + '@pnpm/workspace.read-manifest': ^1000.1.3 '@stylistic/stylelint-plugin': ^3.1.2 '@tailwindcss/nesting': 0.0.0-insiders.565cd3e '@tailwindcss/typography': ^0.5.16 - '@tanstack/vue-query': ^5.71.1 + '@tanstack/vue-query': ^5.72.0 '@tanstack/vue-store': ^0.7.0 '@types/archiver': ^6.0.3 '@types/eslint': ^9.6.1 @@ -46,14 +46,14 @@ catalog: '@types/lodash.get': ^4.4.9 '@types/lodash.isequal': ^4.5.8 '@types/lodash.set': ^4.3.9 - '@types/node': ^22.13.17 + '@types/node': ^22.14.0 '@types/nprogress': ^0.2.3 '@types/postcss-import': ^14.0.3 '@types/qrcode': ^1.5.5 '@types/qs': ^6.9.18 '@types/sortablejs': ^1.15.8 - '@typescript-eslint/eslint-plugin': ^8.29.0 - '@typescript-eslint/parser': ^8.29.0 + '@typescript-eslint/eslint-plugin': ^8.29.1 + '@typescript-eslint/parser': ^8.29.1 '@vee-validate/zod': ^4.15.0 '@vite-pwa/vitepress': ^0.5.4 '@vitejs/plugin-vue': ^5.2.3 @@ -88,17 +88,17 @@ catalog: dotenv: ^16.4.7 echarts: ^5.6.0 element-plus: ^2.9.7 - eslint: ^9.23.0 - eslint-config-turbo: ^2.4.4 + eslint: ^9.24.0 + eslint-config-turbo: ^2.5.0 eslint-plugin-command: ^0.2.7 eslint-plugin-eslint-comments: ^3.2.0 - eslint-plugin-import-x: ^4.10.0 + eslint-plugin-import-x: ^4.10.2 eslint-plugin-jsdoc: ^50.6.9 eslint-plugin-jsonc: ^2.20.0 eslint-plugin-n: ^17.17.0 eslint-plugin-no-only-tests: ^3.3.0 eslint-plugin-perfectionist: ^4.11.0 - eslint-plugin-prettier: ^5.2.5 + eslint-plugin-prettier: ^5.2.6 eslint-plugin-regexp: ^2.7.0 eslint-plugin-unicorn: ^56.0.1 eslint-plugin-unused-imports: ^4.1.4 @@ -146,9 +146,9 @@ catalog: rimraf: ^6.0.1 rollup: ^4.39.0 rollup-plugin-visualizer: ^5.14.0 - sass: ^1.86.1 + sass: ^1.86.3 sortablejs: ^1.15.6 - stylelint: ^16.17.0 + stylelint: ^16.18.0 stylelint-config-recess-order: ^5.1.1 stylelint-config-recommended: ^14.0.1 stylelint-config-recommended-scss: ^14.1.0 @@ -162,12 +162,12 @@ catalog: tailwindcss-animate: ^1.0.7 theme-colors: ^0.1.0 tippy.js: ^6.2.5 - turbo: ^2.4.4 - typescript: ^5.8.2 + turbo: ^2.5.0 + typescript: ^5.8.3 unbuild: ^3.5.0 unplugin-element-plus: ^0.9.1 vee-validate: ^4.15.0 - vite: ^6.2.4 + vite: ^6.2.5 vite-plugin-compression: ^0.5.1 vite-plugin-dts: ^4.5.3 vite-plugin-html: ^3.2.2 @@ -179,12 +179,12 @@ catalog: vitest: ^2.1.9 vue: ^3.5.13 vue-eslint-parser: ^9.4.3 - vue-i18n: ^11.1.2 + vue-i18n: ^11.1.3 vue-json-viewer: ^3.0.4 vue-router: ^4.5.0 vue-tippy: ^6.7.0 vue-tsc: 2.1.10 - vxe-pc-ui: ^4.5.11 + vxe-pc-ui: ^4.5.14 vxe-table: ^4.12.5 watermark-js-plus: ^1.5.8 zod: ^3.24.2