@ithinkdt/ui 4.0.0-23 → 4.0.0-31
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/locale.d.ts +3 -0
- package/package.json +6 -6
- package/src/components/Checkboxes.jsx +1 -1
- package/src/components/DataTable.jsx +57 -10
- package/src/components.d.ts +5 -2
- package/src/page.d.ts +43 -26
- package/src/page.jsx +151 -60
package/locale.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ithinkdt/ui",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "iThinkDT UI",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"sortablejs": "^1.15.6",
|
|
64
64
|
"@types/sortablejs": "^1.15.8",
|
|
65
65
|
"nanoid": "^5.1.6",
|
|
66
|
-
"@ithinkdt/common": "^4.0.0-
|
|
66
|
+
"@ithinkdt/common": "^4.0.0-30"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@ithinkdt/page": ">=4.0",
|
|
@@ -82,13 +82,13 @@
|
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@vitejs/plugin-vue-jsx": "^5.1.1",
|
|
85
|
-
"ithinkdt-ui": "^1.
|
|
85
|
+
"ithinkdt-ui": "^1.8.0",
|
|
86
86
|
"typescript": "~5.9.3",
|
|
87
87
|
"unocss": ">=66.5.4",
|
|
88
|
-
"vite": "npm:rolldown-vite@^7.1.
|
|
88
|
+
"vite": "npm:rolldown-vite@^7.1.19",
|
|
89
89
|
"vue": "^3.5.22",
|
|
90
|
-
"vue-router": "^4.6.
|
|
91
|
-
"@ithinkdt/page": "^4.0.0-
|
|
90
|
+
"vue-router": "^4.6.3",
|
|
91
|
+
"@ithinkdt/page": "^4.0.0-31"
|
|
92
92
|
},
|
|
93
93
|
"scripts": {
|
|
94
94
|
"release": "pnpm publish --no-git-checks"
|
|
@@ -3,7 +3,7 @@ import { computed, defineComponent, ref, watch } from 'vue'
|
|
|
3
3
|
|
|
4
4
|
import { useI18n } from '../use-i18n.js'
|
|
5
5
|
|
|
6
|
-
export const NCheckboxes = defineComponent({
|
|
6
|
+
export const NCheckboxes = /* @__PURE__ */ defineComponent({
|
|
7
7
|
name: 'Checkboxes',
|
|
8
8
|
inheritAttrs: false,
|
|
9
9
|
props: {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { toReactive, unrefElement, until } from '@vueuse/core'
|
|
2
|
-
import { NButton, NDataTable, NFlex, NIcon, NPerformantEllipsis, NTooltip } from 'ithinkdt-ui'
|
|
2
|
+
import { NButton, NDataTable, NFlex, NIcon, NPerformantEllipsis, NTooltip, dataTableProps } from 'ithinkdt-ui'
|
|
3
3
|
import { Sortable } from 'sortablejs'
|
|
4
4
|
import { computed, defineComponent, inject, mergeProps, nextTick, ref, shallowRef, toValue, useTemplateRef, watch, withDirectives } from 'vue'
|
|
5
5
|
|
|
6
6
|
import { PAGE_INJECTION } from '@ithinkdt/page'
|
|
7
7
|
|
|
8
8
|
import { vTooltip } from '../directives/index.js'
|
|
9
|
-
import { useClsPrefix } from '../use-style.js'
|
|
9
|
+
import useStyle, { c, cB, cE, useClsPrefix } from '../use-style.js'
|
|
10
10
|
|
|
11
11
|
import { IHelp } from './assets.jsx'
|
|
12
12
|
|
|
@@ -124,16 +124,20 @@ export const DataTable = /* @__PURE__ */ defineComponent({
|
|
|
124
124
|
selectedKeys: {
|
|
125
125
|
type: Array,
|
|
126
126
|
},
|
|
127
|
+
highlight: {
|
|
128
|
+
type: [Boolean, String, Number, Object],
|
|
129
|
+
default: true,
|
|
130
|
+
},
|
|
131
|
+
rowClassName: dataTableProps.rowClassName,
|
|
132
|
+
rowProps: dataTableProps.rowProps,
|
|
127
133
|
},
|
|
128
|
-
emits:
|
|
129
|
-
sort: () => true,
|
|
130
|
-
select: () => true,
|
|
131
|
-
},
|
|
134
|
+
emits: ['sort', 'select', 'custom', 'highlight'],
|
|
132
135
|
setup(props, { slots, emit, expose }) {
|
|
133
136
|
const { keyField } = inject(PAGE_INJECTION)
|
|
134
137
|
|
|
135
138
|
const clsPrefix = useClsPrefix()
|
|
136
|
-
const cls = `${clsPrefix.value}-
|
|
139
|
+
const cls = `${clsPrefix.value}-datatable`
|
|
140
|
+
useStyle('-datatable', style, clsPrefix)
|
|
137
141
|
|
|
138
142
|
const tableRef = useTemplateRef('table-ref')
|
|
139
143
|
|
|
@@ -165,7 +169,7 @@ export const DataTable = /* @__PURE__ */ defineComponent({
|
|
|
165
169
|
exposed.value.scrollToView = (key) => {
|
|
166
170
|
const index = props.data.findIndex(row => rowKey.value(row) === key)
|
|
167
171
|
if (index === -1) return
|
|
168
|
-
const row = tableRef.value.$el.querySelector(`.${cls}-
|
|
172
|
+
const row = tableRef.value.$el.querySelector(`.${cls}__row-marker:nth-child(${index + 1})`)
|
|
169
173
|
tableRef.value.scrollTo({
|
|
170
174
|
top: row.offsetTop,
|
|
171
175
|
behavior: 'smooth',
|
|
@@ -184,10 +188,33 @@ export const DataTable = /* @__PURE__ */ defineComponent({
|
|
|
184
188
|
columns.value = _map(props.columns, width)
|
|
185
189
|
}, { immediate: true, deep: 1 })
|
|
186
190
|
|
|
191
|
+
const highlightKey = ref()
|
|
192
|
+
watch(() => props.highlight, (val) => {
|
|
193
|
+
highlightKey.value = typeof val === 'boolean' ? null : (val ?? null)
|
|
194
|
+
}, { immediate: true })
|
|
187
195
|
const rowClassName = computed(() => {
|
|
188
196
|
return (row, i) => {
|
|
189
|
-
|
|
190
|
-
|
|
197
|
+
return [
|
|
198
|
+
props.rowClassName?.(row, i) || '',
|
|
199
|
+
`${cls}__row-marker`,
|
|
200
|
+
(highlightKey.value != null && rowKey.value(row) === highlightKey.value) ? `${cls}__row-highlight` : '',
|
|
201
|
+
].join(' ')
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
const rowProps = computed(() => {
|
|
205
|
+
return (row, i) => {
|
|
206
|
+
const props2 = props.rowProps?.(row, i)
|
|
207
|
+
return {
|
|
208
|
+
...props2,
|
|
209
|
+
onClick: (e) => {
|
|
210
|
+
const key = rowKey.value(row)
|
|
211
|
+
if (props.highlight === true) {
|
|
212
|
+
highlightKey.value = key
|
|
213
|
+
}
|
|
214
|
+
emit('highlight', key)
|
|
215
|
+
props2?.onClick?.(e)
|
|
216
|
+
},
|
|
217
|
+
}
|
|
191
218
|
}
|
|
192
219
|
})
|
|
193
220
|
|
|
@@ -207,6 +234,13 @@ export const DataTable = /* @__PURE__ */ defineComponent({
|
|
|
207
234
|
emit('select', keys)
|
|
208
235
|
}
|
|
209
236
|
|
|
237
|
+
const onColumnResize = (resizedWidth, limitedWidth, column) => {
|
|
238
|
+
emit('custom', {
|
|
239
|
+
key: column.key,
|
|
240
|
+
width: resizedWidth,
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
|
|
210
244
|
return () => (
|
|
211
245
|
<NDataTable
|
|
212
246
|
class={cls}
|
|
@@ -217,9 +251,11 @@ export const DataTable = /* @__PURE__ */ defineComponent({
|
|
|
217
251
|
ref="table-ref"
|
|
218
252
|
scrollX={width.value}
|
|
219
253
|
rowClassName={rowClassName.value}
|
|
254
|
+
rowProps={rowProps.value}
|
|
220
255
|
checkedRowKeys={props.selectedKeys}
|
|
221
256
|
onUpdateSorter={onUpdateSorter}
|
|
222
257
|
onUpdateCheckedRowKeys={onUpdateCheckedRowKeys}
|
|
258
|
+
onUnstableColumnResize={onColumnResize}
|
|
223
259
|
>
|
|
224
260
|
{slots}
|
|
225
261
|
</NDataTable>
|
|
@@ -227,6 +263,17 @@ export const DataTable = /* @__PURE__ */ defineComponent({
|
|
|
227
263
|
},
|
|
228
264
|
})
|
|
229
265
|
|
|
266
|
+
const style = /* @__PURE__ */ cB(
|
|
267
|
+
'datatable',
|
|
268
|
+
[
|
|
269
|
+
cE('row-highlight', [
|
|
270
|
+
c('& > td', {
|
|
271
|
+
backgroundColor: 'var(--n-tr-highlight-color, var(--n-merged-border-color)) !important',
|
|
272
|
+
}),
|
|
273
|
+
]),
|
|
274
|
+
],
|
|
275
|
+
)
|
|
276
|
+
|
|
230
277
|
export function useDataTableDrag(
|
|
231
278
|
tableRef,
|
|
232
279
|
{ data, onSort, ...options }) {
|
package/src/components.d.ts
CHANGED
|
@@ -149,6 +149,7 @@ export type DataTableProps<Data extends {}, KeyField extends keyof Data>
|
|
|
149
149
|
data?: Data[] | undefined
|
|
150
150
|
keyField?: KeyField | undefined
|
|
151
151
|
selectedKeys?: Data[KeyField][] | undefined
|
|
152
|
+
highlight?: boolean | Data[KeyField] | undefined
|
|
152
153
|
sorter?: SortParams<Data> | undefined
|
|
153
154
|
onSort?: MaybeArray<(param: SortParams<Data>) => void> | undefined
|
|
154
155
|
onSelect?: MaybeArray<(param: NonNullable<Data[KeyField]>[]) => void> | undefined
|
|
@@ -157,6 +158,8 @@ export type DataTableProps<Data extends {}, KeyField extends keyof Data>
|
|
|
157
158
|
export type DataTableEmits<Data extends {}, KeyField extends keyof Data> = {
|
|
158
159
|
(e: 'sort', param: SortParams<Data>): void
|
|
159
160
|
(e: 'select', param: Data[KeyField][]): void
|
|
161
|
+
(e: 'highlight', rowKey: Data[KeyField]): void
|
|
162
|
+
(e: 'custom', params: { key: string, width: number }): void
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
export type DataTableInst<Data extends {}, KeyField extends keyof Data> = NDataTableInst & {
|
|
@@ -182,7 +185,7 @@ export declare function useDataTableDrag<T>(
|
|
|
182
185
|
{ data, onSort, ...options }: {
|
|
183
186
|
data: MaybeRef<T[]>
|
|
184
187
|
onSort: (info: { from: number, to: number }) => void
|
|
185
|
-
} & Omit<Sortable.Options, 'onSort'
|
|
188
|
+
} & Omit<Sortable.Options, 'onSort'>,
|
|
186
189
|
): void
|
|
187
190
|
|
|
188
191
|
export type DataPaginationProps = (PageParams | { page: PageParams }) & {
|
|
@@ -302,7 +305,7 @@ export declare function DataLocaleInput(
|
|
|
302
305
|
export declare function useLocaleEdit(
|
|
303
306
|
title: VNodeChild | (() => VNodeChild),
|
|
304
307
|
onSubmit: (data: Record<string, string | undefined>) => void,
|
|
305
|
-
defaultRows?: MaybeRef<number | undefined
|
|
308
|
+
defaultRows?: MaybeRef<number | undefined>,
|
|
306
309
|
): {
|
|
307
310
|
open(this: void, data: MaybePromise<Record<string, string | undefined>>, readonly?: boolean): PromiseLike<Record<string, string | undefined>>
|
|
308
311
|
setSupports(this: void, supports: { label: string, value: string, required?: boolean }[]): void
|
package/src/page.d.ts
CHANGED
|
@@ -1,44 +1,46 @@
|
|
|
1
1
|
import {
|
|
2
|
-
CheckboxProps,
|
|
2
|
+
CheckboxProps,
|
|
3
|
+
DatePickerProps, DatePickerSlots,
|
|
3
4
|
DrawerContentProps, DrawerProps,
|
|
4
5
|
InputNumberProps, InputNumberSlots, InputProps, InputSlots,
|
|
5
6
|
ModalOptions,
|
|
6
7
|
SelectGroupOption, SelectOption, SelectProps, SelectSlots,
|
|
7
|
-
UploadFileInfo,
|
|
8
|
+
UploadFileInfo, UploadProps,
|
|
8
9
|
} from 'ithinkdt-ui'
|
|
9
|
-
import { MaybeRef, VNode
|
|
10
|
+
import { MaybeRef, VNode } from 'vue'
|
|
10
11
|
|
|
12
|
+
import { PublicProps } from '@ithinkdt/common'
|
|
11
13
|
import { DictItem, DictTypeKey } from '@ithinkdt/common/dict'
|
|
12
14
|
import { PageOptions } from '@ithinkdt/page'
|
|
13
15
|
|
|
14
16
|
import { CheckboxesProps, RadiosProps, UserDeptProps, UserGroupOption } from './components'
|
|
15
17
|
|
|
16
|
-
type
|
|
18
|
+
type ShallowMaybeRef<T extends {}> = {
|
|
17
19
|
[Key in (keyof T)]: MaybeRef<T[Key]>
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
declare module '@ithinkdt/page' {
|
|
21
23
|
interface FormComponentPresets {
|
|
22
24
|
input: {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
inputProps?: ShallowMaybeRef<Omit<InputProps, 'value' | 'onUpdate:value' | 'disabled'>> & PublicProps
|
|
26
|
+
inputSlots?: InputSlots
|
|
25
27
|
}
|
|
26
28
|
number: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
numberProps?: ShallowMaybeRef<Omit<InputNumberProps, 'value' | 'onUpdate:value' | 'disabled'>> & PublicProps
|
|
30
|
+
numberSlots?: InputNumberSlots
|
|
29
31
|
}
|
|
30
32
|
select: {
|
|
31
|
-
|
|
33
|
+
selectProps?: ShallowMaybeRef<Omit<SelectProps, 'options' | 'value' | 'onUpdate:value' | 'disabled'> & PublicProps
|
|
32
34
|
& {
|
|
33
35
|
dictType?: DictTypeKey | undefined
|
|
34
36
|
options?: DictItem[] | (SelectOption | SelectGroupOption)[] | undefined
|
|
35
37
|
}>
|
|
36
|
-
|
|
38
|
+
selectSlots?: SelectSlots
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
checkbox: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
checkboxProps?: ShallowMaybeRef<Omit<CheckboxProps, 'checked' | 'onUpdate:checked' | 'disabled'>> & PublicProps
|
|
43
|
+
checkboxSlots?: {
|
|
42
44
|
default?: (() => VNode[]) | undefined
|
|
43
45
|
checked?: (() => VNode[]) | undefined
|
|
44
46
|
unchecked?: (() => VNode[]) | undefined
|
|
@@ -46,45 +48,59 @@ declare module '@ithinkdt/page' {
|
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
checkboxes: {
|
|
49
|
-
|
|
51
|
+
checkboxesProps?: ShallowMaybeRef<Omit<CheckboxesProps, 'disabled'> & PublicProps
|
|
50
52
|
& {
|
|
51
53
|
dictType?: DictTypeKey | undefined
|
|
52
54
|
options?: DictItem[] | undefined
|
|
53
55
|
}>
|
|
54
|
-
|
|
56
|
+
checkboxesSlots?: { }
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
radios: {
|
|
58
|
-
|
|
60
|
+
radiosProps?: ShallowMaybeRef<Omit<RadiosProps, 'disabled'> & PublicProps
|
|
59
61
|
& {
|
|
60
62
|
dictType?: DictTypeKey | undefined
|
|
61
63
|
options?: DictItem[] | undefined
|
|
62
64
|
}>
|
|
63
|
-
|
|
65
|
+
radiosSlots?: { }
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
datepicker: {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
datepickerProps?: ShallowMaybeRef<Omit<DatePickerProps, 'value' | 'onUpdate:value' | 'disabled'>> & PublicProps
|
|
70
|
+
datepickerSlots?: DatePickerSlots
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
file: {
|
|
72
|
-
|
|
74
|
+
fileProps?: ShallowMaybeRef<{
|
|
73
75
|
type?: 'file' | 'image' | undefined
|
|
74
76
|
multiple?: boolean | undefined
|
|
75
77
|
max?: number | undefined
|
|
76
78
|
accept?: string | undefined
|
|
77
79
|
maxSize?: number | undefined
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
onBeforeUpload?: UploadProps['onBeforeUpload']
|
|
81
|
+
} & PublicProps>
|
|
82
|
+
fileSlots?: {
|
|
83
|
+
default?: (() => VNode[]) | undefined
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
upload: {
|
|
87
|
+
uploadProps?: ShallowMaybeRef<{
|
|
88
|
+
type?: 'file' | 'image' | undefined
|
|
89
|
+
multiple?: boolean | undefined
|
|
90
|
+
max?: number | undefined
|
|
91
|
+
accept?: string | undefined
|
|
92
|
+
maxSize?: number | undefined
|
|
93
|
+
onBeforeUpload?: UploadProps['onBeforeUpload']
|
|
94
|
+
} & PublicProps>
|
|
95
|
+
uploadSlots?: {
|
|
80
96
|
default?: (() => VNode[]) | undefined
|
|
81
97
|
}
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
user: {
|
|
85
|
-
|
|
86
|
-
| 'users' | 'groups' | 'depts' | 'getUsersByGroup' | 'getUsersByDept'>> &
|
|
87
|
-
|
|
101
|
+
uploadProps?: ShallowMaybeRef<Omit<UserDeptProps<boolean>, 'modelValue' | 'onUpdate:modelValue' | 'disabled'
|
|
102
|
+
| 'users' | 'groups' | 'depts' | 'getUsersByGroup' | 'getUsersByDept'>> & PublicProps
|
|
103
|
+
uploadSlots?: {}
|
|
88
104
|
}
|
|
89
105
|
}
|
|
90
106
|
|
|
@@ -128,9 +144,9 @@ declare module '@ithinkdt/page' {
|
|
|
128
144
|
}
|
|
129
145
|
|
|
130
146
|
type ModalOptionsKey = 'type' | keyof import('@ithinkdt/page').ModalOptions
|
|
131
|
-
interface ModalDrawerOptions extends
|
|
147
|
+
interface ModalDrawerOptions extends ShallowMaybeRef<Omit<DrawerContentProps, ModalOptionsKey>>, ShallowMaybeRef<Omit<DrawerProps, ModalOptionsKey>> { }
|
|
132
148
|
|
|
133
|
-
interface ModalDialogOptions extends
|
|
149
|
+
interface ModalDialogOptions extends ShallowMaybeRef<Omit<ModalOptions, ModalOptionsKey>> {}
|
|
134
150
|
}
|
|
135
151
|
|
|
136
152
|
export declare function createPageFormHelper(options?: {
|
|
@@ -142,6 +158,7 @@ export declare function createPageFormHelper(options?: {
|
|
|
142
158
|
uploadFile?: (file: File, options?: {
|
|
143
159
|
onProgress?: ((percent: number) => void) | undefined
|
|
144
160
|
}) => Promise<string>
|
|
161
|
+
getFileInfos?: (files: string[]) => Promise<UploadFileInfo[]>
|
|
145
162
|
}): PageOptions['getFormItemRenderer']
|
|
146
163
|
export declare function createPageTableHelper(options?: {
|
|
147
164
|
getUsersByUsername?: (usernames: string[]) => Promise<{ username: string, nickname: string }[]>
|
package/src/page.jsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { until } from '@vueuse/core'
|
|
1
2
|
import { format } from 'date-fns'
|
|
2
3
|
import {
|
|
3
4
|
NButton, NCheckbox, NColorPicker, NDatePicker, NDrawer, NDrawerContent, NFlex, NInput,
|
|
4
|
-
NInputNumber, NModal, NScrollbar, NSelect, NText, NUpload,
|
|
5
|
-
useMessage,
|
|
5
|
+
NInputNumber, NModal, NScrollbar, NSelect, NText, NUpload, useMessage,
|
|
6
6
|
} from 'ithinkdt-ui'
|
|
7
|
-
import { defineComponent, h, mergeProps, unref } from 'vue'
|
|
7
|
+
import { computed, defineComponent, h, mergeProps, shallowRef, unref } from 'vue'
|
|
8
8
|
|
|
9
9
|
import { useDict, useDictMap } from '@ithinkdt/common/dict'
|
|
10
10
|
|
|
@@ -14,64 +14,68 @@ import { useI18n } from './use-i18n.js'
|
|
|
14
14
|
const mapProps = (props) => {
|
|
15
15
|
return Object.fromEntries(Object.entries(props || {}).map(([prop, value]) => [prop, unref(value)]))
|
|
16
16
|
}
|
|
17
|
-
export function createPageFormHelper({
|
|
18
|
-
getUserGroups, getUsersByGroup, getUsersByDept, getUsersByUsername, uploadFile,
|
|
19
|
-
}) {
|
|
20
|
-
const SimpleUpload = defineComponent({
|
|
21
|
-
name: 'SimpleUpload',
|
|
22
|
-
props: {
|
|
23
|
-
type: { type: String, default: 'file' }, // file | image
|
|
24
|
-
multiple: { type: Boolean, default: false },
|
|
25
|
-
max: { type: Number, default: undefined },
|
|
26
|
-
accept: { type: String, default: undefined },
|
|
27
|
-
maxSize: { type: Number, default: undefined }, // MB
|
|
28
|
-
disabled: { type: Boolean, default: undefined },
|
|
29
|
-
fileList: { type: Array, default: () => [] },
|
|
30
|
-
onUpdateFileList: { type: [Array, Function] },
|
|
31
|
-
},
|
|
32
|
-
setup(props, { slots }) {
|
|
33
|
-
const { t } = useI18n()
|
|
34
17
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
onUpdate:fileList={onUpdateFileList}
|
|
64
|
-
>
|
|
65
|
-
{{
|
|
66
|
-
default: () => <NButton disabled={props.disabled}>{t('common.page.form.selectFileText')}</NButton>,
|
|
67
|
-
...slots,
|
|
68
|
-
}}
|
|
69
|
-
</NUpload>
|
|
70
|
-
)
|
|
18
|
+
const SimpleUpload = /* @__PURE__ */ defineComponent({
|
|
19
|
+
name: 'SimpleUpload',
|
|
20
|
+
props: {
|
|
21
|
+
type: { type: String, default: 'file' }, // file | image
|
|
22
|
+
multiple: { type: Boolean, default: false },
|
|
23
|
+
max: { type: Number, default: undefined },
|
|
24
|
+
accept: { type: String, default: undefined },
|
|
25
|
+
maxSize: { type: Number, default: undefined }, // MB
|
|
26
|
+
disabled: { type: Boolean, default: undefined },
|
|
27
|
+
fileList: { type: Array, default: () => [] },
|
|
28
|
+
onUpdateFileList: { type: [Array, Function] },
|
|
29
|
+
uploadFile: { type: Function },
|
|
30
|
+
},
|
|
31
|
+
setup(props, { slots, expose }) {
|
|
32
|
+
const { t } = useI18n()
|
|
33
|
+
SimpleUpload.t = t
|
|
34
|
+
|
|
35
|
+
const message = useMessage()
|
|
36
|
+
const customRequest = computed(() => props.customRequest || (
|
|
37
|
+
({ file, onProgress, onFinish, onError }) => {
|
|
38
|
+
props.uploadFile(file.file, percent => onProgress({ percent }))
|
|
39
|
+
.then((id) => {
|
|
40
|
+
file.file.fileId = id
|
|
41
|
+
onFinish()
|
|
42
|
+
}).catch((error) => {
|
|
43
|
+
message.error(error.message)
|
|
44
|
+
onError(error)
|
|
45
|
+
})
|
|
71
46
|
}
|
|
72
|
-
|
|
73
|
-
|
|
47
|
+
))
|
|
48
|
+
|
|
49
|
+
const inst = ref()
|
|
50
|
+
expose({
|
|
51
|
+
submit() {
|
|
52
|
+
return until(inst).toBeTruthy().then(inst => inst.submit())
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
return () => {
|
|
56
|
+
const { type, onUpdateFileList, ...props0 } = props
|
|
57
|
+
return (
|
|
58
|
+
<NUpload
|
|
59
|
+
{...props0}
|
|
60
|
+
ref={inst}
|
|
61
|
+
customRequest={customRequest.value}
|
|
62
|
+
listType={type === 'image' ? 'image-card' : 'text'}
|
|
63
|
+
accept={props0.accept ?? type === 'image' ? 'image/*' : undefined}
|
|
64
|
+
onUpdate:fileList={onUpdateFileList}
|
|
65
|
+
>
|
|
66
|
+
{{
|
|
67
|
+
default: () => <NButton disabled={props.disabled}>{t('common.page.form.selectFileText')}</NButton>,
|
|
68
|
+
...slots,
|
|
69
|
+
}}
|
|
70
|
+
</NUpload>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
})
|
|
74
75
|
|
|
76
|
+
export function createPageFormHelper({
|
|
77
|
+
getUserGroups, getUsersByGroup, getUsersByDept, getUsersByUsername, uploadFile, getFileInfos,
|
|
78
|
+
}) {
|
|
75
79
|
return {
|
|
76
80
|
input: () => (
|
|
77
81
|
{ slots, props },
|
|
@@ -298,9 +302,10 @@ export function createPageFormHelper({
|
|
|
298
302
|
) => {
|
|
299
303
|
props = mapProps(props)
|
|
300
304
|
if (readonly) {
|
|
301
|
-
|
|
305
|
+
console.warn(`[file] 原则上此组建不应该显示在详情中`)
|
|
306
|
+
if (fileList.value.length === 0) return
|
|
302
307
|
return (
|
|
303
|
-
<NFlex gap="8"
|
|
308
|
+
<NFlex gap="8" vertical>
|
|
304
309
|
{modelValue.map(it => (
|
|
305
310
|
<a
|
|
306
311
|
key={it.id}
|
|
@@ -318,11 +323,97 @@ export function createPageFormHelper({
|
|
|
318
323
|
return h(SimpleUpload, {
|
|
319
324
|
...props,
|
|
320
325
|
...params,
|
|
326
|
+
defaultUpload: false,
|
|
327
|
+
uploadFile,
|
|
321
328
|
fileList: modelValue,
|
|
322
329
|
onUpdateFileList: onUpdateValue,
|
|
323
330
|
}, slots)
|
|
324
331
|
}
|
|
325
332
|
},
|
|
333
|
+
upload: () => {
|
|
334
|
+
let lastModelValue = null
|
|
335
|
+
const idMap = new Map()
|
|
336
|
+
const fileMap = new Map()
|
|
337
|
+
const fileList = shallowRef([])
|
|
338
|
+
let key = 0
|
|
339
|
+
|
|
340
|
+
const update = (ids) => {
|
|
341
|
+
const key0 = ++key
|
|
342
|
+
fileList.value = ids.map(id => fileMap.get(id)).filter(Boolean)
|
|
343
|
+
const ids0 = ids.filter(id => !fileMap.has(id))
|
|
344
|
+
Promise.resolve(ids0.length > 0 ? getFileInfos(ids0) : [])
|
|
345
|
+
.then((res) => {
|
|
346
|
+
if (key0 !== key) return
|
|
347
|
+
fileList.value = ids.map(id => fileMap.get(id) || res.find(it => it.id === id))
|
|
348
|
+
fileMap.clear()
|
|
349
|
+
for (const it of fileList.value) {
|
|
350
|
+
fileMap.set(it.id, it)
|
|
351
|
+
}
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let inst
|
|
356
|
+
const renderer = (
|
|
357
|
+
{ slots, props },
|
|
358
|
+
{ modelValue, 'onUpdate:modelValue': onUpdateValue, required, readonly, ...params },
|
|
359
|
+
) => {
|
|
360
|
+
const props0 = mapProps(props)
|
|
361
|
+
inst = (props0.ref ??= shallowRef())
|
|
362
|
+
if (lastModelValue !== modelValue) {
|
|
363
|
+
lastModelValue = modelValue
|
|
364
|
+
update(modelValue?.split(',') ?? [])
|
|
365
|
+
}
|
|
366
|
+
if (readonly) {
|
|
367
|
+
if (fileList.value.length === 0) return
|
|
368
|
+
return (
|
|
369
|
+
<NFlex gap="8" vertical>
|
|
370
|
+
{fileList.value.map(it => (
|
|
371
|
+
<a
|
|
372
|
+
key={it.id}
|
|
373
|
+
href={it.url}
|
|
374
|
+
target="_blank"
|
|
375
|
+
rel="noreferrer"
|
|
376
|
+
title={it.name}
|
|
377
|
+
style="max-width: 100px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; display: inline-block"
|
|
378
|
+
>
|
|
379
|
+
{it.name}
|
|
380
|
+
</a>
|
|
381
|
+
))}
|
|
382
|
+
</NFlex>
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
return h(SimpleUpload, {
|
|
386
|
+
...props0,
|
|
387
|
+
...params,
|
|
388
|
+
uploadFile,
|
|
389
|
+
fileList: fileList.value,
|
|
390
|
+
onUpdateFileList: (fileList0 = []) => {
|
|
391
|
+
fileMap.clear()
|
|
392
|
+
for (const f of fileList0) {
|
|
393
|
+
if (f.file.fileId) {
|
|
394
|
+
idMap.set(f.id, f.file.fileId)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (f.file.fileId) fileMap.set(f.file.fileId, f)
|
|
398
|
+
else fileMap.set(f.id, f)
|
|
399
|
+
}
|
|
400
|
+
fileList.value = fileList0
|
|
401
|
+
const ids = fileList.value.map(f => idMap.get(f.id) || f.id).join(',') || null
|
|
402
|
+
onUpdateValue(ids)
|
|
403
|
+
},
|
|
404
|
+
}, slots)
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
renderer,
|
|
408
|
+
beforeSubmit: async () => {
|
|
409
|
+
await inst?.submit()
|
|
410
|
+
await until(fileList).toMatch(list => list.every(file => !['pending', 'uploading'].includes(file.status)))
|
|
411
|
+
if (fileList.value.some(file => file.status === 'error')) {
|
|
412
|
+
return SimpleUpload.t('common.page.form.validate.fileErrorMessage')
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
}
|
|
416
|
+
},
|
|
326
417
|
user: () => {
|
|
327
418
|
let users, groups, depts
|
|
328
419
|
return (
|