Files
ai-agent-admin/web/apps/web-ele/src/adapter/component/index.ts
T

359 lines
10 KiB
TypeScript

/**
* 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用
* 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
*/
import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben-core/form-ui';
import type { Recordable } from '@vben/types';
import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
import { globalShareState } from '@vben-core/shared/global-state';
import { $t } from '@vben/locales';
import { ApiComponent } from '@vben/common-ui/es/api-component';
const ElButton = defineAsyncComponent(() =>
import('element-plus/es/components/button/index').then((res) => res.ElButton),
);
const ElCheckbox = defineAsyncComponent(() =>
import('element-plus/es/components/checkbox/index').then(
(res) => res.ElCheckbox,
),
);
const ElCheckboxButton = defineAsyncComponent(() =>
import('element-plus/es/components/checkbox/index').then(
(res) => res.ElCheckboxButton,
),
);
const ElCheckboxGroup = defineAsyncComponent(() =>
import('element-plus/es/components/checkbox/index').then(
(res) => res.ElCheckboxGroup,
),
);
const ElDivider = defineAsyncComponent(() =>
import('element-plus/es/components/divider/index').then(
(res) => res.ElDivider,
),
);
const ElInput = defineAsyncComponent(() =>
import('element-plus/es/components/input/index').then((res) => res.ElInput),
);
const ElRadio = defineAsyncComponent(() =>
import('element-plus/es/components/radio/index').then((res) => res.ElRadio),
);
const ElRadioButton = defineAsyncComponent(() =>
import('element-plus/es/components/radio/index').then(
(res) => res.ElRadioButton,
),
);
const ElRadioGroup = defineAsyncComponent(() =>
import('element-plus/es/components/radio/index').then(
(res) => res.ElRadioGroup,
),
);
const ElSpace = defineAsyncComponent(() =>
import('element-plus/es/components/space/index').then((res) => res.ElSpace),
);
const ElSwitch = defineAsyncComponent(() =>
import('element-plus/es/components/switch/index').then((res) => res.ElSwitch),
);
const ElCascader = defineAsyncComponent(() =>
import('element-plus/es/components/cascader/index').then(
(res) => res.ElCascader,
),
);
const ElDatePicker = defineAsyncComponent(() =>
import('element-plus/es/components/date-picker/index').then(
(res) => res.ElDatePicker,
),
);
const ElInputNumber = defineAsyncComponent(() =>
import('element-plus/es/components/input-number/index').then(
(res) => res.ElInputNumber,
),
);
const ElSelectV2 = defineAsyncComponent(() =>
import('element-plus/es/components/select-v2/index').then(
(res) => res.ElSelectV2,
),
);
const ElTimePicker = defineAsyncComponent(() =>
import('element-plus/es/components/time-picker/index').then(
(res) => res.ElTimePicker,
),
);
const ElTreeSelect = defineAsyncComponent(() =>
import('element-plus/es/components/tree-select/index').then(
(res) => res.ElTreeSelect,
),
);
const ElUpload = defineAsyncComponent(() =>
import('element-plus/es/components/upload/index').then((res) => res.ElUpload),
);
const RoleSelector = defineAsyncComponent(() =>
import('#/components/zq-form/role-selector/role-selector.vue').then(
(res) => res.default,
),
);
const FileSelector = defineAsyncComponent(() =>
import('#/components/zq-form/file-selector/file-selector.vue').then(
(res) => res.default,
),
);
const ImageSelector = defineAsyncComponent(() =>
import('#/components/zq-form/image-selector/image-selector.vue').then(
(res) => res.default,
),
);
const UserSelector = defineAsyncComponent(() =>
import('#/components/zq-form/user-selector/user-selector.vue').then(
(res) => res.default,
),
);
const ZqIconPicker = defineAsyncComponent(() =>
import('#/components/zq-form/zq-icon-picker/zq-icon-picker.vue').then(
(res) => res.default,
),
);
const withDefaultPlaceholder = <T extends Component>(
component: T,
type: 'input' | 'select',
componentProps: Recordable<any> = {},
) => {
return defineComponent({
name: (component as any).name,
inheritAttrs: false,
setup: (props: any, { attrs, expose, slots }) => {
const placeholder =
props?.placeholder ||
attrs?.placeholder ||
$t(`ui.placeholder.${type}`);
// 透传组件暴露的方法
const innerRef = ref();
expose(
new Proxy(
{},
{
get: (_target, key) => innerRef.value?.[key],
has: (_target, key) => key in (innerRef.value || {}),
},
),
);
return () =>
h(
component,
{ ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },
slots,
);
},
});
};
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
let initialized = false;
export type ComponentType =
| 'ApiSelect'
| 'ApiTreeSelect'
| 'Cascader'
| 'Checkbox'
| 'CheckboxGroup'
| 'CodeEditor'
| 'DatePicker'
| 'Divider'
| 'FileSelector'
| 'IconPicker'
| 'ImageSelector'
| 'Input'
| 'InputNumber'
| 'RadioGroup'
| 'RoleSelector'
| 'Select'
| 'Space'
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
| 'UserSelector'
| BaseFormComponentType;
function initComponentAdapter() {
if (initialized) {
return;
}
const components: Partial<Record<ComponentType, Component>> = {
// 如果你的组件体积比较大,可以使用异步加载
// Button: () =>
// import('xxx').then((res) => res.Button),
ApiSelect: withDefaultPlaceholder(
{
...ApiComponent,
name: 'ApiSelect',
},
'select',
{
component: ElSelectV2,
loadingSlot: 'loading',
visibleEvent: 'onVisibleChange',
},
),
ApiTreeSelect: withDefaultPlaceholder(
{
...ApiComponent,
name: 'ApiTreeSelect',
},
'select',
{
component: ElTreeSelect,
props: { label: 'label', children: 'children' },
nodeKey: 'value',
loadingSlot: 'loading',
optionsPropName: 'data',
visibleEvent: 'onVisibleChange',
},
),
Cascader: withDefaultPlaceholder(ElCascader, 'select'),
Checkbox: ElCheckbox,
CheckboxGroup: (props, { attrs, slots }) => {
let defaultSlot;
if (Reflect.has(slots, 'default')) {
defaultSlot = slots.default;
} else {
const { options, isButton } = attrs;
if (Array.isArray(options)) {
defaultSlot = () =>
options.map((option) =>
h(isButton ? ElCheckboxButton : ElCheckbox, option),
);
}
}
return h(
ElCheckboxGroup,
{ ...props, ...attrs },
{ ...slots, default: defaultSlot },
);
},
// 自定义默认按钮
DefaultButton: (props, { attrs, slots }) => {
return h(ElButton, { ...props, attrs }, slots);
},
// 自定义主要按钮
PrimaryButton: (props, { attrs, slots }) => {
return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
},
RoleSelector: withDefaultPlaceholder(RoleSelector, 'select'),
Divider: ElDivider,
FileSelector: withDefaultPlaceholder(FileSelector, 'select'),
IconPicker: withDefaultPlaceholder(ZqIconPicker, 'select'),
ImageSelector: withDefaultPlaceholder(ImageSelector, 'select'),
Input: withDefaultPlaceholder(ElInput, 'input'),
Textarea: withDefaultPlaceholder(ElInput, 'input', { type: 'textarea' }),
CodeEditor: withDefaultPlaceholder(ElInput, 'input', {
autosize: { minRows: 8 },
type: 'textarea',
}),
InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
RadioGroup: (props, { attrs, slots }) => {
let defaultSlot;
if (Reflect.has(slots, 'default')) {
defaultSlot = slots.default;
} else {
const { options } = attrs;
if (Array.isArray(options)) {
defaultSlot = () =>
options.map((option) =>
h(attrs.isButton ? ElRadioButton : ElRadio, option),
);
}
}
return h(
ElRadioGroup,
{ ...props, ...attrs },
{ ...slots, default: defaultSlot },
);
},
Select: (props, { attrs, slots }) => {
return h(ElSelectV2, { ...props, attrs }, slots);
},
Space: ElSpace,
Switch: ElSwitch,
TimePicker: (props, { attrs, slots }) => {
const { name, id, isRange } = props;
const extraProps: Recordable<any> = {};
if (isRange) {
if (name && !Array.isArray(name)) {
extraProps.name = [name, `${name}_end`];
}
if (id && !Array.isArray(id)) {
extraProps.id = [id, `${id}_end`];
}
}
return h(
ElTimePicker,
{
...props,
...attrs,
...extraProps,
},
slots,
);
},
DatePicker: (props, { attrs, slots }) => {
const { name, id, type } = props;
const extraProps: Recordable<any> = {};
if (type && type.includes('range')) {
if (name && !Array.isArray(name)) {
extraProps.name = [name, `${name}_end`];
}
if (id && !Array.isArray(id)) {
extraProps.id = [id, `${id}_end`];
}
}
return h(
ElDatePicker,
{
...props,
...attrs,
...extraProps,
},
slots,
);
},
TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),
Upload: ElUpload,
UserSelector: withDefaultPlaceholder(UserSelector, 'select'),
};
// 将组件注册到全局共享状态中
globalShareState.setComponents(components);
initialized = true;
// 定义全局共享状态中的消息提示
globalShareState.defineMessage({
// 复制成功消息提示
copyPreferencesSuccess: (title: string, content: string) => {
void import('element-plus/es/components/notification/index').then(
({ ElNotification }) => {
ElNotification({
title,
message: content,
position: 'bottom-right',
duration: 0,
type: 'success',
});
},
);
},
});
}
export { initComponentAdapter };