index.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /**
  2. * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用
  3. * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
  4. */
  5. import type {
  6. CheckboxGroupProps,
  7. CheckboxProps,
  8. DatePickerProps,
  9. DividerProps,
  10. InputNumberProps,
  11. InputProps,
  12. RadioGroupProps,
  13. SelectProps,
  14. SpaceProps,
  15. SwitchProps,
  16. TimePickerProps,
  17. TreeSelectProps,
  18. UploadProps,
  19. } from 'naive-ui';
  20. import type { Component } from 'vue';
  21. import type {
  22. ApiComponentSharedProps,
  23. BaseFormComponentType,
  24. IconPickerProps,
  25. } from '@vben/common-ui';
  26. import type { Recordable } from '@vben/types';
  27. import { defineAsyncComponent, defineComponent, h, ref } from 'vue';
  28. import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
  29. import { $t } from '@vben/locales';
  30. import { message } from '#/adapter/naive';
  31. const NButton = defineAsyncComponent(() =>
  32. import('naive-ui/es/button').then((res) => res.NButton),
  33. );
  34. const NCheckbox = defineAsyncComponent(() =>
  35. import('naive-ui/es/checkbox').then((res) => res.NCheckbox),
  36. );
  37. const NCheckboxGroup = defineAsyncComponent(() =>
  38. import('naive-ui/es/checkbox').then((res) => res.NCheckboxGroup),
  39. );
  40. const NDatePicker = defineAsyncComponent(() =>
  41. import('naive-ui/es/date-picker').then((res) => res.NDatePicker),
  42. );
  43. const NDivider = defineAsyncComponent(() =>
  44. import('naive-ui/es/divider').then((res) => res.NDivider),
  45. );
  46. const NInput = defineAsyncComponent(() =>
  47. import('naive-ui/es/input').then((res) => res.NInput),
  48. );
  49. const NInputNumber = defineAsyncComponent(() =>
  50. import('naive-ui/es/input-number').then((res) => res.NInputNumber),
  51. );
  52. const NRadio = defineAsyncComponent(() =>
  53. import('naive-ui/es/radio').then((res) => res.NRadio),
  54. );
  55. const NRadioButton = defineAsyncComponent(() =>
  56. import('naive-ui/es/radio').then((res) => res.NRadioButton),
  57. );
  58. const NRadioGroup = defineAsyncComponent(() =>
  59. import('naive-ui/es/radio').then((res) => res.NRadioGroup),
  60. );
  61. const NSelect = defineAsyncComponent(() =>
  62. import('naive-ui/es/select').then((res) => res.NSelect),
  63. );
  64. const NSpace = defineAsyncComponent(() =>
  65. import('naive-ui/es/space').then((res) => res.NSpace),
  66. );
  67. const NSwitch = defineAsyncComponent(() =>
  68. import('naive-ui/es/switch').then((res) => res.NSwitch),
  69. );
  70. const NTimePicker = defineAsyncComponent(() =>
  71. import('naive-ui/es/time-picker').then((res) => res.NTimePicker),
  72. );
  73. const NTreeSelect = defineAsyncComponent(() =>
  74. import('naive-ui/es/tree-select').then((res) => res.NTreeSelect),
  75. );
  76. const NUpload = defineAsyncComponent(() =>
  77. import('naive-ui/es/upload').then((res) => res.NUpload),
  78. );
  79. const withDefaultPlaceholder = <T extends Component>(
  80. component: T,
  81. type: 'input' | 'select',
  82. componentProps: Recordable<any> = {},
  83. ) => {
  84. return defineComponent({
  85. name: component.name,
  86. inheritAttrs: false,
  87. setup: (props: any, { attrs, expose, slots }) => {
  88. const placeholder =
  89. props?.placeholder ||
  90. attrs?.placeholder ||
  91. $t(`ui.placeholder.${type}`);
  92. // 透传组件暴露的方法
  93. const innerRef = ref();
  94. expose(
  95. new Proxy(
  96. {},
  97. {
  98. get: (_target, key) => innerRef.value?.[key],
  99. has: (_target, key) => key in (innerRef.value || {}),
  100. },
  101. ),
  102. );
  103. return () =>
  104. h(
  105. component,
  106. { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef },
  107. slots,
  108. );
  109. },
  110. });
  111. };
  112. // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
  113. export type ComponentType =
  114. | 'ApiSelect'
  115. | 'ApiTreeSelect'
  116. | 'Checkbox'
  117. | 'CheckboxGroup'
  118. | 'DatePicker'
  119. | 'Divider'
  120. | 'IconPicker'
  121. | 'Input'
  122. | 'InputNumber'
  123. | 'RadioGroup'
  124. | 'Select'
  125. | 'Space'
  126. | 'Switch'
  127. | 'TimePicker'
  128. | 'TreeSelect'
  129. | 'Upload'
  130. | BaseFormComponentType;
  131. /**
  132. * 与 {@link ComponentType} 中注册的组件名一一对应,便于 Schema 上 `component` + `componentProps` 联动提示
  133. */
  134. export interface ComponentPropsMap {
  135. ApiSelect: ApiComponentSharedProps & SelectProps;
  136. ApiTreeSelect: ApiComponentSharedProps & TreeSelectProps;
  137. Checkbox: CheckboxProps;
  138. CheckboxGroup: CheckboxGroupProps;
  139. DatePicker: DatePickerProps;
  140. Divider: DividerProps;
  141. IconPicker: IconPickerProps;
  142. Input: InputProps;
  143. InputNumber: InputNumberProps;
  144. RadioGroup: RadioGroupProps;
  145. Select: SelectProps;
  146. Space: SpaceProps;
  147. Switch: SwitchProps;
  148. TimePicker: TimePickerProps;
  149. TreeSelect: TreeSelectProps;
  150. Upload: UploadProps;
  151. }
  152. async function initComponentAdapter() {
  153. const components: Partial<Record<ComponentType, Component>> = {
  154. // 如果你的组件体积比较大,可以使用异步加载
  155. // Button: () =>
  156. // import('xxx').then((res) => res.Button),
  157. ApiSelect: withDefaultPlaceholder(
  158. {
  159. ...ApiComponent,
  160. name: 'ApiSelect',
  161. },
  162. 'select',
  163. {
  164. component: NSelect,
  165. modelPropName: 'value',
  166. },
  167. ),
  168. ApiTreeSelect: withDefaultPlaceholder(
  169. {
  170. ...ApiComponent,
  171. name: 'ApiTreeSelect',
  172. },
  173. 'select',
  174. {
  175. component: NTreeSelect,
  176. nodeKey: 'value',
  177. loadingSlot: 'arrow',
  178. keyField: 'value',
  179. modelPropName: 'value',
  180. optionsPropName: 'options',
  181. visibleEvent: 'onVisibleChange',
  182. },
  183. ),
  184. Checkbox: NCheckbox,
  185. CheckboxGroup: (props, { attrs, slots }) => {
  186. let defaultSlot;
  187. if (Reflect.has(slots, 'default')) {
  188. defaultSlot = slots.default;
  189. } else {
  190. const { options } = attrs;
  191. if (Array.isArray(options)) {
  192. defaultSlot = () => options.map((option) => h(NCheckbox, option));
  193. }
  194. }
  195. return h(
  196. NCheckboxGroup,
  197. { ...props, ...attrs },
  198. { default: defaultSlot },
  199. );
  200. },
  201. DatePicker: NDatePicker,
  202. // 自定义默认按钮
  203. DefaultButton: (props, { attrs, slots }) => {
  204. return h(NButton, { ...props, attrs, type: 'default' }, slots);
  205. },
  206. // 自定义主要按钮
  207. PrimaryButton: (props, { attrs, slots }) => {
  208. return h(NButton, { ...props, attrs, type: 'primary' }, slots);
  209. },
  210. Divider: NDivider,
  211. IconPicker: withDefaultPlaceholder(IconPicker, 'select', {
  212. iconSlot: 'suffix',
  213. inputComponent: NInput,
  214. }),
  215. Input: withDefaultPlaceholder(NInput, 'input'),
  216. InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),
  217. RadioGroup: (props, { attrs, slots }) => {
  218. let defaultSlot;
  219. if (Reflect.has(slots, 'default')) {
  220. defaultSlot = slots.default;
  221. } else {
  222. const { options } = attrs;
  223. if (Array.isArray(options)) {
  224. defaultSlot = () =>
  225. options.map((option) =>
  226. h(attrs.isButton ? NRadioButton : NRadio, option),
  227. );
  228. }
  229. }
  230. const groupRender = h(
  231. NRadioGroup,
  232. { ...props, ...attrs },
  233. { default: defaultSlot },
  234. );
  235. return attrs.isButton
  236. ? h(NSpace, { vertical: true }, () => groupRender)
  237. : groupRender;
  238. },
  239. Select: withDefaultPlaceholder(NSelect, 'select'),
  240. Space: NSpace,
  241. Switch: NSwitch,
  242. TimePicker: NTimePicker,
  243. TreeSelect: withDefaultPlaceholder(NTreeSelect, 'select'),
  244. Upload: NUpload,
  245. };
  246. // 将组件注册到全局共享状态中
  247. globalShareState.setComponents(components);
  248. // 定义全局共享状态中的消息提示
  249. globalShareState.defineMessage({
  250. // 复制成功消息提示
  251. copyPreferencesSuccess: (title, content) => {
  252. message.success(content || title, {
  253. duration: 0,
  254. });
  255. },
  256. });
  257. }
  258. export { initComponentAdapter };