el-plus-crud 0.0.49 → 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -16
- package/dist/el-plus-crud.mjs +3801 -3606
- package/example/App.vue +1 -1
- package/lib/components/el-plus-form/ElPlusForm.vue +775 -771
- package/lib/components/el-plus-form/ElPlusFormDialog.vue +2 -4
- package/lib/components/el-plus-form/ElPlusFormGroup.vue +21 -1
- package/lib/components/el-plus-form/components/ElPlusFormArea.vue +62 -62
- package/lib/components/el-plus-form/components/ElPlusFormBtn.vue +103 -103
- package/lib/components/el-plus-form/components/ElPlusFormBtns.vue +140 -134
- package/lib/components/el-plus-form/components/ElPlusFormCascader.vue +64 -64
- package/lib/components/el-plus-form/components/ElPlusFormCascaderPanel.vue +71 -54
- package/lib/components/el-plus-form/components/ElPlusFormCheckbox.vue +76 -45
- package/lib/components/el-plus-form/components/ElPlusFormCheckboxButton.vue +45 -45
- package/lib/components/el-plus-form/components/ElPlusFormColor.vue +39 -39
- package/lib/components/el-plus-form/components/ElPlusFormDate.vue +40 -40
- package/lib/components/el-plus-form/components/ElPlusFormDaterange.vue +47 -47
- package/lib/components/el-plus-form/components/ElPlusFormDatetime.vue +41 -41
- package/lib/components/el-plus-form/components/ElPlusFormDatetimerange.vue +47 -47
- package/lib/components/el-plus-form/components/ElPlusFormImage.vue +4 -0
- package/lib/components/el-plus-form/components/ElPlusFormInput.vue +62 -62
- package/lib/components/el-plus-form/components/ElPlusFormLink.vue +282 -282
- package/lib/components/el-plus-form/components/ElPlusFormLkuser.vue +490 -490
- package/lib/components/el-plus-form/components/ElPlusFormNbinput.vue +54 -54
- package/lib/components/el-plus-form/components/ElPlusFormNumber.vue +147 -147
- package/lib/components/el-plus-form/components/ElPlusFormPassword.vue +44 -44
- package/lib/components/el-plus-form/components/ElPlusFormQuickInput.vue +96 -96
- package/lib/components/el-plus-form/components/ElPlusFormRadio.vue +68 -68
- package/lib/components/el-plus-form/components/ElPlusFormRate.vue +54 -54
- package/lib/components/el-plus-form/components/ElPlusFormSelect.vue +162 -162
- package/lib/components/el-plus-form/components/ElPlusFormSlider.vue +39 -39
- package/lib/components/el-plus-form/components/ElPlusFormSwitch.vue +69 -39
- package/lib/components/el-plus-form/components/ElPlusFormTextarea.vue +50 -50
- package/lib/components/el-plus-form/components/ElPlusFormTransfer.vue +45 -45
- package/lib/components/el-plus-form/components/ElPlusFormTree.vue +77 -77
- package/lib/components/el-plus-form/components/ElPlusFormTreeSelect.vue +60 -60
- package/lib/components/el-plus-form/components/ElPlusFormUpbtn.vue +144 -0
- package/lib/components/el-plus-form/components/ElPlusFormUpload.vue +369 -369
- package/lib/components/el-plus-form/mixins/index.ts +2 -2
- package/lib/components/el-plus-table/components/columnItem.vue +7 -0
- package/lib/components/el-plus-table/components/header.vue +283 -260
- package/lib/components-list.ts +2 -0
- package/package.json +1 -1
- package/types/formList.d.ts +447 -446
|
@@ -1,771 +1,775 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div :style="formLayout">
|
|
3
|
-
<slot name="top" :formData="props.modelValue"></slot>
|
|
4
|
-
<div :style="{ display: 'flex', justifyContent: isDialog ? 'center' : '' }">
|
|
5
|
-
<el-form class="el-plus-form-panel" ref="refElPlusForm" :model="props.modelValue" @submit.prevent="handleSubmitForm" v-bind="computedFormAttrs">
|
|
6
|
-
<el-row :gutter="10" v-for="(formList, index) in attrMapToTableList" :key="index" :style="{ marginRight: isTable ? '20px' : 0 }">
|
|
7
|
-
<el-col v-for="(formItem, y) in formList" :key="index + '-' + y + '-' + formItem.field" :xs="24" :sm="24" :md="formItem.colspan && formItem.colspan >= column ? 24 : column >= 2 ? 12 : 24" :lg="formItem.colspan && formItem.colspan >= column ? 24 : Math.floor((24 / column) * (formItem.colspan || 1))" :xl="formItem.colspan && formItem.colspan >= column ? 24 : Math.floor((24 / column) * (formItem.colspan || 1))">
|
|
8
|
-
<div v-if="formItem._vif" class="el-plus-form-column-panel" :style="{ 'justify-content': isTable ? 'flex-end' : 'flex-start' }">
|
|
9
|
-
<el-form-item style="min-height: 40px; display: flex" :label="showLabel && formItem.showLabel !== false ? formItem._label : null" :label-width="formItem.labelWidth || labelWidth || (isDialog ? '100px' : '120px')" :prop="formItem.field" :style="{ width: formItem._attrs?.width || formItem.width || (isTable ? '150px' : '100%') }">
|
|
10
|
-
<component style="min-width: 80px; width: 100%" :is="formItem._type" :formData="props.modelValue" :disabled="formItem._disabled ?? disabled ?? false" :readonly="readonly ?? false" v-bind="formItem._attrs" :desc="formItem" :ref="setComponentRef" :field="formItem.field" v-model="props.modelValue[formItem.field || '']" :isTable="isTable" @validateThis="() => handelValidateThis(formItem.field || '')"></component>
|
|
11
|
-
<div class="el-plus-form-tip" v-if="formItem._tip" v-html="formItem._tip" />
|
|
12
|
-
</el-form-item>
|
|
13
|
-
</div>
|
|
14
|
-
</el-col>
|
|
15
|
-
</el-row>
|
|
16
|
-
<slot name="row"></slot>
|
|
17
|
-
</el-form>
|
|
18
|
-
</div>
|
|
19
|
-
<slot name="default"></slot>
|
|
20
|
-
<el-form>
|
|
21
|
-
<slot :data="props.modelValue" name="form-btn">
|
|
22
|
-
<div v-if="btnList && btnList.length > 0" style="display: flex; justify-content: center">
|
|
23
|
-
<template v-for="(btn, index) of btnList" :key="index">
|
|
24
|
-
<ElPlusFormBtn v-bind="btn"></ElPlusFormBtn>
|
|
25
|
-
</template>
|
|
26
|
-
</div>
|
|
27
|
-
</slot>
|
|
28
|
-
<slot name="bottom" :formData="props.modelValue"></slot>
|
|
29
|
-
</el-form>
|
|
30
|
-
<slot name="form-footer" :formData="props.modelValue"></slot>
|
|
31
|
-
</div>
|
|
32
|
-
</template>
|
|
33
|
-
<script lang="ts">
|
|
34
|
-
export default {
|
|
35
|
-
name: 'ElPlusForm',
|
|
36
|
-
inheritAttrs: false,
|
|
37
|
-
customOptions: {}
|
|
38
|
-
}
|
|
39
|
-
</script>
|
|
40
|
-
<script lang="ts" setup>
|
|
41
|
-
import { ref, computed, useAttrs, nextTick, onMounted, watch, inject } from 'vue'
|
|
42
|
-
import { throttle } from 'lodash'
|
|
43
|
-
import { castArray, isMobile } from './util'
|
|
44
|
-
import * as validates from './util/validate'
|
|
45
|
-
import { typeList } from './components/index'
|
|
46
|
-
import ElPlusFormBtn from './components/ElPlusFormBtn.vue'
|
|
47
|
-
import { cloneDeep } from 'lodash'
|
|
48
|
-
|
|
49
|
-
// IFormProps定义
|
|
50
|
-
export interface IFormProps {
|
|
51
|
-
// 表单描述
|
|
52
|
-
formDesc?: IFormDesc | null
|
|
53
|
-
// 表单数据
|
|
54
|
-
modelValue?: { [key: string]: any } | {}
|
|
55
|
-
// 表单自身属性
|
|
56
|
-
formAttrs?: { [key: string]: any }
|
|
57
|
-
// 校检规则
|
|
58
|
-
rules?: { [key: string]: any } | null
|
|
59
|
-
// 提交状态
|
|
60
|
-
isLoading?: boolean
|
|
61
|
-
// 提交函数
|
|
62
|
-
requestFn?: Function | null
|
|
63
|
-
// 表单更新的函数
|
|
64
|
-
updateFn?: Function | null
|
|
65
|
-
// 是否显示底部按钮组
|
|
66
|
-
showBtns?: boolean
|
|
67
|
-
// 是否显示submit按钮
|
|
68
|
-
showSubmit?: boolean
|
|
69
|
-
// 提交按钮文本
|
|
70
|
-
submitBtnText?: string
|
|
71
|
-
// 是否显示 cancel 取消按钮
|
|
72
|
-
// 默认值: isDialog = true 时, 默认值为 true
|
|
73
|
-
showCancel?: boolean
|
|
74
|
-
// 取消按钮文本
|
|
75
|
-
cancelBtnText?: string
|
|
76
|
-
// 是否显示重置按钮
|
|
77
|
-
showReset?: boolean
|
|
78
|
-
// 重置按钮文本
|
|
79
|
-
resetBtnText?: string
|
|
80
|
-
// 是否显示label
|
|
81
|
-
showLabel?: boolean
|
|
82
|
-
// label宽度
|
|
83
|
-
labelWidth?: number | string
|
|
84
|
-
// 全局禁用表单
|
|
85
|
-
disabled?: boolean
|
|
86
|
-
// 全局的readonly
|
|
87
|
-
readonly?: boolean
|
|
88
|
-
// 是否为弹窗
|
|
89
|
-
isDialog?: boolean
|
|
90
|
-
// options 的请求方法
|
|
91
|
-
optionsFn?: Function | null
|
|
92
|
-
// 表单全局size
|
|
93
|
-
size?: string
|
|
94
|
-
// 表单列 默认1
|
|
95
|
-
column?: number
|
|
96
|
-
// 是否是列表头部的表单
|
|
97
|
-
isTable?: boolean
|
|
98
|
-
// 唯一标识符。默认为id
|
|
99
|
-
idKey?: string
|
|
100
|
-
// 最大宽度
|
|
101
|
-
maxWidth?: string
|
|
102
|
-
// 比如 beforeValidate, beforeRequest, success, requestError, requestEnd
|
|
103
|
-
// 其他钩子 直接放到attrs里面去了
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const defaultConf = inject('defaultConf') as ICRUDConfig
|
|
107
|
-
// 定义全局的format对象
|
|
108
|
-
const elPlusFormFormat = inject('format') as any
|
|
109
|
-
|
|
110
|
-
const emits = defineEmits(['request', 'reset', 'cancel'])
|
|
111
|
-
const props = withDefaults(defineProps<IFormProps>(), {
|
|
112
|
-
// 表单描述
|
|
113
|
-
formDesc: null,
|
|
114
|
-
// 表单数据
|
|
115
|
-
modelValue: () => {
|
|
116
|
-
return {}
|
|
117
|
-
},
|
|
118
|
-
// 表单自身属性
|
|
119
|
-
formAttrs: () => {
|
|
120
|
-
return {}
|
|
121
|
-
},
|
|
122
|
-
// 校检规则
|
|
123
|
-
rules: null,
|
|
124
|
-
// 提交状态
|
|
125
|
-
isLoading: false,
|
|
126
|
-
// 提交函数
|
|
127
|
-
requestFn: null,
|
|
128
|
-
// 表单更新的函数
|
|
129
|
-
updateFn: null,
|
|
130
|
-
// 是否显示按钮
|
|
131
|
-
showBtns: true,
|
|
132
|
-
// 是否显示submit按钮
|
|
133
|
-
showSubmit: true,
|
|
134
|
-
// 提交按钮文本
|
|
135
|
-
submitBtnText: '提交',
|
|
136
|
-
// 是否显示 cancel 取消按钮
|
|
137
|
-
// 默认值: isDialog = true 时, 默认值为 true
|
|
138
|
-
showCancel: false,
|
|
139
|
-
// 取消按钮
|
|
140
|
-
cancelBtnText: '取消',
|
|
141
|
-
// 是否显示重置按钮
|
|
142
|
-
showReset: true,
|
|
143
|
-
// 重置按钮
|
|
144
|
-
resetBtnText: '重置',
|
|
145
|
-
// 是否显示标签
|
|
146
|
-
showLabel: true,
|
|
147
|
-
// 标签宽度
|
|
148
|
-
labelWidth: '',
|
|
149
|
-
// 全局禁用表单
|
|
150
|
-
disabled: false,
|
|
151
|
-
// 全局的readonly
|
|
152
|
-
readonly: false,
|
|
153
|
-
// 是否为弹窗
|
|
154
|
-
isDialog: false,
|
|
155
|
-
// options 的请求方法
|
|
156
|
-
optionsFn: null,
|
|
157
|
-
// 表单全局size
|
|
158
|
-
size: 'small',
|
|
159
|
-
// 表单列 默认1
|
|
160
|
-
column: 1,
|
|
161
|
-
// 是否是列表头部的表单
|
|
162
|
-
isTable: false,
|
|
163
|
-
// 唯一标识符。默认为id
|
|
164
|
-
idKey: 'id'
|
|
165
|
-
// 其他钩子 直接放到attrs里面去了
|
|
166
|
-
// 比如 beforeValidate, beforeRequest, success, requestError, requestEnd
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
const refElPlusForm = ref()
|
|
170
|
-
|
|
171
|
-
// 是否开启全局监听
|
|
172
|
-
const isOpenListen = ref(false)
|
|
173
|
-
|
|
174
|
-
const tempAttr = useAttrs()
|
|
175
|
-
|
|
176
|
-
// 每个表单项的ref
|
|
177
|
-
const fieldRefs_ = ref([] as Array<any>)
|
|
178
|
-
|
|
179
|
-
// loading
|
|
180
|
-
const innerIsLoading = ref(false)
|
|
181
|
-
|
|
182
|
-
let oldFormData = null as any
|
|
183
|
-
|
|
184
|
-
const size = computed(() => props.size || defaultConf.size)
|
|
185
|
-
// 组件名称列表
|
|
186
|
-
const compTypeList = [...typeList, ...(defaultConf.form?.comList || [])]
|
|
187
|
-
|
|
188
|
-
// 整体的布局方式
|
|
189
|
-
const formLayout = computed(() => ({ display: 'flex', flexDirection: props.isTable ? 'row' : 'column' })) as any
|
|
190
|
-
|
|
191
|
-
// 表单的Attrs
|
|
192
|
-
const computedFormAttrs = computed(() => {
|
|
193
|
-
return {
|
|
194
|
-
scrollToError: true,
|
|
195
|
-
...props.formAttrs,
|
|
196
|
-
labelWidth: props.labelWidth === 'auto' ? (props.isDialog ? '100px' : '120px') : parseInt(props.labelWidth + '') + 'px',
|
|
197
|
-
// validateOnRuleChange: false,
|
|
198
|
-
disabled: props.disabled || innerIsLoading.value,
|
|
199
|
-
rules: computedRules,
|
|
200
|
-
labelPosition: isMobile() ? 'top' : 'right',
|
|
201
|
-
style: {
|
|
202
|
-
width: props.maxWidth || (props.isTable ? '100%' : props.isDialog ? '80%' : '1000px'),
|
|
203
|
-
paddingRight: props.isTable ? '0' : '20px'
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
// 合并校验规则
|
|
209
|
-
const computedRules = computed(() => {
|
|
210
|
-
// 首先拿到表单总体传入的rules
|
|
211
|
-
const tempRules = props.rules || []
|
|
212
|
-
// 遍历属性描述对象,看看里面有没有校验规则
|
|
213
|
-
if (props.formDesc) {
|
|
214
|
-
Object.keys(props.formDesc).map((field: any) => {
|
|
215
|
-
if (!tempRules[field]) tempRules[field] = []
|
|
216
|
-
if (props.formDesc) {
|
|
217
|
-
if (props.formDesc[field].rules) {
|
|
218
|
-
if (typeof props.formDesc[field].rules === 'string') {
|
|
219
|
-
// string的话,就行默认校验规则中取
|
|
220
|
-
tempRules[field].push(...(validates as any)[props.formDesc[field].rules as string])
|
|
221
|
-
} else {
|
|
222
|
-
// 查看总体规则中是否已经含有了该属性的校验
|
|
223
|
-
castArray(props.formDesc[field].rules).map((item: any) => {
|
|
224
|
-
tempRules[field].push(item)
|
|
225
|
-
})
|
|
226
|
-
}
|
|
227
|
-
} else if (props.formDesc[field].required || props.formDesc[field].require) {
|
|
228
|
-
// 如果直接指定 required || require,手动添加校验信息
|
|
229
|
-
//
|
|
230
|
-
let rules = 'notAllBlank'
|
|
231
|
-
switch (props.formDesc[field].type) {
|
|
232
|
-
case 'upload':
|
|
233
|
-
case 'select':
|
|
234
|
-
case 'password':
|
|
235
|
-
case 'textarea':
|
|
236
|
-
case 'editor':
|
|
237
|
-
rules = props.formDesc[field].type || ''
|
|
238
|
-
break
|
|
239
|
-
case 'cascader':
|
|
240
|
-
case 'tselect':
|
|
241
|
-
case 'linkuser':
|
|
242
|
-
case 'radio':
|
|
243
|
-
rules = 'select'
|
|
244
|
-
break
|
|
245
|
-
}
|
|
246
|
-
tempRules[field].push(...(validates as any)[rules])
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
})
|
|
250
|
-
}
|
|
251
|
-
return tempRules
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
// 属性对象转数组
|
|
255
|
-
const attrMapToTableList = computed(() => {
|
|
256
|
-
const formLayoutRows = [] as Array<Array<IFormDescItem>>
|
|
257
|
-
if (props.formDesc) {
|
|
258
|
-
let tempData = [] as Array<IFormDescItem>
|
|
259
|
-
for (const key in props.formDesc) {
|
|
260
|
-
tempData.push({ ...props.formDesc[key], field: key })
|
|
261
|
-
}
|
|
262
|
-
// 这里处理一下layout的布局-渲染
|
|
263
|
-
let rowItemList = [] as Array<IFormDescItem>
|
|
264
|
-
let tempCount = 0
|
|
265
|
-
tempData.map((item) => {
|
|
266
|
-
if (item._vif) {
|
|
267
|
-
rowItemList.push(item)
|
|
268
|
-
tempCount++
|
|
269
|
-
if (item.colspan) {
|
|
270
|
-
tempCount += item.colspan - 1
|
|
271
|
-
}
|
|
272
|
-
if (tempCount >= props.column) {
|
|
273
|
-
// 一行结束
|
|
274
|
-
formLayoutRows.push(rowItemList)
|
|
275
|
-
rowItemList = [] as Array<IFormDescItem>
|
|
276
|
-
tempCount = 0
|
|
277
|
-
return
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
})
|
|
281
|
-
if (rowItemList.length > 0) {
|
|
282
|
-
formLayoutRows.push(rowItemList)
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return formLayoutRows
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
// 整体初始化属性
|
|
289
|
-
const initFormAttrs = throttle(() => {
|
|
290
|
-
if (props.formDesc) {
|
|
291
|
-
Object.keys(props.formDesc).forEach((field) => {
|
|
292
|
-
if (props.formDesc) {
|
|
293
|
-
const formItem = props.formDesc[field]
|
|
294
|
-
if (formItem && formItem.type) {
|
|
295
|
-
// 设置 _type
|
|
296
|
-
formItem._type = compTypeList.includes(formItem.type.toLowerCase()) ? 'el-plus-form-' + formItem.type : formItem.type
|
|
297
|
-
// 触发 v-if 显示 / 隐藏 设置_vif
|
|
298
|
-
formItem._vif = handelKeyValue(formItem, 'vif', field, !formItem.isBlank ?? true)
|
|
299
|
-
// 触发 disabled 禁用 / 启用 设置_disabled
|
|
300
|
-
formItem._disabled = handelKeyValue(formItem, 'disabled', field, props.disabled ?? false)
|
|
301
|
-
// 动态属性 attrs
|
|
302
|
-
const tempAttr = {} as any
|
|
303
|
-
// if ((typeof formItem.attrs === 'object' && formItem.attrs?.options) || formItem.options) {
|
|
304
|
-
// tempAttr.options = (formItem.attrs as any)?.options || formItem.options
|
|
305
|
-
// }
|
|
306
|
-
formItem._attrs = Object.assign({}, handelKeyValue(formItem, 'attrs', field), tempAttr)
|
|
307
|
-
// 动态options
|
|
308
|
-
// formItem._options = handelKeyValue(formItem, 'options', field)
|
|
309
|
-
// 动态 _label
|
|
310
|
-
formItem._label = handelKeyValue(formItem, 'label', field)
|
|
311
|
-
// 动态 prop
|
|
312
|
-
// formItem._prop = handelKeyValue(formItem, 'prop', field);
|
|
313
|
-
// 动态 _tip
|
|
314
|
-
formItem._tip = handelKeyValue(formItem, 'tip', field)
|
|
315
|
-
// 单独处理下上传
|
|
316
|
-
if (!formItem._tip && !formItem.noTip && formItem.type === 'upload') {
|
|
317
|
-
formItem._tip = `最多上传${formItem.multiple ? formItem.limit || 20 : 1}${formItem.upType === 'file' ? '个文件' : '张图片'}`
|
|
318
|
-
}
|
|
319
|
-
// 这里初始化一下默认值
|
|
320
|
-
if (formItem.default !== undefined && formItem.default !== null && props.modelValue[field] === undefined) {
|
|
321
|
-
props.modelValue[field] = formItem.default
|
|
322
|
-
}
|
|
323
|
-
// 这里初始化一下默认选中项
|
|
324
|
-
if (formItem.defaultItem !== undefined && formItem.defaultItem !== null && props.modelValue[field] === undefined) {
|
|
325
|
-
props.modelValue[field] = formItem.defaultItem.value
|
|
326
|
-
}
|
|
327
|
-
// 这里格式化一下数据
|
|
328
|
-
// if (formItem.format) {
|
|
329
|
-
// if (typeof formItem.format === 'string') {
|
|
330
|
-
// props.modelValue[field] = elPlusFormFormat[formItem.format](props.modelValue[field], props.modelValue)
|
|
331
|
-
// } else if (typeof formItem.format === 'function') {
|
|
332
|
-
// props.modelValue[field] = (formItem as any).format(props.modelValue[field], props.modelValue)
|
|
333
|
-
// } else {
|
|
334
|
-
// // console.log('未知的格式化类型:', formItem.format)
|
|
335
|
-
// }
|
|
336
|
-
// }
|
|
337
|
-
} else if (formItem && formItem.isBlank) {
|
|
338
|
-
// 触发 v-if 显示 / 隐藏 设置_vif
|
|
339
|
-
formItem._vif = handelKeyValue(formItem, 'vif', '', true)
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
})
|
|
343
|
-
}
|
|
344
|
-
}, 500)
|
|
345
|
-
|
|
346
|
-
// 表单底部按钮
|
|
347
|
-
const btnList = computed(() => {
|
|
348
|
-
let btnList_ = [] as any[]
|
|
349
|
-
if (!props.showBtns) {
|
|
350
|
-
return btnList_
|
|
351
|
-
}
|
|
352
|
-
// 取消按钮
|
|
353
|
-
if (props.showCancel) {
|
|
354
|
-
btnList_.push({
|
|
355
|
-
field: '_reset_btn',
|
|
356
|
-
desc: {
|
|
357
|
-
label: props.cancelBtnText || '取消',
|
|
358
|
-
size: size.value,
|
|
359
|
-
disabled: innerIsLoading.value,
|
|
360
|
-
on: { click: () => emits('cancel') }
|
|
361
|
-
}
|
|
362
|
-
})
|
|
363
|
-
}
|
|
364
|
-
// 重置按钮
|
|
365
|
-
if (props.showReset) {
|
|
366
|
-
btnList_.push({
|
|
367
|
-
field: '_reset_btn',
|
|
368
|
-
desc: {
|
|
369
|
-
label: props.resetBtnText || '重置',
|
|
370
|
-
confirm: `确定要${props.resetBtnText || '重置'}?`,
|
|
371
|
-
size: size.value,
|
|
372
|
-
disabled: innerIsLoading.value,
|
|
373
|
-
on: { click: reset }
|
|
374
|
-
}
|
|
375
|
-
})
|
|
376
|
-
}
|
|
377
|
-
// 提交按钮
|
|
378
|
-
if (props.showSubmit) {
|
|
379
|
-
btnList_.push({
|
|
380
|
-
field: '_reset_btn',
|
|
381
|
-
desc: {
|
|
382
|
-
label: props.submitBtnText || '提交',
|
|
383
|
-
size: size.value,
|
|
384
|
-
type: 'primary',
|
|
385
|
-
loading: props.isLoading || innerIsLoading.value,
|
|
386
|
-
on: { click: handleSubmitForm }
|
|
387
|
-
}
|
|
388
|
-
})
|
|
389
|
-
}
|
|
390
|
-
return btnList_
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
// 处理属性
|
|
394
|
-
const handelKeyValue = (formItem: IFormDescItem, key: string, field: string, defVal: number | boolean | string | null = null) => {
|
|
395
|
-
if (typeof formItem[key] === 'function') {
|
|
396
|
-
// 如果有方法类型的判断,则需要启用动态监测
|
|
397
|
-
isOpenListen.value = true
|
|
398
|
-
return formItem[key](props.modelValue, props.modelValue[field])
|
|
399
|
-
} else if (typeof formItem[key] === 'boolean') {
|
|
400
|
-
return formItem[key] ?? false
|
|
401
|
-
} else if (typeof formItem[key] === 'string') {
|
|
402
|
-
return formItem[key] ?? ''
|
|
403
|
-
} else {
|
|
404
|
-
return formItem[key] ?? defVal
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// 验证表单
|
|
409
|
-
const validateForm = () => {
|
|
410
|
-
return new Promise((resolve: any, reject: any) => {
|
|
411
|
-
if (computedRules.value) {
|
|
412
|
-
// 当传递了验证规则
|
|
413
|
-
refElPlusForm.value.validate((valid: Boolean, invalidFields: any) => {
|
|
414
|
-
if (valid) {
|
|
415
|
-
// 验证通过
|
|
416
|
-
resolve()
|
|
417
|
-
} else {
|
|
418
|
-
// 显示错误
|
|
419
|
-
reject(invalidFields)
|
|
420
|
-
}
|
|
421
|
-
})
|
|
422
|
-
} else {
|
|
423
|
-
resolve()
|
|
424
|
-
}
|
|
425
|
-
})
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// 设置子组件的ref-重置form的时候需要用到
|
|
429
|
-
const setComponentRef = (el: any) => {
|
|
430
|
-
if (!el) return
|
|
431
|
-
if (fieldRefs_.value.filter((item: any) => item.field === el.field).length <= 0) {
|
|
432
|
-
fieldRefs_.value.push(el)
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
* 处理单个表单值
|
|
438
|
-
* @param val
|
|
439
|
-
*/
|
|
440
|
-
const handelValToForm = (desc: IFormDescItem, field: string, val: any) => {
|
|
441
|
-
const result = {} as { [key: string]: any }
|
|
442
|
-
if (!desc) return { [field]: val }
|
|
443
|
-
if (!desc._vif || val === undefined || val === null) return result
|
|
444
|
-
if (desc.type === 'category') {
|
|
445
|
-
if (val === null) val = []
|
|
446
|
-
// 如果是直接显示结果
|
|
447
|
-
if (desc.checkStrictly === true) {
|
|
448
|
-
result.categoryId = val[2] ?? val[1] ?? val[0] ?? ''
|
|
449
|
-
} else {
|
|
450
|
-
for (let i = 0; i < 3; i++) {
|
|
451
|
-
result['categoryId' + (i + 1)] = val[i] ?? ''
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
} else if (desc.type === 'area') {
|
|
455
|
-
if (val === null) val = [null, null, null, null]
|
|
456
|
-
const [pid, cid, zid, sid] = val
|
|
457
|
-
if (desc.checkStrictly) {
|
|
458
|
-
result[field] = sid || zid || cid || pid || null
|
|
459
|
-
} else {
|
|
460
|
-
result.provinceId = pid || -1
|
|
461
|
-
result.cityId = cid || -1
|
|
462
|
-
result.zoneId = zid || -1
|
|
463
|
-
result.streetId = sid || -1
|
|
464
|
-
}
|
|
465
|
-
} else if (desc.type === 'daterange') {
|
|
466
|
-
if (val && val.length === 2) {
|
|
467
|
-
result.startTime = val[0]
|
|
468
|
-
if (typeof val[1] === 'string') {
|
|
469
|
-
result.endTime = new Date(val[1]).getTime()
|
|
470
|
-
} else {
|
|
471
|
-
result.endTime = val[1]
|
|
472
|
-
}
|
|
473
|
-
result.endTime = result.endTime + (24 * 60 * 60 - 1) * 1000
|
|
474
|
-
// 再处理一下时间戳
|
|
475
|
-
result.startTime = elPlusFormFormat.time(result.startTime, 3)
|
|
476
|
-
result.endTime = elPlusFormFormat.time(result.endTime, 3)
|
|
477
|
-
}
|
|
478
|
-
} else if (desc.type === 'datetimerange') {
|
|
479
|
-
if (val && val.length === 2) {
|
|
480
|
-
// 处理一下时间戳
|
|
481
|
-
result.startTime = elPlusFormFormat.time(val[0], 3)
|
|
482
|
-
result.endTime = elPlusFormFormat.time(val[1], 3)
|
|
483
|
-
}
|
|
484
|
-
} else if (desc.type === 'linkuser') {
|
|
485
|
-
const [userIds, deptIds, userNames, deptNames] = val
|
|
486
|
-
result.userIds = userIds
|
|
487
|
-
result.deptIds = deptIds
|
|
488
|
-
result.userNames = userNames
|
|
489
|
-
result.deptNames = deptNames
|
|
490
|
-
} else {
|
|
491
|
-
// 这里处理下通用表单的数据类型
|
|
492
|
-
switch (desc.type) {
|
|
493
|
-
case 'checkbox':
|
|
494
|
-
if (Array.isArray(val)) {
|
|
495
|
-
val = val.join(',')
|
|
496
|
-
}
|
|
497
|
-
break
|
|
498
|
-
}
|
|
499
|
-
result[field] = val
|
|
500
|
-
}
|
|
501
|
-
return result
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* 获取处理过后的表单数据
|
|
506
|
-
*/
|
|
507
|
-
const getFormData = () => {
|
|
508
|
-
const tempData = {} as { [key: string]: any }
|
|
509
|
-
if (props.formDesc) {
|
|
510
|
-
// 循环获取表单数据
|
|
511
|
-
Object.keys(props.modelValue).map((key) => {
|
|
512
|
-
if (['provinceId', 'cityId', 'zoneId', 'streetId'].indexOf(key) >= 0) return
|
|
513
|
-
if (props.formDesc) {
|
|
514
|
-
Object.assign(tempData, handelValToForm(props.formDesc[key], key, props.modelValue[key]))
|
|
515
|
-
}
|
|
516
|
-
})
|
|
517
|
-
}
|
|
518
|
-
return tempData
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* 刷新验证码图片
|
|
523
|
-
*/
|
|
524
|
-
const changeValidImg = () => {
|
|
525
|
-
fieldRefs_.value.map((item) => {
|
|
526
|
-
if (item.CID) {
|
|
527
|
-
item.changeValidImg()
|
|
528
|
-
}
|
|
529
|
-
})
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
/**
|
|
533
|
-
* 提交表单
|
|
534
|
-
*/
|
|
535
|
-
const handleSubmitForm = async () => {
|
|
536
|
-
let postData = getFormData()
|
|
537
|
-
try {
|
|
538
|
-
// 校验表单事件处理
|
|
539
|
-
if (tempAttr.beforeValidate) {
|
|
540
|
-
const isPass = await (tempAttr.beforeValidate as Function)(postData)
|
|
541
|
-
if (isPass === false) return
|
|
542
|
-
}
|
|
543
|
-
await validateForm()
|
|
544
|
-
for (const field in postData) {
|
|
545
|
-
// 去除下划线开头的参数
|
|
546
|
-
if (field.indexOf('_') === 0) {
|
|
547
|
-
delete postData[field]
|
|
548
|
-
continue
|
|
549
|
-
}
|
|
550
|
-
if (props.formDesc) {
|
|
551
|
-
const formItem = props.formDesc[field]
|
|
552
|
-
// valueFormatter的处理
|
|
553
|
-
if (formItem && formItem.valueFormat) {
|
|
554
|
-
postData[field] = formItem.valueFormat(postData[field], postData)
|
|
555
|
-
}
|
|
556
|
-
// 处理带有true或者false值
|
|
557
|
-
if (postData[field] === true || postData[field] === false) {
|
|
558
|
-
postData[field] = +postData[field]
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// 提交数据前的通知
|
|
564
|
-
if (tempAttr.beforeRequest) {
|
|
565
|
-
const beforeRequestData = await (tempAttr.beforeRequest as Function)(postData)
|
|
566
|
-
if (beforeRequestData === false) return
|
|
567
|
-
if (typeof beforeRequestData === 'object') {
|
|
568
|
-
postData = beforeRequestData
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
if (props.requestFn) {
|
|
572
|
-
// 在内部调用请求
|
|
573
|
-
if (innerIsLoading.value) return
|
|
574
|
-
innerIsLoading.value = true
|
|
575
|
-
try {
|
|
576
|
-
let response = {}
|
|
577
|
-
if (props.updateFn && postData && (postData as any)[props.idKey]) {
|
|
578
|
-
response = await props.updateFn(postData)
|
|
579
|
-
} else {
|
|
580
|
-
response = await props.requestFn(postData)
|
|
581
|
-
}
|
|
582
|
-
nextTick(() => {
|
|
583
|
-
if (tempAttr.success && typeof tempAttr.success === 'function') {
|
|
584
|
-
tempAttr.success({
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
if (
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
.el-form--inline .el-form-
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
.el-
|
|
745
|
-
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
.el-plus-form-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div :style="formLayout">
|
|
3
|
+
<slot name="top" :formData="props.modelValue"></slot>
|
|
4
|
+
<div :style="{ display: 'flex', justifyContent: isDialog ? 'center' : '' }">
|
|
5
|
+
<el-form class="el-plus-form-panel" ref="refElPlusForm" :model="props.modelValue" @submit.prevent="handleSubmitForm" v-bind="computedFormAttrs">
|
|
6
|
+
<el-row :gutter="10" v-for="(formList, index) in attrMapToTableList" :key="index" :style="{ marginRight: isTable ? '20px' : 0 }">
|
|
7
|
+
<el-col v-for="(formItem, y) in formList" :key="index + '-' + y + '-' + formItem.field" :xs="24" :sm="24" :md="formItem.colspan && formItem.colspan >= column ? 24 : column >= 2 ? 12 : 24" :lg="formItem.colspan && formItem.colspan >= column ? 24 : Math.floor((24 / column) * (formItem.colspan || 1))" :xl="formItem.colspan && formItem.colspan >= column ? 24 : Math.floor((24 / column) * (formItem.colspan || 1))">
|
|
8
|
+
<div v-if="formItem._vif" class="el-plus-form-column-panel" :style="{ 'justify-content': isTable ? 'flex-end' : 'flex-start' }">
|
|
9
|
+
<el-form-item style="min-height: 40px; display: flex" :label="showLabel && formItem.showLabel !== false ? formItem._label : null" :label-width="formItem.labelWidth || labelWidth || (isDialog ? '100px' : '120px')" :prop="formItem.field" :style="{ width: formItem._attrs?.width || formItem.width || (isTable ? '150px' : '100%') }">
|
|
10
|
+
<component style="min-width: 80px; width: 100%" :is="formItem._type" :formData="props.modelValue" :disabled="formItem._disabled ?? disabled ?? false" :readonly="readonly ?? false" v-bind="formItem._attrs" :desc="formItem" :ref="setComponentRef" :field="formItem.field" v-model="props.modelValue[formItem.field || '']" :isTable="isTable" @validateThis="() => handelValidateThis(formItem.field || '')"></component>
|
|
11
|
+
<div class="el-plus-form-tip" v-if="formItem._tip" v-html="formItem._tip" />
|
|
12
|
+
</el-form-item>
|
|
13
|
+
</div>
|
|
14
|
+
</el-col>
|
|
15
|
+
</el-row>
|
|
16
|
+
<slot name="row"></slot>
|
|
17
|
+
</el-form>
|
|
18
|
+
</div>
|
|
19
|
+
<slot name="default"></slot>
|
|
20
|
+
<el-form>
|
|
21
|
+
<slot :data="props.modelValue" name="form-btn">
|
|
22
|
+
<div v-if="btnList && btnList.length > 0" style="display: flex; justify-content: center">
|
|
23
|
+
<template v-for="(btn, index) of btnList" :key="index">
|
|
24
|
+
<ElPlusFormBtn v-bind="btn"></ElPlusFormBtn>
|
|
25
|
+
</template>
|
|
26
|
+
</div>
|
|
27
|
+
</slot>
|
|
28
|
+
<slot name="bottom" :formData="props.modelValue"></slot>
|
|
29
|
+
</el-form>
|
|
30
|
+
<slot name="form-footer" :formData="props.modelValue"></slot>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
<script lang="ts">
|
|
34
|
+
export default {
|
|
35
|
+
name: 'ElPlusForm',
|
|
36
|
+
inheritAttrs: false,
|
|
37
|
+
customOptions: {}
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
<script lang="ts" setup>
|
|
41
|
+
import { ref, computed, useAttrs, nextTick, onMounted, watch, inject } from 'vue'
|
|
42
|
+
import { throttle } from 'lodash'
|
|
43
|
+
import { castArray, isMobile } from './util'
|
|
44
|
+
import * as validates from './util/validate'
|
|
45
|
+
import { typeList } from './components/index'
|
|
46
|
+
import ElPlusFormBtn from './components/ElPlusFormBtn.vue'
|
|
47
|
+
import { cloneDeep } from 'lodash'
|
|
48
|
+
|
|
49
|
+
// IFormProps定义
|
|
50
|
+
export interface IFormProps {
|
|
51
|
+
// 表单描述
|
|
52
|
+
formDesc?: IFormDesc | null
|
|
53
|
+
// 表单数据
|
|
54
|
+
modelValue?: { [key: string]: any } | {}
|
|
55
|
+
// 表单自身属性
|
|
56
|
+
formAttrs?: { [key: string]: any }
|
|
57
|
+
// 校检规则
|
|
58
|
+
rules?: { [key: string]: any } | null
|
|
59
|
+
// 提交状态
|
|
60
|
+
isLoading?: boolean
|
|
61
|
+
// 提交函数
|
|
62
|
+
requestFn?: Function | null
|
|
63
|
+
// 表单更新的函数
|
|
64
|
+
updateFn?: Function | null
|
|
65
|
+
// 是否显示底部按钮组
|
|
66
|
+
showBtns?: boolean
|
|
67
|
+
// 是否显示submit按钮
|
|
68
|
+
showSubmit?: boolean
|
|
69
|
+
// 提交按钮文本
|
|
70
|
+
submitBtnText?: string
|
|
71
|
+
// 是否显示 cancel 取消按钮
|
|
72
|
+
// 默认值: isDialog = true 时, 默认值为 true
|
|
73
|
+
showCancel?: boolean
|
|
74
|
+
// 取消按钮文本
|
|
75
|
+
cancelBtnText?: string
|
|
76
|
+
// 是否显示重置按钮
|
|
77
|
+
showReset?: boolean
|
|
78
|
+
// 重置按钮文本
|
|
79
|
+
resetBtnText?: string
|
|
80
|
+
// 是否显示label
|
|
81
|
+
showLabel?: boolean
|
|
82
|
+
// label宽度
|
|
83
|
+
labelWidth?: number | string
|
|
84
|
+
// 全局禁用表单
|
|
85
|
+
disabled?: boolean
|
|
86
|
+
// 全局的readonly
|
|
87
|
+
readonly?: boolean
|
|
88
|
+
// 是否为弹窗
|
|
89
|
+
isDialog?: boolean
|
|
90
|
+
// options 的请求方法
|
|
91
|
+
optionsFn?: Function | null
|
|
92
|
+
// 表单全局size
|
|
93
|
+
size?: string
|
|
94
|
+
// 表单列 默认1
|
|
95
|
+
column?: number
|
|
96
|
+
// 是否是列表头部的表单
|
|
97
|
+
isTable?: boolean
|
|
98
|
+
// 唯一标识符。默认为id
|
|
99
|
+
idKey?: string
|
|
100
|
+
// 最大宽度
|
|
101
|
+
maxWidth?: string
|
|
102
|
+
// 比如 beforeValidate, beforeRequest, success, requestError, requestEnd
|
|
103
|
+
// 其他钩子 直接放到attrs里面去了
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const defaultConf = inject('defaultConf') as ICRUDConfig
|
|
107
|
+
// 定义全局的format对象
|
|
108
|
+
const elPlusFormFormat = inject('format') as any
|
|
109
|
+
|
|
110
|
+
const emits = defineEmits(['request', 'reset', 'cancel'])
|
|
111
|
+
const props = withDefaults(defineProps<IFormProps>(), {
|
|
112
|
+
// 表单描述
|
|
113
|
+
formDesc: null,
|
|
114
|
+
// 表单数据
|
|
115
|
+
modelValue: () => {
|
|
116
|
+
return {}
|
|
117
|
+
},
|
|
118
|
+
// 表单自身属性
|
|
119
|
+
formAttrs: () => {
|
|
120
|
+
return {}
|
|
121
|
+
},
|
|
122
|
+
// 校检规则
|
|
123
|
+
rules: null,
|
|
124
|
+
// 提交状态
|
|
125
|
+
isLoading: false,
|
|
126
|
+
// 提交函数
|
|
127
|
+
requestFn: null,
|
|
128
|
+
// 表单更新的函数
|
|
129
|
+
updateFn: null,
|
|
130
|
+
// 是否显示按钮
|
|
131
|
+
showBtns: true,
|
|
132
|
+
// 是否显示submit按钮
|
|
133
|
+
showSubmit: true,
|
|
134
|
+
// 提交按钮文本
|
|
135
|
+
submitBtnText: '提交',
|
|
136
|
+
// 是否显示 cancel 取消按钮
|
|
137
|
+
// 默认值: isDialog = true 时, 默认值为 true
|
|
138
|
+
showCancel: false,
|
|
139
|
+
// 取消按钮
|
|
140
|
+
cancelBtnText: '取消',
|
|
141
|
+
// 是否显示重置按钮
|
|
142
|
+
showReset: true,
|
|
143
|
+
// 重置按钮
|
|
144
|
+
resetBtnText: '重置',
|
|
145
|
+
// 是否显示标签
|
|
146
|
+
showLabel: true,
|
|
147
|
+
// 标签宽度
|
|
148
|
+
labelWidth: '',
|
|
149
|
+
// 全局禁用表单
|
|
150
|
+
disabled: false,
|
|
151
|
+
// 全局的readonly
|
|
152
|
+
readonly: false,
|
|
153
|
+
// 是否为弹窗
|
|
154
|
+
isDialog: false,
|
|
155
|
+
// options 的请求方法
|
|
156
|
+
optionsFn: null,
|
|
157
|
+
// 表单全局size
|
|
158
|
+
size: 'small',
|
|
159
|
+
// 表单列 默认1
|
|
160
|
+
column: 1,
|
|
161
|
+
// 是否是列表头部的表单
|
|
162
|
+
isTable: false,
|
|
163
|
+
// 唯一标识符。默认为id
|
|
164
|
+
idKey: 'id'
|
|
165
|
+
// 其他钩子 直接放到attrs里面去了
|
|
166
|
+
// 比如 beforeValidate, beforeRequest, success, requestError, requestEnd
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const refElPlusForm = ref()
|
|
170
|
+
|
|
171
|
+
// 是否开启全局监听
|
|
172
|
+
const isOpenListen = ref(false)
|
|
173
|
+
|
|
174
|
+
const tempAttr = useAttrs()
|
|
175
|
+
|
|
176
|
+
// 每个表单项的ref
|
|
177
|
+
const fieldRefs_ = ref([] as Array<any>)
|
|
178
|
+
|
|
179
|
+
// loading
|
|
180
|
+
const innerIsLoading = ref(false)
|
|
181
|
+
|
|
182
|
+
let oldFormData = null as any
|
|
183
|
+
|
|
184
|
+
const size = computed(() => props.size || defaultConf.size)
|
|
185
|
+
// 组件名称列表
|
|
186
|
+
const compTypeList = [...typeList, ...(defaultConf.form?.comList || [])]
|
|
187
|
+
|
|
188
|
+
// 整体的布局方式
|
|
189
|
+
const formLayout = computed(() => ({ display: 'flex', flexDirection: props.isTable ? 'row' : 'column' })) as any
|
|
190
|
+
|
|
191
|
+
// 表单的Attrs
|
|
192
|
+
const computedFormAttrs = computed(() => {
|
|
193
|
+
return {
|
|
194
|
+
scrollToError: true,
|
|
195
|
+
...props.formAttrs,
|
|
196
|
+
labelWidth: props.labelWidth === 'auto' ? (props.isDialog ? '100px' : '120px') : parseInt(props.labelWidth + '') + 'px',
|
|
197
|
+
// validateOnRuleChange: false,
|
|
198
|
+
disabled: props.disabled || innerIsLoading.value,
|
|
199
|
+
rules: computedRules,
|
|
200
|
+
labelPosition: isMobile() ? 'top' : 'right',
|
|
201
|
+
style: {
|
|
202
|
+
width: props.maxWidth || (props.isTable ? '100%' : props.isDialog ? '80%' : '1000px'),
|
|
203
|
+
paddingRight: props.isTable ? '0' : '20px'
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
// 合并校验规则
|
|
209
|
+
const computedRules = computed(() => {
|
|
210
|
+
// 首先拿到表单总体传入的rules
|
|
211
|
+
const tempRules = props.rules || []
|
|
212
|
+
// 遍历属性描述对象,看看里面有没有校验规则
|
|
213
|
+
if (props.formDesc) {
|
|
214
|
+
Object.keys(props.formDesc).map((field: any) => {
|
|
215
|
+
if (!tempRules[field]) tempRules[field] = []
|
|
216
|
+
if (props.formDesc) {
|
|
217
|
+
if (props.formDesc[field].rules) {
|
|
218
|
+
if (typeof props.formDesc[field].rules === 'string') {
|
|
219
|
+
// string的话,就行默认校验规则中取
|
|
220
|
+
tempRules[field].push(...(validates as any)[props.formDesc[field].rules as string])
|
|
221
|
+
} else {
|
|
222
|
+
// 查看总体规则中是否已经含有了该属性的校验
|
|
223
|
+
castArray(props.formDesc[field].rules).map((item: any) => {
|
|
224
|
+
tempRules[field].push(item)
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
} else if (props.formDesc[field].required || props.formDesc[field].require) {
|
|
228
|
+
// 如果直接指定 required || require,手动添加校验信息
|
|
229
|
+
//
|
|
230
|
+
let rules = 'notAllBlank'
|
|
231
|
+
switch (props.formDesc[field].type) {
|
|
232
|
+
case 'upload':
|
|
233
|
+
case 'select':
|
|
234
|
+
case 'password':
|
|
235
|
+
case 'textarea':
|
|
236
|
+
case 'editor':
|
|
237
|
+
rules = props.formDesc[field].type || ''
|
|
238
|
+
break
|
|
239
|
+
case 'cascader':
|
|
240
|
+
case 'tselect':
|
|
241
|
+
case 'linkuser':
|
|
242
|
+
case 'radio':
|
|
243
|
+
rules = 'select'
|
|
244
|
+
break
|
|
245
|
+
}
|
|
246
|
+
tempRules[field].push(...(validates as any)[rules])
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
return tempRules
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
// 属性对象转数组
|
|
255
|
+
const attrMapToTableList = computed(() => {
|
|
256
|
+
const formLayoutRows = [] as Array<Array<IFormDescItem>>
|
|
257
|
+
if (props.formDesc) {
|
|
258
|
+
let tempData = [] as Array<IFormDescItem>
|
|
259
|
+
for (const key in props.formDesc) {
|
|
260
|
+
tempData.push({ ...props.formDesc[key], field: key })
|
|
261
|
+
}
|
|
262
|
+
// 这里处理一下layout的布局-渲染
|
|
263
|
+
let rowItemList = [] as Array<IFormDescItem>
|
|
264
|
+
let tempCount = 0
|
|
265
|
+
tempData.map((item) => {
|
|
266
|
+
if (item._vif) {
|
|
267
|
+
rowItemList.push(item)
|
|
268
|
+
tempCount++
|
|
269
|
+
if (item.colspan) {
|
|
270
|
+
tempCount += item.colspan - 1
|
|
271
|
+
}
|
|
272
|
+
if (tempCount >= props.column) {
|
|
273
|
+
// 一行结束
|
|
274
|
+
formLayoutRows.push(rowItemList)
|
|
275
|
+
rowItemList = [] as Array<IFormDescItem>
|
|
276
|
+
tempCount = 0
|
|
277
|
+
return
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
if (rowItemList.length > 0) {
|
|
282
|
+
formLayoutRows.push(rowItemList)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return formLayoutRows
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
// 整体初始化属性
|
|
289
|
+
const initFormAttrs = throttle(() => {
|
|
290
|
+
if (props.formDesc) {
|
|
291
|
+
Object.keys(props.formDesc).forEach((field) => {
|
|
292
|
+
if (props.formDesc) {
|
|
293
|
+
const formItem = props.formDesc[field]
|
|
294
|
+
if (formItem && formItem.type) {
|
|
295
|
+
// 设置 _type
|
|
296
|
+
formItem._type = compTypeList.includes(formItem.type.toLowerCase()) ? 'el-plus-form-' + formItem.type : formItem.type
|
|
297
|
+
// 触发 v-if 显示 / 隐藏 设置_vif
|
|
298
|
+
formItem._vif = handelKeyValue(formItem, 'vif', field, !formItem.isBlank ?? true)
|
|
299
|
+
// 触发 disabled 禁用 / 启用 设置_disabled
|
|
300
|
+
formItem._disabled = handelKeyValue(formItem, 'disabled', field, props.disabled ?? false)
|
|
301
|
+
// 动态属性 attrs
|
|
302
|
+
const tempAttr = {} as any
|
|
303
|
+
// if ((typeof formItem.attrs === 'object' && formItem.attrs?.options) || formItem.options) {
|
|
304
|
+
// tempAttr.options = (formItem.attrs as any)?.options || formItem.options
|
|
305
|
+
// }
|
|
306
|
+
formItem._attrs = Object.assign({}, handelKeyValue(formItem, 'attrs', field), tempAttr)
|
|
307
|
+
// 动态options
|
|
308
|
+
// formItem._options = handelKeyValue(formItem, 'options', field)
|
|
309
|
+
// 动态 _label
|
|
310
|
+
formItem._label = handelKeyValue(formItem, 'label', field)
|
|
311
|
+
// 动态 prop
|
|
312
|
+
// formItem._prop = handelKeyValue(formItem, 'prop', field);
|
|
313
|
+
// 动态 _tip
|
|
314
|
+
formItem._tip = handelKeyValue(formItem, 'tip', field)
|
|
315
|
+
// 单独处理下上传
|
|
316
|
+
if (!formItem._tip && !formItem.noTip && formItem.type === 'upload') {
|
|
317
|
+
formItem._tip = `最多上传${formItem.multiple ? formItem.limit || 20 : 1}${formItem.upType === 'file' ? '个文件' : '张图片'}`
|
|
318
|
+
}
|
|
319
|
+
// 这里初始化一下默认值
|
|
320
|
+
if (formItem.default !== undefined && formItem.default !== null && props.modelValue[field] === undefined) {
|
|
321
|
+
props.modelValue[field] = formItem.default
|
|
322
|
+
}
|
|
323
|
+
// 这里初始化一下默认选中项
|
|
324
|
+
if (formItem.defaultItem !== undefined && formItem.defaultItem !== null && props.modelValue[field] === undefined) {
|
|
325
|
+
props.modelValue[field] = formItem.defaultItem.value
|
|
326
|
+
}
|
|
327
|
+
// 这里格式化一下数据
|
|
328
|
+
// if (formItem.format) {
|
|
329
|
+
// if (typeof formItem.format === 'string') {
|
|
330
|
+
// props.modelValue[field] = elPlusFormFormat[formItem.format](props.modelValue[field], props.modelValue)
|
|
331
|
+
// } else if (typeof formItem.format === 'function') {
|
|
332
|
+
// props.modelValue[field] = (formItem as any).format(props.modelValue[field], props.modelValue)
|
|
333
|
+
// } else {
|
|
334
|
+
// // console.log('未知的格式化类型:', formItem.format)
|
|
335
|
+
// }
|
|
336
|
+
// }
|
|
337
|
+
} else if (formItem && formItem.isBlank) {
|
|
338
|
+
// 触发 v-if 显示 / 隐藏 设置_vif
|
|
339
|
+
formItem._vif = handelKeyValue(formItem, 'vif', '', true)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
}, 500)
|
|
345
|
+
|
|
346
|
+
// 表单底部按钮
|
|
347
|
+
const btnList = computed(() => {
|
|
348
|
+
let btnList_ = [] as any[]
|
|
349
|
+
if (!props.showBtns) {
|
|
350
|
+
return btnList_
|
|
351
|
+
}
|
|
352
|
+
// 取消按钮
|
|
353
|
+
if (props.showCancel) {
|
|
354
|
+
btnList_.push({
|
|
355
|
+
field: '_reset_btn',
|
|
356
|
+
desc: {
|
|
357
|
+
label: props.cancelBtnText || '取消',
|
|
358
|
+
size: size.value,
|
|
359
|
+
disabled: innerIsLoading.value,
|
|
360
|
+
on: { click: () => emits('cancel') }
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
// 重置按钮
|
|
365
|
+
if (props.showReset) {
|
|
366
|
+
btnList_.push({
|
|
367
|
+
field: '_reset_btn',
|
|
368
|
+
desc: {
|
|
369
|
+
label: props.resetBtnText || '重置',
|
|
370
|
+
confirm: `确定要${props.resetBtnText || '重置'}?`,
|
|
371
|
+
size: size.value,
|
|
372
|
+
disabled: innerIsLoading.value,
|
|
373
|
+
on: { click: reset }
|
|
374
|
+
}
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
// 提交按钮
|
|
378
|
+
if (props.showSubmit) {
|
|
379
|
+
btnList_.push({
|
|
380
|
+
field: '_reset_btn',
|
|
381
|
+
desc: {
|
|
382
|
+
label: props.submitBtnText || '提交',
|
|
383
|
+
size: size.value,
|
|
384
|
+
type: 'primary',
|
|
385
|
+
loading: props.isLoading || innerIsLoading.value,
|
|
386
|
+
on: { click: handleSubmitForm }
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
}
|
|
390
|
+
return btnList_
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
// 处理属性
|
|
394
|
+
const handelKeyValue = (formItem: IFormDescItem, key: string, field: string, defVal: number | boolean | string | null = null) => {
|
|
395
|
+
if (typeof formItem[key] === 'function') {
|
|
396
|
+
// 如果有方法类型的判断,则需要启用动态监测
|
|
397
|
+
isOpenListen.value = true
|
|
398
|
+
return formItem[key](props.modelValue, props.modelValue[field])
|
|
399
|
+
} else if (typeof formItem[key] === 'boolean') {
|
|
400
|
+
return formItem[key] ?? false
|
|
401
|
+
} else if (typeof formItem[key] === 'string') {
|
|
402
|
+
return formItem[key] ?? ''
|
|
403
|
+
} else {
|
|
404
|
+
return formItem[key] ?? defVal
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// 验证表单
|
|
409
|
+
const validateForm = () => {
|
|
410
|
+
return new Promise((resolve: any, reject: any) => {
|
|
411
|
+
if (computedRules.value) {
|
|
412
|
+
// 当传递了验证规则
|
|
413
|
+
refElPlusForm.value.validate((valid: Boolean, invalidFields: any) => {
|
|
414
|
+
if (valid) {
|
|
415
|
+
// 验证通过
|
|
416
|
+
resolve()
|
|
417
|
+
} else {
|
|
418
|
+
// 显示错误
|
|
419
|
+
reject(invalidFields)
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
} else {
|
|
423
|
+
resolve()
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 设置子组件的ref-重置form的时候需要用到
|
|
429
|
+
const setComponentRef = (el: any) => {
|
|
430
|
+
if (!el) return
|
|
431
|
+
if (fieldRefs_.value.filter((item: any) => item.field === el.field).length <= 0) {
|
|
432
|
+
fieldRefs_.value.push(el)
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* 处理单个表单值
|
|
438
|
+
* @param val
|
|
439
|
+
*/
|
|
440
|
+
const handelValToForm = (desc: IFormDescItem, field: string, val: any) => {
|
|
441
|
+
const result = {} as { [key: string]: any }
|
|
442
|
+
if (!desc) return { [field]: val }
|
|
443
|
+
if (!desc._vif || val === undefined || val === null) return result
|
|
444
|
+
if (desc.type === 'category') {
|
|
445
|
+
if (val === null) val = []
|
|
446
|
+
// 如果是直接显示结果
|
|
447
|
+
if (desc.checkStrictly === true) {
|
|
448
|
+
result.categoryId = val[2] ?? val[1] ?? val[0] ?? ''
|
|
449
|
+
} else {
|
|
450
|
+
for (let i = 0; i < 3; i++) {
|
|
451
|
+
result['categoryId' + (i + 1)] = val[i] ?? ''
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} else if (desc.type === 'area') {
|
|
455
|
+
if (val === null) val = [null, null, null, null]
|
|
456
|
+
const [pid, cid, zid, sid] = val
|
|
457
|
+
if (desc.checkStrictly) {
|
|
458
|
+
result[field] = sid || zid || cid || pid || null
|
|
459
|
+
} else {
|
|
460
|
+
result.provinceId = pid || -1
|
|
461
|
+
result.cityId = cid || -1
|
|
462
|
+
result.zoneId = zid || -1
|
|
463
|
+
result.streetId = sid || -1
|
|
464
|
+
}
|
|
465
|
+
} else if (desc.type === 'daterange') {
|
|
466
|
+
if (val && val.length === 2) {
|
|
467
|
+
result.startTime = val[0]
|
|
468
|
+
if (typeof val[1] === 'string') {
|
|
469
|
+
result.endTime = new Date(val[1]).getTime()
|
|
470
|
+
} else {
|
|
471
|
+
result.endTime = val[1]
|
|
472
|
+
}
|
|
473
|
+
result.endTime = result.endTime + (24 * 60 * 60 - 1) * 1000
|
|
474
|
+
// 再处理一下时间戳
|
|
475
|
+
result.startTime = elPlusFormFormat.time(result.startTime, 3)
|
|
476
|
+
result.endTime = elPlusFormFormat.time(result.endTime, 3)
|
|
477
|
+
}
|
|
478
|
+
} else if (desc.type === 'datetimerange') {
|
|
479
|
+
if (val && val.length === 2) {
|
|
480
|
+
// 处理一下时间戳
|
|
481
|
+
result.startTime = elPlusFormFormat.time(val[0], 3)
|
|
482
|
+
result.endTime = elPlusFormFormat.time(val[1], 3)
|
|
483
|
+
}
|
|
484
|
+
} else if (desc.type === 'linkuser') {
|
|
485
|
+
const [userIds, deptIds, userNames, deptNames] = val
|
|
486
|
+
result.userIds = userIds
|
|
487
|
+
result.deptIds = deptIds
|
|
488
|
+
result.userNames = userNames
|
|
489
|
+
result.deptNames = deptNames
|
|
490
|
+
} else {
|
|
491
|
+
// 这里处理下通用表单的数据类型
|
|
492
|
+
switch (desc.type) {
|
|
493
|
+
case 'checkbox':
|
|
494
|
+
if (Array.isArray(val)) {
|
|
495
|
+
val = val.join(',')
|
|
496
|
+
}
|
|
497
|
+
break
|
|
498
|
+
}
|
|
499
|
+
result[field] = val
|
|
500
|
+
}
|
|
501
|
+
return result
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* 获取处理过后的表单数据
|
|
506
|
+
*/
|
|
507
|
+
const getFormData = () => {
|
|
508
|
+
const tempData = {} as { [key: string]: any }
|
|
509
|
+
if (props.formDesc) {
|
|
510
|
+
// 循环获取表单数据
|
|
511
|
+
Object.keys(props.modelValue).map((key) => {
|
|
512
|
+
if (['provinceId', 'cityId', 'zoneId', 'streetId'].indexOf(key) >= 0) return
|
|
513
|
+
if (props.formDesc) {
|
|
514
|
+
Object.assign(tempData, handelValToForm(props.formDesc[key], key, props.modelValue[key]))
|
|
515
|
+
}
|
|
516
|
+
})
|
|
517
|
+
}
|
|
518
|
+
return tempData
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* 刷新验证码图片
|
|
523
|
+
*/
|
|
524
|
+
const changeValidImg = () => {
|
|
525
|
+
fieldRefs_.value.map((item) => {
|
|
526
|
+
if (item.CID) {
|
|
527
|
+
item.changeValidImg()
|
|
528
|
+
}
|
|
529
|
+
})
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* 提交表单
|
|
534
|
+
*/
|
|
535
|
+
const handleSubmitForm = async () => {
|
|
536
|
+
let postData = getFormData()
|
|
537
|
+
try {
|
|
538
|
+
// 校验表单事件处理
|
|
539
|
+
if (tempAttr.beforeValidate) {
|
|
540
|
+
const isPass = await (tempAttr.beforeValidate as Function)(postData)
|
|
541
|
+
if (isPass === false) return
|
|
542
|
+
}
|
|
543
|
+
await validateForm()
|
|
544
|
+
for (const field in postData) {
|
|
545
|
+
// 去除下划线开头的参数
|
|
546
|
+
if (field.indexOf('_') === 0) {
|
|
547
|
+
delete postData[field]
|
|
548
|
+
continue
|
|
549
|
+
}
|
|
550
|
+
if (props.formDesc) {
|
|
551
|
+
const formItem = props.formDesc[field]
|
|
552
|
+
// valueFormatter的处理
|
|
553
|
+
if (formItem && formItem.valueFormat) {
|
|
554
|
+
postData[field] = formItem.valueFormat(postData[field], postData)
|
|
555
|
+
}
|
|
556
|
+
// 处理带有true或者false值
|
|
557
|
+
if (postData[field] === true || postData[field] === false) {
|
|
558
|
+
postData[field] = +postData[field]
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// 提交数据前的通知
|
|
564
|
+
if (tempAttr.beforeRequest) {
|
|
565
|
+
const beforeRequestData = await (tempAttr.beforeRequest as Function)(postData)
|
|
566
|
+
if (beforeRequestData === false) return
|
|
567
|
+
if (typeof beforeRequestData === 'object') {
|
|
568
|
+
postData = beforeRequestData
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (props.requestFn) {
|
|
572
|
+
// 在内部调用请求
|
|
573
|
+
if (innerIsLoading.value) return
|
|
574
|
+
innerIsLoading.value = true
|
|
575
|
+
try {
|
|
576
|
+
let response = {}
|
|
577
|
+
if (props.updateFn && postData && (postData as any)[props.idKey]) {
|
|
578
|
+
response = await props.updateFn(postData)
|
|
579
|
+
} else {
|
|
580
|
+
response = await props.requestFn(postData)
|
|
581
|
+
}
|
|
582
|
+
nextTick(() => {
|
|
583
|
+
if (tempAttr.success && typeof tempAttr.success === 'function') {
|
|
584
|
+
tempAttr.success({
|
|
585
|
+
response,
|
|
586
|
+
formData: props.modelValue,
|
|
587
|
+
callBack: () => (innerIsLoading.value = false)
|
|
588
|
+
} as IFormBack)
|
|
589
|
+
}
|
|
590
|
+
})
|
|
591
|
+
} catch (error) {
|
|
592
|
+
// 如果用户有处理异常的方法了
|
|
593
|
+
if (tempAttr.requestError && typeof tempAttr.requestError === 'function') {
|
|
594
|
+
tempAttr.requestError(error)
|
|
595
|
+
} else {
|
|
596
|
+
// 处理异常情况
|
|
597
|
+
if (error instanceof Error) {
|
|
598
|
+
// 返回的是Error类型, 则进行解析
|
|
599
|
+
try {
|
|
600
|
+
const msg = JSON.parse(error.message)
|
|
601
|
+
if (msg instanceof Object) {
|
|
602
|
+
// innerFormError.value = msg;
|
|
603
|
+
}
|
|
604
|
+
// eslint-disable-next-line
|
|
605
|
+
} catch {}
|
|
606
|
+
} else if (error instanceof Object) {
|
|
607
|
+
// 返回的是对象类型, 则直接设置
|
|
608
|
+
// innerFormError = error;
|
|
609
|
+
}
|
|
610
|
+
if (tempAttr.requestError && typeof tempAttr.requestError === 'function') {
|
|
611
|
+
tempAttr.requestError()
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// 报错了这里恢复
|
|
615
|
+
innerIsLoading.value = false
|
|
616
|
+
} finally {
|
|
617
|
+
if (!props.isDialog) {
|
|
618
|
+
innerIsLoading.value = false
|
|
619
|
+
}
|
|
620
|
+
if (tempAttr.requestEnd && typeof tempAttr.requestEnd === 'function') {
|
|
621
|
+
tempAttr.requestEnd()
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
} else {
|
|
625
|
+
// 在外部用户自己处理请求
|
|
626
|
+
if (props.isLoading) return
|
|
627
|
+
emits('request', postData)
|
|
628
|
+
}
|
|
629
|
+
} catch (error) {
|
|
630
|
+
// eslint-disable-next-line no-console
|
|
631
|
+
console.log('error: ', error)
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* 重置,并清除校验
|
|
637
|
+
*/
|
|
638
|
+
const reset = () => {
|
|
639
|
+
// refElPlusForm.value.resetFields();
|
|
640
|
+
// 重置
|
|
641
|
+
Object.keys(props.modelValue).map((key) => {
|
|
642
|
+
props.modelValue[key] = oldFormData ? oldFormData[key] : (props.formDesc && props.formDesc[key] && props.formDesc[key].default) ?? null
|
|
643
|
+
})
|
|
644
|
+
setTimeout(() => {
|
|
645
|
+
// 清空校验
|
|
646
|
+
clearValid()
|
|
647
|
+
}, 100)
|
|
648
|
+
// 通知外部
|
|
649
|
+
emits('reset')
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* 清空校验
|
|
654
|
+
*/
|
|
655
|
+
const clearValid = () => {
|
|
656
|
+
refElPlusForm.value?.clearValidate()
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* 清理
|
|
661
|
+
*/
|
|
662
|
+
const clear = () => {
|
|
663
|
+
// 这里进行数据清空
|
|
664
|
+
if (props.modelValue) {
|
|
665
|
+
Object.keys(props.modelValue).map((key) => {
|
|
666
|
+
props.modelValue[key] = null
|
|
667
|
+
})
|
|
668
|
+
}
|
|
669
|
+
// 重置校验
|
|
670
|
+
nextTick(() => {
|
|
671
|
+
setTimeout(() => {
|
|
672
|
+
clearValid()
|
|
673
|
+
}, 10)
|
|
674
|
+
})
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* 单独校验一下字段
|
|
679
|
+
* @param field
|
|
680
|
+
*/
|
|
681
|
+
function handelValidateThis(field: string) {
|
|
682
|
+
refElPlusForm.value.validateField(field, (err: any) => {
|
|
683
|
+
// console.log('err: ', err)
|
|
684
|
+
})
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* 刷新表单
|
|
689
|
+
*/
|
|
690
|
+
function refresh() {
|
|
691
|
+
// 重新刷新表单
|
|
692
|
+
initFormAttrs()
|
|
693
|
+
// 重置校验
|
|
694
|
+
nextTick(() => {
|
|
695
|
+
clearValid()
|
|
696
|
+
})
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// 监听Desc改变
|
|
700
|
+
watch(
|
|
701
|
+
() => props.formDesc,
|
|
702
|
+
(formDesc) => {
|
|
703
|
+
if (formDesc) {
|
|
704
|
+
// 检查联动
|
|
705
|
+
initFormAttrs()
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
// 深度监听data改变
|
|
711
|
+
watch(
|
|
712
|
+
() => props.modelValue,
|
|
713
|
+
(data) => {
|
|
714
|
+
if (!oldFormData || (isOpenListen.value && data && JSON.stringify(data) !== JSON.stringify(oldFormData))) {
|
|
715
|
+
// 检查联动
|
|
716
|
+
if (JSON.stringify(data) !== JSON.stringify(oldFormData)) {
|
|
717
|
+
oldFormData = cloneDeep(data)
|
|
718
|
+
initFormAttrs()
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
{ deep: true }
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
onMounted(async () => {
|
|
726
|
+
// 检查联动
|
|
727
|
+
if (!isOpenListen.value) {
|
|
728
|
+
initFormAttrs()
|
|
729
|
+
}
|
|
730
|
+
nextTick(() => {
|
|
731
|
+
clearValid()
|
|
732
|
+
})
|
|
733
|
+
})
|
|
734
|
+
|
|
735
|
+
// 暴露对外方法
|
|
736
|
+
defineExpose({ submit: handleSubmitForm, getData: getFormData, validate: validateForm, reset, clearValid, clear, changeValidImg, refresh })
|
|
737
|
+
</script>
|
|
738
|
+
<style lang="scss">
|
|
739
|
+
.el-plus-form-panel {
|
|
740
|
+
.el-plus-form--inline .el-plus-form-btns {
|
|
741
|
+
width: auto;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.el-form--inline .el-form-item {
|
|
745
|
+
margin-right: 12px !important;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.el-plus-form-col--break {
|
|
749
|
+
clear: both;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.el-plus-form-tip {
|
|
753
|
+
color: #909399;
|
|
754
|
+
line-height: 1.5em;
|
|
755
|
+
margin-top: 3px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.el-plus-form-tip code {
|
|
759
|
+
padding: 2px 4px;
|
|
760
|
+
font-size: 90%;
|
|
761
|
+
color: #c7254e;
|
|
762
|
+
background-color: #f9f2f4;
|
|
763
|
+
border-radius: 4px;
|
|
764
|
+
}
|
|
765
|
+
.el-plus-form-column-panel {
|
|
766
|
+
& > .el-form-item--default {
|
|
767
|
+
margin-bottom: 18px !important;
|
|
768
|
+
& > .el-form-item__label {
|
|
769
|
+
line-height: 40px;
|
|
770
|
+
margin-bottom: 0;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
</style>
|