index.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /**
  2. * 通用组件共同的使用的基础组件,原先放在 adapter/form 内部,限制了使用范围,这里提取出来,方便其他地方使用
  3. * 可用于 vben-form、vben-modal、vben-drawer 等组件使用,
  4. */
  5. import type { Component } from 'vue';
  6. import type { BaseFormComponentType } from '@vben/common-ui';
  7. import type { Recordable } from '@vben/types';
  8. import { defineComponent, getCurrentInstance, h, ref } from 'vue';
  9. import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
  10. import { $t } from '@vben/locales';
  11. import {
  12. ElButton,
  13. ElCheckbox,
  14. ElCheckboxButton,
  15. ElCheckboxGroup,
  16. ElDatePicker,
  17. ElDivider,
  18. ElInput,
  19. ElInputNumber,
  20. ElNotification,
  21. ElRadio,
  22. ElRadioButton,
  23. ElRadioGroup,
  24. ElSelectV2,
  25. ElSpace,
  26. ElSwitch,
  27. ElTimePicker,
  28. ElTreeSelect,
  29. ElUpload,
  30. } from 'element-plus';
  31. const withDefaultPlaceholder = <T extends Component>(
  32. component: T,
  33. type: 'input' | 'select',
  34. ) => {
  35. return defineComponent({
  36. inheritAttrs: false,
  37. name: component.name,
  38. setup: (props: any, { attrs, expose, slots }) => {
  39. const placeholder =
  40. props?.placeholder ||
  41. attrs?.placeholder ||
  42. $t(`ui.placeholder.${type}`);
  43. // 透传组件暴露的方法
  44. const innerRef = ref();
  45. const publicApi: Recordable<any> = {};
  46. expose(publicApi);
  47. const instance = getCurrentInstance();
  48. instance?.proxy?.$nextTick(() => {
  49. for (const key in innerRef.value) {
  50. if (typeof innerRef.value[key] === 'function') {
  51. publicApi[key] = innerRef.value[key];
  52. }
  53. }
  54. });
  55. return () =>
  56. h(component, { ...props, ...attrs, placeholder, ref: innerRef }, slots);
  57. },
  58. });
  59. };
  60. // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
  61. export type ComponentType =
  62. | 'ApiSelect'
  63. | 'ApiTreeSelect'
  64. | 'Checkbox'
  65. | 'CheckboxGroup'
  66. | 'DatePicker'
  67. | 'Divider'
  68. | 'IconPicker'
  69. | 'Input'
  70. | 'InputNumber'
  71. | 'RadioGroup'
  72. | 'Select'
  73. | 'Space'
  74. | 'Switch'
  75. | 'TimePicker'
  76. | 'TreeSelect'
  77. | 'Upload'
  78. | BaseFormComponentType;
  79. async function initComponentAdapter() {
  80. const components: Partial<Record<ComponentType, Component>> = {
  81. // 如果你的组件体积比较大,可以使用异步加载
  82. // Button: () =>
  83. // import('xxx').then((res) => res.Button),
  84. ApiSelect: (props, { attrs, slots }) => {
  85. return h(
  86. ApiComponent,
  87. {
  88. placeholder: $t('ui.placeholder.select'),
  89. ...props,
  90. ...attrs,
  91. component: ElSelectV2,
  92. loadingSlot: 'loading',
  93. visibleEvent: 'onVisibleChange',
  94. },
  95. slots,
  96. );
  97. },
  98. ApiTreeSelect: (props, { attrs, slots }) => {
  99. return h(
  100. ApiComponent,
  101. {
  102. placeholder: $t('ui.placeholder.select'),
  103. ...props,
  104. ...attrs,
  105. component: ElTreeSelect,
  106. props: { label: 'label', children: 'children' },
  107. nodeKey: 'value',
  108. loadingSlot: 'loading',
  109. optionsPropName: 'data',
  110. visibleEvent: 'onVisibleChange',
  111. },
  112. slots,
  113. );
  114. },
  115. Checkbox: ElCheckbox,
  116. CheckboxGroup: (props, { attrs, slots }) => {
  117. let defaultSlot;
  118. if (Reflect.has(slots, 'default')) {
  119. defaultSlot = slots.default;
  120. } else {
  121. const { options, isButton } = attrs;
  122. if (Array.isArray(options)) {
  123. defaultSlot = () =>
  124. options.map((option) =>
  125. h(isButton ? ElCheckboxButton : ElCheckbox, option),
  126. );
  127. }
  128. }
  129. return h(
  130. ElCheckboxGroup,
  131. { ...props, ...attrs },
  132. { ...slots, default: defaultSlot },
  133. );
  134. },
  135. // 自定义默认按钮
  136. DefaultButton: (props, { attrs, slots }) => {
  137. return h(ElButton, { ...props, attrs, type: 'info' }, slots);
  138. },
  139. // 自定义主要按钮
  140. PrimaryButton: (props, { attrs, slots }) => {
  141. return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
  142. },
  143. Divider: ElDivider,
  144. IconPicker: (props, { attrs, slots }) => {
  145. return h(
  146. IconPicker,
  147. {
  148. iconSlot: 'append',
  149. modelValueProp: 'model-value',
  150. inputComponent: ElInput,
  151. ...props,
  152. ...attrs,
  153. },
  154. slots,
  155. );
  156. },
  157. Input: withDefaultPlaceholder(ElInput, 'input'),
  158. InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
  159. RadioGroup: (props, { attrs, slots }) => {
  160. let defaultSlot;
  161. if (Reflect.has(slots, 'default')) {
  162. defaultSlot = slots.default;
  163. } else {
  164. const { options } = attrs;
  165. if (Array.isArray(options)) {
  166. defaultSlot = () =>
  167. options.map((option) =>
  168. h(attrs.isButton ? ElRadioButton : ElRadio, option),
  169. );
  170. }
  171. }
  172. return h(
  173. ElRadioGroup,
  174. { ...props, ...attrs },
  175. { ...slots, default: defaultSlot },
  176. );
  177. },
  178. Select: (props, { attrs, slots }) => {
  179. return h(ElSelectV2, { ...props, attrs }, slots);
  180. },
  181. Space: ElSpace,
  182. Switch: ElSwitch,
  183. TimePicker: (props, { attrs, slots }) => {
  184. const { name, id, isRange } = props;
  185. const extraProps: Recordable<any> = {};
  186. if (isRange) {
  187. if (name && !Array.isArray(name)) {
  188. extraProps.name = [name, `${name}_end`];
  189. }
  190. if (id && !Array.isArray(id)) {
  191. extraProps.id = [id, `${id}_end`];
  192. }
  193. }
  194. return h(
  195. ElTimePicker,
  196. {
  197. ...props,
  198. ...attrs,
  199. ...extraProps,
  200. },
  201. slots,
  202. );
  203. },
  204. DatePicker: (props, { attrs, slots }) => {
  205. const { name, id, type } = props;
  206. const extraProps: Recordable<any> = {};
  207. if (type && type.includes('range')) {
  208. if (name && !Array.isArray(name)) {
  209. extraProps.name = [name, `${name}_end`];
  210. }
  211. if (id && !Array.isArray(id)) {
  212. extraProps.id = [id, `${id}_end`];
  213. }
  214. }
  215. return h(
  216. ElDatePicker,
  217. {
  218. ...props,
  219. ...attrs,
  220. ...extraProps,
  221. },
  222. slots,
  223. );
  224. },
  225. TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),
  226. Upload: ElUpload,
  227. };
  228. // 将组件注册到全局共享状态中
  229. globalShareState.setComponents(components);
  230. // 定义全局共享状态中的消息提示
  231. globalShareState.defineMessage({
  232. // 复制成功消息提示
  233. copyPreferencesSuccess: (title, content) => {
  234. ElNotification({
  235. title,
  236. message: content,
  237. position: 'bottom-right',
  238. duration: 0,
  239. type: 'success',
  240. });
  241. },
  242. });
  243. }
  244. export { initComponentAdapter };