Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Upload][Refactor] #1723

Merged
merged 23 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
281157d
feat(upload): initial version
chaishi Sep 16, 2022
01791a4
feat(upload): base demo
chaishi Sep 17, 2022
faa1151
feat(upload): initial upload code
chaishi Sep 18, 2022
1e861b7
feat(upload): some features
chaishi Sep 18, 2022
3c927a7
docs(upload): demos
chaishi Sep 18, 2022
99b5817
feat(upload): progress
chaishi Sep 22, 2022
f58306c
test(unit): update snapshots
chaishi Sep 22, 2022
ad14454
Merge remote-tracking branch 'origin/develop' into 20220912_feature_u…
chaishi Sep 22, 2022
d7e471e
Merge remote-tracking branch 'origin/develop' into 20220912_feature_u…
chaishi Sep 22, 2022
7ae21dd
feat: merge from origin/develop
chaishi Sep 22, 2022
622d24f
Merge remote-tracking branch 'origin/develop' into 20220912_feature_u…
chaishi Sep 22, 2022
27f8a46
feat(_common): update
chaishi Sep 22, 2022
6db745b
feat(_common): update commone
chaishi Sep 22, 2022
ad38e0f
feat(image-viewer): show arrow
chaishi Sep 22, 2022
762967c
docs(upload): fix demo @Click to @click
chaishi Sep 22, 2022
c7bd5b2
fix(upload): event name error
chaishi Sep 23, 2022
b4bba76
chore(upload): remove useless code
chaishi Sep 23, 2022
bfd9fdf
feat(upload): demo improvement
chaishi Sep 24, 2022
6da77a3
test(unit): update snapshots
chaishi Sep 24, 2022
4f632aa
docs(upload): update document
chaishi Sep 25, 2022
af3edd0
feat(_common): update common
chaishi Sep 25, 2022
76e1841
Merge remote-tracking branch 'origin/develop' into 20220912_feature_u…
chaishi Sep 25, 2022
74f92cd
feat: merge from develop
chaishi Sep 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/hooks/tnode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { h, getCurrentInstance, ComponentInternalInstance, VNode } from 'vue';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import camelCase from 'lodash/camelCase';
import kebabCase from 'lodash/kebabCase';
Expand All @@ -16,6 +15,16 @@ function handleSlots(instance: ComponentInternalInstance, name: string, params:
return null;
}

/**
* 是否为空节点,需要过滤掉注释节点。注释节点也会被认为是空节点
*/
function isEmptyNode(node: any) {
if ([undefined, null, ''].includes(node)) return true;
const innerNodes = node instanceof Array ? node : [node];
const r = innerNodes.filter((node) => node?.type?.toString() !== 'Symbol(Comment)');
return !r.length;
}

