Pārlūkot izejas kodu

fix[pc-components]: DageUpload组件通配符格式校验不通过

chenlei 9 mēneši atpakaļ
vecāks
revīzija
649779f05a

+ 7 - 0
packages/backend-cli/template/CHANGELOG.md

@@ -1,5 +1,12 @@
 # @dage/backend-template
 
+## 1.0.14
+
+### Patch Changes
+
+- Updated dependencies
+  - @dage/pc-components@1.3.3
+
 ## 1.0.13
 
 ### Patch Changes

+ 6 - 0
packages/pc-components/CHANGELOG.md

@@ -1,5 +1,11 @@
 # @dage/pc-components
 
+## 1.3.3
+
+### Patch Changes
+
+- fix: upload 格式校验通配符不通过
+
 ## 1.3.2
 
 ### Patch Changes

+ 1 - 1
packages/pc-components/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@dage/pc-components",
-  "version": "1.3.2",
+  "version": "1.3.3",
   "description": "PC 端组件库",
   "module": "dist/index.js",
   "main": "dist/index.js",

+ 268 - 267
packages/pc-components/src/components/DageUpload/index.tsx

@@ -1,267 +1,268 @@
-import { Button, Modal, Upload, message } from "antd";
-import type { UploadRequestOption as RcCustomRequestOptions } from "rc-upload/lib/interface";
-import {
-  CloudUploadOutlined,
-  PlusOutlined,
-  UploadOutlined,
-} from "@ant-design/icons";
-import { updateFileList } from "antd/es/upload/utils";
-import { FC, useContext, useEffect, useMemo, useRef, useState } from "react";
-import { requestByPost, getBaseURL } from "@dage/service";
-import { RcFile, UploadFile, UploadProps } from "antd/es/upload";
-import {
-  DageFileAPIResponseType,
-  DageUploadProps,
-  DageUploadType,
-} from "./types";
-import {
-  AntdDragger,
-  AntdDraggerText,
-  AntdUpload,
-  UploadContainer,
-  UploadTips,
-} from "./style";
-import { DageUploadContext } from "./context";
-import { DageUploadItemActions } from "./ItemActions";
-import { ACCEPT, getImageSize, validateFileType } from "./utils";
-
-const getBase64 = (file: RcFile): Promise<string> =>
-  new Promise((resolve, reject) => {
-    const reader = new FileReader();
-    reader.readAsDataURL(file);
-    reader.onload = () => resolve(reader.result as string);
-    reader.onerror = (error) => reject(error);
-  });
-
-export const DageUpload: FC<DageUploadProps> = ({
-  action,
-  value,
-  dType = DageUploadType.IMG,
-  maxCount = 9,
-  maxSize = 5,
-  tips,
-  disabled,
-  name = "file",
-  downloadErrorMessage = "下载失败",
-  onChange,
-  ...rest
-}) => {
-  const context = useContext(DageUploadContext);
-  // 内部维护 mergeFileList
-  // 修复 reat18 受控模式下批量更新导致状态异常
-  const _mergedFileList = useRef<
-    (UploadFile<any> | Readonly<UploadFile<any>>)[]
-  >([]);
-  const [previewOpen, setPreviewOpen] = useState(false);
-  const [previewImage, setPreviewImage] = useState("");
-  const [previewTitle, setPreviewTitle] = useState("");
-  const uploadListType = useMemo(() => {
-    switch (dType) {
-      case DageUploadType.IMG:
-        return "picture-card";
-      default:
-        return "text";
-    }
-  }, [dType]);
-  const isPictureCard = uploadListType === "picture-card";
-
-  // 可选文件类型
-  const accept = useMemo(() => ACCEPT[dType] || "*", [dType]);
-
-  useEffect(() => {
-    if (!value) return;
-    _mergedFileList.current = value;
-  }, [value]);
-
-  const beforeUpload = (file: RcFile) => {
-    if (!validateFileType(file, accept)) {
-      message.error(tips || "选择的文件类型不正确!");
-      return Upload.LIST_IGNORE;
-    }
-
-    // 校验文件大小
-    const isLtM = file.size / 1024 / 1024 < maxSize;
-    if (!isLtM) {
-      message.error(`最大支持 ${maxSize}M!`);
-      return Upload.LIST_IGNORE;
-    }
-
-    context?.handleUploadingFileNum("add");
-    return true;
-  };
-
-  const onUpload = (option: RcCustomRequestOptions) => {
-    const formData = new FormData();
-    const headers = option.headers || {};
-
-    formData.append("type", dType);
-
-    if (option.file instanceof Blob) {
-      formData.append(name, option.file, (option.file as any).name);
-    } else {
-      formData.append(name, option.file);
-    }
-
-    option.data &&
-      Object.keys(option.data).forEach((key) => {
-        const value = option.data?.[key];
-        if (Array.isArray(value)) {
-          value.forEach((item) => {
-            formData.append(`${key}[]`, item);
-          });
-          return;
-        }
-
-        formData.append(key, value as string | Blob);
-      });
-
-    requestByPost<DageFileAPIResponseType>(action, formData, {
-      headers,
-    })
-      .then((data) => {
-        option.onSuccess?.(data);
-      })
-      .catch((err) => {
-        context?.handleUploadingFileNum("uploaded");
-        option.onError?.(err);
-      });
-  };
-
-  const handleChange: UploadProps["onChange"] = async ({
-    fileList: newFileList,
-    file,
-  }) => {
-    if (file.status === "done") {
-      if (typeof file.response !== "object" || !file.response.fileName) {
-        // 上传失败
-        file.status = "error";
-      } else if (isPictureCard && file.originFileObj) {
-        // 如果是图片获取图片宽高
-        try {
-          // @ts-ignore
-          file.imgAttrs = await getImageSize(file.originFileObj);
-          // todo: 缩略图并发上传有时候会丢失
-          file.thumbUrl = getBaseURL() + file.response.filePath;
-        } catch (err) {
-          // 图片加载失败
-          file.status = "error";
-        }
-      }
-
-      context?.handleUploadingFileNum("uploaded");
-    }
-
-    if (_mergedFileList.current.length > newFileList.length) {
-      _mergedFileList.current = newFileList;
-    } else {
-      _mergedFileList.current = updateFileList(file, _mergedFileList.current);
-    }
-
-    onChange?.(
-      _mergedFileList.current.map((i) => ({
-        ...i,
-        dType,
-      })),
-      {
-        ...file,
-        dType,
-      }
-    );
-  };
-
-  const handleCancel = () => setPreviewOpen(false);
-
-  const handlePreview = async (file: UploadFile) => {
-    if (!isPictureCard) return;
-
-    if (!file.url && !file.preview) {
-      file.preview = await getBase64(file.originFileObj as RcFile);
-    }
-
-    setPreviewImage(file.url || (file.preview as string));
-    setPreviewOpen(true);
-    setPreviewTitle(
-      file.name || file.url!.substring(file.url!.lastIndexOf("/") + 1)
-    );
-  };
-
-  const props: UploadProps = {
-    fileList: value,
-    withCredentials: true,
-    customRequest: onUpload,
-    listType: uploadListType,
-    maxCount,
-    accept,
-    disabled,
-    itemRender: (node, file, fileList, actions) => (
-      <DageUploadItemActions
-        isPictureCard={isPictureCard}
-        disabled={disabled}
-        file={file}
-        actions={actions}
-        downloadErrorMessage={downloadErrorMessage}
-      >
-        {node}
-      </DageUploadItemActions>
-    ),
-    showUploadList: {
-      showPreviewIcon: false,
-      showDownloadIcon: false,
-      showRemoveIcon: false,
-    },
-    multiple: maxCount > 1,
-    onPreview: handlePreview,
-    beforeUpload: beforeUpload,
-    onChange: handleChange,
-    ...rest,
-  };
-
-  return (
-    <UploadContainer>
-      {[DageUploadType.MODEL, DageUploadType.MOBILE_MODEL].includes(dType) ? (
-        <AntdDragger style={{ padding: "0 24px", width: "320px" }} {...props}>
-          <CloudUploadOutlined style={{ fontSize: "40px", color: "#1677ff" }} />
-
-          <AntdDraggerText>
-            将文件拖到此处,或<span>点击上传</span>
-          </AntdDraggerText>
-          <UploadTips className="dage-upload__tips">{tips}</UploadTips>
-        </AntdDragger>
-      ) : (
-        <>
-          <AntdUpload {...props}>
-            {isPictureCard ? (
-              !disabled &&
-              (!value || value.length < maxCount) && <PlusOutlined />
-            ) : (
-              <Button disabled={disabled} icon={<UploadOutlined />}>
-                上传
-              </Button>
-            )}
-          </AntdUpload>
-
-          {!!tips && (
-            <UploadTips
-              style={{ marginTop: isPictureCard ? 0 : "8px" }}
-              className="dage-upload__tips"
-            >
-              {tips}
-            </UploadTips>
-          )}
-        </>
-      )}
-
-      <Modal
-        open={previewOpen}
-        title={previewTitle}
-        footer={null}
-        onCancel={handleCancel}
-      >
-        <img alt="example" style={{ width: "100%" }} src={previewImage} />
-      </Modal>
-    </UploadContainer>
-  );
-};
-
-export * from "./types";
-export * from "./context";
+import { Button, Modal, Upload, message } from "antd";
+import type { UploadRequestOption as RcCustomRequestOptions } from "rc-upload/lib/interface";
+import {
+  CloudUploadOutlined,
+  PlusOutlined,
+  UploadOutlined,
+} from "@ant-design/icons";
+import { updateFileList } from "antd/es/upload/utils";
+import { FC, useContext, useEffect, useMemo, useRef, useState } from "react";
+import { requestByPost, getBaseURL } from "@dage/service";
+import { RcFile, UploadFile, UploadProps } from "antd/es/upload";
+import {
+  DageFileAPIResponseType,
+  DageUploadProps,
+  DageUploadType,
+} from "./types";
+import {
+  AntdDragger,
+  AntdDraggerText,
+  AntdUpload,
+  UploadContainer,
+  UploadTips,
+} from "./style";
+import { DageUploadContext } from "./context";
+import { DageUploadItemActions } from "./ItemActions";
+import { ACCEPT, getImageSize, validateFileType } from "./utils";
+
+const getBase64 = (file: RcFile): Promise<string> =>
+  new Promise((resolve, reject) => {
+    const reader = new FileReader();
+    reader.readAsDataURL(file);
+    reader.onload = () => resolve(reader.result as string);
+    reader.onerror = (error) => reject(error);
+  });
+
+export const DageUpload: FC<DageUploadProps> = ({
+  action,
+  value,
+  dType = DageUploadType.IMG,
+  maxCount = 9,
+  maxSize = 5,
+  tips,
+  disabled,
+  name = "file",
+  downloadErrorMessage = "下载失败",
+  onChange,
+  ...rest
+}) => {
+  const [messageApi] = message.useMessage();
+  const context = useContext(DageUploadContext);
+  // 内部维护 mergeFileList
+  // 修复 reat18 受控模式下批量更新导致状态异常
+  const _mergedFileList = useRef<
+    (UploadFile<any> | Readonly<UploadFile<any>>)[]
+  >([]);
+  const [previewOpen, setPreviewOpen] = useState(false);
+  const [previewImage, setPreviewImage] = useState("");
+  const [previewTitle, setPreviewTitle] = useState("");
+  const uploadListType = useMemo(() => {
+    switch (dType) {
+      case DageUploadType.IMG:
+        return "picture-card";
+      default:
+        return "text";
+    }
+  }, [dType]);
+  const isPictureCard = uploadListType === "picture-card";
+
+  // 可选文件类型
+  const accept = useMemo(() => ACCEPT[dType] || "*", [dType]);
+
+  useEffect(() => {
+    if (!value) return;
+    _mergedFileList.current = value;
+  }, [value]);
+
+  const beforeUpload = (file: RcFile) => {
+    if (!validateFileType(file, accept)) {
+      messageApi.error("选择的文件类型不正确!");
+      return Upload.LIST_IGNORE;
+    }
+
+    // 校验文件大小
+    const isLtM = file.size / 1024 / 1024 < maxSize;
+    if (!isLtM) {
+      messageApi.error(`最大支持 ${maxSize}M!`);
+      return Upload.LIST_IGNORE;
+    }
+
+    context?.handleUploadingFileNum("add");
+    return true;
+  };
+
+  const onUpload = (option: RcCustomRequestOptions) => {
+    const formData = new FormData();
+    const headers = option.headers || {};
+
+    formData.append("type", dType);
+
+    if (option.file instanceof Blob) {
+      formData.append(name, option.file, (option.file as any).name);
+    } else {
+      formData.append(name, option.file);
+    }
+
+    option.data &&
+      Object.keys(option.data).forEach((key) => {
+        const value = option.data?.[key];
+        if (Array.isArray(value)) {
+          value.forEach((item) => {
+            formData.append(`${key}[]`, item);
+          });
+          return;
+        }
+
+        formData.append(key, value as string | Blob);
+      });
+
+    requestByPost<DageFileAPIResponseType>(action, formData, {
+      headers,
+    })
+      .then((data) => {
+        option.onSuccess?.(data);
+      })
+      .catch((err) => {
+        context?.handleUploadingFileNum("uploaded");
+        option.onError?.(err);
+      });
+  };
+
+  const handleChange: UploadProps["onChange"] = async ({
+    fileList: newFileList,
+    file,
+  }) => {
+    if (file.status === "done") {
+      if (typeof file.response !== "object" || !file.response.fileName) {
+        // 上传失败
+        file.status = "error";
+      } else if (isPictureCard && file.originFileObj) {
+        // 如果是图片获取图片宽高
+        try {
+          // @ts-ignore
+          file.imgAttrs = await getImageSize(file.originFileObj);
+          // todo: 缩略图并发上传有时候会丢失
+          file.thumbUrl = getBaseURL() + file.response.filePath;
+        } catch (err) {
+          // 图片加载失败
+          file.status = "error";
+        }
+      }
+
+      context?.handleUploadingFileNum("uploaded");
+    }
+
+    if (_mergedFileList.current.length > newFileList.length) {
+      _mergedFileList.current = newFileList;
+    } else {
+      _mergedFileList.current = updateFileList(file, _mergedFileList.current);
+    }
+
+    onChange?.(
+      _mergedFileList.current.map((i) => ({
+        ...i,
+        dType,
+      })),
+      {
+        ...file,
+        dType,
+      }
+    );
+  };
+
+  const handleCancel = () => setPreviewOpen(false);
+
+  const handlePreview = async (file: UploadFile) => {
+    if (!isPictureCard) return;
+
+    if (!file.url && !file.preview) {
+      file.preview = await getBase64(file.originFileObj as RcFile);
+    }
+
+    setPreviewImage(file.url || (file.preview as string));
+    setPreviewOpen(true);
+    setPreviewTitle(
+      file.name || file.url!.substring(file.url!.lastIndexOf("/") + 1)
+    );
+  };
+
+  const props: UploadProps = {
+    fileList: value,
+    withCredentials: true,
+    customRequest: onUpload,
+    listType: uploadListType,
+    maxCount,
+    accept,
+    disabled,
+    itemRender: (node, file, fileList, actions) => (
+      <DageUploadItemActions
+        isPictureCard={isPictureCard}
+        disabled={disabled}
+        file={file}
+        actions={actions}
+        downloadErrorMessage={downloadErrorMessage}
+      >
+        {node}
+      </DageUploadItemActions>
+    ),
+    showUploadList: {
+      showPreviewIcon: false,
+      showDownloadIcon: false,
+      showRemoveIcon: false,
+    },
+    multiple: maxCount > 1,
+    onPreview: handlePreview,
+    beforeUpload: beforeUpload,
+    onChange: handleChange,
+    ...rest,
+  };
+
+  return (
+    <UploadContainer>
+      {[DageUploadType.MODEL, DageUploadType.MOBILE_MODEL].includes(dType) ? (
+        <AntdDragger style={{ padding: "0 24px", width: "320px" }} {...props}>
+          <CloudUploadOutlined style={{ fontSize: "40px", color: "#1677ff" }} />
+
+          <AntdDraggerText>
+            将文件拖到此处,或<span>点击上传</span>
+          </AntdDraggerText>
+          <UploadTips className="dage-upload__tips">{tips}</UploadTips>
+        </AntdDragger>
+      ) : (
+        <>
+          <AntdUpload {...props}>
+            {isPictureCard ? (
+              !disabled &&
+              (!value || value.length < maxCount) && <PlusOutlined />
+            ) : (
+              <Button disabled={disabled} icon={<UploadOutlined />}>
+                上传
+              </Button>
+            )}
+          </AntdUpload>
+
+          {!!tips && (
+            <UploadTips
+              style={{ marginTop: isPictureCard ? 0 : "8px" }}
+              className="dage-upload__tips"
+            >
+              {tips}
+            </UploadTips>
+          )}
+        </>
+      )}
+
+      <Modal
+        open={previewOpen}
+        title={previewTitle}
+        footer={null}
+        onCancel={handleCancel}
+      >
+        <img alt="example" style={{ width: "100%" }} src={previewImage} />
+      </Modal>
+    </UploadContainer>
+  );
+};
+
+export * from "./types";
+export * from "./context";

