@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.
Files changed (51) hide show
  1. package/LayoutResizeObserver.ts +104 -0
  2. package/LocalResizeObserver.ts +46 -0
  3. package/README.md +67 -0
  4. package/antdConfig.ts +361 -0
  5. package/format.ts +458 -0
  6. package/history.md +325 -0
  7. package/icon.ts +65 -0
  8. package/index.test.ts +5 -0
  9. package/index.ts +55 -0
  10. package/package.json +39 -0
  11. package/plugin.ts +95 -0
  12. package/quick/QuickCascade.tsx +107 -0
  13. package/quick/QuickEdit.tsx +117 -0
  14. package/quick/QuickFloat.tsx +32 -0
  15. package/quick/QuickFloatModal.tsx +95 -0
  16. package/quick/QuickFloatValue.tsx +103 -0
  17. package/quick/QuickList.tsx +433 -0
  18. package/quick/data/FloatData.ts +77 -0
  19. package/src/AutoSpin.vue +39 -0
  20. package/src/AutoText.vue +101 -0
  21. package/src/ButtonView.tsx +62 -0
  22. package/src/CollapseArea.tsx +88 -0
  23. package/src/EditArea.tsx +205 -0
  24. package/src/EditView.tsx +179 -0
  25. package/src/FlexBox.tsx +74 -0
  26. package/src/FormList.tsx +226 -0
  27. package/src/ImageViewer.tsx +122 -0
  28. package/src/InfoArea.tsx +182 -0
  29. package/src/InfoView.tsx +150 -0
  30. package/src/MenuView.tsx +91 -0
  31. package/src/ModalView.tsx +274 -0
  32. package/src/MultipleImport.tsx +231 -0
  33. package/src/SearchArea.tsx +170 -0
  34. package/src/SelectText.vue +59 -0
  35. package/src/SimpleTable.tsx +256 -0
  36. package/src/SingleImport.tsx +189 -0
  37. package/src/TableView.tsx +415 -0
  38. package/src/components/AutoRender.tsx +19 -0
  39. package/src/components/ChoiceInfo.vue +73 -0
  40. package/src/components/PaginationView.tsx +103 -0
  41. package/src/components/TableMenu.tsx +93 -0
  42. package/src/dictionary/AutoEditItem.tsx +164 -0
  43. package/src/dictionary/AutoInfoItem.tsx +126 -0
  44. package/src/dictionary/AutoItem.tsx +219 -0
  45. package/src/icons/EmptyImage.vue +30 -0
  46. package/src/icons/ErrorImage.vue +30 -0
  47. package/src/style/index.css +304 -0
  48. package/tsconfig.json +8 -0
  49. package/type.ts +4 -0
  50. package/vitest.config.ts +11 -0
  51. package/widthCalculator.ts +20 -0
