index.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import type { IFormItem, ChildrenFn } from "./type";
  2. import type { FormInstance } from "ant-design-vue";
  3. import { ref, computed, watch, defineComponent } from "vue";
  4. import { Form, Collapse, CollapsePanel } from "ant-design-vue";
  5. import CusFormItem from "./CusFormItem.vue";
  6. import { pick, get } from "lodash-es";
  7. export default defineComponent({
  8. props: {
  9. columns: {
  10. type: Array as () => IFormItem[],
  11. default: () => [],
  12. },
  13. formModel: {
  14. type: Object as () => Record<string, any>,
  15. default: () => ({}),
  16. },
  17. },
  18. emits: ["change"],
  19. setup(props, { emit }) {
  20. const formModel = ref<Record<string, any>>({});
  21. const formRef = ref<FormInstance>();
  22. // 记录被格式化的数据
  23. const formatFormModel = ref<Record<string, any>>({});
  24. const formItems = computed(() => {
  25. return props.columns.map((item) => {
  26. return {
  27. ...item,
  28. rules: item?.rules || [],
  29. };
  30. });
  31. });
  32. const setFormModel = (columns: IFormItem[]) => {
  33. columns?.forEach((item) => {
  34. // 设置表单初始值
  35. if (item.type === "group") {
  36. setFormModel(item.children as IFormItem[]);
  37. } else if (item.type === "dependency") {
  38. const list = (item.children as ChildrenFn)?.(
  39. pick(formModel.value, item.name || []),
  40. formModel
  41. );
  42. setFormModel(list);
  43. } else {
  44. if (item.type === "divider") return;
  45. // 获取初始值 先从formModel中取,没有则取默认值
  46. const value = get(props.formModel, item.prop);
  47. // 表单的值需要转换成把option值转换成表单值
  48. formModel.value[item.prop] = item?.valueToForm
  49. ? item.valueToForm(value, props.formModel)
  50. : value ?? item.defaultValue;
  51. if (item.format) {
  52. item.format(formatFormModel, formModel.value[item.prop]);
  53. } else {
  54. formatFormModel.value[item.prop] = value ?? item.defaultValue;
  55. }
  56. }
  57. });
  58. };
  59. /* 处理修改值 */
  60. const handleValueChange = (val: unknown, child: IFormItem) => {
  61. formModel.value[child.prop] = val;
  62. // 根据传入转换方法,格式化数据
  63. if (child.format) {
  64. child.format(formatFormModel, val);
  65. } else {
  66. formatFormModel.value[child.prop] = val;
  67. }
  68. emit("change", formatFormModel.value);
  69. };
  70. /* 单个表单项 */
  71. const getItem = (child: IFormItem) => {
  72. switch (child.type) {
  73. case "dependency": {
  74. const list = (child.children as ChildrenFn)?.(
  75. pick(formModel.value, child.name || []),
  76. formModel
  77. );
  78. return getFormItems(list);
  79. }
  80. case "group": {
  81. return getGroupItem(child);
  82. }
  83. default: {
  84. return (
  85. <CusFormItem
  86. key={child.prop}
  87. item={child}
  88. modelValue={formModel.value[child.prop]}
  89. onUpdate:modelValue={(val: any) => {
  90. handleValueChange(val, child);
  91. }}
  92. />
  93. );
  94. }
  95. }
  96. };
  97. /* 分组 */
  98. const getGroupItem = (item: IFormItem) => {
  99. return (
  100. <Collapse>
  101. <CollapsePanel key={item.prop} header={item.label}>
  102. {(item.children as IFormItem[])?.map((child) => {
  103. return getItem(child);
  104. })}
  105. </CollapsePanel>
  106. </Collapse>
  107. );
  108. };
  109. /* 获取表单项 */
  110. const getFormItems = (formItemList: IFormItem[]): any => {
  111. return formItemList.map((item) => {
  112. switch (item.type) {
  113. case "group":
  114. return getGroupItem(item);
  115. default:
  116. return getItem(item);
  117. }
  118. });
  119. };
  120. watch(
  121. () => formItems.value,
  122. (val) => {
  123. if (val) setFormModel(val);
  124. },
  125. { immediate: true }
  126. );
  127. return () => (
  128. <Form
  129. model={formModel}
  130. colon={false}
  131. label-col={{ span: 8 }}
  132. ref={formRef}
  133. layout="horizontal"
  134. size="small"
  135. >
  136. {getFormItems(formItems.value)}
  137. </Form>
  138. );
  139. },
  140. });