index.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <template>
  2. <el-form @submit.prevent :model="formModel" v-bind="_options" ref="formRef">
  3. <el-row :gutter="5">
  4. <template v-for="(item, index) in fieldList" :key="index">
  5. <el-col :span="item.span || 24">
  6. <el-form-item :rules="item.rules" :title="item.label" :prop="[item.field]">
  7. <template #label>
  8. <el-space :size="1">
  9. <span>{{ `${item.label}` }}</span>
  10. <el-tooltip v-if="item?.tooltip" effect="dark" :content="item.tooltip" placement="top">
  11. <i :class="'iconfont icon-yiwen'"></i>
  12. </el-tooltip>
  13. </el-space>
  14. </template>
  15. <template #default>
  16. <!-- 单选框 -->
  17. <el-radio-group v-if="item.type === 'radio'" v-model="formModel[item.field]" :disabled="item.disabled">
  18. <el-radio
  19. :label="val[item.options?.valueKey || 'value']"
  20. v-for="val in item.options?.data"
  21. :key="val[item.options?.valueKey || 'value']"
  22. >
  23. {{ val[item.options?.labelKey || 'label'] }}
  24. </el-radio>
  25. </el-radio-group>
  26. <!-- 复选框 -->
  27. <el-checkbox-group v-else-if="item.type === 'checkbox'" v-model="formModel[item.field]" :disabled="item.disabled">
  28. <el-checkbox
  29. v-for="val in item.options?.data"
  30. :key="val[item.options?.valueKey || 'value']"
  31. :label="val[item.options?.valueKey || 'value']"
  32. >{{ val[item.options?.labelKey || 'label'] }}
  33. </el-checkbox>
  34. </el-checkbox-group>
  35. <!-- 下拉框 -->
  36. <el-select
  37. v-else-if="item.type === 'select'"
  38. v-model="formModel[item.field]"
  39. :placeholder="item.options?.placeholder || '请选择'"
  40. :clearable="item.clearable"
  41. :multiple="item.options?.multiple"
  42. :filterable="item.options?.filterable"
  43. :allow-create="item.options?.allowCreate"
  44. :disabled="item.disabled"
  45. >
  46. <el-option
  47. v-for="val in item.options?.data"
  48. :key="val[item.options?.valueKey || 'value']"
  49. :label="val[item.options?.labelKey || 'label']"
  50. :value="val[item.options?.valueKey || 'value']"
  51. />
  52. </el-select>
  53. <el-tree-select
  54. v-else-if="item.type === 'select-tree'"
  55. v-model="formModel[item.field]"
  56. :data="item.options?.data"
  57. :props="{
  58. label: `${item.options?.labelKey || 'label'}`,
  59. children: `${item.options?.children || 'children'}`
  60. }"
  61. :node-key="`${item.options?.valueKey || 'id'}`"
  62. placeholder="请选择归属部门"
  63. clearable
  64. check-strictly
  65. />
  66. <!-- 时间 -->
  67. <el-date-picker
  68. v-else-if="item.type === 'date-picker'"
  69. v-model="formModel[item.field]"
  70. :readonly="item.readonly"
  71. :type="item.options?.type ?? 'data'"
  72. :placeholder="item.placeholder || item.label"
  73. :disabled="item.disabled"
  74. :value-format="item.options?.valueFormat ?? 'YYYY-MM-DD HH:mm:ss'"
  75. :clearable="item.clearable"
  76. />
  77. <el-input-number
  78. v-else-if="item.type === 'input-number'"
  79. v-model="formModel[item.field]"
  80. :min="item.options?.min"
  81. :max="item.options?.max"
  82. controls-position="right"
  83. />
  84. <SelectIcon v-else-if="item.type === 'select-icon'" v-model:icon-value="formModel[item.field]" />
  85. <!-- 默认输入框 -->
  86. <el-input
  87. v-else
  88. v-model="formModel[item.field]"
  89. :readonly="item.readonly"
  90. :type="item.type ?? 'text'"
  91. :placeholder="item.placeholder || item.label"
  92. :disabled="item.disabled"
  93. :show-password="item.showPassword"
  94. :clearable="item.clearable"
  95. @keyup.enter="handleKeyUp(item.enterable)"
  96. />
  97. </template>
  98. </el-form-item>
  99. </el-col>
  100. </template>
  101. </el-row>
  102. <el-form-item v-if="_options.hasFooter">
  103. <slot name="buttons" :model="formModel" :form-ref="formRef">
  104. <el-button type="primary" @click="onSubmit(formRef)">{{ _options.submitButtonText }}</el-button>
  105. <el-button v-if="_options.showResetButton" type="info" @click="resetForm(formRef)">
  106. {{ _options.resetButtonText }}
  107. </el-button>
  108. <el-button v-if="_options.showCancelButton" @click="emit('cancel')">
  109. {{ _options.cancelButtonText }}
  110. </el-button>
  111. </slot>
  112. </el-form-item>
  113. </el-form>
  114. </template>
  115. <script setup lang="ts" name="ProFormOld">
  116. import type { FormInstance } from 'element-plus'
  117. import { ComputedRef, ref, computed, watch, unref } from 'vue'
  118. import SelectIcon from '@/components/SelectIcon/index.vue'
  119. // 父组件传递的值
  120. export interface ProFormProps {
  121. fieldList: Form.FieldItem[]
  122. model?: Record<Form.FieldItem['field'], Form.FieldItem['value']>
  123. options?: Form.Options
  124. }
  125. // 表单的数据
  126. const formModel = ref<Record<string, any>>({})
  127. const formRef = ref<FormInstance>()
  128. const props = defineProps<ProFormProps>()
  129. // 设置option默认值,如果传入自定义的配置则合并option配置项
  130. const _options: ComputedRef<Form.Options> = computed(() => {
  131. const option = {
  132. labelPosition: 'right',
  133. disabled: false,
  134. hasFooter: true,
  135. submitButtonText: '提交',
  136. resetButtonText: '重置',
  137. cancelButtonText: '取消'
  138. }
  139. return Object.assign(option, props?.options)
  140. })
  141. interface EmitEvent {
  142. (e: 'submit', params: any): void
  143. (e: 'reset'): void
  144. (e: 'cancel'): void
  145. }
  146. const enumMap = ref(new Map<string, { [key: string]: any }[]>())
  147. const setEnumMap = async ({ field, enum: enumValue }: Form.FieldItem) => {
  148. if (!enumValue) return
  149. // 如果当前 enumMap 存在相同的值 return
  150. if (enumMap.value.has(field!) && (typeof enumValue === 'function' || enumMap.value.get(field!) === enumValue)) return
  151. // 当前 enum 为静态数据,则直接存储到 enumMap
  152. if (typeof enumValue !== 'function') return enumMap.value.set(field!, unref(enumValue!))
  153. // 为了防止接口执行慢,而存储慢,导致重复请求,所以预先存储为[],接口返回后再二次存储
  154. enumMap.value.set(field!, [])
  155. // 当前 enum 为后台数据需要请求数据,则调用该请求接口,并存储到 enumMap
  156. let { data } = await enumValue()
  157. enumMap.value.set(field!, data)
  158. }
  159. // 处理枚举
  160. const handelEnum = (item: Form.FieldItem) => {
  161. let enumData = enumMap.value.get(item.field)
  162. if (!enumData) return []
  163. // 返回对象类型
  164. if (item.type === 'select-tree' && item.options?.labelKey && item.options?.valueKey) {
  165. enumData = enumData.map((el: { [key: string]: any }) => {
  166. return {
  167. ...el,
  168. label: el[item.options?.labelKey || 'label'],
  169. children: el[item.options?.children || 'children'] || []
  170. }
  171. })
  172. }
  173. return enumData
  174. }
  175. // 处理表单项需要的参数
  176. props.fieldList.forEach(async item => {
  177. await setEnumMap(item)
  178. if (item.options) item.options.data = handelEnum(item)
  179. })
  180. const emit = defineEmits<EmitEvent>()
  181. // 根据fieldList初始化model, 如果formModel有传值就用传递的model数据模型,否则就给上面声明的formModel设置相应的(key,value) [item.field], item.value是表单的默认值(选填)
  182. watch(
  183. () => props.model,
  184. () => {
  185. props.fieldList.map((item: Form.FieldItem) => {
  186. // 如果类型为checkbox,默认值需要设置一个空数组
  187. const value = item.type === 'checkbox' ? [] : ''
  188. props.model ? (formModel.value = props.model) : (formModel.value[item.field] = item.value || value)
  189. })
  190. },
  191. { immediate: true }
  192. )
  193. // 提交按钮
  194. const onSubmit = (formEl: FormInstance | undefined) => {
  195. if (!formEl) return
  196. formEl.validate(valid => {
  197. if (valid) {
  198. emit('submit', formModel.value)
  199. } else {
  200. return false
  201. }
  202. })
  203. }
  204. // 输入框回车事件
  205. const handleKeyUp = (enterable: boolean | undefined) => {
  206. if (!enterable) return
  207. onSubmit(formRef.value)
  208. }
  209. // 重置
  210. const resetForm = (formEl: FormInstance | undefined) => {
  211. if (!formEl) return
  212. formEl.resetFields()
  213. }
  214. defineExpose({
  215. formRef,
  216. resetForm,
  217. onSubmit
  218. })
  219. </script>