index.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import type { Component } from 'vue';
  2. import type { BaseFormComponentType } from '@vben/common-ui';
  3. import type { Recordable } from '@vben/types';
  4. import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
  5. import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
  6. import { $t } from '@vben/locales';
  7. import { notification } from '#/adapter/tdesign';
  8. /**
  9. * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用
  10. * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
  11. */
  12. const AutoComplete = defineAsyncComponent(
  13. () => import('tdesign-vue-next/es/auto-complete'),
  14. );
  15. const Button = defineAsyncComponent(() => import('tdesign-vue-next/es/button'));
  16. const Checkbox = defineAsyncComponent(
  17. () => import('tdesign-vue-next/es/checkbox'),
  18. );
  19. const CheckboxGroup = defineAsyncComponent(() =>
  20. import('tdesign-vue-next/es/checkbox').then((res) => res.CheckboxGroup),
  21. );
  22. const DatePicker = defineAsyncComponent(
  23. () => import('tdesign-vue-next/es/date-picker'),
  24. );
  25. const Divider = defineAsyncComponent(
  26. () => import('tdesign-vue-next/es/divider'),
  27. );
  28. const Input = defineAsyncComponent(() => import('tdesign-vue-next/es/input'));
  29. const InputNumber = defineAsyncComponent(
  30. () => import('tdesign-vue-next/es/input-number'),
  31. );
  32. // const InputPassword = defineAsyncComponent(() =>
  33. // import('tdesign-vue-next/es/input').then((res) => res.InputPassword),
  34. // );
  35. // const Mentions = defineAsyncComponent(
  36. // () => import('tdesign-vue-next/es/mentions'),
  37. // );
  38. const Radio = defineAsyncComponent(() => import('tdesign-vue-next/es/radio'));
  39. const RadioGroup = defineAsyncComponent(() =>
  40. import('tdesign-vue-next/es/radio').then((res) => res.RadioGroup),
  41. );
  42. const RangePicker = defineAsyncComponent(() =>
  43. import('tdesign-vue-next/es/date-picker').then((res) => res.DateRangePicker),
  44. );
  45. const Rate = defineAsyncComponent(() => import('tdesign-vue-next/es/rate'));
  46. const Select = defineAsyncComponent(() => import('tdesign-vue-next/es/select'));
  47. const Space = defineAsyncComponent(() => import('tdesign-vue-next/es/space'));
  48. const Switch = defineAsyncComponent(() => import('tdesign-vue-next/es/switch'));
  49. const Textarea = defineAsyncComponent(
  50. () => import('tdesign-vue-next/es/textarea'),
  51. );
  52. const TimePicker = defineAsyncComponent(
  53. () => import('tdesign-vue-next/es/time-picker'),
  54. );
  55. const TreeSelect = defineAsyncComponent(
  56. () => import('tdesign-vue-next/es/tree-select'),
  57. );
  58. const Upload = defineAsyncComponent(() => import('tdesign-vue-next/es/upload'));
  59. const withDefaultPlaceholder = <T extends Component>(
  60. component: T,
  61. type: 'input' | 'select',
  62. componentProps: Recordable<any> = {},
  63. ) => {
  64. return defineComponent({
  65. name: component.name,
  66. inheritAttrs: false,
  67. setup: (props: any, { attrs, expose, slots }) => {
  68. const placeholder =
  69. props?.placeholder ||
  70. attrs?.placeholder ||
  71. $t(`ui.placeholder.${type}`);
  72. // 透传组件暴露的方法
  73. const innerRef = ref();
  74. expose(
  75. new Proxy(
  76. {},
  77. {
  78. get: (_target, key) => innerRef.value?.[key],
  79. has: (_target, key) => key in (innerRef.value || {}),
  80. },
  81. ),
  82. );
  83. return () =>
  84. h(
  85. component,
  86. { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },
  87. slots,
  88. );
  89. },
  90. });
  91. };
  92. // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
  93. export type ComponentType =
  94. | 'ApiSelect'
  95. | 'ApiTreeSelect'
  96. | 'AutoComplete'
  97. | 'Checkbox'
  98. | 'CheckboxGroup'
  99. | 'DatePicker'
  100. | 'DefaultButton'
  101. | 'Divider'
  102. | 'IconPicker'
  103. | 'Input'
  104. | 'InputNumber'
  105. // | 'InputPassword'
  106. // | 'Mentions'
  107. | 'PrimaryButton'
  108. | 'Radio'
  109. | 'RadioGroup'
  110. | 'RangePicker'
  111. | 'Rate'
  112. | 'Select'
  113. | 'Space'
  114. | 'Switch'
  115. | 'Textarea'
  116. | 'TimePicker'
  117. | 'TreeSelect'
  118. | 'Upload'
  119. | BaseFormComponentType;
  120. async function initComponentAdapter() {
  121. const components: Partial<Record<ComponentType, Component>> = {
  122. // 如果你的组件体积比较大,可以使用异步加载
  123. // Button: () =>
  124. // import('xxx').then((res) => res.Button),
  125. ApiSelect: withDefaultPlaceholder(
  126. {
  127. ...ApiComponent,
  128. name: 'ApiSelect',
  129. },
  130. 'select',
  131. {
  132. component: Select,
  133. loadingSlot: 'suffixIcon',
  134. visibleEvent: 'onDropdownVisibleChange',
  135. modelPropName: 'value',
  136. },
  137. ),
  138. ApiTreeSelect: withDefaultPlaceholder(
  139. {
  140. ...ApiComponent,
  141. name: 'ApiTreeSelect',
  142. },
  143. 'select',
  144. {
  145. component: TreeSelect,
  146. fieldNames: { label: 'label', value: 'value', children: 'children' },
  147. loadingSlot: 'suffixIcon',
  148. modelPropName: 'value',
  149. optionsPropName: 'treeData',
  150. visibleEvent: 'onVisibleChange',
  151. },
  152. ),
  153. AutoComplete,
  154. Checkbox,
  155. CheckboxGroup,
  156. DatePicker,
  157. // 自定义默认按钮
  158. DefaultButton: (props, { attrs, slots }) => {
  159. let ghost = false;
  160. let variant = props.variant;
  161. if (props.variant === 'ghost') {
  162. ghost = true;
  163. variant = 'base';
  164. }
  165. return h(
  166. Button,
  167. { ...props, ghost, variant, attrs, theme: 'default' },
  168. slots,
  169. );
  170. },
  171. Divider,
  172. IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
  173. iconSlot: 'addonAfter',
  174. inputComponent: Input,
  175. modelValueProp: 'value',
  176. }),
  177. Input: withDefaultPlaceholder(Input, 'input'),
  178. InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
  179. // InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
  180. // Mentions: withDefaultPlaceholder(Mentions, 'input'),
  181. // 自定义主要按钮
  182. PrimaryButton: (props, { attrs, slots }) => {
  183. let ghost = false;
  184. let variant = props.variant;
  185. if (props.variant === 'ghost') {
  186. ghost = true;
  187. variant = 'base';
  188. }
  189. return h(
  190. Button,
  191. { ...props, ghost, variant, attrs, theme: 'primary' },
  192. slots,
  193. );
  194. },
  195. Radio,
  196. RadioGroup,
  197. RangePicker: (props, { attrs, slots }) => {
  198. return h(
  199. RangePicker,
  200. { ...props, modelValue: props.modelValue ?? [], attrs },
  201. slots,
  202. );
  203. },
  204. Rate,
  205. Select: withDefaultPlaceholder(Select, 'select'),
  206. Space,
  207. Switch,
  208. Textarea: withDefaultPlaceholder(Textarea, 'input'),
  209. TimePicker,
  210. TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
  211. Upload,
  212. };
  213. // 将组件注册到全局共享状态中
  214. globalShareState.setComponents(components);
  215. // 定义全局共享状态中的消息提示
  216. globalShareState.defineMessage({
  217. // 复制成功消息提示
  218. copyPreferencesSuccess: (title, content) => {
  219. notification.success({
  220. title,
  221. content,
  222. placement: 'bottom-right',
  223. });
  224. },
  225. });
  226. }
  227. export { initComponentAdapter };