/**
* 通过 JSX 的方式渲染 TNode,props 和 插槽同时处理,也能处理默认值为 true 则渲染默认节点的情况
* 优先级:Props 大于插槽
Expand Down Expand Up @@ -103,7 +112,7 @@ export const useContent = () => {
const node1 = renderTNodeJSX(name1, toParams);
const node2 = renderTNodeJSX(name2, toParams);

const res = isEmpty(node1) ? node2 : node1;
return isEmpty(res) ? defaultNode : res;
const res = isEmptyNode(node1) ? node2 : node1;
return isEmptyNode(res) ? defaultNode : res;
};
};
2 changes: 2 additions & 0 deletions src/hooks/useGlobalIcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export function useGlobalIcon(tdIcon: Object) {

return resultIcon;
}

export default useGlobalIcon;
2 changes: 1 addition & 1 deletion src/image-viewer/image-viewer.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ 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 | - | 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
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
defaultVisible | Boolean | false | uncontrolled property | N
Expand Down
2 changes: 1 addition & 1 deletion src/image-viewer/image-viewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mode | String | modal | 模态预览(modal)和非模态预览(modeless)。
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`[通用类型定义](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
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
Expand Down
2 changes: 1 addition & 1 deletion src/image-viewer/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface TdImageViewerProps {
/**
* 触发图片预览的元素,可能是一个预览按钮,可能是一张缩略图,完全自定义
*/
trigger?: string | TNode;
trigger?: string | TNode<{ open: () => void }>;
/**
* 限制预览器缩放的最小宽度和最小高度,仅 `mode=modeless` 时有效
*/
Expand Down
8 changes: 0 additions & 8 deletions src/tree-select/__tests__/__snapshots__/index.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ exports[`TreeSelect > :props > :defaultValue 1`] = `
class="t-tag--text"
style="max-width: 300px;"
>
<!---->
</span>
<svg
class="t-icon t-icon-close t-tag__icon-close"
Expand Down Expand Up @@ -578,9 +576,7 @@ exports[`TreeSelect > :props > :multiple 1`] = `
class="t-tag--text"
style="max-width: 300px;"
>
<!---->
</span>
<svg
class="t-icon t-icon-close t-tag__icon-close"
Expand Down Expand Up @@ -1007,9 +1003,7 @@ exports[`TreeSelect > <slot> > <collapsedItems> 1`] = `
class="t-tag--text"
style="max-width: 300px;"
>
<!---->
</span>
<svg
class="t-icon t-icon-close t-tag__icon-close"
Expand Down Expand Up @@ -1337,9 +1331,7 @@ exports[`TreeSelect > function > :collapsedItems 1`] = `
class="t-tag--text"
style="max-width: 300px;"
>
<!---->
</span>
<svg
class="t-icon t-icon-close t-tag__icon-close"
Expand Down
210 changes: 193 additions & 17 deletions src/upload/_example/base.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,211 @@
<!-- :sizeLimit="{ size: 2, unit: 'MB' }" -->
<!-- :sizeLimit="{ size: 2, unit: 'MB', message: '图片太大' }" -->
<!-- :sizeLimit="{ size: 2, unit: 'MB', message: '图片太大,不能超过 {sizeLimit} MB' }" -->
<t-space direction="vertical">
<t-space>
<t-radio-group v-model="multiple" variant="default-filled">
<t-radio-button :value="false">单文件上传</t-radio-button>
<t-radio-button :value="true">多文件上传</t-radio-button>
</t-radio-group>
</t-space>
<t-space>
<t-checkbox v-model="disabled">禁用状态</t-checkbox>
<t-checkbox v-if="multiple" v-model="uploadInOneRequest">多个文件一个请求上传</t-checkbox>
<t-checkbox v-if="multiple" v-model="isBatchUpload">整体替换上传</t-checkbox>
<t-checkbox v-model="autoUpload">自动上传</t-checkbox>
<t-button v-if="!autoUpload" variant="base" theme="default" style="height: 22px" @click="uploadFiles">
点击手动上传
</t-button>
</t-space>

<!-- 上传接口默认只传一个参数,如果希望自定义参数,可以使用 format 方法格式化参数-->
<t-upload
v-model="files"
action="https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
tips="上传文件大小在 5M 以内"
:size-limit="{ size: 5, unit: 'MB' }"
:format-response="formatResponse"
:on-select-change="handleSelectChange"
@fail="handleFail"
></t-upload>
<br />
<t-space>
<t-upload
ref="uploadRef1"
v-model="files1"
action="https://service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
:placeholder="multiple ? '文件数量不超过 5 个' : '要求文件大小在 1M 以内'"
:multiple="multiple"
:auto-upload="autoUpload"
:upload-all-files-in-one-request="uploadInOneRequest"
:is-batch-upload="isBatchUpload"
:size-limit="{ size: 1, unit: 'MB' }"
:max="5"
:disabled="disabled"
:allow-upload-duplicate-file="true"
@select-change="handleSelectChange"
@fail="handleFail"
@success="handleSuccess"
@one-file-success="onOneFileSuccess"
@validate="onValidate"
/>

<t-upload
ref="uploadRef2"
v-model="files2"
:multiple="multiple"
:disabled="disabled"
:auto-upload="autoUpload"
:upload-all-files-in-one-request="uploadInOneRequest"
:is-batch-upload="isBatchUpload"
:trigger-button-props="{ theme: 'primary', variant: 'base' }"
placeholder="这是一段没有文件时的占位文本"
action="//service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
:style="{ marginLeft: '40px' }"
@fail="handleFail"
/>

<!-- formatResponse 可控制上传成功或者失败 -->
<!-- tips="文件上传失败示例" 和 status="error" 控制固定文本显示 -->
<t-upload
ref="uploadRef3"
v-model="files3"
:multiple="multiple"
:disabled="disabled"
:auto-upload="autoUpload"
:upload-all-files-in-one-request="uploadInOneRequest"
:is-batch-upload="isBatchUpload"
:format-response="formatResponse"
placeholder="文件上传失败示例"
action="//service-bv448zsw-1257786608.gz.apigw.tencentcs.com/api/upload-demo"
:style="{ marginLeft: '60px' }"
@fail="handleFail"
>
<!-- 自定义文件列表,示例代码有效,勿删 -->
<!-- <template #fileListDisplay>
<div>
<div
v-for="(file, index) in files3"
:key="file.name"
class="t-upload__single-display-text t-upload__display-text--margin"
>
{{file.name}}({{file.size}} B)
<CloseIcon class="t-upload__icon-delete" @click="() => outsideRemove(index)" />
</div>
</div>
</template> -->
</t-upload>
</t-space>
</t-space>
</template>
<script setup>
import { ref } from 'vue';
import { ref, watch } from 'vue';
import { MessagePlugin } from 'tdesign-vue-next';
// import { CloseIcon } from 'tdesign-icons-vue-next';