@@ -0,0 +1,433 @@
1
+ import { defineComponent, h, PropType, VNode } from "vue"
2
+ import { notice } from "@complex-suite/plugin"
3
+ import { ComplexList } from "@complex-suite/data"
4
+ import type { resetOptionType, triggerMethodOption } from "@complex-suite/data"
5
+ import AutoSpin from "../src/AutoSpin.vue"
6
+ import TableView from "./../src/TableView"
7
+ import type { tablePayload, TableViewProps, TableViewOption } from "./../src/TableView"
8
+ import SimpleTable from "./../src/SimpleTable"
9
+ import type { ModalViewProps } from "./../src/ModalView"
10
+ import QuickFloatModal from "./QuickFloatModal"
11
+ import SearchArea from "./../src/SearchArea"
12
+ import type { SearchAreaProps, SearchAreaOption } from "./../src/SearchArea"
13
+ import EditArea from "./../src/EditArea"
14
+ import type { EditAreaOption, EditAreaProps, EditAreaSubmitOption } from "./../src/EditArea"
15
+ import InfoArea from "./../src/InfoArea"
16
+ import type { InfoAreaOption, InfoAreaProps } from "./../src/InfoArea"
17
+ // import CollapseArea, { CollapseAreaProps } from "./../src/CollapseArea"
18
+ import type { AutoItemPayloadType } from "./../src/dictionary/AutoItem"
19
+ import FloatData from "./data/FloatData"
20
+ import antdConfig from "../antdConfig"
21
+
22
+ export interface ListModalViewProps extends ModalViewProps {
23
+ formatName?: (name: string, payload?: unknown) => string
24
+ float?: FloatData
25
+ }
26
+
27
+ export type componentsProps = {
28
+ search?: Partial<SearchAreaProps>
29
+ // searchCollapse?: Partial<CollapseAreaProps>
30
+ table?: Partial<TableViewProps>
31
+ editModal?: Partial<ListModalViewProps>
32
+ edit?: Partial<EditAreaProps>
33
+ infoModal?: Partial<ListModalViewProps>
34
+ info?: Partial<InfoAreaProps>
35
+ }
36
+
37
+ export type renderType = {
38
+ top?: (listData: ComplexList) => VNode
39
+ search?: (props: SearchAreaOption) => VNode
40
+ table?: (props: TableViewOption) => VNode
41
+ edit?: (props: EditAreaOption) => VNode
42
+ info?: (props: InfoAreaOption) => VNode
43
+ }
44
+
45
+ export interface QuickListProps {
46
+ listData: ComplexList
47
+ simpleTable?: boolean
48
+ components?: ('spin' | 'search' | 'table' | 'info' | 'edit')[]
49
+ componentsProps?: componentsProps
50
+ editDebounce?: triggerMethodOption['debounce']
51
+ render?: renderType
52
+ reset?: resetOptionType
53
+ destroy?: resetOptionType
54
+ }
55
+
56
+ export default defineComponent({
57
+ name: 'QuickList',
58
+ emits: {
59
+ search: (prop: string, _payload: AutoItemPayloadType<'edit'>) => {
60
+ return !!prop
61
+ },
62
+ table: (prop: string, _payload: tablePayload) => {
63
+ return !!prop
64
+ }
65
+ },
66
+ props: {
67
+ listData: {
68
+ type: Object as PropType<QuickListProps['listData']>,
69
+ required: true
70
+ },
71
+ simpleTable: {
72
+ type: Boolean,
73
+ required: false
74
+ },
75
+ components: {
76
+ type: Array as PropType<QuickListProps['components']>,
77
+ required: false
78
+ },
79
+ componentsProps: {
80
+ type: Object as PropType<QuickListProps['componentsProps']>,
81
+ required: false
82
+ },
83
+ editDebounce: {
84
+ type: Object as PropType<QuickListProps['editDebounce']>,
85
+ required: false,
86
+ default: () => antdConfig.list.editDebounce
87
+ },
88
+ render: {
89
+ type: Object as PropType<QuickListProps['render']>,
90
+ required: false
91
+ },
92
+ reset: {
93
+ type: Object as PropType<QuickListProps['reset']>,
94
+ required: false
95
+ },
96
+ destroy: {
97
+ type: Object as PropType<QuickListProps['destroy']>,
98
+ required: false
99
+ }
100
+ },
101
+ computed: {
102
+ operate() {
103
+ return this.listData.getStatus('operate')
104
+ },
105
+ currentComponents() {
106
+ return this.components || [...antdConfig.list.components]
107
+ },
108
+ currentComponentsProps() {
109
+ return this.componentsProps || {}
110
+ },
111
+ currentRender() {
112
+ return this.render || {}
113
+ },
114
+ currentChoice() {
115
+ return this.listData.getChoiceList()
116
+ },
117
+ choiceSize() {
118
+ return this.currentChoice ? this.currentChoice.length : undefined
119
+ },
120
+ currentSimpleTable() {
121
+ if (this.simpleTable && (this.listData.$module.choice || this.listData.$module.sort)) {
122
+ console.error('SimpleTable无法实现选择/排序功能,无法启用SimpleTable!')
123
+ return false
124
+ } else {
125
+ return this.simpleTable
126
+ }
127
+ }
128
+ },
129
+ beforeMount() {
130
+ if (this.destroy) {
131
+ this.listData.destroy(this.destroy)
132
+ } else if (this.reset) {
133
+ this.listData.reset(this.reset)
134
+ }
135
+ },
136
+ methods: {
137
+ renderSpin() {
138
+ if (this.currentComponents.includes('spin')) {
139
+ return h(AutoSpin, { spinning: this.operate === 'ing' })
140
+ } else {
141
+ return null
142
+ }
143
+ },
144
+ $renderSearch(option: SearchAreaOption) {
145
+ const render = this.$slots.search || this.currentRender.search
146
+ if (!render) {
147
+ return h(SearchArea, option)
148
+ } else {
149
+ return render(option)
150
+ }
151
+ },
152
+ renderSearch() {
153
+ if (this.currentComponents.includes('search') && this.listData.$module.search) {
154
+ return this.$renderSearch({
155
+ ref: 'search',
156
+ search: this.listData.$module.search!,
157
+ choice: this.choiceSize,
158
+ loading: this.operate === 'ing',
159
+ onMenu: this.onSearchMenu,
160
+ onEnter: this.onSearchEnter,
161
+ ...this.currentComponentsProps.search
162
+ })
163
+ // if (this.currentComponentsProps.searchCollapse) {
164
+ // return h(CollapseArea, {
165
+ // ref: 'collapse',
166
+ // height: config.search.lineHeight,
167
+ // ...this.currentComponentsProps.searchCollapse
168
+ // }, {
169
+ // default: () => searchArea
170
+ // })
171
+ // } else {
172
+ // return searchArea
173
+ // }
174
+ } else {
175
+ return null
176
+ }
177
+ },
178
+ onSearchEnter(_prop: string, _payload: AutoItemPayloadType<'edit'>) {
179
+ // 回车自动检索
180
+ this.listData.setSearch()
181
+ },
182
+ onSearchMenu(prop: string, payload: AutoItemPayloadType<'edit'>) {
183
+ this.$emit('search', prop, payload)
184
+ if (prop === '$search') {
185
+ this.listData.setSearch()
186
+ } else if (prop === '$reset') {
187
+ this.listData.resetSearch()
188
+ } else if (prop === '$refresh') {
189
+ this.listData.reloadData({
190
+ data: true,
191
+ sync: true
192
+ })
193
+ } else if (prop === '$build') {
194
+ this.openEdit()
195
+ } else if (prop === '$info') {
196
+ this.openInfo()
197
+ } else if (prop === '$delete') {
198
+ this.deleteChoiceList()
199
+ } else if (prop === '$export') {
200
+ this.listData.triggerMethod('exportData', [], {
201
+ strict: true
202
+ })
203
+ }
204
+ },
205
+ renderTop() {
206
+ const render = this.$slots.top || this.currentRender.top
207
+ if (render) {
208
+ return render(this.listData)
209
+ } else {
210
+ return null
211
+ }
212
+ },
213
+ $renderTable(option: TableViewOption) {
214
+ const render = this.$slots.table || this.currentRender.table
215
+ if (!render) {
216
+ return h(!this.currentSimpleTable ? TableView : SimpleTable, option)
217
+ } else {
218
+ return render(option)
219
+ }
220
+ },
221
+ renderTable() {
222
+ if (this.currentComponents.includes('table')) {
223
+ return this.$renderTable({
224
+ ref: 'table',
225
+ listData: this.listData,
226
+ onMenu: this.onTableMenu,
227
+ ...this.currentComponentsProps.table
228
+ })
229
+ } else {
230
+ return null
231
+ }
232
+ },
233
+ onTableMenu(prop: string, payload: tablePayload) {
234
+ this.$emit('table', prop, payload)
235
+ if (prop === '$change') {
236
+ this.openEdit(payload!.targetData)
237
+ } else if (prop === '$delete') {
238
+ notice.confirm('确认进行删除操作吗?', '警告', (act: string) => {
239
+ if (act === 'ok') {
240
+ this.listData.triggerMethod('deleteData', [payload!.targetData], {
241
+ strict: true,
242
+ debounce: this.editDebounce
243
+ })
244
+ }
245
+ })
246
+ } else if (prop === '$info') {
247
+ this.openInfo(payload!.targetData)
248
+ }
249
+ },
250
+ renderList() {
251
+ const content = [this.renderSpin(), this.renderSearch(), this.renderTop(), this.renderTable()]
252
+ if (content.some(item => item != null)) {
253
+ return h('div', { class: 'complex-quick-list', style: { position: 'relative' } }, content)
254
+ }
255
+ return null
256
+ },
257
+ $getInfoOption(ref: string) {
258
+ return {
259
+ ref: ref,
260
+ dictionary: this.listData.$module.dictionary!,
261
+ loading: this.operate === 'ing',
262
+ ...this.currentComponentsProps.info
263
+ }
264
+ },
265
+ renderInfo() {
266
+ if (this.currentComponents.includes('info')) {
267
+ return h(QuickFloatModal, {
268
+ ref: 'info-modal',
269
+ float: this.currentComponentsProps.infoModal?.float,
270
+ modal: {
271
+ menu: ['close'],
272
+ ...this.currentComponentsProps.infoModal
273
+ },
274
+ content: {
275
+ render: (ref) => {
276
+ return h(InfoArea, this.$getInfoOption(ref))
277
+ },
278
+ show: {
279
+ args: [],
280
+ trigger(content: InstanceType<typeof InfoArea>, args: any[]) {
281
+ content.$show(...args)
282
+ }
283
+ }
284
+ }
285
+ })
286
+ } else {
287
+ return null
288
+ }
289
+ },
290
+ $getEditOption(ref: string) {
291
+ return {
292
+ ref: ref,
293
+ dictionary: this.listData.$module.dictionary!,
294
+ loading: this.operate === 'ing',
295
+ ...this.currentComponentsProps.edit
296
+ }
297
+ },
298
+ renderEdit() {
299
+ if (this.currentComponents.includes('edit')) {
300
+ return h(QuickFloatModal, {
301
+ ref: 'edit-modal',
302
+ float: this.currentComponentsProps.editModal?.float,
303
+ modal: {
304
+ menu: ['cancel', 'submit'],
305
+ submit: this.onEditSubmit,
306
+ ...this.currentComponentsProps.editModal
307
+ },
308
+ content: {
309
+ render: (ref) => {
310
+ return h(EditArea, this.$getEditOption(ref))
311
+ },
312
+ show: {
313
+ args: [],
314
+ trigger(content: InstanceType<typeof EditArea>, args: any[]) {
315
+ content.$show(...args)
316
+ }
317
+ }
318
+ }
319
+ })
320
+ } else {
321
+ return null
322
+ }
323
+ },
324
+ deleteChoiceList() {
325
+ if (this.choiceSize) {
326
+ notice.confirm('确认进行删除操作吗?', '警告', (act: string) => {
327
+ if (act === 'ok') {
328
+ this.listData.triggerMethod('multipleDeleteData', [this.currentChoice], {
329
+ strict: true,
330
+ debounce: this.editDebounce
331
+ }).then(() => {
332
+ this.listData.resetChoice()
333
+ })
334
+ }
335
+ })
336
+ } else {
337
+ notice.message('请先选择要删除的数据!', 'error')
338
+ }
339
+ },
340
+ refreshData(record: Record<PropertyKey, any>, next: (record: Record<PropertyKey, any>) => void) {
341
+ this.listData.triggerMethod('refreshData', [record], {
342
+ strict: true
343
+ }).then(() => {
344
+ next(record)
345
+ }).catch((err: unknown) => {
346
+ console.error(err)
347
+ })
348
+ },
349
+ openInfo(record?: Record<PropertyKey, any>) {
350
+ if (!record) {
351
+ if (this.currentChoice && this.currentChoice.length === 1) {
352
+ record = this.currentChoice[0]
353
+ } else {
354
+ notice.message('详情界面需要先选择一条数据!', 'error')
355
+ return
356
+ }
357
+ }
358
+ this.refreshData(record, (record) => {
359
+ this.showInfo(record)
360
+ })
361
+ },
362
+ showInfo(record: Record<PropertyKey, any>, type = 'info') {
363
+ let name = '详情'
364
+ if (this.currentComponentsProps.infoModal?.formatName) {
365
+ name = this.currentComponentsProps.infoModal.formatName(name, type)
366
+ }
367
+ (this.$refs['info-modal'] as InstanceType<typeof QuickFloatModal>).show([type, record], name)
368
+ },
369
+ startEdit(type: string, name: string, record?: Record<PropertyKey, any>, refresh?: boolean) {
370
+ if (record && refresh) {
371
+ this.refreshData(record, (record) => {
372
+ this.showEdit(name, type, record)
373
+ })
374
+ } else {
375
+ this.showEdit(name, type, record)
376
+ }
377
+ },
378
+ openEdit(record?: Record<PropertyKey, any>, build?: boolean) {
379
+ const isBuild = !record || build
380
+ const type = isBuild ? 'build' : 'change'
381
+ let name = isBuild ? '新增' : '编辑'
382
+ if (this.currentComponentsProps.editModal?.formatName) {
383
+ name = this.currentComponentsProps.editModal.formatName(name, type)
384
+ }
385
+ this.startEdit(type, name, record, !isBuild)
386
+ },
387
+ showEdit(name: string, type: string, record?: Record<PropertyKey, any>) {
388
+ (this.$refs['edit-modal'] as InstanceType<typeof QuickFloatModal>).show([type, record], name)
389
+ },
390
+ onEditSubmit(...args: any[]) {
391
+ const floatModal = (this.$refs['edit-modal'] as InstanceType<typeof QuickFloatModal>)
392
+ const promise = new Promise((resolve, reject) => {
393
+ const editPromise = (floatModal.getContent() as InstanceType<typeof EditArea>).$submit()
394
+ editPromise.then(res => {
395
+ this.$onEditSubmit(res, ...args).then(() => {
396
+ resolve(res)
397
+ }).catch((err: unknown) => {
398
+ reject(err)
399
+ })
400
+ }).catch((err: unknown) => {
401
+ reject(err)
402
+ })
403
+ })
404
+ promise.then(() => {
405
+ floatModal.getModal()?.close('submit')
406
+ })
407
+ return promise
408
+ },
409
+ $onEditSubmit(res: EditAreaSubmitOption, ...args: any[]) {
410
+ let promise
411
+ if (res.type === 'build') {
412
+ promise = this.listData.triggerMethod('buildData', [res.targetData, res.type, res.originData, ...args], {
413
+ strict: true,
414
+ debounce: this.editDebounce
415
+ })
416
+ } else if (res.type === 'change') {
417
+ promise = this.listData.triggerMethod('changeData', [res.targetData, res.originData, res.type, ...args], {
418
+ strict: true,
419
+ debounce: this.editDebounce
420
+ })
421
+ } else {
422
+ promise = this.listData.triggerMethod('editData', [res.targetData, res.originData, res.type, ...args], {
423
+ strict: true,
424
+ debounce: this.editDebounce
425
+ })
426
+ }
427
+ return promise
428
+ },
429
+ },
430
+ render() {
431
+ return [this.renderList(), this.renderEdit(), this.renderInfo()]
432
+ }
433
+ })
@@ -0,0 +1,77 @@
1
+ import { VNode } from "vue"
2
+ import { Data } from "@complex-suite/data"
3
+ import type { MenuValue } from "@complex-suite/data"
4
+ import type { ModalViewProps, ModalViewSlotProps } from "../../src/ModalView"
5
+ import QuickFloatValue from "../QuickFloatValue"
6
+
7
+ let id = 1
8
+
9
+ export interface FloatValueInitOption {
10
+ label: {
11
+ icon?: MenuValue['icon']
12
+ value: string | (() => VNode)
13
+ }
14
+ modal: ModalViewProps
15
+ content: {
16
+ render: (ref: string, modalSlotProps: ModalViewSlotProps,...args: any[]) => VNode
17
+ show?: {
18
+ args: any[]
19
+ trigger: (content: any, args: any[]) => void
20
+ }
21
+ }
22
+ }
23
+
24
+ export class FloatValue extends Data {
25
+ static $formatConfig = { name: 'FloatValue', level: 80, recommend: true } // 不通过通用格式化函数格式化实例判断值
26
+ id: number
27
+ label: FloatValueInitOption['label']
28
+ target?: InstanceType<typeof QuickFloatValue>
29
+ modal: FloatValueInitOption['modal']
30
+ content: FloatValueInitOption['content']
31
+ show: boolean
32
+ init: boolean
33
+ constructor(initOption: FloatValueInitOption, show = true) {
34
+ super()
35
+ this.id = id++
36
+ this.label = initOption.label
37
+ this.modal = initOption.modal
38
+ this.content = initOption.content
39
+ this.show = show
40
+ this.init = false
41
+ }
42
+ close() {
43
+ this.show = false
44
+ }
45
+ }
46
+
47
+ class FloatData extends Data {
48
+ static $formatConfig = { name: 'FloatData', level: 80, recommend: true } // 不通过通用格式化函数格式化实例判断值
49
+ list: FloatValue[]
50
+ constructor() {
51
+ super()
52
+ this.list = []
53
+ }
54
+ push(floatValueInitOption: FloatValueInitOption, show?: boolean) {
55
+ const floatValue = new FloatValue(floatValueInitOption, show)
56
+ this.list.push(floatValue)
57
+ return floatValue
58
+ }
59
+ close(floatValue: FloatValue, _from: string) {
60
+ const index = this.list.indexOf(floatValue)
61
+ if (index > -1) {
62
+ this.list.splice(index, 1)
63
+ floatValue.close()
64
+ }
65
+ return index
66
+ }
67
+ replace(floatValue: FloatValue, floatValueInitOption?: Partial<FloatValueInitOption>, show?: boolean) {
68
+ const index = this.list.indexOf(floatValue)
69
+ this.list.splice(index, 1, new FloatValue({
70
+ ...floatValue,
71
+ ...floatValueInitOption
72
+ }, show))
73
+ }
74
+ }
75
+
76
+
77
+ export default FloatData
@@ -0,0 +1,39 @@
1
+ <style scoped>
2
+ .auto-spin{
3
+ position: absolute;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ bottom: 0;
8
+ z-index: 100;
9
+ background-color: rgba(255, 255, 255, 0.55);
10
+ }
11
+ .auto-spin>.ant-spin{
12
+ width: 100%;
13
+ height: 100%;
14
+ display: flex;
15
+ flex-direction: column;
16
+ justify-content: center;
17
+ align-items: center;
18
+ }
19
+ </style>
20
+ <template>
21
+ <div class="auto-spin" v-if="spinning" >
22
+ <a-spin :spinning="spinning" ></a-spin>
23
+ </div>
24
+ </template>
25
+
26
+ <script lang="ts">
27
+ import { defineComponent } from 'vue'
28
+
29
+ export default defineComponent({
30
+ name: 'AutoSpin',
31
+ props: {
32
+ spinning: {
33
+ type: Boolean,
34
+ required: false,
35
+ default: true
36
+ }
37
+ }
38
+ })
39
+ </script>
@@ -0,0 +1,101 @@
1
+ <style scoped>
2
+ .complex-auto-text{
3
+ display: block;
4
+ width: 100%;
5
+ margin: 0;
6
+ word-wrap: break-word;
7
+ word-break: break-all;
8
+ }
9
+ .complex-auto-text-auto{
10
+ overflow: hidden;
11
+ text-overflow: ellipsis;
12
+ white-space: nowrap;
13
+ }
14
+ .complex-auto-text-is-auto{
15
+ cursor: pointer;
16
+ }
17
+
18
+ </style>
19
+ <template>
20
+ <Tooltip v-bind="tipOption" >
21
+ <p v-bind="$attrs" ref="mainRef" class="complex-auto-text" :class="{ 'complex-auto-text-auto': auto, 'complex-auto-text-is-auto': isEllipsis }" >
22
+ <span ref="sizeRef" >{{ text }}</span>
23
+ </p>
24
+ </Tooltip>
25
+ </template>
26
+
27
+ <script lang="ts">
28
+ import { computed, defineComponent, nextTick, onBeforeMount, onMounted, ref, watch } from "vue"
29
+ import { Tooltip } from "ant-design-vue"
30
+ import LocalResizeObserver from "../LocalResizeObserver"
31
+
32
+ export default defineComponent({
33
+ name: 'ComplexAutoText',
34
+ components: {
35
+ Tooltip
36
+ },
37
+ props: {
38
+ text: {
39
+ required: false,
40
+ default: ''
41
+ },
42
+ auto: {
43
+ type: Boolean,
44
+ required: false,
45
+ default: true
46
+ },
47
+ tip: {
48
+ type: [String, Boolean, Object],
49
+ required: false
50
+ }
51
+ },
52
+ setup (props) {
53
+ const isEllipsis = ref(false)
54
+ const mainRef = ref<HTMLElement>()
55
+ const sizeRef = ref<HTMLElement>()
56
+ const tipOption = computed(() => {
57
+ if (isEllipsis.value && props.tip !== false) {
58
+ return typeof props.tip === 'object' ? {
59
+ title: props.tip.getData ? props.tip.getData(props.text) : (props.tip.data || props.text),
60
+ placement: props.tip.location,
61
+ ...props.tip.localOption
62
+ } : {
63
+ placement: props.tip || 'top',
64
+ title: props.text
65
+ }
66
+ } else {
67
+ return {}
68
+ }
69
+ })
70
+ const onResize = function() {
71
+ if (mainRef.value && sizeRef.value) {
72
+ const mainWidth = mainRef.value.getBoundingClientRect().width
73
+ const sizeWidth = sizeRef.value.getBoundingClientRect().width
74
+ isEllipsis.value = mainWidth < sizeWidth
75
+ }
76
+ }
77
+ const resizeObserver = new LocalResizeObserver(onResize, {
78
+ unCount: true
79
+ })
80
+ onMounted(() => {
81
+ nextTick(() => {
82
+ resizeObserver.observe(mainRef.value!)
83
+ watch(() => props.text, function() {
84
+ nextTick(() => {
85
+ onResize()
86
+ })
87
+ })
88
+ })
89
+ })
90
+ onBeforeMount(() => {
91
+ resizeObserver.disconnect()
92
+ })
93
+ return {
94
+ mainRef,
95
+ sizeRef,
96
+ isEllipsis: isEllipsis,
97
+ tipOption: tipOption,
98
+ }
99
+ }
100
+ })
101
+ </script>
@@ -0,0 +1,62 @@
1
+ import { defineComponent, h, PropType } from "vue"
2
+ import type { ButtonValue } from "@complex-suite/data"
3
+ import { FileView } from "@complex-suite/component"
4
+ import MenuView from "./MenuView"
5
+
6
+ export default defineComponent({
7
+ name: 'ButtonView',
8
+ props: {
9
+ data: {
10
+ type: Object as PropType<ButtonValue<any, [any]>>,
11
+ required: true
12
+ },
13
+ disabled: {
14
+ type: Boolean,
15
+ required: false
16
+ },
17
+ loading: {
18
+ type: Boolean,
19
+ required: false
20
+ }
21
+ },
22
+ methods: {
23
+ renderMenu() {
24
+ return h(MenuView, {
25
+ ...this.$attrs,
26
+ data: this.data
27
+ })
28
+ },
29
+ renderFile() {
30
+ return h(FileView, {
31
+ class: 'complex-menu-file',
32
+ ref: 'file',
33
+ ...this.data.fileOption,
34
+ onSelect: (file: File) => {
35
+ (this.$refs.menu as InstanceType<typeof MenuView>).operate = true
36
+ this.data.upload!(file).finally(() => {
37
+ (this.$refs.menu as InstanceType<typeof MenuView>).operate = false
38
+ })
39
+ }
40
+ })
41
+ },
42
+ renderFileMenu() {
43
+ return h(MenuView, {
44
+ ...this.$attrs,
45
+ ref: 'menu',
46
+ data: this.data,
47
+ disabled: this.disabled,
48
+ loading: this.loading,
49
+ onClick: () => {
50
+ (this.$refs.file as InstanceType<typeof FileView>).$el.click()
51
+ }
52
+ })
53
+ }
54
+ },
55
+ render() {
56
+ if (!this.data.upload) {
57
+ return this.renderMenu()
58
+ } else {
59
+ return [this.renderFile(), this.renderFileMenu()]
60
+ }
61
+ }
62
+ })