From 994eb75bbf61e83631ec2a402ce12bcc76bf4e8e Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 15:37:21 +0800 Subject: [PATCH 01/11] feat(image-viewer): support closeOnEscKeydown --- src/image-viewer/image-viewer.en-US.md | 10 ++++++---- src/image-viewer/image-viewer.md | 8 +++++--- src/image-viewer/image-viewer.tsx | 4 +++- src/image-viewer/props.ts | 6 ++++++ src/image-viewer/type.ts | 9 ++++++++- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/image-viewer/image-viewer.en-US.md b/src/image-viewer/image-viewer.en-US.md index 83520e7f4d..a507da3a27 100644 --- a/src/image-viewer/image-viewer.en-US.md +++ b/src/image-viewer/image-viewer.en-US.md @@ -6,19 +6,21 @@ name | type | default | description | required -- | -- | -- | -- | -- closeBtn | Boolean / Slot / Function | true | Typescript:`boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N +closeOnEscKeydown | Boolean | true | trigger image viewer close event on `ESC` keydown | N closeOnOverlay | Boolean | - | \- | N draggable | Boolean | undefined | \- | N imageScale | Object | - | Typescript:`ImageScale` `interface ImageScale { max: number; min: number; step: number }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/image-viewer/type.ts) | N images | Array | [] | Typescript:`Array` `interface ImageInfo { mainImage: string \| File; thumbnail?: string \| File; download?: boolean }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/image-viewer/type.ts) | N -index | Number | - | `v-model:index` is supported | N -defaultIndex | Number | - | uncontrolled property | N +index | Number | 0 | `v-model:index` is supported | N +defaultIndex | Number | 0 | uncontrolled property | N mode | String | modal | options: modal/modeless | N navigationArrow | Boolean / Slot / Function | true | Typescript:`boolean \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N showOverlay | Boolean | undefined | \- | N title | String / Slot / Function | - | preview title。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N -trigger | String / Slot / Function | - | trigger element。Typescript:`string \| TNode<{ open: () => void }>`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N +trigger | String / Slot / Function | - | trigger element。Typescript:`TNode \| TNode<{ open: () => void }>`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N viewerScale | Object | - | Typescript:`ImageViewerScale` `interface ImageViewerScale { minWidth: number; minHeight: number }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/image-viewer/type.ts) | N -visible | Boolean | false | `v-model` and `v-model:visible` is supported | N +visible | Boolean | false | hide or show image viewer。`v-model` and `v-model:visible` is supported | N +defaultVisible | Boolean | false | hide or show image viewer。uncontrolled property | N zIndex | Number | - | \- | N onClose | Function | | Typescript:`(context: { trigger: 'close-btn' \| 'overlay' \| 'esc'; e: MouseEvent \| KeyboardEvent }) => void`
| N onIndexChange | Function | | Typescript:`(index: number, context: { trigger: 'prev' \| 'next' \| 'current' }) => void`
| N diff --git a/src/image-viewer/image-viewer.md b/src/image-viewer/image-viewer.md index d5a79f7007..2b38657dde 100644 --- a/src/image-viewer/image-viewer.md +++ b/src/image-viewer/image-viewer.md @@ -34,19 +34,21 @@ 名称 | 类型 | 默认值 | 说明 | 必传 -- | -- | -- | -- | -- closeBtn | Boolean / Slot / Function | true | 是否展示关闭按钮,值为 `true` 显示默认关闭按钮;值为 `false` 则不显示关闭按钮;也可以完全自定义关闭按钮。TS 类型:`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N +closeOnEscKeydown | Boolean | true | 按下 ESC 时是否触发图片预览器关闭事件 | N closeOnOverlay | Boolean | - | 是否在点击遮罩层时,触发预览关闭 | N draggable | Boolean | undefined | 是否允许拖拽调整位置。`mode=modal` 时,默认不允许拖拽;`mode=modeless` 时,默认允许拖拽 | N imageScale | Object | - | 图片缩放相关配置。`imageScale.max` 缩放的最大比例;`imageScale.min` 缩放的最小比例;`imageScale.step` 缩放的步长速度。TS 类型:`ImageScale` `interface ImageScale { max: number; min: number; step: number }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/image-viewer/type.ts) | N images | Array | [] | 图片数组。`mainImage` 表示主图,必传;`thumbnail` 表示缩略图,如果不存在,则使用主图显示;`download` 是否允许下载图片,默认允许下载。示例: `['img_url_1', 'img_url_2']`,`[{ thumbnail: 'small_image_url', mainImage: 'big_image_url', download: false }]`。TS 类型:`Array` `interface ImageInfo { mainImage: string \| File; thumbnail?: string \| File; download?: boolean }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/image-viewer/type.ts) | N -index | Number | - | 当前预览图片所在的下标。支持语法糖 `v-model:index` | N -defaultIndex | Number | - | 当前预览图片所在的下标。非受控属性 | N +index | Number | 0 | 当前预览图片所在的下标。支持语法糖 `v-model:index` | N +defaultIndex | Number | 0 | 当前预览图片所在的下标。非受控属性 | N mode | String | modal | 模态预览(modal)和非模态预览(modeless)。可选项:modal/modeless | N navigationArrow | Boolean / Slot / Function | true | 切换预览图片的左图标,可自定义。TS 类型:`boolean \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N showOverlay | Boolean | undefined | 是否显示遮罩层。`mode=modal` 时,默认显示;`mode=modeless` 时,默认不显示 | N title | String / Slot / Function | - | 预览标题。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N -trigger | String / Slot / Function | - | 触发图片预览的元素,可能是一个预览按钮,可能是一张缩略图,完全自定义。TS 类型:`string \| TNode<{ open: () => void }>`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N +trigger | String / Slot / Function | - | 触发图片预览的元素,可能是一个预览按钮,可能是一张缩略图,完全自定义。TS 类型:`TNode \| TNode<{ open: () => void }>`。[通用类型定义](https://github.com/Tencent/tdesign-vue-next/blob/develop/src/common.ts) | N viewerScale | Object | - | 限制预览器缩放的最小宽度和最小高度,仅 `mode=modeless` 时有效。TS 类型:`ImageViewerScale` `interface ImageViewerScale { minWidth: number; minHeight: number }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/image-viewer/type.ts) | N visible | Boolean | false | 隐藏/显示预览。支持语法糖 `v-model` 或 `v-model:visible` | N +defaultVisible | Boolean | false | 隐藏/显示预览。非受控属性 | N zIndex | Number | - | 层级,默认为 2000 | N onClose | Function | | TS 类型:`(context: { trigger: 'close-btn' \| 'overlay' \| 'esc'; e: MouseEvent \| KeyboardEvent }) => void`
关闭时触发,事件参数包含触发关闭的来源:关闭按钮、遮罩层、ESC 键 | N onIndexChange | Function | | TS 类型:`(index: number, context: { trigger: 'prev' \| 'next' \| 'current' }) => void`
预览图片切换时触发,`context.prev` 切换到上一张图片,`context.next` 切换到下一张图片 | N diff --git a/src/image-viewer/image-viewer.tsx b/src/image-viewer/image-viewer.tsx index 9282cdaa8c..b81077f1f7 100644 --- a/src/image-viewer/image-viewer.tsx +++ b/src/image-viewer/image-viewer.tsx @@ -110,7 +110,9 @@ export default defineComponent({ onZoomOut(); break; case EVENT_CODE.esc: - onClose({ e, trigger: 'esc' }); + if (props.closeOnEscKeydown) { + onClose({ e, trigger: 'esc' }); + } break; default: break; diff --git a/src/image-viewer/props.ts b/src/image-viewer/props.ts index 3106a53295..c736635386 100644 --- a/src/image-viewer/props.ts +++ b/src/image-viewer/props.ts @@ -13,6 +13,11 @@ export default { type: [Boolean, Function] as PropType, default: true as TdImageViewerProps['closeBtn'], }, + /** 按下 ESC 时是否触发图片预览器关闭事件 */ + closeOnEscKeydown: { + type: Boolean, + default: true, + }, /** 是否在点击遮罩层时,触发预览关闭 */ closeOnOverlay: Boolean, /** 是否允许拖拽调整位置。`mode=modal` 时,默认不允许拖拽;`mode=modeless` 时,默认允许拖拽 */ @@ -37,6 +42,7 @@ export default { /** 当前预览图片所在的下标,非受控属性 */ defaultIndex: { type: Number, + default: 0, }, /** 模态预览(modal)和非模态预览(modeless) */ mode: { diff --git a/src/image-viewer/type.ts b/src/image-viewer/type.ts index fc43edd45b..8b65c81d56 100644 --- a/src/image-viewer/type.ts +++ b/src/image-viewer/type.ts @@ -12,6 +12,11 @@ export interface TdImageViewerProps { * @default true */ closeBtn?: boolean | TNode; + /** + * 按下 ESC 时是否触发图片预览器关闭事件 + * @default true + */ + closeOnEscKeydown?: boolean; /** * 是否在点击遮罩层时,触发预览关闭 */ @@ -31,10 +36,12 @@ export interface TdImageViewerProps { images?: Array; /** * 当前预览图片所在的下标 + * @default 0 */ index?: number; /** * 当前预览图片所在的下标,非受控属性 + * @default 0 */ defaultIndex?: number; /** @@ -58,7 +65,7 @@ export interface TdImageViewerProps { /** * 触发图片预览的元素,可能是一个预览按钮,可能是一张缩略图,完全自定义 */ - trigger?: string | TNode<{ open: () => void }>; + trigger?: TNode | TNode<{ open: () => void }>; /** * 限制预览器缩放的最小宽度和最小高度,仅 `mode=modeless` 时有效 */ From fa4d8197a2af8db3a188be25f865638c6e795034 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 15:49:58 +0800 Subject: [PATCH 02/11] feat(Upload): support imageViewerProps --- src/upload/_example/image.vue | 3 +++ src/upload/constants.ts | 1 + src/upload/interface.ts | 2 ++ src/upload/props.ts | 4 ++++ src/upload/themes/dragger-file.tsx | 3 ++- src/upload/themes/image-card.tsx | 3 ++- src/upload/themes/multiple-flow-list.tsx | 3 ++- src/upload/type.ts | 5 +++++ src/upload/upload.en-US.md | 1 + src/upload/upload.md | 1 + src/upload/upload.tsx | 1 + 11 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/upload/_example/image.vue b/src/upload/_example/image.vue index a3502816fb..fc6822e357 100644 --- a/src/upload/_example/image.vue +++ b/src/upload/_example/image.vue @@ -21,6 +21,7 @@ { MessagePlugin.error(`文件 ${file.name} 上传失败`); }; diff --git a/src/upload/constants.ts b/src/upload/constants.ts index 0e229e93d4..1a242d0434 100644 --- a/src/upload/constants.ts +++ b/src/upload/constants.ts @@ -26,4 +26,5 @@ export const commonProps = { default: Function as PropType, fileListDisplay: Function as PropType, onRemove: Function as PropType, + imageViewerProps: Object as PropType, }; diff --git a/src/upload/interface.ts b/src/upload/interface.ts index 41051fedb2..81bf2231d1 100644 --- a/src/upload/interface.ts +++ b/src/upload/interface.ts @@ -1,6 +1,7 @@ import { TdUploadProps, UploadRemoveContext } from './type'; import { GlobalConfigProvider } from '../config-provider/type'; import { TNode } from '../common'; +import { ImageViewerProps } from '../image-viewer'; export interface CommonDisplayFileProps { files: TdUploadProps['files']; @@ -26,6 +27,7 @@ export interface CommonDisplayFileProps { fileListDisplay?: TdUploadProps['fileListDisplay']; onRemove?: (p: UploadRemoveContext) => void; onPasteFileChange?: (payload: ClipboardEvent) => void; + imageViewerProps?: ImageViewerProps; } export type UploadProps = TdUploadProps; diff --git a/src/upload/props.ts b/src/upload/props.ts index 412b51a04e..a4b3846ed5 100644 --- a/src/upload/props.ts +++ b/src/upload/props.ts @@ -86,6 +86,10 @@ export default { headers: { type: Object as PropType, }, + /** 透传图片预览组件全部属性 */ + imageViewerProps: { + type: Object as PropType, + }, /** 用于添加属性到 HTML 元素 `input` */ inputAttributes: { type: Object as PropType, diff --git a/src/upload/themes/dragger-file.tsx b/src/upload/themes/dragger-file.tsx index 650249ad07..e43168e098 100644 --- a/src/upload/themes/dragger-file.tsx +++ b/src/upload/themes/dragger-file.tsx @@ -12,7 +12,7 @@ import useCommonClassName from '../../hooks/useCommonClassName'; import TLoading from '../../loading'; import useDrag, { UploadDragEvents } from '../hooks/useDrag'; import useGlobalIcon from '../../hooks/useGlobalIcon'; -import ImageViewer from '../../image-viewer'; +import ImageViewer, { ImageViewerProps } from '../../image-viewer'; import { useTNodeJSX } from '../../hooks'; import { UploadConfig } from '../../config-provider'; import Image from '../../image'; @@ -72,6 +72,7 @@ export default defineComponent({ } + {...(props.imageViewerProps as ImageViewerProps)} > ); diff --git a/src/upload/themes/image-card.tsx b/src/upload/themes/image-card.tsx index 54c02ee0f9..bcae2527a5 100644 --- a/src/upload/themes/image-card.tsx +++ b/src/upload/themes/image-card.tsx @@ -7,7 +7,7 @@ import { } from 'tdesign-icons-vue-next'; import Loading from '../../loading'; import useGlobalIcon from '../../hooks/useGlobalIcon'; -import ImageViewer from '../../image-viewer'; +import ImageViewer, { ImageViewerProps } from '../../image-viewer'; import { CommonDisplayFileProps } from '../interface'; import { commonProps } from '../constants'; import { TdUploadProps, UploadFile } from '../type'; @@ -81,6 +81,7 @@ export default defineComponent({ /> ); }} + {...(props.imageViewerProps as ImageViewerProps)} > {!props.disabled && ( diff --git a/src/upload/themes/multiple-flow-list.tsx b/src/upload/themes/multiple-flow-list.tsx index f1ef54c605..503c1d38e3 100644 --- a/src/upload/themes/multiple-flow-list.tsx +++ b/src/upload/themes/multiple-flow-list.tsx @@ -13,7 +13,7 @@ import { VideoIcon, } from 'tdesign-icons-vue-next'; import useGlobalIcon from '../../hooks/useGlobalIcon'; -import ImageViewer from '../../image-viewer'; +import ImageViewer, { ImageViewerProps } from '../../image-viewer'; import { CommonDisplayFileProps } from '../interface'; import { commonProps } from '../constants'; import TButton from '../../button'; @@ -395,6 +395,7 @@ export default defineComponent({ }} index={previewIndex.value} onIndexChange={(val) => (previewIndex.value = val)} + {...(props.imageViewerProps as ImageViewerProps)} > ); diff --git a/src/upload/type.ts b/src/upload/type.ts index f8dc08ad57..9465500c7c 100644 --- a/src/upload/type.ts +++ b/src/upload/type.ts @@ -4,6 +4,7 @@ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { ImageViewerProps } from '../image-viewer'; import { UploadConfig } from '../config-provider/type'; import { ButtonProps } from '../button'; import { PlainObject, TNode, UploadDisplayDragEvents } from '../common'; @@ -91,6 +92,10 @@ export interface TdUploadProps { * 设置上传的请求头部,`action` 存在时有效 */ headers?: { [key: string]: string }; + /** + * 透传图片预览组件全部属性 + */ + imageViewerProps?: ImageViewerProps; /** * 用于添加属性到 HTML 元素 `input` */ diff --git a/src/upload/upload.en-US.md b/src/upload/upload.en-US.md index dfe7ff20cd..15345f7f06 100644 --- a/src/upload/upload.en-US.md +++ b/src/upload/upload.en-US.md @@ -24,6 +24,7 @@ format | Function | - | to redefine `UploadFile` data structure。Typescript: formatRequest | Function | - | redefine request data。Typescript:`(requestData: { [key: string]: any }) => { [key: string]: any }` | N formatResponse | Function | - | redefine response data structure。Typescript:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N headers | Object | - | HTTP Request Header。Typescript:`{[key: string]: string}` | N +imageViewerProps | Object | - | ImageViewer Component Props。Typescript:`ImageViewerProps`,[ImageViewer API Documents](./image-viewer?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N inputAttributes | Object | - | add attributes to HTML element `input`。Typescript:`CSSProperties` | N isBatchUpload | Boolean | false | make all files to be a whole package, files can only be replaced or deleted together, can not add more files | N locale | Object | - | upload language config, priority of `locale` is higher than global language config。Typescript:`UploadConfig` `import { UploadConfig } from '../config-provider/type'`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N diff --git a/src/upload/upload.md b/src/upload/upload.md index 4ee8cde7f8..5be479db95 100644 --- a/src/upload/upload.md +++ b/src/upload/upload.md @@ -24,6 +24,7 @@ format | Function | - | 转换文件 `UploadFile` 的数据结构,可新增或 formatRequest | Function | - | 用于新增或修改文件上传请求 参数。`action` 存在时有效。一个请求上传一个文件时,默认请求字段有 `file`。
一个请求上传多个文件时,默认字段有 `file[0]/file[1]/file[2]/.../length`,其中 `length` 表示本次上传的文件数量。
⚠️非常注意,此处的 `file[0]/file[1]` 仅仅是一个字段名,并非表示 `file` 是一个数组,接口获取字段时注意区分。
可以使用 `name` 定义 `file` 字段的别名。
也可以使用 `formatRequest` 自定义任意字段,如添加一个字段 `fileList` ,存储文件数组。TS 类型:`(requestData: { [key: string]: any }) => { [key: string]: any }` | N formatResponse | Function | - | 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒,如果存在会判定为本次上传失败。
此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接。TS 类型:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N headers | Object | - | 设置上传的请求头部,`action` 存在时有效。TS 类型:`{[key: string]: string}` | N +imageViewerProps | Object | - | 透传图片预览组件全部属性。TS 类型:`ImageViewerProps`,[ImageViewer API Documents](./image-viewer?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N inputAttributes | Object | - | 用于添加属性到 HTML 元素 `input`。TS 类型:`CSSProperties` | N isBatchUpload | Boolean | false | 多个文件是否作为一个独立文件包,整体替换,整体删除。不允许追加文件,只允许替换文件。`theme=file-flow` 时有效 | N locale | Object | - | 上传组件文本语言配置,支持自定义配置组件中的全部文本。优先级高于全局配置中语言。TS 类型:`UploadConfig` `import { UploadConfig } from '../config-provider/type'`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx index 3a27175db8..019ecadd19 100644 --- a/src/upload/upload.tsx +++ b/src/upload/upload.tsx @@ -100,6 +100,7 @@ export default defineComponent({ onRemove: onInnerRemove, uploadPastedFiles: props.uploadPastedFiles, onPasteFileChange: onPasteFileChange, + imageViewerProps: props.imageViewerProps, })); const dragProps: UploadDragEvents = { From 941d8ebf8169102fb7053845d89c1888a186b322 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 16:05:49 +0800 Subject: [PATCH 03/11] feat(upload): image Upload support size limit tips --- src/upload/_example/image.vue | 6 +++++- src/upload/themes/image-card.tsx | 1 + src/upload/themes/normal-file.tsx | 2 -- src/upload/upload.tsx | 2 ++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/upload/_example/image.vue b/src/upload/_example/image.vue index fc6822e357..17f4376126 100644 --- a/src/upload/_example/image.vue +++ b/src/upload/_example/image.vue @@ -22,6 +22,7 @@ ref="uploadRef1" v-model="file1" :image-viewer-props="imageViewerProps" + :size-limit="sizeLimit" action="https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo" theme="image" tips="单张图片文件上传(上传成功状态演示)" @@ -73,7 +74,8 @@ theme="image" tips="允许选择多张图片文件上传,最多只能上传 3 张图片" accept="image/*" - :abridge-name="[6, 6]" + :size-limit="sizeLimit" + :abridge-name="abridgeName" :disabled="disabled" :auto-upload="autoUpload" :upload-all-files-in-one-request="uploadAllFilesInOneRequest" @@ -100,6 +102,8 @@ const uploadRef2 = ref(); const uploadRef3 = ref(); const imageViewerProps = ref({ closeOnEscKeydown: false }); +const sizeLimit = ref({ size: 500, unit: 'KB' }); +const abridgeName = [6, 6]; const handleFail = ({ file }) => { MessagePlugin.error(`文件 ${file.name} 上传失败`); diff --git a/src/upload/themes/image-card.tsx b/src/upload/themes/image-card.tsx index bcae2527a5..a94e1d5a34 100644 --- a/src/upload/themes/image-card.tsx +++ b/src/upload/themes/image-card.tsx @@ -128,6 +128,7 @@ export default defineComponent({ const customList = renderTNodeJSX('fileListDisplay', { params: { files: displayFiles.value, + ...props, }, }); if (customList) return customList; diff --git a/src/upload/themes/normal-file.tsx b/src/upload/themes/normal-file.tsx index 467e36d39e..c1ee4d879d 100644 --- a/src/upload/themes/normal-file.tsx +++ b/src/upload/themes/normal-file.tsx @@ -153,8 +153,6 @@ const NormalFile = defineComponent({ {fileListDisplay || renderFilePreviewAsText(displayFiles)} - {props.sizeOverLimitMessage && {props.sizeOverLimitMessage}} - {/* 单文件上传失败要显示失败的原因 */} {!props.multiple && displayFiles[0]?.status === 'fail' && theme.value === 'file' ? ( diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx index 019ecadd19..5fe0bf9302 100644 --- a/src/upload/upload.tsx +++ b/src/upload/upload.tsx @@ -221,6 +221,8 @@ export default defineComponent({ {renderTNodeJSX('tips')} )} + + {sizeOverLimitMessage.value && {sizeOverLimitMessage.value}} ); }, From 3cf85280ef3b651ddb9de9143fa8d553a584a649 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 16:12:45 +0800 Subject: [PATCH 04/11] docs(upload): add docs explanation --- src/upload/props.ts | 2 +- src/upload/type.ts | 2 +- src/upload/upload.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/upload/props.ts b/src/upload/props.ts index a4b3846ed5..0d5f3a2192 100644 --- a/src/upload/props.ts +++ b/src/upload/props.ts @@ -100,7 +100,7 @@ export default { locale: { type: Object as PropType, }, - /** 用于控制文件上传数量,值为 0 则不限制 */ + /** 用于控制文件上传数量,值为 0 则不限制。注意,单文件上传场景,请勿设置 `max` 属性 */ max: { type: Number, default: 0, diff --git a/src/upload/type.ts b/src/upload/type.ts index 9465500c7c..3e962a9b6b 100644 --- a/src/upload/type.ts +++ b/src/upload/type.ts @@ -110,7 +110,7 @@ export interface TdUploadProps { */ locale?: UploadConfig; /** - * 用于控制文件上传数量,值为 0 则不限制 + * 用于控制文件上传数量,值为 0 则不限制。注意,单文件上传场景,请勿设置 `max` 属性 * @default 0 */ max?: number; diff --git a/src/upload/upload.md b/src/upload/upload.md index 5be479db95..bcaa427fb6 100644 --- a/src/upload/upload.md +++ b/src/upload/upload.md @@ -28,7 +28,7 @@ imageViewerProps | Object | - | 透传图片预览组件全部属性。TS 类型 inputAttributes | Object | - | 用于添加属性到 HTML 元素 `input`。TS 类型:`CSSProperties` | N isBatchUpload | Boolean | false | 多个文件是否作为一个独立文件包,整体替换,整体删除。不允许追加文件,只允许替换文件。`theme=file-flow` 时有效 | N locale | Object | - | 上传组件文本语言配置,支持自定义配置组件中的全部文本。优先级高于全局配置中语言。TS 类型:`UploadConfig` `import { UploadConfig } from '../config-provider/type'`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N -max | Number | 0 | 用于控制文件上传数量,值为 0 则不限制 | N +max | Number | 0 | 用于控制文件上传数量,值为 0 则不限制。注意,单文件上传场景,请勿设置 `max` 属性 | N method | String | POST | HTTP 请求类型。可选项:POST/GET/PUT/OPTION/PATCH/post/get/put/option/patch | N mockProgressDuration | Number | - | 模拟进度间隔时间,单位:毫秒,默认:300。由于原始的上传请求,小文件上传进度只有 0 和 100,故而新增模拟进度,每间隔 `mockProgressDuration` 毫秒刷新一次模拟进度。小文件设置小一点,大文件设置大一点。注意:当 `useMockProgress` 为真时,当前设置有效 | N multiple | Boolean | false | 支持多文件上传 | N From c9ba8afa64d84e9a53b70e997861638b6c9b2a4c Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 16:18:47 +0800 Subject: [PATCH 05/11] fix(upload): max=1 and multiple=false --- src/upload/hooks/useUpload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upload/hooks/useUpload.ts b/src/upload/hooks/useUpload.ts index 6abffa688b..5a1836883a 100644 --- a/src/upload/hooks/useUpload.ts +++ b/src/upload/hooks/useUpload.ts @@ -147,7 +147,7 @@ export default function useUpload(props: TdUploadProps) { // @ts-ignore files: [...files], allowUploadDuplicateFile: props.allowUploadDuplicateFile, - max: props.max, + max: props.multiple ? props.max : 0, sizeLimit: props.sizeLimit, isBatchUpload: isBatchUpload.value, autoUpload: autoUpload.value, From 68e5517cdfc55c7e064abd2fb83ad829f607d267 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 16:37:56 +0800 Subject: [PATCH 06/11] feat(upload): add more params to fileListDisplay --- .../__snapshots__/vitest-upload.test.jsx.snap | 7 +++++++ src/upload/themes/image-card.tsx | 9 ++++++++- src/upload/themes/multiple-flow-list.tsx | 8 ++++++++ src/upload/themes/normal-file.tsx | 10 +++++++++- src/upload/upload.tsx | 1 - 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap b/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap index 2dbf2f442a..ee13165e80 100644 --- a/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap +++ b/src/upload/__tests__/__snapshots__/vitest-upload.test.jsx.snap @@ -159,6 +159,7 @@ exports[`Upload Component > props.draggable: theme=image & draggable=true, fail + `; @@ -326,6 +327,7 @@ exports[`Upload Component > props.draggable: theme=image & draggable=true, progr + `; @@ -488,6 +490,7 @@ exports[`Upload Component > props.draggable: theme=image & draggable=true, succe + `; @@ -650,6 +653,7 @@ exports[`Upload Component > props.draggable: theme=image & draggable=true, succe + `; @@ -783,6 +787,7 @@ exports[`Upload Component > props.draggable: theme=image & draggable=true, waiti + `; @@ -1084,6 +1089,7 @@ exports[`Upload Component > props.theme: theme=file-flow works fine 1`] = ` + `; @@ -1621,5 +1627,6 @@ exports[`Upload Component > props.theme: theme=image-flow works fine 1`] = ` + `; diff --git a/src/upload/themes/image-card.tsx b/src/upload/themes/image-card.tsx index a94e1d5a34..69675ece6d 100644 --- a/src/upload/themes/image-card.tsx +++ b/src/upload/themes/image-card.tsx @@ -127,8 +127,15 @@ export default defineComponent({ // render custom UI with fileListDisplay const customList = renderTNodeJSX('fileListDisplay', { params: { + triggerUpload: props.triggerUpload, + uploadFiles: props.uploadFiles, + cancelUpload: props.cancelUpload, + onPreview: props.onPreview, + onRemove: props.onRemove, + toUploadFiles: props.toUploadFiles, + sizeOverLimitMessage: props.sizeOverLimitMessage, + locale: props.locale, files: displayFiles.value, - ...props, }, }); if (customList) return customList; diff --git a/src/upload/themes/multiple-flow-list.tsx b/src/upload/themes/multiple-flow-list.tsx index 503c1d38e3..237bc88359 100644 --- a/src/upload/themes/multiple-flow-list.tsx +++ b/src/upload/themes/multiple-flow-list.tsx @@ -264,6 +264,13 @@ export default defineComponent({ const renderFileList = () => { const customList = renderTNodeJSX('fileListDisplay', { params: { + cancelUpload: props.cancelUpload, + uploadFiles: props.uploadFiles, + onPreview: props.onPreview, + onRemove: props.onRemove, + toUploadFiles: props.toUploadFiles, + sizeOverLimitMessage: props.sizeOverLimitMessage, + locale: props.locale, files: props.displayFiles, dragEvents: innerDragEvents.value, }, @@ -327,6 +334,7 @@ export default defineComponent({ const renderImageList = () => { const customList = renderTNodeJSX('fileListDisplay', { params: { + ...props, files: props.displayFiles, dragEvents: innerDragEvents.value, }, diff --git a/src/upload/themes/normal-file.tsx b/src/upload/themes/normal-file.tsx index c1ee4d879d..9238c76d13 100644 --- a/src/upload/themes/normal-file.tsx +++ b/src/upload/themes/normal-file.tsx @@ -138,7 +138,15 @@ const NormalFile = defineComponent({ return () => { const classes = [`${uploadPrefix}__single`, `${uploadPrefix}__single-${theme.value}`]; - const fileListDisplay = renderTNodeJSX('fileListDisplay', { params: { files: props.displayFiles } }); + const fileListDisplay = renderTNodeJSX('fileListDisplay', { + params: { + onRemove: props.onRemove, + toUploadFiles: props.toUploadFiles, + sizeOverLimitMessage: props.sizeOverLimitMessage, + locale: props.locale, + files: props.displayFiles, + }, + }); const { displayFiles } = props; return ( diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx index 5fe0bf9302..f56dc30e25 100644 --- a/src/upload/upload.tsx +++ b/src/upload/upload.tsx @@ -221,7 +221,6 @@ export default defineComponent({ {renderTNodeJSX('tips')} )} - {sizeOverLimitMessage.value && {sizeOverLimitMessage.value}} ); From ded07964ffb155ba6a034d71928b5ad8f1802b27 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 17:03:43 +0800 Subject: [PATCH 07/11] test: update snapshots --- test/unit/snap/__snapshots__/csr.test.js.snap | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/test/unit/snap/__snapshots__/csr.test.js.snap b/test/unit/snap/__snapshots__/csr.test.js.snap index 3659806745..c19f091bd3 100644 --- a/test/unit/snap/__snapshots__/csr.test.js.snap +++ b/test/unit/snap/__snapshots__/csr.test.js.snap @@ -62385,6 +62385,7 @@ exports[`csr snapshot test > csr test ./src/form/_example/disabled.vue 1`] = ` > 请选择单张图片文件上传 + @@ -199397,7 +199398,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/base.vue 1`] = ` - @@ -199405,6 +199405,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/base.vue 1`] = ` + @@ -199493,7 +199494,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/base.vue 1`] = ` - @@ -199501,6 +199501,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/base.vue 1`] = ` + @@ -199563,7 +199564,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/base.vue 1`] = ` - @@ -199571,6 +199571,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/base.vue 1`] = ` + @@ -199665,6 +199666,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/custom-drag.vue 1`] + `; @@ -199804,6 +199806,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/draggable.vue 1`] = + @@ -199915,6 +199918,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/draggable.vue 1`] = + @@ -200234,6 +200238,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/file-flow-list.vue 1 + @@ -200420,6 +200425,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/image.vue 1`] = ` > 单张图片文件上传(上传成功状态演示) + @@ -200478,6 +200484,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/image.vue 1`] = ` > 单张图片文件上传(上传失败状态演示) + @@ -200639,6 +200646,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/image.vue 1`] = ` + @@ -200698,6 +200706,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/image.vue 1`] = ` > 允许选择多张图片文件上传,最多只能上传 3 张图片 + @@ -200959,6 +200968,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/img-flow-list.vue 1` + @@ -201035,7 +201045,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/listType.vue 1`] = ` - @@ -201043,6 +201052,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/listType.vue 1`] = ` + @@ -201180,7 +201190,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/request-method.vue 1 - @@ -201188,6 +201197,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/request-method.vue 1 + @@ -201249,6 +201259,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/single-custom.vue 1` > 上传文件大小在 5M 以内 + @@ -201313,7 +201324,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/single-input.vue 1`] - @@ -201321,6 +201331,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/single-input.vue 1`] + `; @@ -201382,7 +201393,6 @@ exports[`csr snapshot test > csr test ./src/upload/_example/table.vue 1`] = ` - @@ -201390,6 +201400,7 @@ exports[`csr snapshot test > csr test ./src/upload/_example/table.vue 1`] = ` +
Date: Sun, 5 Nov 2023 19:24:02 +0800 Subject: [PATCH 08/11] feat(upload): support cancelUploadButton/uploadButton/showImageFileName --- src/upload/_example/image.vue | 5 ++ src/upload/_example/img-flow-list.vue | 57 ++++++++++++++++-- src/upload/props.ts | 13 ++++ src/upload/themes/image-card.tsx | 2 + src/upload/themes/multiple-flow-list.tsx | 77 ++++++++++++++++++------ src/upload/type.ts | 19 ++++++ src/upload/upload.en-US.md | 3 + src/upload/upload.md | 3 + src/upload/upload.tsx | 4 ++ 9 files changed, 160 insertions(+), 23 deletions(-) diff --git a/src/upload/_example/image.vue b/src/upload/_example/image.vue index 17f4376126..90e962e411 100644 --- a/src/upload/_example/image.vue +++ b/src/upload/_example/image.vue @@ -1,6 +1,7 @@ @@ -41,4 +42,11 @@ const showThumbnail = ref(false); const allowUploadDuplicateFile = ref(false); const isBatchUpload = ref(false); const uploadAllFilesInOneRequest = ref(false); + +const formatResponse = (res) => { + if (!res) { + return { status: 'fail', error: '上传失败,原因:文件过大或网络不通' }; + } + return res; +}; diff --git a/src/upload/props.ts b/src/upload/props.ts index b4c138b859..0fe9c59603 100644 --- a/src/upload/props.ts +++ b/src/upload/props.ts @@ -82,7 +82,7 @@ export default { formatRequest: { type: Function as PropType, }, - /** 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒,如果存在会判定为本次上传失败。
此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接 */ + /** 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
示例返回值:`{ error, url, status, files }`
此函数的返回值 `error` 会作为错误文本提醒,表示上传失败的原因,如果存在会判定为本次上传失败。
此函数的返回值 `url` 会作为单个文件上传成功后的链接。
`files` 表示一个请求同时上传多个文件后的文件列表 */ formatResponse: { type: Function as PropType, }, diff --git a/src/upload/themes/multiple-flow-list.tsx b/src/upload/themes/multiple-flow-list.tsx index 109e09a91a..7574bfd915 100644 --- a/src/upload/themes/multiple-flow-list.tsx +++ b/src/upload/themes/multiple-flow-list.tsx @@ -196,7 +196,7 @@ export default defineComponent({
{iconMap[file.status]} - {textMap[file.status]} + {file.response?.error ? file.response?.error || textMap[file.status] : textMap[file.status]} {props.showUploadProgress && file.status === 'progress' ? ` ${file.percent || 0}%` : ''}
diff --git a/src/upload/type.ts b/src/upload/type.ts index 0154073278..6ba32db359 100644 --- a/src/upload/type.ts +++ b/src/upload/type.ts @@ -92,7 +92,7 @@ export interface TdUploadProps { */ formatRequest?: (requestData: { [key: string]: any }) => { [key: string]: any }; /** - * 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒,如果存在会判定为本次上传失败。
此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接 + * 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
示例返回值:`{ error, url, status, files }`
此函数的返回值 `error` 会作为错误文本提醒,表示上传失败的原因,如果存在会判定为本次上传失败。
此函数的返回值 `url` 会作为单个文件上传成功后的链接。
`files` 表示一个请求同时上传多个文件后的文件列表 */ formatResponse?: (response: any, context: FormatResponseContext) => ResponseType; /** @@ -360,7 +360,10 @@ export interface UploadFile extends PlainObject { url?: string; } -export type ResponseType = { error?: string; url?: string } & Record; +export type ResponseType = { error?: string; url?: string; status?: 'fail' | 'success'; files?: UploadFile[] } & Record< + string, + any +>; export interface FormatResponseContext { file: UploadFile; diff --git a/src/upload/upload.en-US.md b/src/upload/upload.en-US.md index 8a74c702ba..8498d15672 100644 --- a/src/upload/upload.en-US.md +++ b/src/upload/upload.en-US.md @@ -23,7 +23,7 @@ files | Array | [] | `v-model:files` is supported。Typescript:`Array` | N defaultFiles | Array | [] | uncontrolled property。Typescript:`Array` | N format | Function | - | to redefine `UploadFile` data structure。Typescript:`(file: File) => UploadFile` | N formatRequest | Function | - | redefine request data。Typescript:`(requestData: { [key: string]: any }) => { [key: string]: any }` | N -formatResponse | Function | - | redefine response data structure。Typescript:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N +formatResponse | Function | - | redefine response data structure。Typescript:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string; status?: 'fail' \| 'success'; files?: UploadFile[] } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N headers | Object | - | HTTP Request Header。Typescript:`{[key: string]: string}` | N imageViewerProps | Object | - | ImageViewer Component Props。Typescript:`ImageViewerProps`,[ImageViewer API Documents](./image-viewer?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N inputAttributes | Object | - | add attributes to HTML element `input`。Typescript:`CSSProperties` | N diff --git a/src/upload/upload.md b/src/upload/upload.md index bf71981a9d..d87556a148 100644 --- a/src/upload/upload.md +++ b/src/upload/upload.md @@ -23,7 +23,7 @@ files | Array | [] | 已上传文件列表,同 `value`。TS 类型:`UploadFi defaultFiles | Array | [] | 已上传文件列表,同 `value`。TS 类型:`UploadFile`。非受控属性。TS 类型:`Array` | N format | Function | - | 转换文件 `UploadFile` 的数据结构,可新增或修改 `UploadFile` 的属性,注意不能删除 `UploadFile` 属性。`action` 存在时有效。TS 类型:`(file: File) => UploadFile` | N formatRequest | Function | - | 用于新增或修改文件上传请求 参数。`action` 存在时有效。一个请求上传一个文件时,默认请求字段有 `file`。
一个请求上传多个文件时,默认字段有 `file[0]/file[1]/file[2]/.../length`,其中 `length` 表示本次上传的文件数量。
⚠️非常注意,此处的 `file[0]/file[1]` 仅仅是一个字段名,并非表示 `file` 是一个数组,接口获取字段时注意区分。
可以使用 `name` 定义 `file` 字段的别名。
也可以使用 `formatRequest` 自定义任意字段,如添加一个字段 `fileList` ,存储文件数组。TS 类型:`(requestData: { [key: string]: any }) => { [key: string]: any }` | N -formatResponse | Function | - | 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
此函数的返回值 `error` 或 `response.error` 会作为错误文本提醒,如果存在会判定为本次上传失败。
此函数的返回值 `url` 或 `response.url` 会作为上传成功后的链接。TS 类型:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N +formatResponse | Function | - | 用于格式化文件上传后的接口响应数据,`response` 便是接口响应的原始数据。`action` 存在时有效。
示例返回值:`{ error, url, status, files }`
此函数的返回值 `error` 会作为错误文本提醒,表示上传失败的原因,如果存在会判定为本次上传失败。
此函数的返回值 `url` 会作为单个文件上传成功后的链接。
`files` 表示一个请求同时上传多个文件后的文件列表。TS 类型:`(response: any, context: FormatResponseContext) => ResponseType ` `type ResponseType = { error?: string; url?: string; status?: 'fail' \| 'success'; files?: UploadFile[] } & Record` `interface FormatResponseContext { file: UploadFile; currentFiles?: UploadFile[] }`。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N headers | Object | - | 设置上传的请求头部,`action` 存在时有效。TS 类型:`{[key: string]: string}` | N imageViewerProps | Object | - | 透传图片预览组件全部属性。TS 类型:`ImageViewerProps`,[ImageViewer API Documents](./image-viewer?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-vue-next/tree/develop/src/upload/type.ts) | N inputAttributes | Object | - | 用于添加属性到 HTML 元素 `input`。TS 类型:`CSSProperties` | N From 3665bcfe6f7531efec28fa41c1574514c04e980e Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sun, 5 Nov 2023 20:28:30 +0800 Subject: [PATCH 11/11] feat(_common): update commmon --- src/_common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_common b/src/_common index 35fc9546a1..56f3acdc7c 160000 --- a/src/_common +++ b/src/_common @@ -1 +1 @@ -Subproject commit 35fc9546a193fdf02a6c4e7391603b075830a2a1 +Subproject commit 56f3acdc7c44c2a1dde6c74deb68f6b952de1a7d