easybill-ui 1.3.3 → 1.4.0
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/components/CurdForm/src/CurdForm.vue +148 -94
- package/components/CurdForm/src/FormItem.vue +2 -2
- package/components/CurdForm/src/FormTooltip.vue +4 -5
- package/components/CurdForm/src/components/schema-form-date-picker.vue +2 -2
- package/components/CurdForm/src/components/schema-form-input-number.vue +1 -1
- package/components/CurdForm/src/components/schema-form-time-picker.vue +2 -2
- package/components/CurdForm/src/types.ts +41 -26
- package/components/CurdGroupForm/src/CurdGroupForm.vue +5 -7
- package/components/CurdGroupForm/src/hooks/useFormHook.ts +5 -5
- package/components/CurdTable/src/CurdTable.vue +8 -5
- package/components/CurdTable/src/STableItem.vue +5 -2
- package/components/CurdTable/src/types.ts +7 -5
- package/components/DetailInfo/src/types.ts +2 -2
- package/components/FormDialog/src/FormDialog.vue +6 -5
- package/components/FormDialog/src/types.ts +13 -8
- package/components/TableFilter/types.ts +8 -2
- package/package.json +56 -1
- package/utils/hooks/useLocal.ts +12 -10
|
@@ -28,31 +28,24 @@
|
|
|
28
28
|
|
|
29
29
|
<!-- 其他类型使用 el-form-item 包裹 -->
|
|
30
30
|
<template v-else>
|
|
31
|
-
<el-form-item
|
|
32
|
-
v-if="!$slots[formItem.prop + 'Item']"
|
|
33
|
-
:required="rules && rules[formItem.prop]?.find((a) => a.hasOwnProperty('required'))?.required"
|
|
34
|
-
:label="formItem.label"
|
|
35
|
-
:prop="formItem.prop"
|
|
36
|
-
:label-width="formItem.labelWidth"
|
|
37
|
-
:class="getFormItemStyle(formItem)"
|
|
38
|
-
v-bind="getFormItemProps(formItem)"
|
|
39
|
-
>
|
|
31
|
+
<el-form-item v-if="!$slots[formItem.prop + 'Item']" :required="hasRequiredRule(formItem.prop)" :label="formItem.label" :prop="formItem.prop" :label-width="formItem.labelWidth" :class="getFormItemStyle(formItem)" v-bind="getFormItemProps(formItem)">
|
|
40
32
|
<template v-for="(item, key) in getFormItemProps(formItem)?.slots || {}" :key="key" #[key]="row">
|
|
41
33
|
<component :is="item" v-bind="row" />
|
|
42
34
|
</template>
|
|
43
|
-
|
|
35
|
+
<component :is="formItem.slots?.top" :formItem="formItem" :formModel="formModel" />
|
|
44
36
|
<slot :name="formItem.prop" :form-item="formItem" :form-model="formModel"></slot>
|
|
45
37
|
<FormItem v-if="!(formItem.prop && $slots[formItem.prop])" :form-item="formItem" :form-model="formModel" @change="onChange">
|
|
46
38
|
<template #prefix>
|
|
47
|
-
<slot :name="formItem.prop + 'Prefix'" :
|
|
39
|
+
<slot :name="formItem.prop + 'Prefix'" :formItem="formItem" :formModel="formModel"></slot>
|
|
48
40
|
</template>
|
|
49
41
|
<template #suffix>
|
|
50
|
-
<slot :name="formItem.prop + 'Suffix'" :
|
|
42
|
+
<slot :name="formItem.prop + 'Suffix'" :formItem="formItem" :formModel="formModel"></slot>
|
|
51
43
|
</template>
|
|
52
44
|
</FormItem>
|
|
53
|
-
<slot :name="formItem.prop + 'Bottom'" :
|
|
45
|
+
<slot :name="formItem.prop + 'Bottom'" :formItem="formItem" :formModel="formModel"></slot>
|
|
46
|
+
<component :is="formItem.slots?.bottom" :formItem="formItem" :formModel="formModel" />
|
|
54
47
|
</el-form-item>
|
|
55
|
-
<slot :name="formItem.prop + 'Item'" :
|
|
48
|
+
<slot :name="formItem.prop + 'Item'" :formItem="formItem" :formModel="formModel"></slot>
|
|
56
49
|
</template>
|
|
57
50
|
</template>
|
|
58
51
|
<template v-if="$slots['operate-button']">
|
|
@@ -64,10 +57,10 @@
|
|
|
64
57
|
</template>
|
|
65
58
|
|
|
66
59
|
<script lang="ts" setup>
|
|
67
|
-
import { ElForm, type FormRules } from "element-plus"
|
|
60
|
+
import { ElForm, type FormItemRule, type FormRules } from "element-plus"
|
|
68
61
|
import { computed, getCurrentInstance, onMounted, provide, reactive, ref, triggerRef, watch, type PropType } from "vue"
|
|
69
62
|
import FormItem from "./FormItem.vue"
|
|
70
|
-
import type { CurdFormOptionItem, Fields, FormContext, FormItem as FormItemType, FormSchema } from "./types"
|
|
63
|
+
import type { CurdFormOptionItem, Fields, FormContext, FormItemProvider, FormItemSearchResult, FormItem as FormItemType, FormSchema } from "./types"
|
|
71
64
|
import { deepClone } from "./utils/common"
|
|
72
65
|
|
|
73
66
|
const props = defineProps({
|
|
@@ -97,6 +90,101 @@ const sFormSchema = ref(props.formSchema)
|
|
|
97
90
|
let formModel = reactive<Fields>(props.modelValue || {})
|
|
98
91
|
const curdFormContext = reactive<FormContext>({} as FormContext)
|
|
99
92
|
const instance = getCurrentInstance()
|
|
93
|
+
const formItemProviders = new Map<string | symbol, FormItemProvider["getItems"]>()
|
|
94
|
+
|
|
95
|
+
const normalizeFormItems = (items?: FormItemType[] | null) => {
|
|
96
|
+
return Array.isArray(items) ? items : []
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const walkBuiltInFormItems = (items: FormItemType[], callback: (item: FormItemType, parent?: FormItemType, path?: string) => void | boolean, parent?: FormItemType, parentPath = "") => {
|
|
100
|
+
for (const item of normalizeFormItems(items)) {
|
|
101
|
+
const currentPath = parentPath ? `${parentPath}.${item.prop}` : item.prop
|
|
102
|
+
const shouldStop = callback(item, parent, currentPath)
|
|
103
|
+
if (shouldStop) return true
|
|
104
|
+
|
|
105
|
+
if (item.type === "choose" && item.options) {
|
|
106
|
+
for (const option of item.options) {
|
|
107
|
+
if (option.items?.length && walkBuiltInFormItems(option.items, callback, item, `${currentPath}.${option.value}`)) {
|
|
108
|
+
return true
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const getRegisteredFormItems = (providerId?: string | symbol) => {
|
|
117
|
+
const items: FormItemType[] = []
|
|
118
|
+
formItemProviders.forEach((getItems, id) => {
|
|
119
|
+
if (typeof providerId !== "undefined" && id !== providerId) return
|
|
120
|
+
items.push(...normalizeFormItems(getItems()))
|
|
121
|
+
})
|
|
122
|
+
return items
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const collectDefaultValues = (items: FormItemType[]) => {
|
|
126
|
+
const values: Fields = {}
|
|
127
|
+
walkBuiltInFormItems(items, (item) => {
|
|
128
|
+
item.eventObject ??= {}
|
|
129
|
+
if (typeof item.value !== "undefined" && item.prop && (typeof formModel[item.prop] == "undefined" || formModel[item.prop] === "" || formModel[item.prop] === null)) {
|
|
130
|
+
values[item.prop] = item.value
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
return values
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const loadFormItemOptions = async (formItem: FormItemType, option?: unknown) => {
|
|
137
|
+
if (formItem.asyncOptions && !instance?.isUnmounted) {
|
|
138
|
+
formItem.loading = true
|
|
139
|
+
triggerRef(schemaItems)
|
|
140
|
+
formItem.options =
|
|
141
|
+
(await formItem
|
|
142
|
+
.asyncOptions(formModel, formItem, curdFormContext, option)
|
|
143
|
+
.catch((err) => console.error("loadOptionError", err))
|
|
144
|
+
.finally(() => (formItem.loading = false))) || []
|
|
145
|
+
triggerRef(schemaItems)
|
|
146
|
+
if (!instance?.isUnmounted && formItem.eventObject?.optionLoaded) formItem.eventObject.optionLoaded(formModel, formItem, curdFormContext, option)
|
|
147
|
+
}
|
|
148
|
+
return formItem.options || []
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const loadAutoloadFormItems = (items: FormItemType[]) => {
|
|
152
|
+
walkBuiltInFormItems(items, (item) => {
|
|
153
|
+
if (item.asyncOptions && (item.autoload || typeof item.autoload == "undefined") && item.asyncOptions instanceof Function) {
|
|
154
|
+
void loadFormItemOptions(item)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const findFormItemInItems = (items: FormItemType[], prop: string, providerId?: string | symbol): FormItemSearchResult | undefined => {
|
|
160
|
+
let result: FormItemSearchResult | undefined
|
|
161
|
+
walkBuiltInFormItems(items, (item, parent, path) => {
|
|
162
|
+
if (item.prop == prop) {
|
|
163
|
+
result = { item, parent, path: path || prop, providerId }
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
return false
|
|
167
|
+
})
|
|
168
|
+
return result
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const refreshFormItems = (providerId?: string | symbol) => {
|
|
172
|
+
const registeredItems = getRegisteredFormItems(providerId)
|
|
173
|
+
Object.assign(formModel, collectDefaultValues(registeredItems))
|
|
174
|
+
loadAutoloadFormItems(registeredItems)
|
|
175
|
+
triggerRef(schemaItems)
|
|
176
|
+
triggerRef(rules)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const registerFormItems = (provider: FormItemProvider) => {
|
|
180
|
+
formItemProviders.set(provider.id, provider.getItems)
|
|
181
|
+
refreshFormItems(provider.id)
|
|
182
|
+
return () => {
|
|
183
|
+
formItemProviders.delete(provider.id)
|
|
184
|
+
triggerRef(schemaItems)
|
|
185
|
+
triggerRef(rules)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
100
188
|
|
|
101
189
|
watch(
|
|
102
190
|
() => props.modelValue,
|
|
@@ -116,28 +204,7 @@ watch(
|
|
|
116
204
|
{ deep: true },
|
|
117
205
|
)
|
|
118
206
|
// 先从schema中读取默认值
|
|
119
|
-
const schemaValues = sFormSchema.value.formItem
|
|
120
|
-
currentValue.eventObject ??= {}
|
|
121
|
-
if (typeof currentValue.value !== "undefined" && currentValue.prop && (typeof formModel[currentValue.prop] == "undefined" || formModel[currentValue.prop] === "" || formModel[currentValue.prop] === null)) {
|
|
122
|
-
previousValue[currentValue.prop] = currentValue.value
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 处理 choose 类型 items 的默认值
|
|
126
|
-
if (currentValue.type === "choose" && currentValue.options) {
|
|
127
|
-
currentValue.options.forEach((option) => {
|
|
128
|
-
if (option.items) {
|
|
129
|
-
option.items.forEach((subItem) => {
|
|
130
|
-
subItem.eventObject ??= {}
|
|
131
|
-
if (typeof subItem.value !== "undefined" && subItem.prop && (typeof formModel[subItem.prop] == "undefined" || formModel[subItem.prop] === "" || formModel[subItem.prop] === null)) {
|
|
132
|
-
previousValue[subItem.prop] = subItem.value
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return previousValue
|
|
140
|
-
}, {})
|
|
207
|
+
const schemaValues = collectDefaultValues(sFormSchema.value.formItem)
|
|
141
208
|
|
|
142
209
|
Object.assign(formModel, schemaValues)
|
|
143
210
|
// 如果有默认值,则覆盖
|
|
@@ -157,29 +224,7 @@ const schemaItems = computed(() => {
|
|
|
157
224
|
})
|
|
158
225
|
})
|
|
159
226
|
// 异步设置默认数据
|
|
160
|
-
sFormSchema.value.formItem
|
|
161
|
-
// 异步选项 - 顶层表单项
|
|
162
|
-
if (item.asyncOptions && (item.autoload || typeof item.autoload == "undefined") && item.asyncOptions instanceof Function) {
|
|
163
|
-
item.loading = true
|
|
164
|
-
item.options = await item.asyncOptions(formModel, item, curdFormContext).finally(() => (item.loading = false))
|
|
165
|
-
if (!instance?.isUnmounted && item.eventObject?.optionLoaded) item.eventObject.optionLoaded(formModel, item, curdFormContext)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 处理 choose 类型的 items 的异步选项
|
|
169
|
-
if (item.type === "choose" && item.options) {
|
|
170
|
-
for (const option of item.options) {
|
|
171
|
-
if (option.items && option.items.length > 0) {
|
|
172
|
-
for (const subItem of option.items) {
|
|
173
|
-
if (subItem.asyncOptions && (subItem.autoload || typeof subItem.autoload == "undefined") && subItem.asyncOptions instanceof Function) {
|
|
174
|
-
subItem.loading = true
|
|
175
|
-
subItem.options = await subItem.asyncOptions(formModel, subItem, curdFormContext).finally(() => (subItem.loading = false))
|
|
176
|
-
if (!instance?.isUnmounted && subItem.eventObject?.optionLoaded) subItem.eventObject.optionLoaded(formModel, subItem, curdFormContext)
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
})
|
|
227
|
+
loadAutoloadFormItems(sFormSchema.value.formItem)
|
|
183
228
|
|
|
184
229
|
// 生成表单验证规则
|
|
185
230
|
const rules = computed(() => {
|
|
@@ -196,7 +241,7 @@ const rules = computed(() => {
|
|
|
196
241
|
baseRules = sFormSchema.value.rules || {}
|
|
197
242
|
}
|
|
198
243
|
|
|
199
|
-
// 合并 choose 类型 items
|
|
244
|
+
// 合并 choose 类型 items 和自定义组件注册项的验证规则
|
|
200
245
|
const mergedRules: FormRules = { ...baseRules }
|
|
201
246
|
sFormSchema.value.formItem.forEach((formItem) => {
|
|
202
247
|
if (formItem.type === "choose" && formItem.options) {
|
|
@@ -211,38 +256,39 @@ const rules = computed(() => {
|
|
|
211
256
|
})
|
|
212
257
|
}
|
|
213
258
|
})
|
|
259
|
+
walkBuiltInFormItems(getRegisteredFormItems(), (formItem) => {
|
|
260
|
+
if (formItem.prop && formItem.rules) {
|
|
261
|
+
mergedRules[formItem.prop] = formItem.rules
|
|
262
|
+
}
|
|
263
|
+
})
|
|
214
264
|
|
|
215
265
|
return mergedRules
|
|
216
266
|
})
|
|
267
|
+
const normalizeFormItemRules = (rule: FormItemRule | FormItemRule[] | undefined) => {
|
|
268
|
+
if (!rule) return []
|
|
269
|
+
return Array.isArray(rule) ? rule : [rule]
|
|
270
|
+
}
|
|
271
|
+
const hasRequiredRule = (prop: string) => {
|
|
272
|
+
return normalizeFormItemRules(rules.value[prop] as FormItemRule | FormItemRule[] | undefined).some((rule) => Object.prototype.hasOwnProperty.call(rule, "required") && rule.required)
|
|
273
|
+
}
|
|
217
274
|
|
|
218
275
|
/**
|
|
219
276
|
* 递归查找表单项
|
|
220
277
|
* @param prop 表单项的 prop
|
|
221
278
|
* @returns 找到的表单项对象,包含 parent 信息
|
|
222
279
|
*/
|
|
223
|
-
const findFormItem = (prop: string):
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (topLevelItem) {
|
|
227
|
-
return { item: topLevelItem, path: prop }
|
|
228
|
-
}
|
|
280
|
+
const findFormItem = (prop: string): FormItemSearchResult | undefined => {
|
|
281
|
+
const schemaResult = findFormItemInItems(sFormSchema.value.formItem, prop)
|
|
282
|
+
if (schemaResult) return schemaResult
|
|
229
283
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
for (const option of formItem.options) {
|
|
234
|
-
if (option.items) {
|
|
235
|
-
const foundItem = option.items.find((item) => item.prop === prop)
|
|
236
|
-
if (foundItem) {
|
|
237
|
-
return { item: foundItem, parent: formItem, path: `${formItem.prop}.${option.value}.${prop}` }
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
284
|
+
for (const [providerId, getItems] of formItemProviders) {
|
|
285
|
+
const providerResult = findFormItemInItems(normalizeFormItems(getItems()), prop, providerId)
|
|
286
|
+
if (providerResult) return providerResult
|
|
242
287
|
}
|
|
243
288
|
|
|
244
289
|
return undefined
|
|
245
290
|
}
|
|
291
|
+
const hasFormItem = (prop: string) => Boolean(findFormItem(prop))
|
|
246
292
|
|
|
247
293
|
// 供外部使用
|
|
248
294
|
const validate = (callback: (valid: boolean) => void) => {
|
|
@@ -257,18 +303,14 @@ const loadOptions = async (prop: string, option?: unknown) => {
|
|
|
257
303
|
}
|
|
258
304
|
|
|
259
305
|
const cur = result.item
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
.asyncOptions(formModel, cur, curdFormContext, option)
|
|
266
|
-
.catch((err) => console.error("loadOptionError", err))
|
|
267
|
-
.finally(() => (cur.loading = false))) || []
|
|
268
|
-
triggerRef(schemaItems)
|
|
269
|
-
if (!instance?.isUnmounted && cur.eventObject?.optionLoaded) cur.eventObject.optionLoaded(formModel, cur, curdFormContext, option)
|
|
306
|
+
return loadFormItemOptions(cur, option)
|
|
307
|
+
}
|
|
308
|
+
const contextLoadOptions = (prop: string, option?: unknown) => {
|
|
309
|
+
if (hasFormItem(prop)) {
|
|
310
|
+
return loadOptions(prop, option)
|
|
270
311
|
}
|
|
271
|
-
|
|
312
|
+
|
|
313
|
+
return props.extendContext?.loadOptions?.(prop, option)
|
|
272
314
|
}
|
|
273
315
|
// 给某个item赋值options
|
|
274
316
|
const setOptions = async (prop: string, options: CurdFormOptionItem[], option?: unknown) => {
|
|
@@ -360,13 +402,21 @@ const getFormProps = computed(() => {
|
|
|
360
402
|
return { ...args }
|
|
361
403
|
})
|
|
362
404
|
|
|
363
|
-
curdFormContext.loadOptions =
|
|
405
|
+
curdFormContext.loadOptions = contextLoadOptions
|
|
364
406
|
curdFormContext.setOptions = setOptions
|
|
365
407
|
curdFormContext.change = onChange
|
|
366
408
|
curdFormContext.formModel = formModel
|
|
367
409
|
curdFormContext.formSchema = props.formSchema
|
|
368
|
-
|
|
369
|
-
|
|
410
|
+
curdFormContext.findFormItem = findFormItem
|
|
411
|
+
curdFormContext.hasFormItem = hasFormItem
|
|
412
|
+
curdFormContext.registerFormItems = registerFormItems
|
|
413
|
+
curdFormContext.refreshFormItems = refreshFormItems
|
|
414
|
+
|
|
415
|
+
if (props.extendContext) {
|
|
416
|
+
const extendContext = { ...props.extendContext }
|
|
417
|
+
delete extendContext.loadOptions
|
|
418
|
+
Object.assign(curdFormContext, extendContext)
|
|
419
|
+
}
|
|
370
420
|
|
|
371
421
|
provide("curdFormContext", curdFormContext)
|
|
372
422
|
onMounted(() => {
|
|
@@ -384,6 +434,10 @@ defineExpose({
|
|
|
384
434
|
getFormItemStyle,
|
|
385
435
|
getFormItemProps,
|
|
386
436
|
validate,
|
|
437
|
+
findFormItem,
|
|
438
|
+
hasFormItem,
|
|
439
|
+
registerFormItems,
|
|
440
|
+
refreshFormItems,
|
|
387
441
|
loadOptions,
|
|
388
442
|
setOptions,
|
|
389
443
|
onChange,
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<slot name="prefix"></slot>
|
|
6
6
|
<component :is="comp" v-if="comp" v-model="modelRef[props.formItem.prop || '']" :form-item="props.formItem" :form-model="modelRef" :props="formItemProps" :event-object="eventObject">
|
|
7
7
|
<template v-for="(item, key) in formItemProps.slots" :key="key" #[key]="slotScope">
|
|
8
|
-
<component :is="item" v-model="modelRef[props.formItem.prop || '']" :form-item="props.formItem" :form-model="modelRef" :props="formItemProps" :event-object="eventObject" />
|
|
8
|
+
<component :is="item" v-model="modelRef[props.formItem.prop || '']" v-bind="slotScope" :form-item="props.formItem" :form-model="modelRef" :props="formItemProps" :event-object="eventObject" />
|
|
9
9
|
</template>
|
|
10
10
|
</component>
|
|
11
11
|
<component :is="props.formItem.type" v-else v-model="modelRef[props.formItem.prop || '']" v-bind="formItemProps" v-on="eventObject">
|
|
12
12
|
<template v-for="(item, key) in formItemProps.slots" :key="key" #[key]="slotScope">
|
|
13
|
-
<component :is="item" v-model="modelRef[props.formItem.prop || '']" :form-item="props.formItem" :form-model="modelRef" :props="formItemProps" :event-object="eventObject" />
|
|
13
|
+
<component :is="item" v-model="modelRef[props.formItem.prop || '']" v-bind="slotScope" :form-item="props.formItem" :form-model="modelRef" :props="formItemProps" :event-object="eventObject" />
|
|
14
14
|
</template>
|
|
15
15
|
</component>
|
|
16
16
|
|
|
@@ -10,12 +10,11 @@
|
|
|
10
10
|
</template>
|
|
11
11
|
<script lang="ts" setup>
|
|
12
12
|
import { Warning } from "@element-plus/icons-vue"
|
|
13
|
-
import { type ElTooltipProps } from "element-plus"
|
|
14
13
|
import { type PropType, computed } from "vue"
|
|
15
|
-
import type { Fields, FormItem } from "./types"
|
|
14
|
+
import type { Fields, FormItem, TooltipProps } from "./types"
|
|
16
15
|
const props = defineProps({
|
|
17
16
|
tooltip: {
|
|
18
|
-
type: [String, Function] as PropType<string | ((formModel: Fields, formItem: FormItem) => Partial<
|
|
17
|
+
type: [String, Function, Object] as PropType<string | ((formModel: Fields, formItem: FormItem) => Partial<TooltipProps> | string) | Partial<TooltipProps>>,
|
|
19
18
|
default: null,
|
|
20
19
|
},
|
|
21
20
|
formItem: {
|
|
@@ -40,11 +39,11 @@ const tooltipModel = computed(() => {
|
|
|
40
39
|
return getTooltip(tooltip)
|
|
41
40
|
})
|
|
42
41
|
// 获取组件tooltip内容
|
|
43
|
-
const getTooltip = (tooltip: Partial<
|
|
42
|
+
const getTooltip = (tooltip: Partial<TooltipProps> | string): Partial<TooltipProps> => {
|
|
44
43
|
if (!tooltip) {
|
|
45
44
|
return { content: "" }
|
|
46
45
|
}
|
|
47
|
-
let t: Partial<
|
|
46
|
+
let t: Partial<TooltipProps> = {}
|
|
48
47
|
if (typeof tooltip == "string") {
|
|
49
48
|
t = { content: tooltip }
|
|
50
49
|
} else {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-date-picker v-model="model" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD" v-bind="props" v-on="eventObject">
|
|
3
|
-
<template v-for="(item, key) in props.
|
|
4
|
-
<component :is="item" v-model="model" :form-item="
|
|
3
|
+
<template v-for="(item, key) in props.slots" :key="key" #[key]="slotScope">
|
|
4
|
+
<component :is="item" v-model="model" v-bind="slotScope" :form-item="formItem" :form-model="formModel" :props="props" :event-object="eventObject" />
|
|
5
5
|
</template>
|
|
6
6
|
</el-date-picker>
|
|
7
7
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-input-number v-model="model" v-bind="props.props" v-on="eventObject">
|
|
3
3
|
<template v-for="(item, key) in props.props?.slots" :key="key" #[key]="slotScope">
|
|
4
|
-
<component :is="item" v-model="model" :form-item="props.formItem" :form-model="props.formModel" :props="props.props" :event-object="eventObject" />
|
|
4
|
+
<component :is="item" v-model="model" v-bind="slotScope" :form-item="props.formItem" :form-model="props.formModel" :props="props.props" :event-object="eventObject" />
|
|
5
5
|
</template>
|
|
6
6
|
</el-input-number>
|
|
7
7
|
</template>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-time-picker v-model="model" v-bind="props" v-on="eventObject">
|
|
3
|
-
<template v-for="(item, key) in props.
|
|
4
|
-
<component :is="item" v-model="model" :form-item="formItem" :form-model="formModel" :props="
|
|
3
|
+
<template v-for="(item, key) in props.slots" :key="key" #[key]="slotScope">
|
|
4
|
+
<component :is="item" v-model="model" v-bind="slotScope" :form-item="formItem" :form-model="formModel" :props="props" :event-object="eventObject" />
|
|
5
5
|
</template>
|
|
6
6
|
</el-time-picker>
|
|
7
7
|
</template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ElForm, type FormItemRule, type FormRules
|
|
1
|
+
import { ElForm, type FormItemRule, type FormRules } from "element-plus"
|
|
2
2
|
import type { Arrayable } from "element-plus/es/utils"
|
|
3
3
|
import { defineComponent, type PropType, type VNode } from "vue"
|
|
4
4
|
import type { OptionItem } from "../../ConstantStatus"
|
|
@@ -32,7 +32,7 @@ export interface FormItem {
|
|
|
32
32
|
hidden?: boolean | ((model: Fields) => boolean)
|
|
33
33
|
rules?: Arrayable<FormItemRule>
|
|
34
34
|
props?: FormItemPropObject | ((formModel: Fields, formItem: FormItem) => FormItemPropObject)
|
|
35
|
-
formItemProps?: FormItemPropObject | ((formModel: Fields, formItem: FormItem) =>
|
|
35
|
+
formItemProps?: FormItemPropObject | ((formModel: Fields, formItem: FormItem) => FormItemPropObject)
|
|
36
36
|
labelWidth?: string | number
|
|
37
37
|
labelPosition?: "left" | "right" | "top" | string
|
|
38
38
|
span?: number
|
|
@@ -47,37 +47,41 @@ export interface FormItem {
|
|
|
47
47
|
export type FormItemTypeEmun = "input" | "select" | "radio" | "checkbox" | "input-number" | "switch" | "file" | "date-picker" | "time-picker" | "color-picker" | "value" | "tree-select" | "autocomplete" | "choose"
|
|
48
48
|
export interface FormItemPropObject extends Fields {
|
|
49
49
|
slots?: Record<string, (props?: FormItemPropObject) => VNode | VNode[] | string | null>
|
|
50
|
-
all?: boolean |
|
|
50
|
+
all?: boolean | OptionItem
|
|
51
51
|
empty?: string | VNode
|
|
52
52
|
noDataText?: string
|
|
53
53
|
style?: Record<string, string> | string
|
|
54
54
|
}
|
|
55
|
-
export interface TooltipProps {
|
|
56
|
-
effect
|
|
57
|
-
content
|
|
58
|
-
rawContent
|
|
59
|
-
placement
|
|
60
|
-
disabled
|
|
61
|
-
offset
|
|
62
|
-
transition
|
|
63
|
-
popperOptions
|
|
64
|
-
showAfter
|
|
65
|
-
showArrow
|
|
66
|
-
hideAfter
|
|
67
|
-
autoClose
|
|
68
|
-
popperClass
|
|
69
|
-
enterable
|
|
70
|
-
teleported
|
|
71
|
-
trigger
|
|
55
|
+
export interface TooltipProps extends Record<string, unknown> {
|
|
56
|
+
effect?: "dark" | "light" | string
|
|
57
|
+
content?: string
|
|
58
|
+
rawContent?: boolean
|
|
59
|
+
placement?: string
|
|
60
|
+
disabled?: boolean
|
|
61
|
+
offset?: number
|
|
62
|
+
transition?: string
|
|
63
|
+
popperOptions?: unknown
|
|
64
|
+
showAfter?: number
|
|
65
|
+
showArrow?: boolean
|
|
66
|
+
hideAfter?: number
|
|
67
|
+
autoClose?: number
|
|
68
|
+
popperClass?: string
|
|
69
|
+
enterable?: boolean
|
|
70
|
+
teleported?: boolean
|
|
71
|
+
trigger?: string | string[]
|
|
72
72
|
}
|
|
73
73
|
export interface FormContext {
|
|
74
|
-
loadOptions: (prop: string, config?:
|
|
75
|
-
setOptions: (prop: string, options: CurdFormOptionItem[], config?: unknown) => void
|
|
74
|
+
loadOptions: (prop: string, config?: unknown) => void | Promise<CurdFormOptionItem[]> | CurdFormOptionItem[]
|
|
75
|
+
setOptions: (prop: string, options: CurdFormOptionItem[], config?: unknown) => void | Promise<void>
|
|
76
76
|
change: (formModel: Fields, formItem: FormItem) => void
|
|
77
77
|
formModel: Fields
|
|
78
78
|
formSchema: FormSchema
|
|
79
79
|
formRef: InstanceType<typeof ElForm> | undefined
|
|
80
80
|
components: Record<string, unknown>
|
|
81
|
+
findFormItem?: (prop: string) => FormItemSearchResult | undefined
|
|
82
|
+
hasFormItem?: (prop: string) => boolean
|
|
83
|
+
registerFormItems?: (provider: FormItemProvider) => () => void
|
|
84
|
+
refreshFormItems?: (providerId?: string | symbol) => void
|
|
81
85
|
}
|
|
82
86
|
export interface Fields {
|
|
83
87
|
[key: string]: unknown
|
|
@@ -92,13 +96,24 @@ export interface CurdFormOptionItem extends OptionItem {
|
|
|
92
96
|
/** 内联表单项定义,用于 choose 类型 */
|
|
93
97
|
items?: FormItem[]
|
|
94
98
|
}
|
|
99
|
+
export interface FormItemProvider {
|
|
100
|
+
id: string | symbol
|
|
101
|
+
getItems: () => FormItem[] | undefined | null
|
|
102
|
+
}
|
|
103
|
+
export interface FormItemSearchResult {
|
|
104
|
+
item: FormItem
|
|
105
|
+
parent?: FormItem
|
|
106
|
+
path: string
|
|
107
|
+
providerId?: string | symbol
|
|
108
|
+
}
|
|
95
109
|
// interface EventObjectDefault {
|
|
96
110
|
// change?: (formModel: Fields, formItem: FormItem, proxy: any) => void
|
|
97
111
|
// }
|
|
112
|
+
export type EventObjectHandler = (formModel: Fields, formItem: FormItem, context?: FormContext, ...args: unknown[]) => void | boolean
|
|
98
113
|
export interface EventObject {
|
|
99
|
-
change?:
|
|
100
|
-
optionLoaded?:
|
|
101
|
-
[key: string]:
|
|
114
|
+
change?: EventObjectHandler
|
|
115
|
+
optionLoaded?: EventObjectHandler
|
|
116
|
+
[key: string]: EventObjectHandler | undefined
|
|
102
117
|
}
|
|
103
118
|
// export interface OptionItem {
|
|
104
119
|
// label: string
|
|
@@ -121,7 +136,7 @@ export const FormItemProps = {
|
|
|
121
136
|
default: () => ({}),
|
|
122
137
|
},
|
|
123
138
|
eventObject: {
|
|
124
|
-
type: Object as PropType<
|
|
139
|
+
type: Object as PropType<EventObject>,
|
|
125
140
|
default: () => ({}),
|
|
126
141
|
},
|
|
127
142
|
modelValue: {
|
|
@@ -70,13 +70,11 @@ const loadOptions = (prop: string, config?: unknown) => {
|
|
|
70
70
|
let has = false
|
|
71
71
|
for (const index in props.schema.items) {
|
|
72
72
|
const group = props.schema.items[index]
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
formRef.value[(group.step || "") + group.groupName + index]?.loadOptions(prop, config)
|
|
79
|
-
}
|
|
73
|
+
const form = formRef.value[(group.step || "") + group.groupName + index]
|
|
74
|
+
const hasFormItem = form?.hasFormItem ? form.hasFormItem(prop) : group.schema.formItem.some((item) => item.prop == prop)
|
|
75
|
+
if (hasFormItem) {
|
|
76
|
+
has = true
|
|
77
|
+
form?.loadOptions(prop, config)
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
if (!has) {
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { CurdForm } from "easybill-ui"
|
|
2
2
|
import { ref, type Ref } from "vue"
|
|
3
|
-
import type {
|
|
3
|
+
import type { CurdGroupFormSchema, CurdGroupFormSchemaItem } from "../../types"
|
|
4
4
|
|
|
5
5
|
export const useFormHook = (): {
|
|
6
6
|
form: Ref<Record<string, unknown>>
|
|
7
7
|
formRef: Ref<Record<string, InstanceType<typeof CurdForm>>>
|
|
8
8
|
submit: () => void
|
|
9
|
-
schema: Ref<
|
|
9
|
+
schema: Ref<CurdGroupFormSchema | undefined>
|
|
10
10
|
validate: (callback: (valid: boolean) => void) => void
|
|
11
11
|
loading: Ref<boolean>
|
|
12
|
-
schemaItemHidden: (item:
|
|
12
|
+
schemaItemHidden: (item: CurdGroupFormSchemaItem) => boolean
|
|
13
13
|
} => {
|
|
14
14
|
const formRef = ref<Record<string, InstanceType<typeof CurdForm>>>({})
|
|
15
15
|
const form = ref<Record<string, unknown>>({})
|
|
16
|
-
const schema = ref<
|
|
16
|
+
const schema = ref<CurdGroupFormSchema>()
|
|
17
17
|
const loading = ref(false)
|
|
18
|
-
const schemaItemHidden = (item:
|
|
18
|
+
const schemaItemHidden = (item: CurdGroupFormSchemaItem) => {
|
|
19
19
|
if (item?.hidden && item?.hidden instanceof Function) {
|
|
20
20
|
return item.hidden(form.value, item)
|
|
21
21
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<el-table-column v-else-if="item.type == 'selection'" type="selection" v-bind="item" />
|
|
22
22
|
<STableItem v-else :ref="getTableItemRef(item.prop)" :schema="item" :is-slot="!!$slots[item.prop]" :is-slot-header="!!$slots[item.prop + 'Header']" :option="option" @search="onItemChange">
|
|
23
23
|
<template v-for="(_slot, key) in $slots" :key="key" #[key]="scopeChild">
|
|
24
|
-
<slot :name="key" v-bind="scopeChild"></slot>
|
|
24
|
+
<slot :name="key" v-bind="normalizeSlotScope(scopeChild)"></slot>
|
|
25
25
|
</template>
|
|
26
26
|
</STableItem>
|
|
27
27
|
</template>
|
|
@@ -133,12 +133,12 @@ const props = defineProps({
|
|
|
133
133
|
},
|
|
134
134
|
// 自定义创建函数
|
|
135
135
|
fetchCreate: {
|
|
136
|
-
type: Function as PropType<(formModel: Fields) => Promise<void>>,
|
|
136
|
+
type: Function as PropType<(formModel: Fields) => void | boolean | Promise<void | boolean>>,
|
|
137
137
|
default: null,
|
|
138
138
|
},
|
|
139
139
|
// 自定义编辑函数
|
|
140
140
|
fetchEdit: {
|
|
141
|
-
type: Function as PropType<(
|
|
141
|
+
type: Function as PropType<(formModel: Fields, row: Record<string, unknown>, index?: number) => void | boolean | Promise<void | boolean>>,
|
|
142
142
|
|
|
143
143
|
default: null,
|
|
144
144
|
},
|
|
@@ -248,6 +248,7 @@ const fetchData = async (opt?: FetchDataOpt) => {
|
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
const tableItemRefs: Ref<Record<string, InstanceType<typeof STableItem>>> = ref({})
|
|
251
|
+
const normalizeSlotScope = (scope: unknown) => (scope && typeof scope === "object" ? scope : {})
|
|
251
252
|
const getTableItemRef = (prop: string) => {
|
|
252
253
|
return (el: unknown) => {
|
|
253
254
|
if (el) {
|
|
@@ -404,8 +405,10 @@ const create = (row?: Record<string, unknown>, index?: number) => {
|
|
|
404
405
|
fields: row as Fields,
|
|
405
406
|
width: formAttrs?.width || 600,
|
|
406
407
|
handleOk: async (modelRef: Fields) => {
|
|
407
|
-
|
|
408
|
-
|
|
408
|
+
if (row) {
|
|
409
|
+
return await props.fetchEdit?.(modelRef, row, index)
|
|
410
|
+
}
|
|
411
|
+
return await props.fetchCreate?.(modelRef)
|
|
409
412
|
},
|
|
410
413
|
...eoptions,
|
|
411
414
|
})
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<template v-for="item in props.schema.children" :key="item.label">
|
|
15
15
|
<STableItem :ref="(el) => (tableItemRefs[item.prop] = el)" :schema="item" :is-slot="!!$slots[item.prop]" :is-slot-header="!!$slots[item.prop + 'Header']" :option="option" @search="onItemChange">
|
|
16
16
|
<template v-for="(_slot, key) in $slots" :key="key" #[key]="scopeChild">
|
|
17
|
-
<slot :name="key" v-bind="scopeChild"></slot>
|
|
17
|
+
<slot :name="key" v-bind="normalizeSlotScope(scopeChild)"></slot>
|
|
18
18
|
</template>
|
|
19
19
|
</STableItem>
|
|
20
20
|
</template>
|
|
@@ -44,6 +44,7 @@ import { useLocale } from "easybill-ui"
|
|
|
44
44
|
import { ElMessage } from "element-plus"
|
|
45
45
|
import { computed, inject, type PropType, ref, type Ref } from "vue"
|
|
46
46
|
import ConstantStatus from "../../ConstantStatus"
|
|
47
|
+
import type { Fields } from "../../CurdForm"
|
|
47
48
|
import type { ParamsItem } from "../../TableFilter"
|
|
48
49
|
import { copy } from "../utils/common"
|
|
49
50
|
import STableItemFilter from "./STableItemFilter.vue"
|
|
@@ -72,6 +73,7 @@ const props = defineProps({
|
|
|
72
73
|
default: () => ({}),
|
|
73
74
|
},
|
|
74
75
|
})
|
|
76
|
+
defineSlots<Record<string, (scope: Record<string, unknown>) => unknown>>()
|
|
75
77
|
const selectParams = inject<Ref<Array<ParamsItem>>>("selectParams")
|
|
76
78
|
const filterSchema = computed(() => {
|
|
77
79
|
let result = selectParams?.value.filter((a) => a.prop == props.schema.filter?.prop || a.prop == props.schema.prop) //getFilterFromColumn(props.schema)
|
|
@@ -94,7 +96,7 @@ const copyValue = async (value: unknown) => {
|
|
|
94
96
|
ElMessage.success(t("el.table.clickCopySuccess"))
|
|
95
97
|
}
|
|
96
98
|
const emits = defineEmits(["search"])
|
|
97
|
-
const search = inject("search")
|
|
99
|
+
const search = inject<Fields>("search", {})
|
|
98
100
|
const getColumnHidden = computed(() => {
|
|
99
101
|
if (props.schema.hidden && props.schema.hidden instanceof Function) {
|
|
100
102
|
return props.schema.hidden(props.schema, search)
|
|
@@ -109,6 +111,7 @@ const onSearch = (opt: { listQuery: Record<string, unknown> }) => {
|
|
|
109
111
|
if (tableItemFilterRef.value) tableItemFilterRef.value.search(opt)
|
|
110
112
|
}
|
|
111
113
|
const tableItemRefs: Ref<Record<string, unknown>> = ref({})
|
|
114
|
+
const normalizeSlotScope = (scope: unknown) => (scope && typeof scope === "object" ? scope : {})
|
|
112
115
|
const onItemChange = (prop: string, value: string) => {
|
|
113
116
|
emits("search", prop, value, filterSchema.value)
|
|
114
117
|
}
|
|
@@ -8,6 +8,8 @@ import type { EventObject, FormSchema } from "./../../CurdForm/src/types"
|
|
|
8
8
|
import type { VNode } from "vue"
|
|
9
9
|
import type { FormDialogOptions } from "../../FormDialog/src/types"
|
|
10
10
|
|
|
11
|
+
export type MaybePromise<T> = T | Promise<T>
|
|
12
|
+
|
|
11
13
|
export interface CurdTableProps<T = unknown> extends Partial<TableProps<T>> {
|
|
12
14
|
rowKey?: string
|
|
13
15
|
data?: T[]
|
|
@@ -15,22 +17,22 @@ export interface CurdTableProps<T = unknown> extends Partial<TableProps<T>> {
|
|
|
15
17
|
pageOptions?: { pageIndex?: number; pageSize?: number; total?: number } & Fields
|
|
16
18
|
option?: Partial<PropOption>
|
|
17
19
|
fetchData?: (opt: FeachDataParam) => Promise<{ total?: number; list?: T[] } | void>
|
|
18
|
-
fetchCreate?: (formModel: Fields) =>
|
|
19
|
-
fetchEdit?: (row: T) =>
|
|
20
|
-
fetchRemove?: (row: T) => Promise<void>
|
|
20
|
+
fetchCreate?: (formModel: Fields) => MaybePromise<void | boolean>
|
|
21
|
+
fetchEdit?: (formModel: Fields, row: T, index?: number) => MaybePromise<void | boolean>
|
|
22
|
+
fetchRemove?: (row: T, index: number) => Promise<void>
|
|
21
23
|
}
|
|
22
24
|
// extends Partial<TableColumnCtx<T>>
|
|
23
25
|
export interface ColumnItemCtx<T> extends Partial<TableColumnCtx<T>> {
|
|
24
26
|
prop: string
|
|
25
27
|
label: string
|
|
26
28
|
type?: string
|
|
27
|
-
hidden?: boolean | ((item: ColumnItemCtx<T>,
|
|
29
|
+
hidden?: boolean | ((item: ColumnItemCtx<T>, query: Fields) => boolean)
|
|
28
30
|
neverShow?: boolean // 表示不在列控制器里
|
|
29
31
|
children?: ColumnItem<T>[]
|
|
30
32
|
options?: Array<OptionItem> //数据字典
|
|
31
33
|
asyncOptions?: () => Promise<OptionItem[]>
|
|
32
34
|
eventObject?: EventObject
|
|
33
|
-
form?: Partial<FormItemType> | ((
|
|
35
|
+
form?: Partial<FormItemType> | ((column: ColumnItemCtx<T>, row: T, query: Fields) => Partial<FormItemType>)
|
|
34
36
|
filter?: ColumnItemFilter
|
|
35
37
|
empty?: string | unknown
|
|
36
38
|
detail?: ColumnItemDetail
|
|
@@ -14,8 +14,8 @@ export interface DetailDataItem extends Record<string, unknown> {
|
|
|
14
14
|
labelWidth?: number | string
|
|
15
15
|
props?: Record<string, string>
|
|
16
16
|
slot?: string
|
|
17
|
-
tooltip?: string |
|
|
18
|
-
labelPosition?:
|
|
17
|
+
tooltip?: string | ElTooltipProps
|
|
18
|
+
labelPosition?: string | "left" | "right" | "center" | "top"
|
|
19
19
|
labelStyle?: string | Record<string, string | number>
|
|
20
20
|
showOverflowTooltip?: boolean | string | Partial<ElTooltipProps>
|
|
21
21
|
rawContent?: boolean
|
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
|
|
29
29
|
<script lang="ts">
|
|
30
30
|
import { CurdForm, CurdGroupForm, type CurdGroupFormSchema, useLocale } from "easybill-ui"
|
|
31
|
-
import { computed, defineComponent, type PropType, provide, reactive, ref, type Ref, toRefs, useAttrs } from "vue"
|
|
31
|
+
import { type Component, computed, defineComponent, type PropType, provide, reactive, ref, type Ref, toRefs, useAttrs } from "vue"
|
|
32
32
|
import { type Fields, type FormSchema } from "../../CurdForm"
|
|
33
33
|
import { useStepList } from "./hooks/useStepList"
|
|
34
34
|
import { useStepNavigation } from "./hooks/useStepNavigation"
|
|
35
|
+
import type { FormDialogHandleOk } from "./types"
|
|
35
36
|
export default defineComponent({
|
|
36
37
|
name: "FormDialog",
|
|
37
38
|
components: {
|
|
@@ -69,7 +70,7 @@ export default defineComponent({
|
|
|
69
70
|
},
|
|
70
71
|
// 点击确定
|
|
71
72
|
handleOk: {
|
|
72
|
-
type: Function
|
|
73
|
+
type: Function as PropType<FormDialogHandleOk>,
|
|
73
74
|
default: null,
|
|
74
75
|
},
|
|
75
76
|
// 关闭的回调,通过类型判断是点取消按钮还是右上角关闭按钮
|
|
@@ -99,11 +100,11 @@ export default defineComponent({
|
|
|
99
100
|
default: "dialog",
|
|
100
101
|
},
|
|
101
102
|
stepComponent: {
|
|
102
|
-
type: Object
|
|
103
|
+
type: Object as PropType<Component>,
|
|
103
104
|
default: null,
|
|
104
105
|
},
|
|
105
106
|
footerComponent: {
|
|
106
|
-
type: Object
|
|
107
|
+
type: Object as PropType<Component>,
|
|
107
108
|
default: null,
|
|
108
109
|
},
|
|
109
110
|
},
|
|
@@ -151,7 +152,7 @@ export default defineComponent({
|
|
|
151
152
|
state.confirmLoading = false
|
|
152
153
|
return
|
|
153
154
|
}
|
|
154
|
-
const pass = await (props.handleOk
|
|
155
|
+
const pass = await Promise.resolve(props.handleOk?.(form.value, state)).finally(() => (state.confirmLoading = false))
|
|
155
156
|
if (typeof pass == "undefined" || pass) {
|
|
156
157
|
state.visible = false
|
|
157
158
|
onCancel()
|
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
import type { DialogProps, StepProps } from "element-plus"
|
|
2
|
+
import type { Component, Ref } from "vue"
|
|
2
3
|
import type { Fields, FormContext, FormSchema } from "../../CurdForm"
|
|
3
4
|
import type { CurdGroupFormSchema } from "../../CurdGroupForm/types"
|
|
4
5
|
import type { StepItem } from "./hooks/useStepList"
|
|
5
6
|
|
|
7
|
+
export interface FormDialogState {
|
|
8
|
+
visible: boolean
|
|
9
|
+
confirmLoading: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type FormDialogHandleOk = (modelRef: Fields, state: FormDialogState) => void | boolean | Promise<void | boolean>
|
|
13
|
+
|
|
6
14
|
export interface FormDialogOptions extends Partial<DialogProps> {
|
|
7
15
|
title?: string
|
|
8
16
|
width?: string | number
|
|
9
17
|
fields?: Fields
|
|
10
18
|
formSchema?: FormSchema
|
|
11
19
|
groupSchema?: CurdGroupFormSchema
|
|
12
|
-
handleOk?:
|
|
20
|
+
handleOk?: FormDialogHandleOk
|
|
13
21
|
handleClose?: (e: "close" | "cancel") => void
|
|
14
|
-
setForm?: (form: Fields) => void
|
|
22
|
+
setForm?: (form: Ref<Fields>) => void
|
|
15
23
|
stepProps?: Partial<StepProps & Fields>
|
|
16
24
|
extendContext?: Partial<FormContext>
|
|
17
25
|
confirmBtnText?: string
|
|
18
26
|
cancelBtnText?: string
|
|
19
|
-
stepComponent?:
|
|
20
|
-
footerComponent?:
|
|
27
|
+
stepComponent?: Component
|
|
28
|
+
footerComponent?: Component
|
|
21
29
|
mode?: "dialog" | "drawer"
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
export interface FormDialogContext {
|
|
25
33
|
form: Fields
|
|
26
|
-
state:
|
|
27
|
-
visible: boolean
|
|
28
|
-
confirmLoading: boolean
|
|
29
|
-
}
|
|
34
|
+
state: FormDialogState
|
|
30
35
|
stepList: StepItem[]
|
|
31
36
|
activeStep: { value: number }
|
|
32
37
|
loadOptions: (prop: string, config?: unknown) => void
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent } from "vue"
|
|
2
|
-
import type { FormContext, FormItem, FormItemTypeEmun } from "../CurdForm"
|
|
2
|
+
import type { CurdFormOptionItem, FormContext, FormItem, FormItemTypeEmun } from "../CurdForm"
|
|
3
3
|
export interface ParamsItem extends FormItem {
|
|
4
4
|
type?: FormItemTypeEmun | ReturnType<typeof defineComponent>
|
|
5
5
|
tableKey?: Array<string>
|
|
@@ -9,10 +9,16 @@ export interface ParamsItem extends FormItem {
|
|
|
9
9
|
tagNames?: string
|
|
10
10
|
}
|
|
11
11
|
export type FilterItem = ParamsItem
|
|
12
|
-
export interface TableFilterContext
|
|
12
|
+
export interface TableFilterContext {
|
|
13
13
|
loadOptions: (prop: string, config?: unknown) => void
|
|
14
|
+
setOptions: (prop: string, options: CurdFormOptionItem[], config?: unknown) => void
|
|
14
15
|
setValue: (prop: string, value: unknown) => void
|
|
15
16
|
search: () => void
|
|
17
|
+
formModel: ListQuery
|
|
18
|
+
components: FormContext["components"]
|
|
19
|
+
change: FormContext["change"]
|
|
20
|
+
formRef?: FormContext["formRef"]
|
|
21
|
+
formSchema?: FormContext["formSchema"]
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
export interface ListQuery {
|
package/package.json
CHANGED
|
@@ -1,11 +1,66 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "easybill-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A component library for easybill",
|
|
5
5
|
"author": "tuchongyang <779311998@qq.com>",
|
|
6
6
|
"private": false,
|
|
7
7
|
"license": "ISC",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"typecheck": "vue-tsc -p tsconfig.typecheck.json --noEmit --skipLibCheck"
|
|
10
|
+
},
|
|
8
11
|
"main": "index.ts",
|
|
12
|
+
"types": "index.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./index.ts",
|
|
16
|
+
"import": "./index.ts",
|
|
17
|
+
"default": "./index.ts"
|
|
18
|
+
},
|
|
19
|
+
"./index": {
|
|
20
|
+
"types": "./index.ts",
|
|
21
|
+
"import": "./index.ts",
|
|
22
|
+
"default": "./index.ts"
|
|
23
|
+
},
|
|
24
|
+
"./index.ts": {
|
|
25
|
+
"types": "./index.ts",
|
|
26
|
+
"import": "./index.ts",
|
|
27
|
+
"default": "./index.ts"
|
|
28
|
+
},
|
|
29
|
+
"./components/CurdForm/src/types": {
|
|
30
|
+
"types": "./components/CurdForm/src/types.ts",
|
|
31
|
+
"import": "./components/CurdForm/src/types.ts",
|
|
32
|
+
"default": "./components/CurdForm/src/types.ts"
|
|
33
|
+
},
|
|
34
|
+
"./components/*": {
|
|
35
|
+
"types": "./components/*",
|
|
36
|
+
"import": "./components/*",
|
|
37
|
+
"default": "./components/*"
|
|
38
|
+
},
|
|
39
|
+
"./utils/*": {
|
|
40
|
+
"types": "./utils/*",
|
|
41
|
+
"import": "./utils/*",
|
|
42
|
+
"default": "./utils/*"
|
|
43
|
+
},
|
|
44
|
+
"./locale/*": {
|
|
45
|
+
"types": "./locale/*",
|
|
46
|
+
"import": "./locale/*",
|
|
47
|
+
"default": "./locale/*"
|
|
48
|
+
},
|
|
49
|
+
"./theme-chalk/*": {
|
|
50
|
+
"types": "./theme-chalk/*",
|
|
51
|
+
"import": "./theme-chalk/*",
|
|
52
|
+
"default": "./theme-chalk/*"
|
|
53
|
+
},
|
|
54
|
+
"./package.json": "./package.json"
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"index.ts",
|
|
58
|
+
"components",
|
|
59
|
+
"utils",
|
|
60
|
+
"locale",
|
|
61
|
+
"theme-chalk",
|
|
62
|
+
"README.md"
|
|
63
|
+
],
|
|
9
64
|
"peerDependencies": {
|
|
10
65
|
"@element-plus/icons-vue": "^2.0.6",
|
|
11
66
|
"element-plus": "^2.7.0",
|
package/utils/hooks/useLocal.ts
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import { computed, isRef, ref,
|
|
1
|
+
import { computed, isRef, ref, type ComputedRef, type Ref } from "vue"
|
|
2
2
|
import en from "../../locale/lang/en"
|
|
3
3
|
|
|
4
|
-
import type { MaybeRef } from "@vueuse/core"
|
|
5
4
|
import { useGlobalConfig } from "easybill-ui"
|
|
6
|
-
import type { Ref } from "vue"
|
|
7
5
|
import type { Language } from "../../locale"
|
|
8
6
|
|
|
9
7
|
export type TranslatorOption = Record<string, string | number> | string[]
|
|
10
8
|
export type Translator = (path: string, option?: TranslatorOption) => string
|
|
9
|
+
export type LocaleSource = Language | Ref<Language> | ComputedRef<Language>
|
|
10
|
+
export type LocaleRef = Ref<Language> | ComputedRef<Language>
|
|
11
11
|
export type LocaleContext = {
|
|
12
|
-
locale:
|
|
13
|
-
lang:
|
|
12
|
+
locale: LocaleRef
|
|
13
|
+
lang: ComputedRef<string>
|
|
14
14
|
t: Translator
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
const resolveLocale = (locale: LocaleSource): Language => (isRef(locale) ? locale.value : locale)
|
|
18
|
+
|
|
17
19
|
export const buildTranslator =
|
|
18
|
-
(locale:
|
|
20
|
+
(locale: LocaleSource): Translator =>
|
|
19
21
|
(path, option) =>
|
|
20
|
-
translate(path, option,
|
|
22
|
+
translate(path, option, resolveLocale(locale))
|
|
21
23
|
|
|
22
24
|
export const translate = (path: string, option: undefined | TranslatorOption, locale: Language): string => {
|
|
23
25
|
const value = get(locale, path, path) as string
|
|
@@ -27,9 +29,9 @@ export const translate = (path: string, option: undefined | TranslatorOption, lo
|
|
|
27
29
|
return value.replace(/\{(\w+)\}/g, (_, key) => `${option?.[key] ?? `{${key}}`}`)
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
export const buildLocaleContext = (locale:
|
|
31
|
-
const
|
|
32
|
-
const
|
|
32
|
+
export const buildLocaleContext = (locale: LocaleSource): LocaleContext => {
|
|
33
|
+
const localeRef = (isRef(locale) ? locale : ref(locale)) as LocaleRef
|
|
34
|
+
const lang = computed(() => localeRef.value.name)
|
|
33
35
|
return {
|
|
34
36
|
lang,
|
|
35
37
|
locale: localeRef,
|