index.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import { __awaiter, __rest } from "tslib";
  2. import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
  3. import { Button, Modal, Upload, message } from "antd";
  4. import { CloudUploadOutlined, PlusOutlined, UploadOutlined, } from "@ant-design/icons";
  5. import { updateFileList } from "antd/es/upload/utils";
  6. import { useContext, useEffect, useMemo, useRef, useState } from "react";
  7. import { requestByPost, getBaseURL } from "@dage/service";
  8. import { DageUploadType, } from "./types";
  9. import { AntdDragger, AntdDraggerText, AntdUpload, UploadContainer, UploadTips, } from "./style";
  10. import { DageUploadContext } from "./context";
  11. import { DageUploadItemActions } from "./ItemActions";
  12. import { ACCEPT, getImageSize, validateFileType } from "./utils";
  13. const getBase64 = (file) => new Promise((resolve, reject) => {
  14. const reader = new FileReader();
  15. reader.readAsDataURL(file);
  16. reader.onload = () => resolve(reader.result);
  17. reader.onerror = (error) => reject(error);
  18. });
  19. export const DageUpload = (_a) => {
  20. var { action, value, dType = DageUploadType.IMG, maxCount = 9, maxSize = 5, tips, disabled, name = "file", downloadErrorMessage = "下载失败", children, className, onChange } = _a, rest = __rest(_a, ["action", "value", "dType", "maxCount", "maxSize", "tips", "disabled", "name", "downloadErrorMessage", "children", "className", "onChange"]);
  21. const [messageApi] = message.useMessage();
  22. const context = useContext(DageUploadContext);
  23. // 内部维护 mergeFileList
  24. // 修复 reat18 受控模式下批量更新导致状态异常
  25. const _mergedFileList = useRef([]);
  26. const [previewOpen, setPreviewOpen] = useState(false);
  27. const [previewImage, setPreviewImage] = useState("");
  28. const [previewTitle, setPreviewTitle] = useState("");
  29. const uploadListType = useMemo(() => {
  30. switch (dType) {
  31. case DageUploadType.IMG:
  32. return "picture-card";
  33. default:
  34. return "text";
  35. }
  36. }, [dType]);
  37. const isPictureCard = uploadListType === "picture-card";
  38. // 可选文件类型
  39. const accept = useMemo(() => ACCEPT[dType] || "*", [dType]);
  40. useEffect(() => {
  41. if (!value)
  42. return;
  43. _mergedFileList.current = value;
  44. }, [value]);
  45. const beforeUpload = (file) => {
  46. if (!validateFileType(file, accept)) {
  47. messageApi.error("选择的文件类型不正确!");
  48. return Upload.LIST_IGNORE;
  49. }
  50. // 校验文件大小
  51. const isLtM = file.size / 1024 / 1024 < maxSize;
  52. if (!isLtM) {
  53. messageApi.error(`最大支持 ${maxSize}M!`);
  54. return Upload.LIST_IGNORE;
  55. }
  56. context === null || context === void 0 ? void 0 : context.handleUploadingFileNum("add");
  57. return true;
  58. };
  59. const onUpload = (option) => {
  60. const formData = new FormData();
  61. const headers = option.headers || {};
  62. formData.append("type", dType);
  63. if (option.file instanceof Blob) {
  64. formData.append(name, option.file, option.file.name);
  65. }
  66. else {
  67. formData.append(name, option.file);
  68. }
  69. option.data &&
  70. Object.keys(option.data).forEach((key) => {
  71. var _a;
  72. const value = (_a = option.data) === null || _a === void 0 ? void 0 : _a[key];
  73. if (Array.isArray(value)) {
  74. value.forEach((item) => {
  75. formData.append(`${key}[]`, item);
  76. });
  77. return;
  78. }
  79. formData.append(key, value);
  80. });
  81. requestByPost(action, formData, {
  82. headers,
  83. })
  84. .then((data) => {
  85. var _a;
  86. (_a = option.onSuccess) === null || _a === void 0 ? void 0 : _a.call(option, data);
  87. })
  88. .catch((err) => {
  89. var _a;
  90. context === null || context === void 0 ? void 0 : context.handleUploadingFileNum("uploaded");
  91. (_a = option.onError) === null || _a === void 0 ? void 0 : _a.call(option, err);
  92. });
  93. };
  94. const handleChange = ({ fileList: newFileList, file, }) => __awaiter(void 0, void 0, void 0, function* () {
  95. if (file.status === "done") {
  96. if (typeof file.response !== "object" || !file.response.fileName) {
  97. // 上传失败
  98. file.status = "error";
  99. }
  100. else if (isPictureCard && file.originFileObj) {
  101. // 如果是图片获取图片宽高
  102. try {
  103. // @ts-ignore
  104. file.imgAttrs = yield getImageSize(file.originFileObj);
  105. // todo: 缩略图并发上传有时候会丢失
  106. file.thumbUrl = getBaseURL() + file.response.filePath;
  107. }
  108. catch (err) {
  109. // 图片加载失败
  110. file.status = "error";
  111. }
  112. }
  113. context === null || context === void 0 ? void 0 : context.handleUploadingFileNum("uploaded");
  114. }
  115. if (_mergedFileList.current.length > newFileList.length) {
  116. _mergedFileList.current = newFileList;
  117. }
  118. else {
  119. _mergedFileList.current = updateFileList(file, _mergedFileList.current);
  120. }
  121. onChange === null || onChange === void 0 ? void 0 : onChange(_mergedFileList.current.map((i) => (Object.assign(Object.assign({}, i), { dType }))), Object.assign(Object.assign({}, file), { dType }));
  122. });
  123. const handleCancel = () => setPreviewOpen(false);
  124. const handlePreview = (file) => __awaiter(void 0, void 0, void 0, function* () {
  125. if (!isPictureCard)
  126. return;
  127. if (!file.url && !file.preview) {
  128. file.preview = yield getBase64(file.originFileObj);
  129. }
  130. setPreviewImage(file.url || file.preview);
  131. setPreviewOpen(true);
  132. setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf("/") + 1));
  133. });
  134. const props = Object.assign({ fileList: value, withCredentials: true, customRequest: onUpload, listType: uploadListType, maxCount,
  135. accept,
  136. disabled, itemRender: (node, file, fileList, actions) => (_jsx(DageUploadItemActions, { isPictureCard: isPictureCard, disabled: disabled, file: file, actions: actions, downloadErrorMessage: downloadErrorMessage, children: node })), showUploadList: {
  137. showPreviewIcon: false,
  138. showDownloadIcon: false,
  139. showRemoveIcon: false,
  140. }, multiple: maxCount > 1, onPreview: handlePreview, beforeUpload: beforeUpload, onChange: handleChange }, rest);
  141. return (_jsxs(UploadContainer, { className: className, children: [[DageUploadType.MODEL, DageUploadType.MOBILE_MODEL].includes(dType) ? (_jsx(AntdDragger, Object.assign({ style: { padding: "0 24px", width: "320px" } }, props, { children: children || (_jsxs(_Fragment, { children: [_jsx(CloudUploadOutlined, { style: { fontSize: "40px", color: "#1677ff" } }), _jsxs(AntdDraggerText, { children: ["\u5C06\u6587\u4EF6\u62D6\u5230\u6B64\u5904\uFF0C\u6216", _jsx("span", { children: "\u70B9\u51FB\u4E0A\u4F20" })] }), _jsx(UploadTips, { className: "dage-upload__tips", children: tips })] })) }))) : (_jsxs(_Fragment, { children: [_jsx(AntdUpload, Object.assign({}, props, { children: children ||
  142. (isPictureCard ? (!disabled &&
  143. (!value || value.length < maxCount) && _jsx(PlusOutlined, {})) : (_jsx(Button, { disabled: disabled, icon: _jsx(UploadOutlined, {}), children: "\u4E0A\u4F20" }))) })), !!tips && (_jsx(UploadTips, { style: { marginTop: isPictureCard ? 0 : "8px" }, className: "dage-upload__tips", children: tips }))] })), _jsx(Modal, { open: previewOpen, title: previewTitle, footer: null, onCancel: handleCancel, children: _jsx("img", { alt: "example", style: { width: "100%" }, src: previewImage }) })] }));
  144. };
  145. export * from "./types";
  146. export * from "./context";