@ecoding/components.antd 0.3.58 → 0.3.60
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/lib/core/multiple-img-upload/index.d.ts +29 -0
- package/lib/core/multiple-img-upload/index.js +231 -0
- package/lib/core/multiple-single-img-upload/index.js +15 -6
- package/lib/core/single-img-upload/index.js +4 -5
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { UploadFile } from 'antd';
|
|
3
|
+
interface IOpts {
|
|
4
|
+
size?: number;
|
|
5
|
+
w?: number;
|
|
6
|
+
h?: number;
|
|
7
|
+
}
|
|
8
|
+
interface IProps {
|
|
9
|
+
message?: string;
|
|
10
|
+
showMessage?: boolean;
|
|
11
|
+
actionParams?: any;
|
|
12
|
+
i18n?: any;
|
|
13
|
+
opts?: IOpts;
|
|
14
|
+
value?: UploadFile[] | string[];
|
|
15
|
+
headers?: any;
|
|
16
|
+
data?: any;
|
|
17
|
+
gif?: boolean;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
name?: string;
|
|
20
|
+
action: string | (() => string);
|
|
21
|
+
buttonText?: string;
|
|
22
|
+
maxCount?: number;
|
|
23
|
+
onChange?: (infos: string[]) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* @returns 返回地址的string
|
|
27
|
+
*/
|
|
28
|
+
declare const MultipleImgUpload: React.FC<IProps>;
|
|
29
|
+
export default MultipleImgUpload;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
11
|
+
import { Upload, Image as Img, Alert, Flex, message } from 'antd';
|
|
12
|
+
import { PlusOutlined } from '@ant-design/icons';
|
|
13
|
+
import { buildURL } from "@ecoding/helper.url";
|
|
14
|
+
import Toast from "../../core/toast";
|
|
15
|
+
import Loading from "../../core/loading";
|
|
16
|
+
import { DndContext, PointerSensor, useSensor } from '@dnd-kit/core';
|
|
17
|
+
import { arrayMove, SortableContext, useSortable, horizontalListSortingStrategy, } from '@dnd-kit/sortable';
|
|
18
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
19
|
+
const DraggableUploadListItem = ({ originNode, file }) => {
|
|
20
|
+
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
21
|
+
id: file.uid,
|
|
22
|
+
});
|
|
23
|
+
const style = {
|
|
24
|
+
transform: CSS.Translate.toString(transform),
|
|
25
|
+
transition,
|
|
26
|
+
cursor: 'move',
|
|
27
|
+
height: '102px',
|
|
28
|
+
width: '102px',
|
|
29
|
+
};
|
|
30
|
+
return (React.createElement("div", Object.assign({ ref: setNodeRef, style: style,
|
|
31
|
+
// prevent preview event when drag end
|
|
32
|
+
className: isDragging ? 'is-dragging' : '' }, attributes, listeners), file.status === 'error' && isDragging ? originNode.props.children : originNode));
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @returns 返回地址的string
|
|
36
|
+
*/
|
|
37
|
+
const MultipleImgUpload = (props) => {
|
|
38
|
+
const { name, buttonText, maxCount, disabled, value, onChange } = props;
|
|
39
|
+
const [previewOpen, setPreviewOpen] = useState(false);
|
|
40
|
+
const [previewImage, setPreviewImage] = useState('');
|
|
41
|
+
const [imgList, setImgList] = useState((value === null || value === void 0 ? void 0 : value.map((url, index) => {
|
|
42
|
+
if (typeof url === "string") {
|
|
43
|
+
return {
|
|
44
|
+
uid: String(index),
|
|
45
|
+
status: 'done',
|
|
46
|
+
url,
|
|
47
|
+
name: url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.'))
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return url;
|
|
52
|
+
}
|
|
53
|
+
})) || []);
|
|
54
|
+
const updateItems = (newItems) => {
|
|
55
|
+
setImgList(newItems);
|
|
56
|
+
let isEmpty = true;
|
|
57
|
+
const urls = newItems.map((item) => item.url);
|
|
58
|
+
urls.forEach((item) => {
|
|
59
|
+
if (item) {
|
|
60
|
+
isEmpty = false;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
onChange && (onChange === null || onChange === void 0 ? void 0 : onChange(!isEmpty ? urls : undefined));
|
|
65
|
+
};
|
|
66
|
+
const handleChange = (info) => {
|
|
67
|
+
switch (info.file.status) {
|
|
68
|
+
case 'uploading':
|
|
69
|
+
Loading.show();
|
|
70
|
+
break;
|
|
71
|
+
case 'done': {
|
|
72
|
+
Loading.hide();
|
|
73
|
+
const response = info.file.response;
|
|
74
|
+
if (response && response.code === 200) {
|
|
75
|
+
const data = response.data || {};
|
|
76
|
+
const temp = imgList.concat([Object.assign({}, data)]);
|
|
77
|
+
updateItems(temp);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
Toast.error({
|
|
81
|
+
mask: true,
|
|
82
|
+
title: response.message || '服务出错,图片上传失败'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case 'error': {
|
|
88
|
+
const response = info.file.response;
|
|
89
|
+
Toast.error({
|
|
90
|
+
mask: true,
|
|
91
|
+
title: response.message || '服务出错,图片上传失败'
|
|
92
|
+
});
|
|
93
|
+
Loading.hide();
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
default:
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const handleRemove = (file) => {
|
|
101
|
+
const lefts = imgList.filter(item => item.uid !== file.uid);
|
|
102
|
+
updateItems(lefts);
|
|
103
|
+
};
|
|
104
|
+
const action = useMemo(() => {
|
|
105
|
+
if (typeof props.action === "string") {
|
|
106
|
+
return buildURL(props.action, props.actionParams);
|
|
107
|
+
}
|
|
108
|
+
return buildURL(props.action(), props.actionParams);
|
|
109
|
+
}, [props.actionParams, props.action]);
|
|
110
|
+
const getBase64 = (file) => new Promise((resolve, reject) => {
|
|
111
|
+
const reader = new FileReader();
|
|
112
|
+
reader.readAsDataURL(file);
|
|
113
|
+
reader.onload = () => resolve(reader.result);
|
|
114
|
+
reader.onerror = (error) => reject(error);
|
|
115
|
+
});
|
|
116
|
+
const handlePreview = (file) => __awaiter(void 0, void 0, void 0, function* () {
|
|
117
|
+
if (!file.url && !file.preview) {
|
|
118
|
+
file.preview = yield getBase64(file.originFileObj);
|
|
119
|
+
}
|
|
120
|
+
setPreviewImage(file.url || file.preview);
|
|
121
|
+
setPreviewOpen(true);
|
|
122
|
+
});
|
|
123
|
+
const uploadButton = (React.createElement("button", { style: { border: 0, background: 'none' }, type: "button" },
|
|
124
|
+
React.createElement(PlusOutlined, null),
|
|
125
|
+
React.createElement("div", { style: { marginTop: 8 } }, buttonText ? buttonText : '上传')));
|
|
126
|
+
const sensor = useSensor(PointerSensor, {
|
|
127
|
+
activationConstraint: { distance: 10 },
|
|
128
|
+
});
|
|
129
|
+
const onDragEnd = ({ active, over }) => {
|
|
130
|
+
if (!imgList || imgList.length == 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (active.id !== (over === null || over === void 0 ? void 0 : over.id)) {
|
|
134
|
+
const temp = [...imgList];
|
|
135
|
+
const activeIndex = temp.findIndex((i) => i.uid === active.id);
|
|
136
|
+
const overIndex = temp.findIndex((i) => i.uid === (over === null || over === void 0 ? void 0 : over.id));
|
|
137
|
+
// 使用arrayMove计算新的排序结果
|
|
138
|
+
const newItems = arrayMove(temp, activeIndex, overIndex);
|
|
139
|
+
updateItems(newItems);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const getImgwh = useCallback((base64) => {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const img = new Image();
|
|
145
|
+
img.onload = () => {
|
|
146
|
+
// 宽度固定
|
|
147
|
+
resolve({
|
|
148
|
+
w: img.width,
|
|
149
|
+
h: img.height
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
img.onerror = () => reject();
|
|
153
|
+
img.src = base64;
|
|
154
|
+
});
|
|
155
|
+
}, []);
|
|
156
|
+
const beforeUpload = useCallback((file) => {
|
|
157
|
+
return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
|
|
158
|
+
const ary = ["jpg", "jpeg", "png"];
|
|
159
|
+
if (props.gif) {
|
|
160
|
+
ary.push("gif");
|
|
161
|
+
}
|
|
162
|
+
if (ary.indexOf(file.type.toLowerCase().replace(/image\//g, "")) === -1) {
|
|
163
|
+
message.error(`请上传 ${ary.join(",")} 格式的图片!`);
|
|
164
|
+
reject();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const isLt2M = file.size / 1024 / 1024 < (props.opts.size || 1);
|
|
168
|
+
if (!isLt2M) {
|
|
169
|
+
message.error(`图片大小必须小于${props.opts.size} MB!`);
|
|
170
|
+
reject();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const base64 = yield getBase64(file);
|
|
174
|
+
const wh = yield getImgwh(base64);
|
|
175
|
+
if (props.opts.w && props.opts.w !== wh.w) {
|
|
176
|
+
message.error(`图片宽度不符合 ${props.opts.w}px 约定!`);
|
|
177
|
+
reject();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (props.opts.h && props.opts.h !== wh.h) {
|
|
181
|
+
message.error(`图片高度不符合 ${props.opts.h}px 约定!`);
|
|
182
|
+
reject();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
resolve();
|
|
186
|
+
}));
|
|
187
|
+
}, []);
|
|
188
|
+
return (React.createElement(React.Fragment, null,
|
|
189
|
+
props.showMessage && (React.createElement(Alert, { className: 'mb20', message: props.message ? props.message : (React.createElement(Flex, { gap: 10 },
|
|
190
|
+
React.createElement("div", null,
|
|
191
|
+
props.i18n ? props.i18n.$t("global.size", "大小") : "大小",
|
|
192
|
+
"\uFF1A",
|
|
193
|
+
props.i18n ? props.i18n.$t("global.lt", "小于") : "小于",
|
|
194
|
+
" ",
|
|
195
|
+
props.opts.size || 1,
|
|
196
|
+
"MB;"),
|
|
197
|
+
React.createElement("div", null,
|
|
198
|
+
props.i18n ? props.i18n.$t("global.dimension", "尺寸") : "尺寸",
|
|
199
|
+
"\uFF1A",
|
|
200
|
+
props.opts.w ? `${props.opts.w}px` : "n",
|
|
201
|
+
" * ",
|
|
202
|
+
props.opts.h ? `${props.opts.h}px` : "n",
|
|
203
|
+
";"),
|
|
204
|
+
React.createElement("div", null,
|
|
205
|
+
props.i18n ? props.i18n.$t("global.support", "支持") : "支持",
|
|
206
|
+
"\uFF1Ajpg\u3001jpeg\u3001png",
|
|
207
|
+
props.gif ? "、gif" : "",
|
|
208
|
+
";"))), type: "warning", showIcon: true })),
|
|
209
|
+
React.createElement(DndContext, { sensors: [sensor], onDragEnd: onDragEnd },
|
|
210
|
+
React.createElement(SortableContext, { items: imgList === null || imgList === void 0 ? void 0 : imgList.map((i) => i.uid), strategy: horizontalListSortingStrategy },
|
|
211
|
+
React.createElement(Upload, { listType: "picture-card", fileList: imgList, action: action, beforeUpload: beforeUpload, onPreview: handlePreview, onChange: handleChange, onRemove: handleRemove, name: name, data: props.data, multiple: true, disabled: disabled, withCredentials: true, itemRender: (originNode, file) => (React.createElement(DraggableUploadListItem, { originNode: originNode, file: file })) }, maxCount && imgList.length >= maxCount ? null : uploadButton),
|
|
212
|
+
previewImage && (React.createElement(Img, { wrapperStyle: { display: 'none' }, preview: {
|
|
213
|
+
visible: previewOpen,
|
|
214
|
+
onVisibleChange: (visible) => setPreviewOpen(visible),
|
|
215
|
+
afterOpenChange: (visible) => !visible && setPreviewImage('')
|
|
216
|
+
}, src: previewImage }))))));
|
|
217
|
+
};
|
|
218
|
+
MultipleImgUpload.defaultProps = {
|
|
219
|
+
maxCount: 6,
|
|
220
|
+
showMessage: true,
|
|
221
|
+
action: "/api/upload/img",
|
|
222
|
+
name: "file",
|
|
223
|
+
gif: false,
|
|
224
|
+
buttonText: '上传图片',
|
|
225
|
+
data: {},
|
|
226
|
+
actionParams: {},
|
|
227
|
+
opts: {
|
|
228
|
+
size: 1
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
export default MultipleImgUpload;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Flex, Alert } from 'antd';
|
|
3
3
|
import { DragOutlined } from '@ant-design/icons';
|
|
4
4
|
import { DndContext, closestCenter, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
|
|
5
5
|
import { arrayMove, SortableContext, horizontalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
|
|
@@ -14,7 +14,8 @@ const SortableItem = (props) => {
|
|
|
14
14
|
transform: CSS.Transform.toString(transform),
|
|
15
15
|
transition,
|
|
16
16
|
position: 'relative',
|
|
17
|
-
margin: '0 8px'
|
|
17
|
+
margin: '0 8px',
|
|
18
|
+
fontSize: 0
|
|
18
19
|
};
|
|
19
20
|
const handleChange = (url) => {
|
|
20
21
|
const newItems = [...items];
|
|
@@ -36,7 +37,15 @@ const SortableItem = (props) => {
|
|
|
36
37
|
alignItems: 'center',
|
|
37
38
|
justifyContent: 'center'
|
|
38
39
|
} }),
|
|
39
|
-
React.createElement(DragOutlined,
|
|
40
|
+
React.createElement(DragOutlined, { style: { fontSize: 14 } })),
|
|
41
|
+
index == 0 ? (React.createElement("div", { style: {
|
|
42
|
+
position: 'absolute',
|
|
43
|
+
bottom: 0,
|
|
44
|
+
left: 0,
|
|
45
|
+
padding: '0 2px',
|
|
46
|
+
fontSize: '12px',
|
|
47
|
+
background: 'rgba(0,0,0,0.1)',
|
|
48
|
+
} }, "\u4E3B\u56FE")) : null,
|
|
40
49
|
React.createElement(ImgUpload, Object.assign({}, props, { value: props.value, onChange: handleChange }))));
|
|
41
50
|
};
|
|
42
51
|
const MultiPileImgUpload = (props) => {
|
|
@@ -82,8 +91,8 @@ const MultiPileImgUpload = (props) => {
|
|
|
82
91
|
setItems(initItems);
|
|
83
92
|
}
|
|
84
93
|
}, [props.value]);
|
|
85
|
-
return (React.createElement(
|
|
86
|
-
props.showMessage && (React.createElement(Alert, { className: 'mb20', message: props.message ? props.message : (React.createElement(
|
|
94
|
+
return (React.createElement(React.Fragment, null,
|
|
95
|
+
props.showMessage && (React.createElement(Alert, { className: 'mb20', message: props.message ? props.message : (React.createElement(Flex, { gap: 10 },
|
|
87
96
|
React.createElement("div", null,
|
|
88
97
|
props.i18n ? props.i18n.$t("global.size", "大小") : "大小",
|
|
89
98
|
"\uFF1A",
|
|
@@ -105,7 +114,7 @@ const MultiPileImgUpload = (props) => {
|
|
|
105
114
|
";"))), type: "warning", showIcon: true })),
|
|
106
115
|
React.createElement(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd },
|
|
107
116
|
React.createElement(SortableContext, { items: items, strategy: horizontalListSortingStrategy },
|
|
108
|
-
React.createElement(
|
|
117
|
+
React.createElement(Flex, { wrap: true, align: "start" }, items.map((item, index) => (React.createElement(SortableItem, Object.assign({}, props, { index: index, items: items, updateItems: updateItems, value: item.url, key: item.id, id: item.id })))))))));
|
|
109
118
|
};
|
|
110
119
|
MultiPileImgUpload.defaultProps = {
|
|
111
120
|
showMessage: true,
|
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
11
|
-
import { Upload, message,
|
|
11
|
+
import { Upload, message, Flex, Image as Img } from "antd";
|
|
12
12
|
import { LoadingOutlined, PlusOutlined, DeleteOutlined } from "@ant-design/icons";
|
|
13
13
|
import { buildURL } from "@ecoding/helper.url";
|
|
14
14
|
import Toast from "../../core/toast";
|
|
@@ -123,7 +123,7 @@ const ImgUpload = (props) => {
|
|
|
123
123
|
setImageUrl(props.value);
|
|
124
124
|
}
|
|
125
125
|
}, [props.value]);
|
|
126
|
-
return (React.createElement(
|
|
126
|
+
return (React.createElement(Flex, { style: { fontSize: 0 } },
|
|
127
127
|
imageUrl ? (React.createElement("div", { style: { position: "relative" } },
|
|
128
128
|
React.createElement("span", { style: {
|
|
129
129
|
position: "absolute",
|
|
@@ -133,14 +133,13 @@ const ImgUpload = (props) => {
|
|
|
133
133
|
height: "18px",
|
|
134
134
|
opacity: ".9",
|
|
135
135
|
cursor: "pointer",
|
|
136
|
-
zIndex: 10
|
|
137
136
|
}, onClick: (e) => {
|
|
138
137
|
e.stopPropagation();
|
|
139
138
|
clear();
|
|
140
139
|
} },
|
|
141
|
-
React.createElement(DeleteOutlined,
|
|
140
|
+
React.createElement(DeleteOutlined, { style: { fontSize: 14 } })),
|
|
142
141
|
React.createElement(Img, { style: { width: "102px", height: "102px", objectFit: "contain", cursor: "pointer" }, src: imageUrl }))) : (React.createElement(Upload, { withCredentials: true, beforeUpload: beforeUpload, name: props.name, data: props.data, headers: props.headers, disabled: props.disabled, listType: "picture-card", showUploadList: false, action: action, onChange: handleChange }, uploadButton)),
|
|
143
|
-
props.isTip ? (React.createElement("div",
|
|
142
|
+
props.isTip ? (React.createElement("div", { style: { fontSize: '13px', marginLeft: '18px', lineHeight: '30px' } },
|
|
144
143
|
React.createElement("p", null,
|
|
145
144
|
props.i18n ? props.i18n.$t("global.size", "大小") : "大小",
|
|
146
145
|
"\uFF1A",
|
package/lib/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { default as RangePicker } from "./core/range-picker";
|
|
|
12
12
|
export { default as DatePicker } from "./core/date.picker";
|
|
13
13
|
export { default as SingleImgUpload } from "./core/single-img-upload";
|
|
14
14
|
export { default as MultipleSingleImgUpload } from "./core/multiple-single-img-upload";
|
|
15
|
+
export { default as MultipleImgUpload } from "./core/multiple-img-upload";
|
|
15
16
|
export { default as SingleFileUpload } from "./core/single-file-upload";
|
|
16
17
|
export { default as MultipleUpload } from "./core/multiple-upload";
|
|
17
18
|
export { default as FormLabel } from "./core/form.label";
|
package/lib/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export { default as RangePicker } from "./core/range-picker";
|
|
|
12
12
|
export { default as DatePicker } from "./core/date.picker";
|
|
13
13
|
export { default as SingleImgUpload } from "./core/single-img-upload";
|
|
14
14
|
export { default as MultipleSingleImgUpload } from "./core/multiple-single-img-upload";
|
|
15
|
+
export { default as MultipleImgUpload } from "./core/multiple-img-upload";
|
|
15
16
|
export { default as SingleFileUpload } from "./core/single-file-upload";
|
|
16
17
|
export { default as MultipleUpload } from "./core/multiple-upload";
|
|
17
18
|
export { default as FormLabel } from "./core/form.label";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecoding/components.antd",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.60",
|
|
4
4
|
"author": "cxc",
|
|
5
5
|
"homepage": "",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"antd": "5.27.0",
|
|
48
48
|
"axios": "^1.1.2"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "ba3818c41417032a2fb1c71f400cf283940dd54f"
|
|
51
51
|
}
|