deepsea-components 5.7.0 → 5.7.2
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/README.md +23 -23
- package/dist/cjs/components/AutoFit.js +3 -1
- package/dist/cjs/components/AutoFit.js.map +2 -2
- package/dist/cjs/components/AutoScroll.js +16 -1
- package/dist/cjs/components/AutoScroll.js.map +2 -2
- package/dist/cjs/components/AutoSizeTextarea.js.map +1 -1
- package/dist/cjs/components/CircleText.js +31 -2
- package/dist/cjs/components/CircleText.js.map +2 -2
- package/dist/cjs/components/CopyButton.js.map +1 -1
- package/dist/cjs/components/Echart.js.map +2 -2
- package/dist/cjs/components/Flow.js +56 -3
- package/dist/cjs/components/Flow.js.map +2 -2
- package/dist/cjs/components/FormLabel.js.map +1 -1
- package/dist/cjs/components/HlsPlayer.js.map +1 -1
- package/dist/cjs/components/InfiniteScroll.js +15 -1
- package/dist/cjs/components/InfiniteScroll.js.map +2 -2
- package/dist/cjs/components/InputFile.js.map +1 -1
- package/dist/cjs/components/LoopSwiper.js +23 -2
- package/dist/cjs/components/LoopSwiper.js.map +2 -2
- package/dist/cjs/components/Ring.js +13 -1
- package/dist/cjs/components/Ring.js.map +2 -2
- package/dist/cjs/components/Scroll.js.map +2 -2
- package/dist/cjs/components/SectionRing.js +3 -1
- package/dist/cjs/components/SectionRing.js.map +2 -2
- package/dist/cjs/components/Skeleton.js.map +2 -2
- package/dist/cjs/components/Title.js.map +2 -2
- package/dist/cjs/components/TransitionBox.js +9 -1
- package/dist/cjs/components/TransitionBox.js.map +2 -2
- package/dist/cjs/components/TransitionNum.js.map +1 -1
- package/dist/cjs/components/Trapezium.js.map +1 -1
- package/dist/cjs/utils/getReactVersion.js.map +1 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/esm/components/AutoFit.js +9 -9
- package/dist/esm/components/AutoFit.js.map +1 -1
- package/dist/esm/components/AutoScroll.js.map +1 -1
- package/dist/esm/components/AutoSizeTextarea.js +2 -2
- package/dist/esm/components/AutoSizeTextarea.js.map +1 -1
- package/dist/esm/components/CircleText.js.map +1 -1
- package/dist/esm/components/CopyButton.js.map +1 -1
- package/dist/esm/components/Echart.js.map +1 -1
- package/dist/esm/components/Flow.js.map +1 -1
- package/dist/esm/components/FormLabel.js +2 -2
- package/dist/esm/components/FormLabel.js.map +1 -1
- package/dist/esm/components/HlsPlayer.js.map +1 -1
- package/dist/esm/components/InfiniteScroll.js +4 -4
- package/dist/esm/components/InfiniteScroll.js.map +1 -1
- package/dist/esm/components/InputFile.js.map +1 -1
- package/dist/esm/components/LoopSwiper.js.map +1 -1
- package/dist/esm/components/Ring.js.map +1 -1
- package/dist/esm/components/Scroll.js.map +1 -1
- package/dist/esm/components/SectionRing.js.map +1 -1
- package/dist/esm/components/Skeleton.js.map +1 -1
- package/dist/esm/components/Title.js.map +1 -1
- package/dist/esm/components/TransitionBox.js.map +1 -1
- package/dist/esm/components/TransitionNum.js.map +1 -1
- package/dist/esm/components/Trapezium.js.map +1 -1
- package/dist/esm/utils/getReactVersion.js.map +1 -1
- package/dist/esm/utils/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/AutoFit.tsx +103 -101
- package/src/components/AutoScroll.tsx +148 -132
- package/src/components/AutoSizeTextarea.tsx +49 -49
- package/src/components/CircleText.tsx +81 -56
- package/src/components/CopyButton.tsx +29 -29
- package/src/components/Echart.tsx +67 -44
- package/src/components/Flow.tsx +270 -214
- package/src/components/FormLabel.tsx +38 -38
- package/src/components/HlsPlayer.tsx +34 -34
- package/src/components/InfiniteScroll.tsx +161 -135
- package/src/components/InputFile.tsx +234 -234
- package/src/components/LoopSwiper.tsx +125 -101
- package/src/components/Ring.tsx +30 -19
- package/src/components/Scroll.tsx +96 -95
- package/src/components/SectionRing.tsx +39 -36
- package/src/components/Skeleton.tsx +47 -46
- package/src/components/Title.tsx +23 -24
- package/src/components/TransitionBox.tsx +44 -36
- package/src/components/TransitionNum.tsx +54 -54
- package/src/components/Trapezium.tsx +59 -59
- package/src/utils/getReactVersion.ts +7 -7
- package/src/utils/index.ts +33 -33
|
@@ -1,234 +1,234 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState
|
|
4
|
-
import { read, utils, writeFile } from "xlsx"
|
|
5
|
-
|
|
6
|
-
export interface InputFileDataTypes {
|
|
7
|
-
base64: string
|
|
8
|
-
text: string
|
|
9
|
-
arrayBuffer: ArrayBuffer
|
|
10
|
-
binary: string
|
|
11
|
-
file: File
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type InputFileDataType = keyof InputFileDataTypes
|
|
15
|
-
|
|
16
|
-
export interface InputFileData<T> {
|
|
17
|
-
result: T
|
|
18
|
-
file: File
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type InputFileProps = (
|
|
22
|
-
| {
|
|
23
|
-
multiple?: false
|
|
24
|
-
type: "base64" | "text" | "binary"
|
|
25
|
-
onChange?: (data: InputFileData<string>) => void
|
|
26
|
-
}
|
|
27
|
-
| {
|
|
28
|
-
multiple?: false
|
|
29
|
-
type: "arrayBuffer"
|
|
30
|
-
onChange?: (data: InputFileData<ArrayBuffer>) => void
|
|
31
|
-
}
|
|
32
|
-
| {
|
|
33
|
-
multiple?: false
|
|
34
|
-
type?: "file"
|
|
35
|
-
onChange?: (data: InputFileData<File>) => void
|
|
36
|
-
}
|
|
37
|
-
| {
|
|
38
|
-
multiple: true
|
|
39
|
-
type: "base64" | "text" | "binary"
|
|
40
|
-
onChange?: (data: InputFileData<string>[]) => void
|
|
41
|
-
}
|
|
42
|
-
| {
|
|
43
|
-
multiple: true
|
|
44
|
-
type: "arrayBuffer"
|
|
45
|
-
onChange?: (data: InputFileData<ArrayBuffer>[]) => void
|
|
46
|
-
}
|
|
47
|
-
| {
|
|
48
|
-
multiple: true
|
|
49
|
-
type?: "file"
|
|
50
|
-
onChange?: (data: InputFileData<File>[]) => void
|
|
51
|
-
}
|
|
52
|
-
) &
|
|
53
|
-
Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "multiple" | "type"> & {
|
|
54
|
-
/** 是否在捕获文件后清除 input 上的文件,默认为 false,主要区别在于如果不清除,连续两次选择同样的文件不会触发 onChange 事件,如果用于 form 表单,请设置为 flase */
|
|
55
|
-
clearAfterChange?: boolean
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export async function getFileData<T extends InputFileDataType>(file: File, type: T): Promise<InputFileDataTypes[T]> {
|
|
59
|
-
const fileReader = new FileReader()
|
|
60
|
-
switch (type) {
|
|
61
|
-
case "arrayBuffer":
|
|
62
|
-
fileReader.readAsArrayBuffer(file)
|
|
63
|
-
break
|
|
64
|
-
case "binary":
|
|
65
|
-
fileReader.readAsBinaryString(file)
|
|
66
|
-
break
|
|
67
|
-
case "base64":
|
|
68
|
-
fileReader.readAsDataURL(file)
|
|
69
|
-
break
|
|
70
|
-
case "text":
|
|
71
|
-
fileReader.readAsText(file)
|
|
72
|
-
break
|
|
73
|
-
default:
|
|
74
|
-
return file as any
|
|
75
|
-
}
|
|
76
|
-
return new Promise(resolve => {
|
|
77
|
-
fileReader.addEventListener("load", () => {
|
|
78
|
-
resolve(fileReader.result as any)
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** 专用于读取文件的组件 */
|
|
84
|
-
export const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, ref) => {
|
|
85
|
-
const { multiple = false, type = "file", onChange, disabled: inputDisabled, clearAfterChange, ...rest } = props
|
|
86
|
-
const [disabled, setDisabled] = useState(false)
|
|
87
|
-
|
|
88
|
-
async function onInputChange(e: ChangeEvent<HTMLInputElement>) {
|
|
89
|
-
const input = e.target
|
|
90
|
-
const { files } = input
|
|
91
|
-
if (!files || files.length === 0) return
|
|
92
|
-
setDisabled(true)
|
|
93
|
-
try {
|
|
94
|
-
if (multiple) {
|
|
95
|
-
const result: any[] = []
|
|
96
|
-
for (const file of Array.from(files)) {
|
|
97
|
-
result.push({
|
|
98
|
-
result: await getFileData(file, type),
|
|
99
|
-
file
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
onChange?.(result as any)
|
|
103
|
-
} else {
|
|
104
|
-
onChange?.({
|
|
105
|
-
result: await getFileData(files[0], type),
|
|
106
|
-
file: files[0]
|
|
107
|
-
} as any)
|
|
108
|
-
}
|
|
109
|
-
} finally {
|
|
110
|
-
if (clearAfterChange) input.value = ""
|
|
111
|
-
setDisabled(false)
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return <input ref={ref} disabled={disabled || inputDisabled} type="file" multiple={multiple} onChange={onInputChange} {...rest} />
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
export type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
119
|
-
input: InputFileProps
|
|
120
|
-
dragFile?: boolean
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/** 专用于读取文件的 button 组件 */
|
|
124
|
-
export const InputFileButton = forwardRef<HTMLButtonElement, InputFileButtonProps>((props, ref) => {
|
|
125
|
-
const { onClick: _onClick, input: inputProps, onDrop: _onDrop, onDragOver: _onDragOver, dragFile, disabled: _disabled, ...rest } = props
|
|
126
|
-
const { style, disabled: __disabled, multiple, onChange, type = "file", ...restInputProps } = inputProps
|
|
127
|
-
const [disabled, setDisabled] = useState(false)
|
|
128
|
-
const input = useRef<HTMLInputElement>(null)
|
|
129
|
-
|
|
130
|
-
function onClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {
|
|
131
|
-
input.current?.click()
|
|
132
|
-
_onClick?.(e)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function onDrop(e: DragEvent<HTMLButtonElement>) {
|
|
136
|
-
_onDrop?.(e)
|
|
137
|
-
if (disabled || !dragFile) return
|
|
138
|
-
e.preventDefault()
|
|
139
|
-
const { files } = e.dataTransfer
|
|
140
|
-
if (!files || files.length === 0) return
|
|
141
|
-
setDisabled(true)
|
|
142
|
-
try {
|
|
143
|
-
if (multiple) {
|
|
144
|
-
const result: any[] = []
|
|
145
|
-
for (const file of Array.from(files)) {
|
|
146
|
-
result.push({
|
|
147
|
-
result: await getFileData(file, type),
|
|
148
|
-
file
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
onChange?.(result as any)
|
|
152
|
-
} else {
|
|
153
|
-
onChange?.({
|
|
154
|
-
result: await getFileData(files[0], type),
|
|
155
|
-
file: files[0]
|
|
156
|
-
} as any)
|
|
157
|
-
}
|
|
158
|
-
} finally {
|
|
159
|
-
setDisabled(false)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function onDragOver(e: DragEvent<HTMLButtonElement>) {
|
|
164
|
-
_onDragOver?.(e)
|
|
165
|
-
if (disabled || !dragFile) return
|
|
166
|
-
e.preventDefault()
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return (
|
|
170
|
-
<Fragment>
|
|
171
|
-
<InputFile
|
|
172
|
-
ref={input}
|
|
173
|
-
disabled={disabled || _disabled || __disabled}
|
|
174
|
-
style={{ display: "none", ...style }}
|
|
175
|
-
multiple={multiple as any}
|
|
176
|
-
onChange={onChange as any}
|
|
177
|
-
type={type as any}
|
|
178
|
-
{...restInputProps}
|
|
179
|
-
/>
|
|
180
|
-
<button ref={ref} type="button" disabled={disabled || _disabled} onClick={onClick} onDrop={onDrop} onDragOver={onDragOver} {...rest} />
|
|
181
|
-
</Fragment>
|
|
182
|
-
)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
export interface ImportExcelProps extends Omit<InputFileProps, "multiple" | "onChange" | "accept" | "type"> {
|
|
186
|
-
onChange?: (data: Record<string, string>[]) => void
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** 专门用于读取 excel 的组件 */
|
|
190
|
-
export const ImportExcel = forwardRef<HTMLInputElement, ImportExcelProps>((props, ref) => {
|
|
191
|
-
const { onChange, ...rest } = props
|
|
192
|
-
|
|
193
|
-
function onInputChange(data: InputFileData<ArrayBuffer>) {
|
|
194
|
-
const wb = read(data.result)
|
|
195
|
-
const result = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]])
|
|
196
|
-
if (typeof result === "object") {
|
|
197
|
-
const $ = result.map(it => {
|
|
198
|
-
const _: Record<string, string> = {}
|
|
199
|
-
Object.keys(it)
|
|
200
|
-
.filter(key => key !== "__rowNum__")
|
|
201
|
-
.forEach(key => (_[key] = String(it[key])))
|
|
202
|
-
return _
|
|
203
|
-
})
|
|
204
|
-
onChange?.($)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return <InputFile ref={ref} accept=".xlsx" type="arrayBuffer" onChange={onInputChange} {...rest} />
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
/** 手动导出 excel */
|
|
212
|
-
export function exportExcel(data: Record<string, string>[], name: string) {
|
|
213
|
-
const workSheet = utils.json_to_sheet(data)
|
|
214
|
-
const workBook = utils.book_new()
|
|
215
|
-
utils.book_append_sheet(workBook, workSheet)
|
|
216
|
-
writeFile(workBook, `${name}${name.endsWith(".xlsx") ? "" : ".xlsx"}`)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export interface ExportExcelProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
220
|
-
data: Record<string, string>[]
|
|
221
|
-
fileName: string
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/** 导出 excel 的 button 组件 */
|
|
225
|
-
export const ExportExcel = forwardRef<HTMLButtonElement, ExportExcelProps>((props, ref) => {
|
|
226
|
-
const { data, fileName, onClick, ...rest } = props
|
|
227
|
-
|
|
228
|
-
function onButtonClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {
|
|
229
|
-
exportExcel(data, fileName)
|
|
230
|
-
onClick?.(e)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return <button ref={ref} onClick={onButtonClick} {...rest} />
|
|
234
|
-
})
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { ButtonHTMLAttributes, ChangeEvent, DragEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState } from "react"
|
|
4
|
+
import { read, utils, writeFile } from "xlsx"
|
|
5
|
+
|
|
6
|
+
export interface InputFileDataTypes {
|
|
7
|
+
base64: string
|
|
8
|
+
text: string
|
|
9
|
+
arrayBuffer: ArrayBuffer
|
|
10
|
+
binary: string
|
|
11
|
+
file: File
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type InputFileDataType = keyof InputFileDataTypes
|
|
15
|
+
|
|
16
|
+
export interface InputFileData<T> {
|
|
17
|
+
result: T
|
|
18
|
+
file: File
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type InputFileProps = (
|
|
22
|
+
| {
|
|
23
|
+
multiple?: false
|
|
24
|
+
type: "base64" | "text" | "binary"
|
|
25
|
+
onChange?: (data: InputFileData<string>) => void
|
|
26
|
+
}
|
|
27
|
+
| {
|
|
28
|
+
multiple?: false
|
|
29
|
+
type: "arrayBuffer"
|
|
30
|
+
onChange?: (data: InputFileData<ArrayBuffer>) => void
|
|
31
|
+
}
|
|
32
|
+
| {
|
|
33
|
+
multiple?: false
|
|
34
|
+
type?: "file"
|
|
35
|
+
onChange?: (data: InputFileData<File>) => void
|
|
36
|
+
}
|
|
37
|
+
| {
|
|
38
|
+
multiple: true
|
|
39
|
+
type: "base64" | "text" | "binary"
|
|
40
|
+
onChange?: (data: InputFileData<string>[]) => void
|
|
41
|
+
}
|
|
42
|
+
| {
|
|
43
|
+
multiple: true
|
|
44
|
+
type: "arrayBuffer"
|
|
45
|
+
onChange?: (data: InputFileData<ArrayBuffer>[]) => void
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
multiple: true
|
|
49
|
+
type?: "file"
|
|
50
|
+
onChange?: (data: InputFileData<File>[]) => void
|
|
51
|
+
}
|
|
52
|
+
) &
|
|
53
|
+
Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "multiple" | "type"> & {
|
|
54
|
+
/** 是否在捕获文件后清除 input 上的文件,默认为 false,主要区别在于如果不清除,连续两次选择同样的文件不会触发 onChange 事件,如果用于 form 表单,请设置为 flase */
|
|
55
|
+
clearAfterChange?: boolean
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function getFileData<T extends InputFileDataType>(file: File, type: T): Promise<InputFileDataTypes[T]> {
|
|
59
|
+
const fileReader = new FileReader()
|
|
60
|
+
switch (type) {
|
|
61
|
+
case "arrayBuffer":
|
|
62
|
+
fileReader.readAsArrayBuffer(file)
|
|
63
|
+
break
|
|
64
|
+
case "binary":
|
|
65
|
+
fileReader.readAsBinaryString(file)
|
|
66
|
+
break
|
|
67
|
+
case "base64":
|
|
68
|
+
fileReader.readAsDataURL(file)
|
|
69
|
+
break
|
|
70
|
+
case "text":
|
|
71
|
+
fileReader.readAsText(file)
|
|
72
|
+
break
|
|
73
|
+
default:
|
|
74
|
+
return file as any
|
|
75
|
+
}
|
|
76
|
+
return new Promise(resolve => {
|
|
77
|
+
fileReader.addEventListener("load", () => {
|
|
78
|
+
resolve(fileReader.result as any)
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** 专用于读取文件的组件 */
|
|
84
|
+
export const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, ref) => {
|
|
85
|
+
const { multiple = false, type = "file", onChange, disabled: inputDisabled, clearAfterChange, ...rest } = props
|
|
86
|
+
const [disabled, setDisabled] = useState(false)
|
|
87
|
+
|
|
88
|
+
async function onInputChange(e: ChangeEvent<HTMLInputElement>) {
|
|
89
|
+
const input = e.target
|
|
90
|
+
const { files } = input
|
|
91
|
+
if (!files || files.length === 0) return
|
|
92
|
+
setDisabled(true)
|
|
93
|
+
try {
|
|
94
|
+
if (multiple) {
|
|
95
|
+
const result: any[] = []
|
|
96
|
+
for (const file of Array.from(files)) {
|
|
97
|
+
result.push({
|
|
98
|
+
result: await getFileData(file, type),
|
|
99
|
+
file,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
onChange?.(result as any)
|
|
103
|
+
} else {
|
|
104
|
+
onChange?.({
|
|
105
|
+
result: await getFileData(files[0], type),
|
|
106
|
+
file: files[0],
|
|
107
|
+
} as any)
|
|
108
|
+
}
|
|
109
|
+
} finally {
|
|
110
|
+
if (clearAfterChange) input.value = ""
|
|
111
|
+
setDisabled(false)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return <input ref={ref} disabled={disabled || inputDisabled} type="file" multiple={multiple} onChange={onInputChange} {...rest} />
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
export type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
119
|
+
input: InputFileProps
|
|
120
|
+
dragFile?: boolean
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** 专用于读取文件的 button 组件 */
|
|
124
|
+
export const InputFileButton = forwardRef<HTMLButtonElement, InputFileButtonProps>((props, ref) => {
|
|
125
|
+
const { onClick: _onClick, input: inputProps, onDrop: _onDrop, onDragOver: _onDragOver, dragFile, disabled: _disabled, ...rest } = props
|
|
126
|
+
const { style, disabled: __disabled, multiple, onChange, type = "file", ...restInputProps } = inputProps
|
|
127
|
+
const [disabled, setDisabled] = useState(false)
|
|
128
|
+
const input = useRef<HTMLInputElement>(null)
|
|
129
|
+
|
|
130
|
+
function onClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {
|
|
131
|
+
input.current?.click()
|
|
132
|
+
_onClick?.(e)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function onDrop(e: DragEvent<HTMLButtonElement>) {
|
|
136
|
+
_onDrop?.(e)
|
|
137
|
+
if (disabled || !dragFile) return
|
|
138
|
+
e.preventDefault()
|
|
139
|
+
const { files } = e.dataTransfer
|
|
140
|
+
if (!files || files.length === 0) return
|
|
141
|
+
setDisabled(true)
|
|
142
|
+
try {
|
|
143
|
+
if (multiple) {
|
|
144
|
+
const result: any[] = []
|
|
145
|
+
for (const file of Array.from(files)) {
|
|
146
|
+
result.push({
|
|
147
|
+
result: await getFileData(file, type),
|
|
148
|
+
file,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
onChange?.(result as any)
|
|
152
|
+
} else {
|
|
153
|
+
onChange?.({
|
|
154
|
+
result: await getFileData(files[0], type),
|
|
155
|
+
file: files[0],
|
|
156
|
+
} as any)
|
|
157
|
+
}
|
|
158
|
+
} finally {
|
|
159
|
+
setDisabled(false)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function onDragOver(e: DragEvent<HTMLButtonElement>) {
|
|
164
|
+
_onDragOver?.(e)
|
|
165
|
+
if (disabled || !dragFile) return
|
|
166
|
+
e.preventDefault()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<Fragment>
|
|
171
|
+
<InputFile
|
|
172
|
+
ref={input}
|
|
173
|
+
disabled={disabled || _disabled || __disabled}
|
|
174
|
+
style={{ display: "none", ...style }}
|
|
175
|
+
multiple={multiple as any}
|
|
176
|
+
onChange={onChange as any}
|
|
177
|
+
type={type as any}
|
|
178
|
+
{...restInputProps}
|
|
179
|
+
/>
|
|
180
|
+
<button ref={ref} type="button" disabled={disabled || _disabled} onClick={onClick} onDrop={onDrop} onDragOver={onDragOver} {...rest} />
|
|
181
|
+
</Fragment>
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
export interface ImportExcelProps extends Omit<InputFileProps, "multiple" | "onChange" | "accept" | "type"> {
|
|
186
|
+
onChange?: (data: Record<string, string>[]) => void
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** 专门用于读取 excel 的组件 */
|
|
190
|
+
export const ImportExcel = forwardRef<HTMLInputElement, ImportExcelProps>((props, ref) => {
|
|
191
|
+
const { onChange, ...rest } = props
|
|
192
|
+
|
|
193
|
+
function onInputChange(data: InputFileData<ArrayBuffer>) {
|
|
194
|
+
const wb = read(data.result)
|
|
195
|
+
const result = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]])
|
|
196
|
+
if (typeof result === "object") {
|
|
197
|
+
const $ = result.map(it => {
|
|
198
|
+
const _: Record<string, string> = {}
|
|
199
|
+
Object.keys(it)
|
|
200
|
+
.filter(key => key !== "__rowNum__")
|
|
201
|
+
.forEach(key => (_[key] = String(it[key])))
|
|
202
|
+
return _
|
|
203
|
+
})
|
|
204
|
+
onChange?.($)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return <InputFile ref={ref} accept=".xlsx" type="arrayBuffer" onChange={onInputChange} {...rest} />
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
/** 手动导出 excel */
|
|
212
|
+
export function exportExcel(data: Record<string, string>[], name: string) {
|
|
213
|
+
const workSheet = utils.json_to_sheet(data)
|
|
214
|
+
const workBook = utils.book_new()
|
|
215
|
+
utils.book_append_sheet(workBook, workSheet)
|
|
216
|
+
writeFile(workBook, `${name}${name.endsWith(".xlsx") ? "" : ".xlsx"}`)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface ExportExcelProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
220
|
+
data: Record<string, string>[]
|
|
221
|
+
fileName: string
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** 导出 excel 的 button 组件 */
|
|
225
|
+
export const ExportExcel = forwardRef<HTMLButtonElement, ExportExcelProps>((props, ref) => {
|
|
226
|
+
const { data, fileName, onClick, ...rest } = props
|
|
227
|
+
|
|
228
|
+
function onButtonClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {
|
|
229
|
+
exportExcel(data, fileName)
|
|
230
|
+
onClick?.(e)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return <button ref={ref} onClick={onButtonClick} {...rest} />
|
|
234
|
+
})
|