DynamicFormItemContainer.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <template>
  2. <Col
  3. v-if="isShow"
  4. :class="[
  5. 'dynamic-form-item-wrapper',
  6. finalOptions?.nestObjectMargin !== false && item.nestObjectMargin !== false ? 'nest-with-margin' : '',
  7. ]"
  8. :data-dynamic-form-item="item.name"
  9. :data-dynamic-form-item-type="item.type"
  10. v-bind="{
  11. ...colProps,
  12. ...(item.colProps as {})
  13. }"
  14. >
  15. <!--对象组-->
  16. <DynamicFormCheckEmpty
  17. v-if="item.type === 'object'"
  18. :model="model"
  19. :modelWithDefault="finalModel"
  20. :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
  21. :name="name"
  22. checkType="object"
  23. >
  24. <!--标题-->
  25. <DynamicFormItemNormal
  26. v-if="item.label"
  27. :item="item"
  28. :parent="parent"
  29. :name="''"
  30. :rawModel="rawModel"
  31. :model="null"
  32. :noLabel="true"
  33. :disabled="disabled || evaluateCallback(item.disabled)"
  34. >
  35. <template #insertion>
  36. <span v-if="item.label" class="dynamic-form-object-title">{{ evaluateCallback(item.label) }}</span>
  37. </template>
  38. </DynamicFormItemNormal>
  39. <!--循环子条目-->
  40. <DynamicFormItemContainerFuckMp
  41. v-for="(child, k) in item.children"
  42. :key="k"
  43. :item="child"
  44. :name="name+'.'+child.name"
  45. :rawModel="rawModel"
  46. :model="(finalModel as IDynamicFormObject)[child.name]"
  47. :parent="item"
  48. :parentModel="finalModel"
  49. :parentName="name"
  50. :isFirst="k === 0"
  51. :isLast="k === (item.children?.length || 0) - 1"
  52. @update:model="(v: unknown) => (model as IDynamicFormObject)[child.name] = v"
  53. :disabled="disabled || evaluateCallback(item.disabled)"
  54. />
  55. </DynamicFormCheckEmpty>
  56. <!--对象组-->
  57. <DynamicFormCheckEmpty
  58. v-else-if="item.type === 'object-group'"
  59. :model="model"
  60. :modelWithDefault="finalModel"
  61. :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
  62. :name="name"
  63. checkType="object"
  64. >
  65. <FormGroup :title="evaluateCallback(item.label)" v-bind="(item.additionalProps as object)">
  66. <Row v-bind="item.rowProps">
  67. <!--循环子条目-->
  68. <DynamicFormItemContainerFuckMp
  69. v-for="(child, k) in item.children"
  70. :key="k"
  71. :item="child"
  72. :colProps="{ ...item.childrenColProps, ...child.colProps }"
  73. :name="name+'.'+child.name"
  74. :rawModel="rawModel"
  75. :model="((finalModel as IDynamicFormObject)[child.name] as IDynamicFormObject)"
  76. :parent="item"
  77. :parentModel="finalModel"
  78. :parentName="name"
  79. :isFirst="k === 0"
  80. :isLast="k === (item.children?.length || 0) - 1"
  81. @update:model="(v: unknown) => (model as IDynamicFormObject)[child.name] = v"
  82. :disabled="disabled || evaluateCallback(item.disabled)"
  83. />
  84. </Row>
  85. </FormGroup>
  86. </DynamicFormCheckEmpty>
  87. <!--扁平组-->
  88. <FormGroup v-else-if="item.type === 'flat-group'" :title="evaluateCallback(item.label)" v-bind="(item.additionalProps as object)">
  89. <Row v-bind="item.rowProps">
  90. <!--循环子条目-->
  91. <DynamicFormItemContainerFuckMp
  92. v-for="(child, k) in item.children"
  93. :colProps="{ ...item.childrenColProps, ...child.colProps }"
  94. :key="k"
  95. :item="child"
  96. :name="parentName ? `${parentName}.${child.name}` : child.name"
  97. :rawModel="rawModel"
  98. :model="((parentModel as IDynamicFormObject)[child.name])"
  99. :parent="item"
  100. :parentModel="parentModel"
  101. :parentName="parentName"
  102. :isFirst="k === 0"
  103. :isLast="k === (item.children?.length || 0) - 1"
  104. @update:model="(v: unknown) => (parentModel as IDynamicFormObject)[child.name] = v"
  105. :disabled="disabled || evaluateCallback(item.disabled)"
  106. >
  107. <template #formCeil="values">
  108. <slot name="formCeil" :data="values.data" />
  109. </template>
  110. </DynamicFormItemContainerFuckMp>
  111. </Row>
  112. </FormGroup>
  113. <!--扁平普通-->
  114. <DynamicFormItemNormal v-else-if="item.type === 'flat-simple'"
  115. :item="item"
  116. :parent="parent"
  117. :name="name"
  118. :disabled="disabled || evaluateCallback(item.disabled)"
  119. :model="(finalModel as IDynamicFormObject)"
  120. :rawModel="rawModel"
  121. :parentModel="parentModel"
  122. :parentName="parentName"
  123. >
  124. <template #insertion>
  125. <Row v-bind="item.rowProps">
  126. <!--循环子条目-->
  127. <DynamicFormItemContainerFuckMp
  128. v-for="(child, k) in item.children"
  129. :key="k"
  130. :item="child"
  131. :colProps="{ ...item.childrenColProps, ...child.colProps }"
  132. :name="parentName ? `${parentName}.${child.name}` : child.name"
  133. :rawModel="rawModel"
  134. :model="((parentModel as IDynamicFormObject)[child.name])"
  135. :parent="item"
  136. :parentModel="parentModel"
  137. :parentName="parentName"
  138. :isFirst="k === 0"
  139. :isLast="k === (item.children?.length || 0) - 1"
  140. @update:model="(v: unknown) => (parentModel as IDynamicFormObject)[child.name] = v"
  141. :disabled="disabled || evaluateCallback(item.disabled)"
  142. >
  143. <template #formCeil="values">
  144. <slot name="formCeil" :data="values.data" />
  145. </template>
  146. </DynamicFormItemContainerFuckMp>
  147. </Row>
  148. </template>
  149. </DynamicFormItemNormal>
  150. <!--数组变量组-->
  151. <DynamicFormCheckEmpty
  152. v-else-if="item.type === 'array-single'"
  153. :model="model"
  154. :modelWithDefault="finalModel"
  155. :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
  156. :name="name"
  157. checkType="array"
  158. >
  159. <DynamicFormItemNormal
  160. :item="item"
  161. :name="name"
  162. :disabled="disabled || evaluateCallback(item.disabled)"
  163. :model="(finalModel as IDynamicFormObject)"
  164. :rawModel="rawModel"
  165. :parentModel="parentModel"
  166. :parent="parent"
  167. :parentName="name"
  168. >
  169. <template #insertion>
  170. <FormArrayGroup
  171. :model="(finalModel as unknown as unknown[])"
  172. :item="item"
  173. :parent="parent"
  174. :name="name"
  175. :rawModel="rawModel"
  176. :isObject="false"
  177. :addCallback="item.newChildrenObject"
  178. :deleteCallback="item.deleteChildrenCallback"
  179. v-bind="(item.additionalProps as IDynamicFormObject)"
  180. >
  181. <template #addButton="props">
  182. <slot name="arrayButtonAdd" :onClick="props.onClick" />
  183. </template>
  184. <template #itemButton="props">
  185. <slot name="arrayButtons"
  186. :onDeleteClick="props.onDeleteClick"
  187. :onUpClick="props.onUpClick"
  188. :onDownClick="props.onDownClick"
  189. />
  190. </template>
  191. <template #child="{ item, pitem, kname, model: child, onUpdateValue, isFirst, isLast }">
  192. <DynamicFormItemContainerFuckMp
  193. :item="item"
  194. :name="kname"
  195. :rawModel="rawModel"
  196. :model="child"
  197. :parent="pitem"
  198. :parentModel="model"
  199. :parentName="name"
  200. :disabled="disabled || evaluateCallback(item.disabled)"
  201. :isFirst="isFirst"
  202. :isLast="isLast"
  203. @update:model="(v: unknown) => onUpdateValue(v)"
  204. />
  205. </template>
  206. </FormArrayGroup>
  207. </template>
  208. </DynamicFormItemNormal>
  209. </DynamicFormCheckEmpty>
  210. <!--数组对象组-->
  211. <DynamicFormCheckEmpty
  212. v-else-if="item.type === 'array-object'"
  213. :model="model"
  214. :modelWithDefault="finalModel"
  215. :suppressEmptyError="editmode || finalOptions?.suppressEmptyError || item.suppressEmptyError"
  216. :name="name"
  217. checkType="array"
  218. >
  219. <DynamicFormItemNormal
  220. :item="item"
  221. :parent="parent"
  222. :name="name"
  223. :disabled="disabled || evaluateCallback(item.disabled)"
  224. :model="finalModel"
  225. :rawModel="rawModel"
  226. :parentModel="parentModel"
  227. :parentName="parentName"
  228. :isFirst="isFirst"
  229. :isLast="isLast"
  230. >
  231. <template #insertion>
  232. <FormArrayGroup
  233. :model="(finalModel as unknown as unknown[])"
  234. :item="item"
  235. :parent="parent"
  236. :name="name"
  237. :rawModel="rawModel"
  238. :isObject="true"
  239. :addCallback="item.newChildrenObject"
  240. :deleteCallback="item.deleteChildrenCallback"
  241. v-bind="(item.additionalProps as IDynamicFormObject)"
  242. >
  243. <template #addButton="props">
  244. <slot name="arrayButtonAdd" :onClick="props.onClick" />
  245. </template>
  246. <template #itemButton="props">
  247. <slot name="arrayButtons"
  248. :onDeleteClick="props.onDeleteClick"
  249. :onUpClick="props.onUpClick"
  250. :onDownClick="props.onDownClick"
  251. />
  252. </template>
  253. <template #child="{ item, pitem, kname, model: child, onUpdateValue, isFirst, isLast }">
  254. <DynamicFormItemContainerFuckMp
  255. :item="item"
  256. :name="kname"
  257. :rawModel="rawModel"
  258. :model="child"
  259. :parent="pitem"
  260. :parentModel="model"
  261. :parentName="name"
  262. :isFirst="isFirst"
  263. :isLast="isLast"
  264. :disabled="disabled || evaluateCallback(item.disabled)"
  265. @update:model="(v: unknown) => onUpdateValue(v)"
  266. />
  267. </template>
  268. </FormArrayGroup>
  269. </template>
  270. </DynamicFormItemNormal>
  271. </DynamicFormCheckEmpty>
  272. <!--正常条目-->
  273. <DynamicFormItemNormal
  274. v-else
  275. :item="item"
  276. :parent="parent"
  277. :name="name"
  278. :disabled="disabled || evaluateCallback(item.disabled)"
  279. :rawModel="rawModel"
  280. :parentModel="parentModel"
  281. :model="finalModel"
  282. :isFirst="isFirst"
  283. :isLast="isLast"
  284. @update:model="(v: unknown) => $emit('update:model', v)"
  285. >
  286. <template #formCeil="values">
  287. <slot name="formCeil" :data="values.data" />
  288. </template>
  289. </DynamicFormItemNormal>
  290. </Col>
  291. </template>
  292. <script lang="ts" setup>
  293. import { inject, type Ref, toRefs, computed, provide } from 'vue';
  294. import type { Rules } from 'async-validator';
  295. import type { IDynamicFormItem, IDynamicFormItemCallback, IDynamicFormObject, IDynamicFormOptions, IDynamicFormRef, IEvaluateCallback } from '..';
  296. import DynamicFormItemNormal, { type FormCeilProps } from '../DynamicFormControl.vue';
  297. import FormGroup from '../group/FormGroup.vue';
  298. import FormArrayGroup from '../group/FormArrayGroup.vue';;
  299. import Col, { type ColProps } from '@/components/layout/grid/Col.vue';
  300. import Row from '@/components/layout/grid/Row.vue';
  301. import DynamicFormCheckEmpty from './DynamicFormCheckEmpty.vue';
  302. import DynamicFormItemContainerFuckMp from './DynamicFormItemContainerFuckMp.vue';
  303. /**
  304. * 动态表单条目包装组件,处理基础类型分支、数据传入、回调处理、事件传递。
  305. */
  306. export interface DynamicFormItemContainerProps {
  307. item: IDynamicFormItem;
  308. name: string;
  309. disabled?: boolean;
  310. model?: any;
  311. rawModel?: IDynamicFormObject;
  312. parent?: IDynamicFormItem;
  313. parentModel?: unknown;
  314. parentName?: string;
  315. colProps?: ColProps;
  316. isFirst?: boolean;
  317. isLast: boolean;
  318. }
  319. const props = withDefaults(defineProps<DynamicFormItemContainerProps>(), {
  320. isFirst: false,
  321. isLast: false,
  322. });
  323. const containerTypes = ['object', 'object-group', 'array-single','group-array','flat-simple','flat-group'];
  324. const isContainer = computed(() => props.item.type && containerTypes.includes(props.item.type));
  325. defineEmits([ 'update:model' ]);
  326. defineSlots<{
  327. formCeil(props: {
  328. data: FormCeilProps;
  329. }): any,
  330. arrayButtonAdd(props: {
  331. onClick: () => void;
  332. }): any,
  333. arrayButtons(props: {
  334. onDeleteClick: () => void;
  335. onUpClick: () => void;
  336. onDownClick: () => void;
  337. }): any,
  338. }>()
  339. const propsP = toRefs(props);
  340. const finalOptions = inject<Ref<IDynamicFormOptions>>('finalOptions');
  341. const globalParams = inject<Ref<IDynamicFormObject>>('globalParams');
  342. const formRef = inject<IDynamicFormRef>('formRef');
  343. const editmode = inject('editmode', false);
  344. const formName = inject('formName', '')
  345. //判断是否显示当前条目
  346. const isShow = computed(() => props.item.show === undefined || evaluateCallback(props.item.show));
  347. //处理默认值
  348. const finalModel = computed(() => {
  349. const val = props.model
  350. if (val !== undefined && val !== null)
  351. return props.model;
  352. if (props.item.defaultValue) {
  353. if (typeof props.item.defaultValue === 'function')
  354. return props.item.defaultValue();
  355. return props.item.defaultValue;
  356. }
  357. return null;
  358. });
  359. //处理回调函数
  360. function evaluateCallback<T>(val: T|IDynamicFormItemCallback<T>) {
  361. if (typeof val === 'object' && typeof (val as IDynamicFormItemCallback<T>).callback === 'function')
  362. return (val as IDynamicFormItemCallback<T>).callback(
  363. finalModel.value,
  364. propsP.rawModel.value,
  365. propsP.parentModel?.value,
  366. {
  367. item: propsP.item.value,
  368. form: formRef!,
  369. formGlobalParams: globalParams?.value || {},
  370. formRules: (finalOptions?.value.formRules ?? {}) as Record<string, Rules>,
  371. isFirst: propsP.isFirst.value,
  372. isLast: propsP.isLast.value,
  373. }
  374. );
  375. return val as T;
  376. }
  377. provide<IEvaluateCallback>('evaluateCallback', evaluateCallback);
  378. defineOptions({
  379. name: 'DynamicFormItemContainer',
  380. options: {
  381. virtualHost: true,
  382. styleIsolation: 'shared',
  383. }
  384. })
  385. </script>
  386. <style lang="scss">
  387. .dynamic-form-item-wrapper {
  388. position: relative;
  389. }
  390. </style>