Merge branch 'main' into antdv-next

This commit is contained in:
dap
2026-03-31 10:45:50 +08:00
8 changed files with 258 additions and 139 deletions

View File

@@ -3,60 +3,94 @@
* 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
*/
import type { Component } from "vue";
import type { Component } from 'vue';
import type { BaseFormComponentType } from "@vben/common-ui";
import type { Recordable } from "@vben/types";
import type { BaseFormComponentType } from '@vben/common-ui';
import type { Recordable } from '@vben/types';
import { computed, defineAsyncComponent, defineComponent, h, ref } from "vue";
import { computed, defineAsyncComponent, defineComponent, h, ref } from 'vue';
import { ApiComponent, globalShareState, IconPicker } from "@vben/common-ui";
import { $t } from "@vben/locales";
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales';
const RichTextarea = defineAsyncComponent(() =>
import("#/components/tinymce/index").then((res) => res.Tinymce),
import('#/components/tinymce/index').then((res) => res.Tinymce),
);
const FileUpload = defineAsyncComponent(() =>
import("#/components/upload").then((res) => res.FileUpload),
import('#/components/upload').then((res) => res.FileUpload),
);
const ImageUpload = defineAsyncComponent(() =>
import("#/components/upload").then((res) => res.ImageUpload),
import('#/components/upload').then((res) => res.ImageUpload),
);
const Button = defineAsyncComponent(() => import("antdv-next/dist/button/index"));
const Cascader = defineAsyncComponent(() => import("antdv-next/dist/cascader/index"));
const Checkbox = defineAsyncComponent(() => import("antdv-next/dist/checkbox/index"));
const CheckboxGroup = defineAsyncComponent(() => import("antdv-next/dist/checkbox/Group"));
const DatePicker = defineAsyncComponent(() => import("antdv-next/dist/date-picker/index"));
const Divider = defineAsyncComponent(() => import("antdv-next/dist/divider/index"));
const Input = defineAsyncComponent(() => import("antdv-next/dist/input/index"));
const InputNumber = defineAsyncComponent(() => import("antdv-next/dist/input-number/index"));
const InputPassword = defineAsyncComponent(() => import("antdv-next/dist/input/Password"));
const Mentions = defineAsyncComponent(() => import("antdv-next/dist/mentions/index"));
const Radio = defineAsyncComponent(() => import("antdv-next/dist/radio/index"));
const Button = defineAsyncComponent(
() => import('antdv-next/dist/button/index'),
);
const Cascader = defineAsyncComponent(
() => import('antdv-next/dist/cascader/index'),
);
const Checkbox = defineAsyncComponent(
() => import('antdv-next/dist/checkbox/index'),
);
const CheckboxGroup = defineAsyncComponent(
() => import('antdv-next/dist/checkbox/Group'),
);
const DatePicker = defineAsyncComponent(
() => import('antdv-next/dist/date-picker/index'),
);
const Divider = defineAsyncComponent(
() => import('antdv-next/dist/divider/index'),
);
const Input = defineAsyncComponent(() => import('antdv-next/dist/input/index'));
const InputNumber = defineAsyncComponent(
() => import('antdv-next/dist/input-number/index'),
);
const InputPassword = defineAsyncComponent(
() => import('antdv-next/dist/input/Password'),
);
const Mentions = defineAsyncComponent(
() => import('antdv-next/dist/mentions/index'),
);
const Radio = defineAsyncComponent(() => import('antdv-next/dist/radio/index'));
const RadioGroup = defineAsyncComponent(() =>
import("antdv-next/dist/radio/index").then((res) => res.RadioGroup),
import('antdv-next/dist/radio/index').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
import("antdv-next/dist/date-picker/index").then((res) => res.DateRangePicker),
import('antdv-next/dist/date-picker/index').then(
(res) => res.DateRangePicker,
),
);
const Rate = defineAsyncComponent(() => import('antdv-next/dist/rate/index'));
const Select = defineAsyncComponent(
() => import('antdv-next/dist/select/index'),
);
const Space = defineAsyncComponent(() => import('antdv-next/dist/space/index'));
const Switch = defineAsyncComponent(
() => import('antdv-next/dist/switch/index'),
);
const Textarea = defineAsyncComponent(
() => import('antdv-next/dist/input/TextArea'),
);
const TimePicker = defineAsyncComponent(
() => import('antdv-next/dist/time-picker/index'),
);
const Rate = defineAsyncComponent(() => import("antdv-next/dist/rate/index"));
const Select = defineAsyncComponent(() => import("antdv-next/dist/select/index"));
const Space = defineAsyncComponent(() => import("antdv-next/dist/space/index"));
const Switch = defineAsyncComponent(() => import("antdv-next/dist/switch/index"));
const Textarea = defineAsyncComponent(() => import("antdv-next/dist/input/TextArea"));
const TimePicker = defineAsyncComponent(() => import("antdv-next/dist/time-picker/index"));
const TimeRangePicker = defineAsyncComponent(() =>
import("antdv-next/dist/time-picker/index").then((res) => res.TimeRangePicker),
import('antdv-next/dist/time-picker/index').then(
(res) => res.TimeRangePicker,
),
);
const TreeSelect = defineAsyncComponent(
() => import('antdv-next/dist/tree-select/index'),
);
const Upload = defineAsyncComponent(
() => import('antdv-next/dist/upload/Upload'),
);
const TreeSelect = defineAsyncComponent(() => import("antdv-next/dist/tree-select/index"));
const Upload = defineAsyncComponent(() => import("antdv-next/dist/upload/Upload"));
const withDefaultPlaceholder = <T extends Component>(
component: T,
type: "input" | "select",
type: 'input' | 'select',
componentProps: Recordable<any> = {},
) => {
return defineComponent({
@@ -65,7 +99,10 @@ const withDefaultPlaceholder = <T extends Component>(
setup: (props: any, { attrs, expose, slots }) => {
// 改为placeholder 解决在keepalive & 语言切换 & tab切换 显示不变的问题
const computedPlaceholder = computed(
() => props?.placeholder || attrs?.placeholder || $t(`ui.placeholder.${type}`),
() =>
props?.placeholder ||
attrs?.placeholder ||
$t(`ui.placeholder.${type}`),
);
// 透传组件暴露的方法
@@ -97,37 +134,37 @@ const withDefaultPlaceholder = <T extends Component>(
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType =
| "ApiCascader"
| "ApiSelect"
| "ApiTreeSelect"
| "AutoComplete"
| "Cascader"
| "Checkbox"
| "CheckboxGroup"
| "DatePicker"
| "DefaultButton"
| "Divider"
| "FileUpload"
| "IconPicker"
| "ImageUpload"
| "Input"
| "InputNumber"
| "InputPassword"
| "Mentions"
| "PrimaryButton"
| "Radio"
| "RadioGroup"
| "RangePicker"
| "Rate"
| "RichTextarea"
| "Select"
| "Space"
| "Switch"
| "Textarea"
| "TimePicker"
| "TimeRangePicker"
| "TreeSelect"
| "Upload"
| 'ApiCascader'
| 'ApiSelect'
| 'ApiTreeSelect'
| 'AutoComplete'
| 'Cascader'
| 'Checkbox'
| 'CheckboxGroup'
| 'DatePicker'
| 'DefaultButton'
| 'Divider'
| 'FileUpload'
| 'IconPicker'
| 'ImageUpload'
| 'Input'
| 'InputNumber'
| 'InputPassword'
| 'Mentions'
| 'PrimaryButton'
| 'Radio'
| 'RadioGroup'
| 'RangePicker'
| 'Rate'
| 'RichTextarea'
| 'Select'
| 'Space'
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TimeRangePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
async function initComponentAdapter() {
@@ -136,74 +173,74 @@ async function initComponentAdapter() {
// Button: () =>
// import('xxx').then((res) => res.Button),
ApiCascader: withDefaultPlaceholder(ApiComponent, "select", {
ApiCascader: withDefaultPlaceholder(ApiComponent, 'select', {
component: Cascader,
fieldNames: { label: "label", value: "value", children: "children" },
loadingSlot: "suffixIcon",
modelPropName: "value",
visibleEvent: "onVisibleChange",
fieldNames: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon',
modelPropName: 'value',
visibleEvent: 'onVisibleChange',
}),
ApiSelect: withDefaultPlaceholder(
{
...ApiComponent,
name: "ApiSelect",
name: 'ApiSelect',
},
"select",
'select',
{
component: Select,
loadingSlot: "suffixIcon",
visibleEvent: "onDropdownVisibleChange",
modelPropName: "value",
loadingSlot: 'suffixIcon',
visibleEvent: 'onDropdownVisibleChange',
modelPropName: 'value',
},
),
ApiTreeSelect: withDefaultPlaceholder(
{
...ApiComponent,
name: "ApiTreeSelect",
name: 'ApiTreeSelect',
},
"select",
'select',
{
component: TreeSelect,
fieldNames: { label: "label", value: "value", children: "children" },
loadingSlot: "suffixIcon",
modelPropName: "value",
optionsPropName: "treeData",
visibleEvent: "onVisibleChange",
fieldNames: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon',
modelPropName: 'value',
optionsPropName: 'treeData',
visibleEvent: 'onVisibleChange',
},
),
Cascader: withDefaultPlaceholder(Cascader, "select"),
Cascader: withDefaultPlaceholder(Cascader, 'select'),
Checkbox,
CheckboxGroup,
DatePicker,
// 自定义默认按钮
DefaultButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: "default" }, slots);
return h(Button, { ...props, attrs, type: 'default' }, slots);
},
Divider,
IconPicker: withDefaultPlaceholder(IconPicker, "select", {
iconSlot: "addonAfter",
IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
iconSlot: 'addonAfter',
inputComponent: Input,
modelValueProp: "value",
modelValueProp: 'value',
}),
Input: withDefaultPlaceholder(Input, "input"),
InputNumber: withDefaultPlaceholder(InputNumber, "input"),
InputPassword: withDefaultPlaceholder(InputPassword, "input"),
Mentions: withDefaultPlaceholder(Mentions, "input"),
Input: withDefaultPlaceholder(Input, 'input'),
InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
Mentions: withDefaultPlaceholder(Mentions, 'input'),
// 自定义主要按钮
PrimaryButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: "primary" }, slots);
return h(Button, { ...props, attrs, type: 'primary' }, slots);
},
Radio,
RadioGroup,
RangePicker,
Rate,
Select: withDefaultPlaceholder(Select, "select"),
Select: withDefaultPlaceholder(Select, 'select'),
Space,
Switch,
Textarea: withDefaultPlaceholder(Textarea, "input"),
Textarea: withDefaultPlaceholder(Textarea, 'input'),
TimePicker,
TimeRangePicker,
TreeSelect: withDefaultPlaceholder(TreeSelect, "select"),
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
Upload,
ImageUpload,
FileUpload,
@@ -220,7 +257,7 @@ async function initComponentAdapter() {
window.notification.success({
description: content,
title,
placement: "bottomRight",
placement: 'bottomRight',
});
},
});