feat: 自定义预览图/文件名

This commit is contained in:
dap 2025-03-30 21:57:01 +08:00
parent 755a30583f
commit 23ff03d40c
5 changed files with 121 additions and 19 deletions

View File

@ -68,7 +68,7 @@ const {
handleRemove, handleRemove,
beforeUpload, beforeUpload,
innerFileList, innerFileList,
} = useUpload(props, emit, ossIdList); } = useUpload(props, emit, ossIdList, 'file');
</script> </script>
<!-- <!--

View File

@ -8,7 +8,12 @@ import type {
import type { ModelRef } from 'vue'; import type { ModelRef } from 'vue';
import type { BaseUploadProps, UploadEmits } from './props'; import type {
BaseUploadProps,
CustomGetter,
UploadEmits,
UploadType,
} from './props';
import type { AxiosProgressEvent, UploadResult } from '#/api'; import type { AxiosProgressEvent, UploadResult } from '#/api';
import type { OssFile } from '#/api/system/oss/model'; import type { OssFile } from '#/api/system/oss/model';
@ -83,12 +88,14 @@ export function useImagePreview() {
* @param props props * @param props props
* @param emit * @param emit
* @param bindValue idList * @param bindValue idList
* @param uploadType
* @returns hook * @returns hook
*/ */
export function useUpload( export function useUpload(
props: Readonly<BaseUploadProps>, props: Readonly<BaseUploadProps>,
emit: UploadEmits, emit: UploadEmits,
bindValue: ModelRef<string | string[]>, bindValue: ModelRef<string | string[]>,
uploadType: UploadType,
) { ) {
// 组件内部维护fileList // 组件内部维护fileList
const innerFileList = ref<UploadFile[]>([]); const innerFileList = ref<UploadFile[]>([]);
@ -114,6 +121,45 @@ export function useUpload(
.join(', '); .join(', ');
}); });
/**
*
* @param cb callback
* @returns
*/
function transformFilename(cb: Parameters<CustomGetter<string>>[0]) {
if (isFunction(props.customFilename)) {
return props.customFilename(cb);
}
// info接口
if (cb.type === 'info') {
return cb.response.originalName;
}
// 上传接口
return cb.response.fileName;
}
/**
*
* @param cb callback
* @returns
*/
function transformThumbUrl(cb: Parameters<CustomGetter<undefined>>[0]) {
if (isFunction(props.customThumbUrl)) {
return props.customThumbUrl(cb);
}
// image 默认返回图片链接
if (uploadType === 'image') {
// info接口
if (cb.type === 'info') {
return cb.response.url;
}
// 上传接口
return cb.response.url;
}
// 文件默认返回空 走antd默认的预览图逻辑
return undefined;
}
function handleChange(info: UploadChangeParam) { function handleChange(info: UploadChangeParam) {
/** /**
* *
@ -141,10 +187,19 @@ export function useUpload(
} }
// 获取返回结果 为customRequest的reslove参数 // 获取返回结果 为customRequest的reslove参数
// 只有success才会走到这里 // 只有success才会走到这里
const { ossId, fileName, url } = currentFile.response as UploadResult; const { ossId, url } = currentFile.response as UploadResult;
currentFile.url = url; currentFile.url = url;
currentFile.fileName = fileName;
currentFile.uid = ossId; currentFile.uid = ossId;
const cb = {
type: 'upload',
response: currentFile.response as UploadResult,
} as const;
currentFile.fileName = transformFilename(cb);
currentFile.name = transformFilename(cb);
currentFile.thumbUrl = transformThumbUrl(cb);
// ossID添加 单个文件会被当做string // ossID添加 单个文件会被当做string
if (props.maxCount === 1) { if (props.maxCount === 1) {
bindValue.value = ossId; bindValue.value = ossId;
@ -262,11 +317,14 @@ export function useUpload(
} }
const resp = await ossInfo(value); const resp = await ossInfo(value);
function transformFile(info: OssFile) { function transformFile(info: OssFile) {
const cb = { type: 'info', response: info } as const;
const fileitem: UploadFile = { const fileitem: UploadFile = {
uid: info.ossId, uid: info.ossId,
name: info.originalName, name: transformFilename(cb),
fileName: info.originalName, fileName: transformFilename(cb),
url: info.url, url: info.url,
thumbUrl: transformThumbUrl(cb),
status: 'done', status: 'done',
}; };
return fileitem; return fileitem;

View File

@ -59,7 +59,7 @@ const {
beforeUpload, beforeUpload,
innerFileList, innerFileList,
customRequest, customRequest,
} = useUpload(props, emit, ossIdList); } = useUpload(props, emit, ossIdList, 'image');
const { previewVisible, previewImage, handleCancel, handlePreview } = const { previewVisible, previewImage, handleCancel, handlePreview } =
useImagePreview(); useImagePreview();

View File

@ -2,9 +2,22 @@ import type { UploadFile } from 'ant-design-vue';
import type { RcFile } from 'ant-design-vue/es/vc-upload/interface'; import type { RcFile } from 'ant-design-vue/es/vc-upload/interface';
import type { UploadApi, UploadResult } from '#/api'; import type { UploadApi, UploadResult } from '#/api';
import type { OssFile } from '#/api/system/oss/model';
import { UploadChangeParam } from 'ant-design-vue'; import { UploadChangeParam } from 'ant-design-vue';
export type UploadType = 'file' | 'image';
/**
* /使
* type if判断
*/
export type CustomGetter<T extends string | undefined> = (
cb:
| { response: OssFile; type: 'info' }
| { response: UploadResult; type: 'upload' },
) => T extends undefined ? string | undefined : string;
export interface BaseUploadProps { export interface BaseUploadProps {
/** /**
* *
@ -99,6 +112,14 @@ export interface BaseUploadProps {
* @default true * @default true
*/ */
abortOnUnmounted?: boolean; abortOnUnmounted?: boolean;
/**
*
*/
customFilename?: CustomGetter<string>;
/**
*
*/
customThumbUrl?: CustomGetter<undefined>;
} }
export interface UploadEmits { export interface UploadEmits {

View File

@ -1,6 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { UploadFile } from 'ant-design-vue/es/upload/interface'; import type { UploadFile } from 'ant-design-vue/es/upload/interface';
import type { CustomGetter } from '#/components/upload/src/props';
import { h, ref } from 'vue'; import { h, ref } from 'vue';
import { Page } from '@vben/common-ui'; import { Page } from '@vben/common-ui';
@ -34,32 +36,40 @@ const showComponent = ref(true);
const { imageListOptions, currentImageListType } = useImageType(); const { imageListOptions, currentImageListType } = useImageType();
const { fileListOptions, currentFileListType } = useFileType(); const { fileListOptions, currentFileListType } = useFileType();
const customName: CustomGetter<string> = (cb) => {
if (cb.type === 'info') {
return `加上自定义前缀显示 - ${cb.response.originalName.toUpperCase()}`;
}
return `加上自定义前缀显示 - ${cb.response.fileName.toUpperCase()}`;
};
const customThumbnailUrl: CustomGetter<undefined> = () => {
return 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp';
};
</script> </script>
<template> <template>
<Page> <Page>
<div class="grid grid-cols-2 gap-4"> <div class="grid grid-cols-2 gap-4">
<Card title="单图片上传, 会绑定为string" size="small"> <Card title="单上传, 会绑定为string" size="small">
<ImageUpload v-model:value="singleImageId" /> <ImageUpload v-model:value="singleImageId" />
当前绑定值: {{ singleImageId }} 当前绑定值: {{ singleImageId }}
</Card>
<Card title="单文件上传, 会绑定为string" size="small"> <FileUpload class="mt-6" v-model:value="singleFileId" />
<FileUpload v-model:value="singleFileId" />
当前绑定值: {{ singleFileId }} 当前绑定值: {{ singleFileId }}
</Card> </Card>
<Card title="多图片上传, maxCount参数控制(开启深度监听)" size="small"> <Card title="多上传, maxCount参数控制(开启深度监听)" size="small">
<ImageUpload <ImageUpload
v-model:value="multipleImageId" v-model:value="multipleImageId"
:max-count="3" :max-count="3"
:deep-watch="true" :deep-watch="true"
/> />
当前绑定值: {{ multipleImageId }} 当前绑定值: {{ multipleImageId }}
</Card>
<Card title="多文件上传, maxCount参数控制(开启深度监听)" size="small">
<FileUpload <FileUpload
class="mt-6"
v-model:value="multipleFileId" v-model:value="multipleFileId"
:max-count="3" :max-count="3"
:deep-watch="true" :deep-watch="true"
@ -79,7 +89,7 @@ const { fileListOptions, currentFileListType } = useFileType();
:help-message="false" :help-message="false"
/> />
<ImageUpload <ImageUpload
class="mt-3" class="mt-6"
v-model:value="multipleImageId" v-model:value="multipleImageId"
:max-count="3" :max-count="3"
:preview="handlePreview" :preview="handlePreview"
@ -87,14 +97,14 @@ const { fileListOptions, currentFileListType } = useFileType();
/> />
</Card> </Card>
<Card title="文件拖拽上传" size="small"> <Card title="文件/图片拖拽上传" size="small">
<FileUpload <FileUpload
v-model:value="multipleFileId" v-model:value="multipleFileId"
:max-count="3" :max-count="3"
:enable-drag-upload="true" :enable-drag-upload="true"
/> />
<ImageUpload <ImageUpload
class="mt-3" class="mt-6"
v-model:value="multipleImageId" v-model:value="multipleImageId"
:enable-drag-upload="true" :enable-drag-upload="true"
:max-count="6" :max-count="6"
@ -104,7 +114,7 @@ const { fileListOptions, currentFileListType } = useFileType();
<Card title="禁用上传" size="small"> <Card title="禁用上传" size="small">
<ImageUpload :disabled="true" :max-count="3" :help-message="false" /> <ImageUpload :disabled="true" :max-count="3" :help-message="false" />
<FileUpload <FileUpload
class="mt-3" class="mt-6"
:disabled="true" :disabled="true"
:max-count="3" :max-count="3"
:help-message="false" :help-message="false"
@ -119,7 +129,9 @@ const { fileListOptions, currentFileListType } = useFileType();
accept="*" accept="*"
> >
<template #helpMessage="slotProps"> <template #helpMessage="slotProps">
<div>自定义helpMessage: {{ JSON.stringify(slotProps) }}</div> <div class="mt-2 font-semibold text-green-500">
自定义helpMessage: {{ JSON.stringify(slotProps) }}
</div>
</template> </template>
</FileUpload> </FileUpload>
</Card> </Card>
@ -130,6 +142,7 @@ const { fileListOptions, currentFileListType } = useFileType();
:accept-format="customAccept" :accept-format="customAccept"
/> />
<ImageUpload <ImageUpload
class="mt-6"
v-model:value="singleImageId" v-model:value="singleImageId"
accept-format="自定义显示允许的文件类型" accept-format="自定义显示允许的文件类型"
/> />
@ -171,6 +184,16 @@ const { fileListOptions, currentFileListType } = useFileType();
:list-type="currentFileListType" :list-type="currentFileListType"
/> />
</Card> </Card>
<Card title="自定义缩略图和文件名" size="small">
<FileUpload
v-model:value="multipleFileId"
:max-count="5"
list-type="picture"
:custom-filename="customName"
:custom-thumb-url="customThumbnailUrl"
/>
</Card>
</div> </div>
</Page> </Page>
</template> </template>