@aspire-ui/element-component-pro 1.0.4 → 1.0.6

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.
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div ref="formWrapRef" class="ecp-pro-form">
3
- <el-form class="ecp-pro-form" ref="formRef" :model="formModel" :rules="formRules" :label-width="effectiveProps.labelWidth"
3
+ <el-form class="ecp-pro-form" ref="formRef" :model="currentFormModel" :rules="formRules" :label-width="effectiveProps.labelWidth"
4
4
  :label-position="effectiveProps.labelPosition" :size="effectiveProps.size" :disabled="effectiveProps.disabled"
5
5
  v-bind="$attrs" v-on="formListeners">
6
6
  <slot name="formHeader" />
@@ -8,12 +8,12 @@
8
8
  <template v-for="schema in displaySchemas">
9
9
  <el-col v-if="shouldShow(schema)" :key="schema.field" v-bind="getColProps(schema)"
10
10
  :offset="schema.colProps?.offset ?? effectiveProps.baseColProps?.offset ?? 0" :data-field="schema.field">
11
- <ProFormItem :schema="schema" :form-model="formModel" :form-disabled="effectiveProps.disabled"
11
+ <ProFormItem :schema="schema" :form-model="currentFormModel" :form-disabled="effectiveProps.disabled"
12
12
  :auto-placeholder="effectiveProps.autoSetPlaceholder" :form-action-type="formActionRef"
13
- :custom-components="formCustomComponents">
13
+ :custom-components="formCustomComponents" :on-field-change="handleFieldChange">
14
14
  <template v-if="slots[getSlotName(schema)]">
15
- <slot :name="getSlotName(schema)" :model="formModel" :schema="schema" :field="schema.field"
16
- :values="formModel" />
15
+ <slot :name="getSlotName(schema)" :model="currentFormModel" :schema="schema" :field="schema.field"
16
+ :values="currentFormModel" />
17
17
  </template>
18
18
  </ProFormItem>
19
19
  </el-col>
