@complex-suite/component-antd 4.10.12
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/LayoutResizeObserver.ts +104 -0
- package/LocalResizeObserver.ts +46 -0
- package/README.md +67 -0
- package/antdConfig.ts +361 -0
- package/format.ts +458 -0
- package/history.md +325 -0
- package/icon.ts +65 -0
- package/index.test.ts +5 -0
- package/index.ts +55 -0
- package/package.json +39 -0
- package/plugin.ts +95 -0
- package/quick/QuickCascade.tsx +107 -0
- package/quick/QuickEdit.tsx +117 -0
- package/quick/QuickFloat.tsx +32 -0
- package/quick/QuickFloatModal.tsx +95 -0
- package/quick/QuickFloatValue.tsx +103 -0
- package/quick/QuickList.tsx +433 -0
- package/quick/data/FloatData.ts +77 -0
- package/src/AutoSpin.vue +39 -0
- package/src/AutoText.vue +101 -0
- package/src/ButtonView.tsx +62 -0
- package/src/CollapseArea.tsx +88 -0
- package/src/EditArea.tsx +205 -0
- package/src/EditView.tsx +179 -0
- package/src/FlexBox.tsx +74 -0
- package/src/FormList.tsx +226 -0
- package/src/ImageViewer.tsx +122 -0
- package/src/InfoArea.tsx +182 -0
- package/src/InfoView.tsx +150 -0
- package/src/MenuView.tsx +91 -0
- package/src/ModalView.tsx +274 -0
- package/src/MultipleImport.tsx +231 -0
- package/src/SearchArea.tsx +170 -0
- package/src/SelectText.vue +59 -0
- package/src/SimpleTable.tsx +256 -0
- package/src/SingleImport.tsx +189 -0
- package/src/TableView.tsx +415 -0
- package/src/components/AutoRender.tsx +19 -0
- package/src/components/ChoiceInfo.vue +73 -0
- package/src/components/PaginationView.tsx +103 -0
- package/src/components/TableMenu.tsx +93 -0
- package/src/dictionary/AutoEditItem.tsx +164 -0
- package/src/dictionary/AutoInfoItem.tsx +126 -0
- package/src/dictionary/AutoItem.tsx +219 -0
- package/src/icons/EmptyImage.vue +30 -0
- package/src/icons/ErrorImage.vue +30 -0
- package/src/style/index.css +304 -0
- package/tsconfig.json +8 -0
- package/type.ts +4 -0
- package/vitest.config.ts +11 -0
- package/widthCalculator.ts +20 -0
package/src/MenuView.tsx
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { defineComponent, h, PropType } from "vue"
|
|
2
|
+
import { Button } from "ant-design-vue"
|
|
3
|
+
import type { ButtonType } from "ant-design-vue/es/button"
|
|
4
|
+
import { isPromise } from "@complex-suite/utils"
|
|
5
|
+
import type { MenuValue } from "@complex-suite/data"
|
|
6
|
+
import icon from "../icon"
|
|
7
|
+
import antdConfig from "../antdConfig"
|
|
8
|
+
|
|
9
|
+
export default defineComponent({
|
|
10
|
+
name: 'MenuView',
|
|
11
|
+
props: {
|
|
12
|
+
data: {
|
|
13
|
+
type: Object as PropType<MenuValue<any>>,
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
disabled: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
required: false
|
|
19
|
+
},
|
|
20
|
+
loading: {
|
|
21
|
+
type: Boolean,
|
|
22
|
+
required: false
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
data() {
|
|
26
|
+
return {
|
|
27
|
+
operate: false
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
render() {
|
|
31
|
+
if (!this.data.render) {
|
|
32
|
+
const type = this.data.type
|
|
33
|
+
let loading = this.operate
|
|
34
|
+
if (!loading) {
|
|
35
|
+
loading = this.loading || (typeof this.data.loading === 'function' ? this.data.loading() : (this.data.loading || false))
|
|
36
|
+
}
|
|
37
|
+
const disabled = this.disabled || (typeof this.data.disabled === 'function' ? this.data.disabled() : (this.data.disabled || false))
|
|
38
|
+
const render = h(Button, {
|
|
39
|
+
class: 'complex-menu',
|
|
40
|
+
loading: loading,
|
|
41
|
+
type: type === 'danger' ? 'primary' : type as ButtonType,
|
|
42
|
+
danger: type === 'danger',
|
|
43
|
+
icon: icon.parse(this.data.icon),
|
|
44
|
+
disabled: disabled,
|
|
45
|
+
onClick: (e: MouseEvent) => {
|
|
46
|
+
if (this.data.modifiers) {
|
|
47
|
+
if (this.data.modifiers.includes('.stop')) {
|
|
48
|
+
e.stopPropagation()
|
|
49
|
+
}
|
|
50
|
+
if (this.data.modifiers.includes('.prevent')) {
|
|
51
|
+
e.preventDefault()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
antdConfig.parseMenuConfirm(this.data.confirm, () => {
|
|
55
|
+
this.$emit('click', e)
|
|
56
|
+
if (this.data.click) {
|
|
57
|
+
const res = this.data.click(e)
|
|
58
|
+
if (isPromise(res)) {
|
|
59
|
+
this.operate = true
|
|
60
|
+
res.finally(() => {
|
|
61
|
+
if (this.data.debounce) {
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
this.operate = false
|
|
64
|
+
}, this.data.debounce)
|
|
65
|
+
} else {
|
|
66
|
+
this.operate = false
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
} else {
|
|
70
|
+
if (this.data.debounce) {
|
|
71
|
+
this.operate = true
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
this.operate = false
|
|
74
|
+
}, this.data.debounce)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
},
|
|
80
|
+
...this.$attrs
|
|
81
|
+
}, {
|
|
82
|
+
default: () => this.data.name
|
|
83
|
+
})
|
|
84
|
+
return render
|
|
85
|
+
} else {
|
|
86
|
+
return this.data.render({
|
|
87
|
+
data: this.data
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
})
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { defineComponent, h, markRaw, PropType } from "vue"
|
|
2
|
+
import { Modal } from "ant-design-vue"
|
|
3
|
+
import type { ModalProps } from "ant-design-vue"
|
|
4
|
+
import { deepCloneData, updateData } from "@complex-suite/utils"
|
|
5
|
+
import { dataConfig } from "@complex-suite/data"
|
|
6
|
+
import type { MenuValue } from "@complex-suite/data"
|
|
7
|
+
import ButtonView from "./ButtonView"
|
|
8
|
+
import antdConfig from "../antdConfig"
|
|
9
|
+
|
|
10
|
+
export type modalLayoutOption = {
|
|
11
|
+
type: 'auto' | 'fixed'
|
|
12
|
+
top: number
|
|
13
|
+
bottom: number
|
|
14
|
+
header: number
|
|
15
|
+
menu: number
|
|
16
|
+
padding: [number, number, number, number]
|
|
17
|
+
mainPadding: [number, number, number, number]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ModalViewProps {
|
|
21
|
+
width?: number
|
|
22
|
+
title?: string
|
|
23
|
+
destroyOnClose?: boolean
|
|
24
|
+
layout?: Partial<modalLayoutOption>
|
|
25
|
+
menu?: (string | MenuValue)[] // 菜单列表,字符串则通过config.modal.getMenu实现
|
|
26
|
+
menuOption?: Record<string, Partial<MenuValue>> // 根据prop匹配菜单列表中的字符串数据获取的默认值,通过可选参数重写属性
|
|
27
|
+
submit?: () => Promise<unknown>
|
|
28
|
+
modalProps?: ModalProps
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ModalViewSlotProps {
|
|
32
|
+
width: number
|
|
33
|
+
height: number
|
|
34
|
+
modal: any
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default defineComponent({
|
|
38
|
+
name: 'ModalView',
|
|
39
|
+
emits: {
|
|
40
|
+
// 关闭
|
|
41
|
+
close: (from: string) => {
|
|
42
|
+
return typeof from === 'string'
|
|
43
|
+
},
|
|
44
|
+
// 菜单
|
|
45
|
+
menu: (prop: string, _self: any) => {
|
|
46
|
+
return typeof prop === 'string'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
props: {
|
|
50
|
+
width: {
|
|
51
|
+
type: Number,
|
|
52
|
+
required: false
|
|
53
|
+
},
|
|
54
|
+
title: {
|
|
55
|
+
type: String,
|
|
56
|
+
required: false
|
|
57
|
+
},
|
|
58
|
+
destroyOnClose: {
|
|
59
|
+
type: Boolean,
|
|
60
|
+
required: false,
|
|
61
|
+
default: () => {
|
|
62
|
+
return antdConfig.modal.destroyOnClose
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
layout: {
|
|
66
|
+
type: Object as PropType<ModalViewProps['layout']>,
|
|
67
|
+
required: false
|
|
68
|
+
},
|
|
69
|
+
menu: {
|
|
70
|
+
type: Object as PropType<ModalViewProps['menu']>,
|
|
71
|
+
required: false
|
|
72
|
+
},
|
|
73
|
+
menuOption: {
|
|
74
|
+
type: Object as PropType<ModalViewProps['menuOption']>,
|
|
75
|
+
required: false
|
|
76
|
+
},
|
|
77
|
+
submit: {
|
|
78
|
+
type: Function as PropType<ModalViewProps['submit']>,
|
|
79
|
+
required: false
|
|
80
|
+
},
|
|
81
|
+
modalProps: {
|
|
82
|
+
type: Object as PropType<ModalViewProps['modalProps']>,
|
|
83
|
+
required: false,
|
|
84
|
+
default: () => {
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
data() {
|
|
90
|
+
return {
|
|
91
|
+
$open: false,
|
|
92
|
+
localTitle: undefined as undefined | string,
|
|
93
|
+
localModalProps: undefined as undefined | ModalProps
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
computed: {
|
|
97
|
+
currentTitle() {
|
|
98
|
+
return this.localTitle || this.title
|
|
99
|
+
},
|
|
100
|
+
currentLayout() {
|
|
101
|
+
return updateData(deepCloneData(antdConfig.modal.layout), this.layout)
|
|
102
|
+
},
|
|
103
|
+
menuList() {
|
|
104
|
+
let menuList: MenuValue[]
|
|
105
|
+
const close = () => {
|
|
106
|
+
this.close('close')
|
|
107
|
+
}
|
|
108
|
+
const submit = () => {
|
|
109
|
+
if (this.submit) {
|
|
110
|
+
const promise = this.submit!()
|
|
111
|
+
promise.then(() => {
|
|
112
|
+
this.close('submit')
|
|
113
|
+
})
|
|
114
|
+
return promise
|
|
115
|
+
} else {
|
|
116
|
+
console.error('submit按钮需要定义对应的submit函数')
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!this.menu) {
|
|
120
|
+
menuList = [
|
|
121
|
+
antdConfig.modal.getMenu('close', {
|
|
122
|
+
click: close
|
|
123
|
+
})
|
|
124
|
+
]
|
|
125
|
+
} else {
|
|
126
|
+
menuList = this.menu.map(menu => {
|
|
127
|
+
if (typeof menu !== 'object') {
|
|
128
|
+
const menuOption = this.menuOption ? this.menuOption[menu] : undefined
|
|
129
|
+
if (menu === 'close' || menu === 'cancel') {
|
|
130
|
+
return antdConfig.modal.getMenu(menu, {
|
|
131
|
+
...menuOption,
|
|
132
|
+
click: close
|
|
133
|
+
})
|
|
134
|
+
} else if (menu === 'submit') {
|
|
135
|
+
return antdConfig.modal.getMenu(menu, {
|
|
136
|
+
...menuOption,
|
|
137
|
+
click: submit
|
|
138
|
+
})
|
|
139
|
+
} else {
|
|
140
|
+
return antdConfig.modal.getMenu(menu, {
|
|
141
|
+
...menuOption,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
return menu
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
return menuList
|
|
150
|
+
},
|
|
151
|
+
currentWidth() {
|
|
152
|
+
if (!this.width) {
|
|
153
|
+
return antdConfig.modal.width
|
|
154
|
+
} else {
|
|
155
|
+
return this.width
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
contentHeight() {
|
|
159
|
+
const mainHeight = document.documentElement.clientHeight
|
|
160
|
+
let height = mainHeight - this.currentLayout.top - this.currentLayout.bottom - this.currentLayout.header - this.currentLayout.padding[0] - this.currentLayout.padding[2] - this.currentLayout.mainPadding[0] - this.currentLayout.mainPadding[2]
|
|
161
|
+
if (this.menuList.length > 0) {
|
|
162
|
+
height = height - this.currentLayout.menu
|
|
163
|
+
}
|
|
164
|
+
return height
|
|
165
|
+
},
|
|
166
|
+
contentWidth() {
|
|
167
|
+
return this.currentWidth - this.currentLayout.padding[1] - this.currentLayout.padding[3] - this.currentLayout.mainPadding[1] - this.currentLayout.mainPadding[3]
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
methods: {
|
|
171
|
+
show(title?: string, option?: ModalProps) {
|
|
172
|
+
this.localTitle = title
|
|
173
|
+
this.localModalProps = option
|
|
174
|
+
this.$data.$open = true
|
|
175
|
+
},
|
|
176
|
+
close(from: string) {
|
|
177
|
+
this.$data.$open = false
|
|
178
|
+
this.localTitle = undefined
|
|
179
|
+
this.localModalProps = undefined
|
|
180
|
+
this.$emit('close', from)
|
|
181
|
+
},
|
|
182
|
+
renderContent() {
|
|
183
|
+
return this.$slots.default ? this.$slots.default({
|
|
184
|
+
width: this.contentWidth,
|
|
185
|
+
height: this.contentHeight,
|
|
186
|
+
modal: markRaw(this)
|
|
187
|
+
}) : null
|
|
188
|
+
},
|
|
189
|
+
onMenu(prop: string) {
|
|
190
|
+
this.$emit('menu', prop, this)
|
|
191
|
+
},
|
|
192
|
+
renderFooter() {
|
|
193
|
+
if (this.menuList.length > 0) {
|
|
194
|
+
return this.menuList.map(item => {
|
|
195
|
+
if (!item.render) {
|
|
196
|
+
const onClick = item.click
|
|
197
|
+
return h(ButtonView, {
|
|
198
|
+
data: {
|
|
199
|
+
...item,
|
|
200
|
+
click: (payload: any) => {
|
|
201
|
+
this.onMenu(item.prop!)
|
|
202
|
+
if (onClick) {
|
|
203
|
+
return onClick(payload)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
} else {
|
|
209
|
+
return item.render({
|
|
210
|
+
modal: this,
|
|
211
|
+
menuList: this.menuList,
|
|
212
|
+
menu: item
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
} else {
|
|
217
|
+
return null
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
render() {
|
|
222
|
+
const top = dataConfig.formatPixel(this.currentLayout.top)
|
|
223
|
+
const padding = this.currentLayout.padding.map(num => dataConfig.formatPixel(num)).join(' ')
|
|
224
|
+
interface ModalPropsWithClass extends ModalProps {
|
|
225
|
+
class: string
|
|
226
|
+
}
|
|
227
|
+
const props: ModalPropsWithClass = {
|
|
228
|
+
class: 'complex-modal',
|
|
229
|
+
open: this.$data.$open,
|
|
230
|
+
width: this.currentWidth,
|
|
231
|
+
title: this.currentTitle,
|
|
232
|
+
destroyOnClose: this.destroyOnClose,
|
|
233
|
+
...this.modalProps,
|
|
234
|
+
...this.localModalProps,
|
|
235
|
+
onCancel: (e: MouseEvent | KeyboardEvent) => {
|
|
236
|
+
if (e instanceof KeyboardEvent) {
|
|
237
|
+
this.close('escape')
|
|
238
|
+
} else {
|
|
239
|
+
const target = e.target as HTMLDivElement
|
|
240
|
+
if (target.classList.contains('ant-modal-wrap')) {
|
|
241
|
+
this.close('mask')
|
|
242
|
+
} else {
|
|
243
|
+
this.close('modal')
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (this.menuList.length === 0) {
|
|
249
|
+
props.footer = null
|
|
250
|
+
}
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
|
+
if (!(props as any).style) {
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
254
|
+
(props as any).style = {
|
|
255
|
+
top: top
|
|
256
|
+
}
|
|
257
|
+
} else {
|
|
258
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
|
+
(props as any).style.top = top
|
|
260
|
+
}
|
|
261
|
+
if (!props.bodyStyle) {
|
|
262
|
+
props.bodyStyle = {
|
|
263
|
+
padding: padding
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
props.bodyStyle.padding = padding
|
|
267
|
+
}
|
|
268
|
+
const render = h(Modal, props, {
|
|
269
|
+
default: () => [this.renderContent()],
|
|
270
|
+
footer: () => this.renderFooter()
|
|
271
|
+
})
|
|
272
|
+
return render
|
|
273
|
+
}
|
|
274
|
+
})
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { defineComponent, h, PropType, ref, watch, VNode, computed } from "vue"
|
|
2
|
+
import { useInjectFormItemContext } from "ant-design-vue/es/form"
|
|
3
|
+
import { notice } from "@complex-suite/plugin"
|
|
4
|
+
import type { fileDataType } from "@complex-suite/data"
|
|
5
|
+
import type { FileEditOption } from "@complex-suite/data"
|
|
6
|
+
import { FileValue } from "@complex-suite/data"
|
|
7
|
+
import { FileMultipleValue, type fileValueType } from "@complex-suite/data"
|
|
8
|
+
import { FileView } from "@complex-suite/component"
|
|
9
|
+
import type { FileProps, MultipleFileProps } from "@complex-suite/component"
|
|
10
|
+
import type { DefaultImportProps } from "./SingleImport"
|
|
11
|
+
import antdConfig from "../antdConfig"
|
|
12
|
+
|
|
13
|
+
export interface MultipleImportProps extends FileProps, MultipleFileProps, DefaultImportProps{
|
|
14
|
+
value?: fileValueType[]
|
|
15
|
+
upload?: FileEditOption<true>['upload']
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const defaultMultipleUpload = function(fileList: File[]) {
|
|
19
|
+
return Promise.resolve({ file: fileList.map(file => { return { value: file, name: file.name} } ) })
|
|
20
|
+
} as NonNullable<MultipleImportProps['upload']>
|
|
21
|
+
|
|
22
|
+
export default defineComponent({
|
|
23
|
+
name: 'MultipleImport',
|
|
24
|
+
props: {
|
|
25
|
+
value: {
|
|
26
|
+
type: Array as PropType<MultipleImportProps['value']>
|
|
27
|
+
},
|
|
28
|
+
button: {
|
|
29
|
+
type: Object as PropType<MultipleImportProps['button']>,
|
|
30
|
+
required: false
|
|
31
|
+
},
|
|
32
|
+
complex: {
|
|
33
|
+
type: Boolean as PropType<MultipleImportProps['complex']>,
|
|
34
|
+
required: false
|
|
35
|
+
},
|
|
36
|
+
isUrl: {
|
|
37
|
+
type: Boolean as PropType<MultipleImportProps['isUrl']>,
|
|
38
|
+
required: false
|
|
39
|
+
},
|
|
40
|
+
image: {
|
|
41
|
+
type: Object as PropType<MultipleImportProps['image']>,
|
|
42
|
+
required: false
|
|
43
|
+
},
|
|
44
|
+
upload: {
|
|
45
|
+
type: Function as PropType<MultipleImportProps['upload']>,
|
|
46
|
+
required: false
|
|
47
|
+
},
|
|
48
|
+
render: {
|
|
49
|
+
type: Object as PropType<MultipleImportProps['render']>,
|
|
50
|
+
required: false
|
|
51
|
+
},
|
|
52
|
+
loading: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
required: false
|
|
55
|
+
},
|
|
56
|
+
accept: {
|
|
57
|
+
type: String,
|
|
58
|
+
required: false
|
|
59
|
+
},
|
|
60
|
+
size: { // MB
|
|
61
|
+
type: Number,
|
|
62
|
+
required: false
|
|
63
|
+
},
|
|
64
|
+
multiple: {
|
|
65
|
+
type: Object as PropType<MultipleImportProps['multiple']>,
|
|
66
|
+
required: false
|
|
67
|
+
},
|
|
68
|
+
disabled: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
required: false
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
setup(props, { emit }) {
|
|
74
|
+
const formItemContext = useInjectFormItemContext()
|
|
75
|
+
const parseValue = function (value?: fileValueType[]) {
|
|
76
|
+
return new FileMultipleValue((value || []).map(valueItem => new FileValue(valueItem, props.isUrl)))
|
|
77
|
+
}
|
|
78
|
+
const operate = ref(false)
|
|
79
|
+
const currentValue = ref(props.value)
|
|
80
|
+
const data = ref(parseValue(props.value))
|
|
81
|
+
|
|
82
|
+
const syncValue = () => {
|
|
83
|
+
// 此处基于外部数据整合内部数据
|
|
84
|
+
if (props.value !== currentValue.value) {
|
|
85
|
+
currentValue.value = props.value
|
|
86
|
+
}
|
|
87
|
+
// 多选模式下,value可能存在splice的改变或者是splice后重新赋值,此时需要将额外数据删除
|
|
88
|
+
if (props.value) {
|
|
89
|
+
data.value.assign(parseValue(props.value))
|
|
90
|
+
} else {
|
|
91
|
+
data.value.reset()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
watch(() => props.value, () => {
|
|
96
|
+
syncValue()
|
|
97
|
+
formItemContext.onFieldChange()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const onSelect = (file: File[]) => {
|
|
101
|
+
operate.value = true;
|
|
102
|
+
(props.upload || defaultMultipleUpload)(file).then(res => {
|
|
103
|
+
onUpload(res.file, true)
|
|
104
|
+
}).catch((err: unknown) => {
|
|
105
|
+
console.error(err)
|
|
106
|
+
}).finally(() => {
|
|
107
|
+
operate.value = false
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const max = computed(() => {
|
|
112
|
+
if (props.multiple) {
|
|
113
|
+
return props.multiple.max || 0
|
|
114
|
+
} else {
|
|
115
|
+
return 0
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const onUpload = (fileList: fileDataType[], emit?: boolean) => {
|
|
120
|
+
if (currentValue.value) {
|
|
121
|
+
fileList.forEach(file => {
|
|
122
|
+
// 通过data判断,避免complex模式下的判断错误
|
|
123
|
+
if (!data.value.has(file.value)) {
|
|
124
|
+
currentValue.value!.push(!props.complex ? file.value : file)
|
|
125
|
+
data.value.push(new FileValue(file, props.isUrl))
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
} else {
|
|
129
|
+
currentValue.value = []
|
|
130
|
+
fileList.forEach(file => {
|
|
131
|
+
currentValue.value!.push(!props.complex ? file.value : file)
|
|
132
|
+
data.value.push(new FileValue(file, props.isUrl))
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
if (max.value && currentValue.value.length > max.value) {
|
|
136
|
+
currentValue.value.length = max.value
|
|
137
|
+
data.value.truncation(max.value)
|
|
138
|
+
notice.message(`当前选择的文件数量超过限制值${max.value},超过部分已被删除!`, 'error')
|
|
139
|
+
}
|
|
140
|
+
if (emit) {
|
|
141
|
+
emitData()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const emitData = () => {
|
|
146
|
+
emit('change', currentValue.value)
|
|
147
|
+
formItemContext.onFieldChange()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const renderFile = () => {
|
|
151
|
+
let disabled = props.disabled
|
|
152
|
+
if (max.value && currentValue.value && currentValue.value.length >= max.value) {
|
|
153
|
+
disabled = true
|
|
154
|
+
}
|
|
155
|
+
return h(FileView, {
|
|
156
|
+
class: 'complex-import-file',
|
|
157
|
+
ref: 'file',
|
|
158
|
+
accept: props.accept,
|
|
159
|
+
multiple: props.multiple,
|
|
160
|
+
disabled: disabled,
|
|
161
|
+
size: props.size,
|
|
162
|
+
onSelect: onSelect,
|
|
163
|
+
onChange(e: Event) {
|
|
164
|
+
e.stopPropagation() // 阻止事件冒泡
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const renderList = (list: FileMultipleValue) => {
|
|
170
|
+
return h('div', {
|
|
171
|
+
class: !props.image ? 'complex-import-content-list' : 'complex-import-image-list'
|
|
172
|
+
}, {
|
|
173
|
+
default: () => list.value.map((file, index) => {
|
|
174
|
+
return renderContent(file, index)
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const deleteData = (key: any, index: number) => {
|
|
180
|
+
if (props.disabled || props.loading) {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
currentValue.value!.splice(index, 1)
|
|
184
|
+
data.value.delete(key)
|
|
185
|
+
emitData()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const renderContent = (file: FileValue, index: number) => {
|
|
189
|
+
return antdConfig.import.renderContent(file, props.disabled, props.image, () => {
|
|
190
|
+
deleteData(file.value, index)
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
operate,
|
|
196
|
+
currentValue,
|
|
197
|
+
data,
|
|
198
|
+
onSelect,
|
|
199
|
+
onUpload,
|
|
200
|
+
emitData,
|
|
201
|
+
renderFile,
|
|
202
|
+
renderList,
|
|
203
|
+
deleteData,
|
|
204
|
+
renderContent
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
render() {
|
|
208
|
+
let content: null | VNode | VNode[]
|
|
209
|
+
if (this.$slots.content || (this.render && this.render.content)) {
|
|
210
|
+
content = (this.$slots.content || this.render!.content)!({
|
|
211
|
+
props: {
|
|
212
|
+
multiple: this.multiple,
|
|
213
|
+
upload: this.upload,
|
|
214
|
+
value: this.currentValue,
|
|
215
|
+
data: this.data
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
} else {
|
|
219
|
+
content = this.renderList(this.data)
|
|
220
|
+
}
|
|
221
|
+
return h('div', {
|
|
222
|
+
class: 'complex-import'
|
|
223
|
+
}, {
|
|
224
|
+
default: () => [
|
|
225
|
+
this.renderFile(),
|
|
226
|
+
antdConfig.import.renderMenu(this as any),
|
|
227
|
+
content
|
|
228
|
+
]
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
})
|