+ 43 - 41
packages/pc-components/src/components/DageUpload/utils.ts

@@ -1,41 +1,43 @@
-import { RcFile } from "antd/es/upload";
-import { DageUploadType } from "./types";
-
-/**
- * 可选文件类型
- */
-export const ACCEPT: Record<string, string> = {
-  [DageUploadType.IMG]: ".jpg,.jpeg,.png,.gif",
-  [DageUploadType.MOBILE_MODEL]: ".zip",
-  [DageUploadType.MODEL]: ".4dage",
-  [DageUploadType.VIDEO]: ".mp4",
-  [DageUploadType.AUDIO]: ".mp3",
-};
-
-/**
- * 校验文件类型
- */
-export const validateFileType = (file: File, accept: string) => {
-  const fileName = file.name.toLowerCase();
-  const fileExtension = fileName.substring(fileName.lastIndexOf("."));
-
-  return accept.split(",").includes(fileExtension);
-};
-
-export async function getImageSize(
-  file: RcFile
-): Promise<{ width: number; height: number }> {
-  return new Promise((resolve, reject) => {
-    const img = new Image();
-
-    img.onload = () => {
-      resolve({ width: img.width, height: img.height });
-    };
-
-    img.onerror = (err) => {
-      reject(err);
-    };
-
-    img.src = URL.createObjectURL(file);
-  });
-}
+import { RcFile } from "antd/es/upload";
+import { DageUploadType } from "./types";
+
+/**
+ * 可选文件类型
+ */
+export const ACCEPT: Record<string, string> = {
+  [DageUploadType.IMG]: ".jpg,.jpeg,.png,.gif",
+  [DageUploadType.MOBILE_MODEL]: ".zip",
+  [DageUploadType.MODEL]: ".4dage",
+  [DageUploadType.VIDEO]: ".mp4",
+  [DageUploadType.AUDIO]: ".mp3",
+};
+
+/**
+ * 校验文件类型
+ */
+export const validateFileType = (file: File, accept: string) => {
+  if (accept === "*") return true;
+
+  const fileName = file.name.toLowerCase();
+  const fileExtension = fileName.substring(fileName.lastIndexOf("."));
+
+  return accept.split(",").includes(fileExtension);
+};
+
+export async function getImageSize(
+  file: RcFile
+): Promise<{ width: number; height: number }> {
+  return new Promise((resolve, reject) => {
+    const img = new Image();
+
+    img.onload = () => {
+      resolve({ width: img.width, height: img.height });
+    };
+
+    img.onerror = (err) => {
+      reject(err);
+    };
+
+    img.src = URL.createObjectURL(file);
+  });
+}