@@ -65,6 +65,7 @@ import type { ProFormSchema, ProFormProps, FormActionType, ColEx, ScrollToFieldO
65
65
  const props = withDefaults(
66
66
  defineProps<{
67
67
  schemas?: ProFormSchema[]
68
+ modelValue?: Record<string, unknown>
68
69
  initialValues?: Record<string, unknown>
69
70
  labelWidth?: string
70
71
  labelPosition?: 'left' | 'right' | 'top'
@@ -118,6 +119,7 @@ const emit = defineEmits<{
118
119
  (e: 'submit', values: Record<string, unknown>): void
119
120
  (e: 'reset'): void
120
121
  (e: 'register', formAction: FormActionType): void
122
+ (e: 'update:modelValue', values: Record<string, unknown>): void
121
123
  }>()
122
124
  const slots = useSlots()
123
125
  const formRef = ref()
@@ -148,10 +150,17 @@ const getEffectiveSpan = (colProps?: ColEx | null, baseColProps?: ColEx | null,
148
150
 
149
151
  const { getSetting: getComponentSetting } = useComponentSetting()
150
152
  const effectiveProps = computed(() => ({ ...getComponentSetting('ProForm'), ...props, ...innerProps.value }))
153
+ const controlledModelValue = computed(() => effectiveProps.value.modelValue)
154
+ const isControlled = computed(() => controlledModelValue.value !== undefined)
155
+ const currentFormModel = computed<Record<string, unknown>>(() => {
156
+ return isControlled.value
157
+ ? (controlledModelValue.value ?? {})
158
+ : formModel.value
159
+ })
151
160
  /** 传给 ProFormItem 的自定义组件映射:显式合并 setSetting 与 props,避免响应式代理导致组件引用丢失 */
152
161
  const formCustomComponents = computed(() => ({
153
162
  ...(getComponentSetting('ProForm').components as Record<string, unknown> | undefined) ?? {},
154
- ...(props.components ?? {}),
163
+ ...(effectiveProps.value.components ?? {}),
155
164
  ...(innerProps.value.components ?? {}),
156
165
  }))
157
166
  const effectiveActionColOptions = computed(() => effectiveProps.value.actionColOptions ?? { span: 24 })
@@ -190,7 +199,6 @@ const hasMoreFields = computed(() => {
190
199
  const lines = effectiveProps.value.alwaysShowLines ?? 1
191
200
  const baseColProps = effectiveProps.value.baseColProps
192
201
  const maxVisible = getVisibleSchemaCount(schemas, baseColProps, lines, windowWidth.value)
193
- console.log(schemas.length, maxVisible)
194
202
  return schemas.length > maxVisible
195
203
  })
196
204
 
@@ -213,13 +221,13 @@ const shouldShow = (schema: ProFormSchema) => {
213
221
  let ifShow = true
214
222
  let show = true
215
223
  if (typeof schema.ifShow === 'function') {
216
- ifShow = schema.ifShow({ schema, values: formModel.value, model: formModel.value, field: schema.field })
224
+ ifShow = schema.ifShow({ schema, values: currentFormModel.value, model: currentFormModel.value, field: schema.field })
217
225
  }
218
226
  if (typeof schema.ifShow === 'boolean') {
219
227
  ifShow = schema.ifShow
220
228
  }
221
229
  if (typeof schema.show === 'function') {
222
- show = schema.show({ schema, values: formModel.value, model: formModel.value, field: schema.field })
230
+ show = schema.show({ schema, values: currentFormModel.value, model: currentFormModel.value, field: schema.field })
223
231
  }
224
232
  if (typeof schema.show === 'boolean') {
225
233
  show = schema.show
@@ -230,16 +238,44 @@ const getColProps = (schema: ProFormSchema) => {
230
238
  return schema.colProps ?? effectiveProps.value.baseColProps ?? {}
231
239
  }
232
240
  const getSlotName = (schema: ProFormSchema) => schema.slot || schema.field
241
+ /**
242
+ *
243
+ * @param baseModel
244
+ * @param preserveExisting
245
+ */
246
+ const resolveSchemaModel = (baseModel?: Record<string, unknown>, preserveExisting = true) => {
247
+ const nextModel = preserveExisting ? { ...(baseModel ?? {}) } : {}
248
+ const initialValues = effectiveProps.value.initialValues ?? props.initialValues
249
+ innerSchemas.value.forEach((schema) => {
250
+ if (preserveExisting && Object.prototype.hasOwnProperty.call(nextModel, schema.field)) return
251
+ if (schema.defaultValue !== undefined) {
252
+ nextModel[schema.field] = schema.defaultValue
253
+ return
254
+ }
255
+ if (initialValues && Object.prototype.hasOwnProperty.call(initialValues, schema.field)) {
256
+ nextModel[schema.field] = initialValues[schema.field]
257
+ }
258
+ })
259
+ return nextModel
260
+ }
261
+
262
+ const applyFormModel = (nextModel: Record<string, unknown>, shouldEmit = true) => {
263
+ formModel.value = nextModel
264
+ if (shouldEmit) emit('update:modelValue', nextModel)
265
+ }
266
+
267
+ const updateFormModel = (values: Record<string, unknown>) => {
268
+ const nextModel = resolveSchemaModel({ ...currentFormModel.value, ...values })
269
+ applyFormModel(nextModel)
270
+ return nextModel
271
+ }
233
272
 
234
273
  const initForm = () => {
235
- const model: Record<string, unknown> = {}
236
274
  const rules: Record<string, unknown[]> = {}
237
- const initialValues = effectiveProps.value.initialValues ?? props.initialValues
238
275
  innerSchemas.value.forEach((schema) => {
239
- model[schema.field] = schema.defaultValue ?? initialValues?.[schema.field]
240
276
  if (schema.rules?.length) rules[schema.field] = schema.rules
241
277
  })
242
- formModel.value = { ...formModel.value, ...model }
278
+ applyFormModel(resolveSchemaModel(currentFormModel.value), false)
243
279
  formRules.value = rules
244
280
  }
245
281
 
@@ -277,7 +313,7 @@ const handleSubmit = async () => {
277
313
  await effectiveProps.value.submitFunc()
278
314
  } else {
279
315
  submitLoading.value = true
280
- emit('submit', processFieldMapToTime({ ...formModel.value }))
316
+ emit('submit', processFieldMapToTime({ ...currentFormModel.value }))
281
317
  }
282
318
  } catch (e) {
283
319
  console.error('Form validation failed:', e)
@@ -298,15 +334,19 @@ const handleReset = async () => {
298
334
  }
299
335
 
300
336
  const setFieldsValue = (values: Record<string, unknown>) => {
301
- formModel.value = { ...formModel.value, ...values }
337
+ updateFormModel(values)
302
338
  return Promise.resolve()
303
339
  }
304
340
 
305
- const getFieldsValue = () => processFieldMapToTime({ ...formModel.value })
341
+ const getFieldsValue = () => processFieldMapToTime({ ...currentFormModel.value })
306
342
 
307
343
  const resetFields = async () => {
308
344
  formRef.value?.resetFields()
309
- initForm()
345
+ applyFormModel(resolveSchemaModel(undefined, false))
346
+ }
347
+
348
+ const handleFieldChange = (field: string, value: unknown) => {
349
+ updateFormModel({ [field]: value })
310
350
  }
311
351
 
312
352
  const validate = (nameList?: string[]) =>
@@ -398,6 +438,11 @@ onUnmounted(() => {
398
438
  if (typeof window !== 'undefined') window.removeEventListener('resize', handleResize)
399
439
  })
400
440
 
441
+ watch(() => controlledModelValue.value, (value) => {
442
+ if (!isControlled.value || value === undefined) return
443
+ applyFormModel(resolveSchemaModel(value), false)
444
+ }, { deep: true, immediate: true })
445
+
401
446
  watch(() => [props.schemas, props.initialValues], syncSchemas, { deep: true })
402
447
  </script>
403
448
 
@@ -181,6 +181,7 @@ const props = defineProps<{
181
181
  formDisabled?: boolean
182
182
  autoPlaceholder?: boolean
183
183
  formActionType?: import('../types').FormActionType
184
+ onFieldChange?: (field: string, value: unknown) => void
184
185
  /** 自定义组件映射(由 ProForm 传入) */
185
186
  customComponents?: Record<string, unknown>
186
187
  }>()
@@ -266,7 +267,7 @@ const resolvedCustomComponent = computed(() => {
266
267
  })
267
268
 
268
269
  const setFieldValue = (v: unknown) => {
269
- props.formModel[props.schema.field] = v
270
+ props.onFieldChange?.(props.schema.field, v)
270
271
  }
271
272
 
272
273
  const renderComponent = computed(() => {
package/src/index.ts CHANGED
@@ -1,15 +1,19 @@
1
1
  import type { VueConstructor } from 'vue'
2
2
  import ProTable, { TableAction } from './ProTable'
3
3
  import ProForm, { ProFormItem, FormActions } from './ProForm'
4
+ import ProDescriptions from './ProDescriptions'
4
5
  import { useForm } from './ProForm/useForm'
6
+ import { useDescription } from './ProDescriptions/useDescription'
5
7
  import { useProTable } from './ProTable/useProTable'
6
8
  import { useComponentSetting } from './useComponentSetting'
7
9
 
8
10
  export { ProForm, ProFormItem, FormActions, useForm }
9
11
  export { ProTable, useProTable, TableAction }
12
+ export { ProDescriptions, useDescription }
10
13
  export { useComponentSetting }
11
14
  export type { UseComponentSettingReturn } from './useComponentSetting'
12
15
  export type { UseProTableReturn, UseProTablePropsReactive } from './ProTable/useProTable'
16
+ export type { UseDescriptionReturn, UseDescriptionPropsReactive } from './ProDescriptions/useDescription'
13
17
  export * from './ProTable/types'
14
18
  export * from './types'
15
19
 
@@ -19,6 +23,7 @@ const components = [
19
23
  { name: 'ProForm', component: ProForm },
20
24
  { name: 'ProFormItem', component: ProFormItem },
21
25
  { name: 'FormActions', component: FormActions },
26
+ { name: 'ProDescriptions', component: ProDescriptions },
22
27
  ]
23
28
 
24
29
  export function install(Vue: VueConstructor) {
@@ -31,5 +36,6 @@ export default {
31
36
  install,
32
37
  ProTable,
33
38
  ProForm,
39
+ ProDescriptions,
34
40
  TableAction,
35
41
  }
@@ -56,6 +56,7 @@ export type FormListeners = Record<string, ((...args: unknown[]) => unknown) | (
56
56
  /** ProForm Props */
57
57
  export interface ProFormProps {
58
58
  schemas?: ProFormSchema[]
59
+ modelValue?: Record<string, unknown>
59
60
  initialValues?: Record<string, unknown>
60
61
  labelWidth?: string
61
62
  labelPosition?: 'left' | 'right' | 'top'
@@ -159,3 +160,67 @@ export interface ProDescriptionsSchema {
159
160
  /** 栅格占位 */
160
161
  span?: number
161
162
  }
163
+
164
+ /** Description 列数配置 */
165
+ export type DescriptionColumn = number | {
166
+ xxl?: number
167
+ xl?: number
168
+ lg?: number
169
+ md?: number
170
+ sm?: number
171
+ xs?: number
172
+ }
173
+
174
+ /** Description 描述项配置 */
175
+ export interface DescriptionSchema {
176
+ /** 标签 */
177
+ label: string
178
+ /** 数据字段(兼容 Vben Description 的 field) */
179
+ field?: string
180
+ /** 数据字段 */
181
+ dataIndex: string
182
+ /** 栅格占位 */
183
+ span?: number
184
+ /** 是否显示 */
185
+ show?: boolean | ((data: Record<string, unknown>) => boolean)
186
+ /** 标签最小宽度 */
187
+ labelMinWidth?: number
188
+ /** 内容最小宽度 */
189
+ contentMinWidth?: number
190
+ /** 标签样式 */
191
+ labelStyle?: Record<string, string | number>
192
+ /** 内容样式 */
193
+ contentStyle?: Record<string, string | number>
194
+ /** 自定义插槽名称 */
195
+ slot?: string
196
+ /** 自定义渲染 */
197
+ render?: (value: unknown, record: Record<string, unknown>) => VNode | string | number | null | undefined
198
+ }
199
+
200
+ /** Description Props */
201
+ export interface DescriptionProps {
202
+ title?: string
203
+ helpMessage?: string | string[]
204
+ size?: 'medium' | 'small'
205
+ bordered?: boolean
206
+ column?: DescriptionColumn
207
+ schema?: DescriptionSchema[]
208
+ data?: Record<string, unknown>
209
+ emptyText?: string
210
+ useCollapse?: boolean
211
+ collapseOptions?: {
212
+ canExpand?: boolean
213
+ defaultExpand?: boolean
214
+ expandButtonText?: string
215
+ collapseButtonText?: string
216
+ helpMessage?: string | string[]
217
+ visibleRows?: number
218
+ }
219
+ }
220
+
221
+ /** Description 操作实例 */
222
+ export interface DescriptionActionType {
223
+ setProps: (props: Partial<DescriptionProps>) => Promise<void>
224
+ setData: (data: Record<string, unknown>) => Promise<void>
225
+ getData: () => Record<string, unknown>
226
+ }