DynamicForm.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <template>
  2. <Form
  3. ref="formEditor"
  4. :name="name"
  5. v-bind="finalOptions.formAdditionaProps"
  6. :model="model || {}"
  7. :rules="finalOptions.formRules"
  8. @submit="(e) => emit('submit', e)"
  9. @submitFailed="() => emit('finishFailed')"
  10. >
  11. <DynamicFormRoot
  12. :options="finalOptions"
  13. :model="model"
  14. :name="name"
  15. />
  16. </Form>
  17. </template>
  18. <script setup lang="ts">
  19. import { computed, onMounted, provide, ref, toRef, toRefs, type PropType } from 'vue';
  20. import Form, { type FormInstance } from '../form/Form.vue';
  21. import {
  22. type IDynamicFormOptions, type IDynamicFormItem, type IDynamicFormRef,
  23. type IDynamicFormObject, defaultDynamicFormOptions,
  24. type IDynamicFormMessageCenter,
  25. type IDynamicFormMessageCenterCallback,
  26. MESSAGE_RELOAD
  27. } from '.';
  28. import DynamicFormRoot from './nest/DynamicFormRoot.vue';
  29. const props = defineProps({
  30. /**
  31. * 动态表单选项
  32. */
  33. options: {
  34. type: Object as PropType<IDynamicFormOptions>,
  35. default: null
  36. },
  37. /**
  38. * 表单数据模型
  39. */
  40. model: {
  41. type: Object,
  42. default: null
  43. },
  44. /**
  45. * 表单名称, 设置到表单组件上。
  46. */
  47. name: {
  48. type: String,
  49. default: ''
  50. },
  51. /**
  52. * 全局参数。用于向每个表单项的参数中添加额外的参数,可以在回调中的 formGlobalParams 中访问。
  53. */
  54. globalParams: {
  55. type: Object as PropType<IDynamicFormObject>,
  56. default: null
  57. },
  58. });
  59. const emit = defineEmits(['ready', 'submit', 'finish', 'finishFailed']);
  60. const { options, model, name } = toRefs(props);
  61. const finalOptions = computed<IDynamicFormOptions>(() => ({
  62. ...defaultDynamicFormOptions,
  63. ...options.value,
  64. }));
  65. provide('rawModel', model);
  66. provide('globalParams', toRef(props, 'globalParams'));
  67. provide('finalOptions', finalOptions);
  68. const formEditor = ref<FormInstance>();
  69. const widgetsRefMap = ref<Record<string,() => unknown>>({});
  70. const messageCenterMap = new Map<string, IDynamicFormMessageCenterCallback>();
  71. provide('widgetsRefMap', widgetsRefMap.value);
  72. provide('messageCenter', {
  73. addInstance: (name: string, fn: IDynamicFormMessageCenterCallback) => messageCenterMap.set(name, fn),
  74. removeInstance: (name: string) => messageCenterMap.delete(name),
  75. } as IDynamicFormMessageCenter);
  76. //获取组件引用
  77. function getFormItemControlRef(key: string) {
  78. return widgetsRefMap.value[key]?.();
  79. }
  80. //通过路径访问
  81. function accessFormModel(keyName: string, isSet: boolean, setValue: unknown) : unknown {
  82. const keys = keyName.split('.');
  83. let ret : unknown = undefined;
  84. let obj = model.value as Record<string, unknown>;
  85. let keyIndex = 0;
  86. let key = keys[keyIndex];
  87. while (obj) {
  88. const leftIndex = key.indexOf('[');
  89. if (leftIndex > 0 && key.endsWith(']')) {
  90. const arr = obj[key.substring(0, leftIndex)] as Record<string, unknown>[];
  91. const index = parseInt(key.substring(leftIndex + 1, key.length - 1))
  92. obj = arr[index];
  93. if (keyIndex >= keys.length - 1) {
  94. ret = obj;
  95. if (isSet) arr[index] = setValue as Record<string, unknown>;
  96. }
  97. } else {
  98. const newObj = obj[key] as Record<string, unknown>;
  99. if (keyIndex >= keys.length - 1) {
  100. ret = newObj;
  101. if (isSet)
  102. obj[key] = setValue as Record<string, unknown>;
  103. }
  104. obj = newObj;
  105. }
  106. if (keyIndex < keys.length - 1)
  107. key = keys[++keyIndex];
  108. else
  109. break;
  110. }
  111. return ret;
  112. }
  113. //发送通知消息
  114. function dispatchMessage(messageName: string, data?: unknown, receiveFilter?: RegExp) {
  115. for (const iterator of messageCenterMap) {
  116. if (!receiveFilter || receiveFilter.test(iterator[0]))
  117. iterator[1](messageName, data);
  118. }
  119. }
  120. //发送重新加载消息
  121. function dispatchReload() {
  122. dispatchMessage(MESSAGE_RELOAD);
  123. }
  124. //初始化默认值到模型
  125. function initDefaultValuesToModel() {
  126. function loopItems(key: string, parentKey: string, type: string, items: IDynamicFormItem[]) {
  127. let i = 0;
  128. for (const item of items) {
  129. let currentKey = key;
  130. switch (type) {
  131. case 'flat-simple':
  132. case 'flat-group':
  133. currentKey = (parentKey ? parentKey + '.' : '') + item.name;
  134. break;
  135. default:
  136. case 'object':
  137. case 'object-group':
  138. currentKey = (key ? key + '.' : '') + item.name;
  139. break
  140. case 'array':
  141. currentKey = (parentKey ? parentKey + '.' : '') + `[${i}]`;
  142. break;
  143. case 'array-object':
  144. currentKey = (parentKey ? parentKey + '.' : '') + `[${i}]` + item.name;
  145. break;
  146. }
  147. if (item.children) {
  148. loopItems(currentKey, key, item.type || '', item.children);
  149. }
  150. //console.log(currentKey);
  151. if (item.defaultValue !== undefined) {
  152. const oldValue = accessFormModel(currentKey, false, undefined);
  153. if (oldValue !== undefined && oldValue !== null)
  154. continue;
  155. accessFormModel(currentKey, true, item.defaultValue);
  156. }
  157. i++;
  158. }
  159. }
  160. loopItems('', '', '', finalOptions.value.formItems);
  161. }
  162. //获取当前表单中可见的所有字段名
  163. function getVisibleFormNames() {
  164. return Array.from(messageCenterMap.keys());
  165. }
  166. onMounted(() => {
  167. setTimeout(() => {
  168. emit('ready');
  169. }, 400);
  170. });
  171. const formRef : IDynamicFormRef = {
  172. initDefaultValuesToModel,
  173. getVisibleFormNames,
  174. getFormRef() {
  175. if (!formEditor.value)
  176. throw new Error('Form instance is not create.');
  177. return formEditor.value
  178. },
  179. getFormItemControlRef: getFormItemControlRef as any,
  180. submit() { return this.getFormRef().validate(); },
  181. validate() { return this.getFormRef().validate(); },
  182. setValueByPath: (path: string|string[], value: unknown) => {
  183. if (Array.isArray(path))
  184. path = path.join('.');
  185. return accessFormModel(path, true, value);
  186. },
  187. getValueByPath: (path: string|string[]) => {
  188. if (Array.isArray(path))
  189. path = path.join('.');
  190. return accessFormModel(path, false, undefined);
  191. },
  192. dispatchMessage,
  193. dispatchReload,
  194. };
  195. provide('formRef', formRef);
  196. provide('formName', name.value || 'unnamed');
  197. defineExpose(formRef);
  198. </script>