const uploadRef1 = ref();
const uploadRef2 = ref();
const uploadRef3 = ref();

const files1 = ref([]);
const files2 = ref([
{
name: '这是一个默认文件',
status: 'success',
url: 'https://tdesign.gtimg.com/site/source/figma-pc.png',
size: 1000,
},
]);
const files3 = ref([]);

const multiple = ref(false);
const uploadInOneRequest = ref(false);
const autoUpload = ref(true);
const isBatchUpload = ref(false);
const disabled = ref(false);

const files = ref([]);
watch(multiple, (multiple) => {
files3.value = multiple
? [
{
name: '这是一个上传成功的文件',
status: 'success',
url: 'https://tdesign.gtimg.com/site/source/figma-pc.png',
size: 1000,
},
{
name: '这是一个上传中的文件',
status: 'progress',
percent: 30,
url: 'https://tdesign.gtimg.com/site/source/figma-pc.png',
size: 1000,
},
{
name: '这是一个上传失败的文件',
status: 'fail',
url: 'https://tdesign.gtimg.com/site/source/figma-pc.png',
size: 1000,
},
{
name: '这是一个等待上传的文件',
status: 'waiting',
url: 'https://tdesign.gtimg.com/site/source/figma-pc.png',
size: 1000,
},
]
: [];
});

const handleFail = ({ file }) => {
MessagePlugin.error(`文件 ${file.name} 上传失败`);
};

const handleSelectChange = (files) => {
console.log(files);
console.log('onSelectChange', files);
};

const handleSuccess = () => {
MessagePlugin.success('上传成功');
};

// 多文件上传,一个文件一个请求场景,每个文件也会单独触发上传成功的事件
const onOneFileSuccess = (params) => {
console.log('onOneFileSuccess', params);
};

const formatResponse = (res) => {
if (!res.url) {
return { error: '上传失败,请重试' };
// 有文件数量超出时会触发,文件大小超出限制、文件同名时会触发等场景。注意如果设置允许上传同名文件,则此事件不会触发
const onValidate = (params) => {
const { files, type } = params;
console.log('onValidate', params);
if (type === 'FILE_OVER_SIZE_LIMIT') {
files.map((t) => t.name).join('、');
MessagePlugin.warning(`${files.map((t) => t.name).join('、')} 等文件大小超出限制,已自动过滤`, 5000);
} else if (type === 'FILES_OVER_LENGTH_LIMIT') {
MessagePlugin.warning('文件数量超出限制,仅上传未超出数量的文件');
} else if (type === 'FILTER_FILE_SAME_NAME') {
// 如果希望支持上传同名文件,请设置 allowUploadDuplicateFile={true}
MessagePlugin.warning('不允许上传同名文件');
}
return { ...res, url: res.url };
};

// 仅自定义文件列表所需
// eslint-disable-next-line
const outsideRemove = (index) => {
const tmpFiles = [...files3.value];
tmpFiles.splice(index, 1);
files3.value = tmpFiles;
};

// 非自动上传文件,需要在父组件单独执行上传请求
const uploadFiles = () => {
uploadRef1.value.uploadFiles();
uploadRef2.value.uploadFiles();
uploadRef3.value.uploadFiles();
};

const formatResponse = () => {
return { error: '上传失败,请重试' };
};

/** 单个文件校验方法,示例代码有效,勿删 */
// const beforeUpload = (file) => {
// MessagePlugin.error(`文件 ${file.name} 不满足条件`);
// return false;
// };

/** 全部文件一次性校验方法,示例代码有效,勿删 */
// const beforeAllFilesUpload = () => {
// MessagePlugin.error(`文件不满足条件`);
// return false;
// };
</script>
7 changes: 3 additions & 4 deletions src/upload/_example/custom-drag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@
@success="handleSuccess"
@progress="onProgress"
>
<template #default="params">
<ul v-if="files && files.length">
<li v-for="file in files" :key="file.name">{{ file.name }}</li>
<template #dragContent="params">
<ul v-if="files && files.length" style="padding: 0">
<li v-for="file in files" :key="file.name" style="list-style-type: none">{{ file.name }}</li>
</ul>
<template v-else>
<p v-if="params && params.dragActive">释放鼠标</p>
<t-button v-else-if="progress < 1">自定义拖拽区域</t-button>
</template>
<t-button v-if="files && files.length" size="small" style="margin-top: 36px">更换文件</t-button>
<br /><br />
<!-- <span>数据状态:{{params}}</span> -->
</template>
</t-upload>
Expand Down
Loading