19 changed files with 847 additions and 21 deletions
@ -0,0 +1,5 @@ |
|||
export interface UploadApiResult { |
|||
message: string; |
|||
code: number; |
|||
url: string; |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
import { UploadApiResult } from './model/uploadModel'; |
|||
import { defHttp } from '/@/utils/http/axios'; |
|||
import { UploadFileParams } from '/@/utils/http/axios/types'; |
|||
|
|||
enum Api { |
|||
UPLOAD_URL = '/upload', |
|||
} |
|||
|
|||
/** |
|||
* @description: 上传接口 |
|||
*/ |
|||
export function uploadApi( |
|||
params: UploadFileParams, |
|||
onUploadProgress: (progressEvent: ProgressEvent) => void |
|||
) { |
|||
return defHttp.uploadFile<UploadApiResult>( |
|||
{ |
|||
url: Api.UPLOAD_URL, |
|||
onUploadProgress, |
|||
}, |
|||
params |
|||
); |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export { default as UploadContainer } from './src/UploadContainer.vue'; |
|||
// export * from './src/types';
|
|||
@ -0,0 +1,29 @@ |
|||
<template> |
|||
<span> |
|||
<img v-if="fileUrl" :src="fileUrl" /> |
|||
<span v-else>{{ fileType }}</span> |
|||
</span> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent } from 'vue'; |
|||
|
|||
export default defineComponent({ |
|||
props: { |
|||
fileUrl: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
fileType: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
fileName: { |
|||
type: String, |
|||
default: '', |
|||
}, |
|||
}, |
|||
setup() { |
|||
return {}; |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,62 @@ |
|||
<template> |
|||
<div> |
|||
<a-button-group> |
|||
<a-button type="primary" @click="openUploadModal">上传</a-button> |
|||
<a-button @click="openPreviewModal"> |
|||
<Icon icon="ant-design:eye-outlined" /> |
|||
</a-button> |
|||
</a-button-group> |
|||
<UploadModal v-bind="$props" @register="registerUploadModal" @change="handleChange" /> |
|||
<UploadPreviewModal |
|||
:value="fileListRef" |
|||
@register="registerPreviewModal" |
|||
@change="handlePreviewChange" |
|||
/> |
|||
</div> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent, ref, watch, unref } from 'vue'; |
|||
import { useModal } from '/@/components/Modal'; |
|||
import UploadModal from './UploadModal.vue'; |
|||
import { uploadContainerProps } from './props'; |
|||
import UploadPreviewModal from './UploadPreviewModal.vue'; |
|||
import Icon from '/@/components/Icon/index'; |
|||
export default defineComponent({ |
|||
components: { UploadModal, UploadPreviewModal, Icon }, |
|||
props: uploadContainerProps, |
|||
setup(props, { emit }) { |
|||
// 上传modal |
|||
const [registerUploadModal, { openModal: openUploadModal }] = useModal(); |
|||
// 预览modal |
|||
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal(); |
|||
|
|||
const fileListRef = ref<string[]>([]); |
|||
watch( |
|||
() => props.value, |
|||
(value) => { |
|||
fileListRef.value = [...(value || [])]; |
|||
}, |
|||
{ immediate: true } |
|||
); |
|||
// 上传modal保存操作 |
|||
function handleChange(urls: string[]) { |
|||
fileListRef.value = [...unref(fileListRef), ...(urls || [])]; |
|||
emit('change', fileListRef.value); |
|||
} |
|||
// 预览modal保存操作 |
|||
function handlePreviewChange(urls: string[]) { |
|||
fileListRef.value = [...(urls || [])]; |
|||
emit('change', fileListRef.value); |
|||
} |
|||
return { |
|||
registerUploadModal, |
|||
openUploadModal, |
|||
handleChange, |
|||
handlePreviewChange, |
|||
registerPreviewModal, |
|||
openPreviewModal, |
|||
fileListRef, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,244 @@ |
|||
<template> |
|||
<BasicModal |
|||
v-bind="$attrs" |
|||
@register="register" |
|||
@ok="handleOk" |
|||
:closeFunc="handleCloseFunc" |
|||
:maskClosable="false" |
|||
width="800px" |
|||
title="上传组件" |
|||
wrapClassName="upload-modal" |
|||
:okButtonProps="{ disabled: isUploadingRef }" |
|||
:cancelButtonProps="{ disabled: isUploadingRef }" |
|||
> |
|||
<template #centerdFooter> |
|||
<a-button @click="handleStartUpload" color="success" :loading="isUploadingRef"> |
|||
{{ isUploadingRef ? '上传中' : '开始上传' }} |
|||
</a-button> |
|||
</template> |
|||
<Upload :accept="getStringAccept" :multiple="multiple" :before-upload="beforeUpload"> |
|||
<a-button type="primary"> 选择文件 </a-button> |
|||
<span class="px-2">{{ getHelpText }}</span> |
|||
</Upload> |
|||
<BasicTable @register="registerTable" :dataSource="fileListRef" /> |
|||
</BasicModal> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent, reactive, ref, toRef, unref } from 'vue'; |
|||
import { Upload } from 'ant-design-vue'; |
|||
import { BasicModal, useModalInner } from '/@/components/Modal'; |
|||
import { BasicTable, useTable } from '/@/components/Table'; |
|||
// hooks |
|||
import { useUploadType } from './useUpload'; |
|||
import { useMessage } from '/@/hooks/web/useMessage'; |
|||
// types |
|||
import { FileItem, UploadResultStatus } from './types'; |
|||
import { basicProps } from './props'; |
|||
import { createTableColumns, createActionColumn } from './data'; |
|||
// utils |
|||
import { checkFileType, checkImgType, getBase64WithFile } from './utils'; |
|||
import { buildUUID } from '/@/utils/uuid'; |
|||
import { createImgPreview } from '/@/components/Preview/index'; |
|||
import { uploadApi } from '/@/api/demo/upload'; |
|||
|
|||
export default defineComponent({ |
|||
components: { BasicModal, Upload, BasicTable }, |
|||
props: basicProps, |
|||
setup(props, { emit }) { |
|||
const [register, { closeModal }] = useModalInner(); |
|||
const { getAccept, getStringAccept, getHelpText } = useUploadType({ |
|||
acceptRef: toRef(props, 'accept'), |
|||
helpTextRef: toRef(props, 'helpText'), |
|||
maxNumberRef: toRef(props, 'maxNumber'), |
|||
maxSizeRef: toRef(props, 'maxSize'), |
|||
}); |
|||
|
|||
const fileListRef = ref<FileItem[]>([]); |
|||
const state = reactive<{ fileList: FileItem[] }>({ fileList: [] }); |
|||
const { createMessage } = useMessage(); |
|||
// 上传前校验 |
|||
function beforeUpload(file: File) { |
|||
const { size, name } = file; |
|||
const { maxSize } = props; |
|||
const accept = unref(getAccept); |
|||
|
|||
// 设置最大值,则判断 |
|||
if (maxSize && file.size / 1024 / 1024 >= maxSize) { |
|||
createMessage.error(`只能上传不超过${maxSize}MB的文件!`); |
|||
return false; |
|||
} |
|||
|
|||
// 设置类型,则判断 |
|||
if (accept.length > 0 && !checkFileType(file, accept)) { |
|||
createMessage.error!(`只能上传${accept.join(',')}格式文件`); |
|||
return false; |
|||
} |
|||
// 生成图片缩略图 |
|||
if (checkImgType(file)) { |
|||
// beforeUpload,如果异步会调用自带上传方法 |
|||
// file.thumbUrl = await getBase64(file); |
|||
getBase64WithFile(file).then(({ result: thumbUrl }) => { |
|||
fileListRef.value = [ |
|||
...unref(fileListRef), |
|||
{ |
|||
uuid: buildUUID(), |
|||
file, |
|||
thumbUrl, |
|||
size, |
|||
name, |
|||
percent: 0, |
|||
type: name.split('.').pop(), |
|||
}, |
|||
]; |
|||
}); |
|||
} else { |
|||
fileListRef.value = [ |
|||
...unref(fileListRef), |
|||
{ |
|||
uuid: buildUUID(), |
|||
|
|||
file, |
|||
size, |
|||
name, |
|||
percent: 0, |
|||
type: name.split('.').pop(), |
|||
}, |
|||
]; |
|||
} |
|||
return false; |
|||
} |
|||
// 删除 |
|||
function handleRemove(record: FileItem) { |
|||
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid); |
|||
index !== -1 && fileListRef.value.splice(index, 1); |
|||
} |
|||
// 预览 |
|||
function handlePreview(record: FileItem) { |
|||
const { thumbUrl = '' } = record; |
|||
createImgPreview({ |
|||
imageList: [thumbUrl], |
|||
}); |
|||
} |
|||
const [registerTable] = useTable({ |
|||
columns: createTableColumns(), |
|||
actionColumn: createActionColumn(handleRemove, handlePreview), |
|||
pagination: false, |
|||
}); |
|||
// 是否正在上传 |
|||
const isUploadingRef = ref(false); |
|||
async function uploadApiByItem(item: FileItem) { |
|||
try { |
|||
item.status = UploadResultStatus.UPLOADING; |
|||
|
|||
const { data } = await uploadApi( |
|||
{ |
|||
file: item.file, |
|||
}, |
|||
function onUploadProgress(progressEvent: ProgressEvent) { |
|||
const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0; |
|||
item.percent = complete; |
|||
} |
|||
); |
|||
item.status = UploadResultStatus.SUCCESS; |
|||
item.responseData = data; |
|||
return { |
|||
success: true, |
|||
error: null, |
|||
}; |
|||
} catch (e) { |
|||
console.log(e); |
|||
item.status = UploadResultStatus.ERROR; |
|||
return { |
|||
success: false, |
|||
error: e, |
|||
}; |
|||
} |
|||
} |
|||
// 点击开始上传 |
|||
async function handleStartUpload() { |
|||
try { |
|||
isUploadingRef.value = true; |
|||
const data = await Promise.all( |
|||
unref(fileListRef).map((item) => { |
|||
return uploadApiByItem(item); |
|||
}) |
|||
); |
|||
isUploadingRef.value = false; |
|||
// 生产环境:抛出错误 |
|||
const errorList = data.filter((item) => !item.success); |
|||
if (errorList.length > 0) { |
|||
throw errorList; |
|||
} |
|||
} catch (e) { |
|||
isUploadingRef.value = false; |
|||
throw e; |
|||
} |
|||
} |
|||
// 点击保存 |
|||
function handleOk() { |
|||
// TODO: 没起作用:okButtonProps={{ disabled: state.isUploading }} |
|||
if (isUploadingRef.value) { |
|||
createMessage.warning('请等待文件上传后,保存'); |
|||
return; |
|||
} |
|||
const fileList: string[] = []; |
|||
|
|||
for (const item of fileListRef.value) { |
|||
const { status, responseData } = item; |
|||
if (status === UploadResultStatus.SUCCESS && responseData) { |
|||
fileList.push(responseData.url); |
|||
} |
|||
} |
|||
|
|||
// 存在一个上传成功的即可保存 |
|||
|
|||
if (fileList.length <= 0) { |
|||
createMessage.warning('没有上传成功的文件,无法保存'); |
|||
return; |
|||
} |
|||
console.log(fileList); |
|||
emit('change', fileList); |
|||
fileListRef.value = []; |
|||
closeModal(); |
|||
} |
|||
// 点击关闭:则所有操作不保存,包括上传的 |
|||
function handleCloseFunc() { |
|||
if (!isUploadingRef.value) { |
|||
fileListRef.value = []; |
|||
return true; |
|||
} else { |
|||
createMessage.warning('请等待文件上传结束后操作'); |
|||
return false; |
|||
} |
|||
} |
|||
return { |
|||
register, |
|||
closeModal, |
|||
getHelpText, |
|||
getStringAccept, |
|||
beforeUpload, |
|||
registerTable, |
|||
fileListRef, |
|||
state, |
|||
isUploadingRef, |
|||
handleStartUpload, |
|||
handleOk, |
|||
handleCloseFunc, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="less"> |
|||
// /deep/ .ant-upload-list { |
|||
// display: none; |
|||
// } |
|||
.upload-modal { |
|||
.ant-upload-list { |
|||
display: none; |
|||
} |
|||
|
|||
.ant-table-wrapper .ant-spin-nested-loading { |
|||
padding: 0; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,93 @@ |
|||
<template> |
|||
<BasicModal |
|||
wrapClassName="upload-preview-modal" |
|||
v-bind="$attrs" |
|||
width="800px" |
|||
@register="register" |
|||
title="预览" |
|||
:showOkBtn="false" |
|||
> |
|||
<BasicTable @register="registerTable" :dataSource="fileListRef" /> |
|||
</BasicModal> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent, watch, ref, unref } from 'vue'; |
|||
import { BasicTable, useTable } from '/@/components/Table'; |
|||
import { createPreviewColumns, createPreviewActionColumn } from './data'; |
|||
import { BasicModal, useModalInner } from '/@/components/Modal'; |
|||
import { priviewProps } from './props'; |
|||
import { PreviewFileItem } from './types'; |
|||
import { createImgPreview } from '/@/components/Preview/index'; |
|||
import { downloadByUrl } from '/@/utils/file/FileDownload'; |
|||
|
|||
export default defineComponent({ |
|||
components: { BasicModal, BasicTable }, |
|||
props: priviewProps, |
|||
setup(props, { emit }) { |
|||
const [register, { closeModal }] = useModalInner(); |
|||
const fileListRef = ref<PreviewFileItem[]>([]); |
|||
watch( |
|||
() => props.value, |
|||
(value) => { |
|||
fileListRef.value = []; |
|||
value.forEach((item) => { |
|||
fileListRef.value = [ |
|||
...unref(fileListRef), |
|||
{ |
|||
url: item, |
|||
type: item.split('.').pop() || '', |
|||
name: item.split('/').pop() || '', |
|||
}, |
|||
]; |
|||
}); |
|||
}, |
|||
{ immediate: true } |
|||
); |
|||
// 删除 |
|||
function handleRemove(record: PreviewFileItem) { |
|||
const index = fileListRef.value.findIndex((item) => item.url === record.url); |
|||
if (index !== -1) { |
|||
fileListRef.value.splice(index, 1); |
|||
emit( |
|||
'change', |
|||
fileListRef.value.map((item) => item.url) |
|||
); |
|||
} |
|||
} |
|||
// 预览 |
|||
function handlePreview(record: PreviewFileItem) { |
|||
const { url = '' } = record; |
|||
createImgPreview({ |
|||
imageList: [url], |
|||
}); |
|||
} |
|||
// 下载 |
|||
function handleDownload(record: PreviewFileItem) { |
|||
const { url = '' } = record; |
|||
downloadByUrl({ url }); |
|||
} |
|||
const [registerTable] = useTable({ |
|||
columns: createPreviewColumns(), |
|||
pagination: false, |
|||
actionColumn: createPreviewActionColumn({ handleRemove, handlePreview, handleDownload }), |
|||
}); |
|||
return { |
|||
register, |
|||
closeModal, |
|||
fileListRef, |
|||
registerTable, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="less"> |
|||
.upload-preview-modal { |
|||
.ant-upload-list { |
|||
display: none; |
|||
} |
|||
|
|||
.ant-table-wrapper .ant-spin-nested-loading { |
|||
padding: 0; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,159 @@ |
|||
// import { BasicColumn, TableAction, ActionItem } from '@/components/table';
|
|||
import { checkImgType, isImgTypeByName } from './utils'; |
|||
// import ThumnUrl from './ThumbUrl.vue';
|
|||
import { Progress } from 'ant-design-vue'; |
|||
import { FileItem, PreviewFileItem, UploadResultStatus } from './types'; |
|||
// import { ElecArchivesSaveResult } from '@/api/biz/file/model/fileModel';
|
|||
// import { quryFile } from '@/api/biz/file/file';
|
|||
import { BasicColumn, ActionItem, TableAction } from '/@/components/Table/index'; |
|||
|
|||
// 文件上传列表
|
|||
export function createTableColumns(): BasicColumn[] { |
|||
return [ |
|||
{ |
|||
dataIndex: 'thumbUrl', |
|||
title: '图例', |
|||
width: 100, |
|||
customRender: ({ record }) => { |
|||
const { thumbUrl, type } = (record as FileItem) || {}; |
|||
return <span>{thumbUrl ? <img src={thumbUrl} style={{ width: '50px' }} /> : type}</span>; |
|||
// return <ThumnUrl fileUrl={thumbUrl} fileType={type} fileName={type} />;
|
|||
}, |
|||
}, |
|||
{ |
|||
dataIndex: 'name', |
|||
title: '文件名', |
|||
align: 'left', |
|||
customRender: ({ text, record }) => { |
|||
const { percent, status: uploadStatus } = (record as FileItem) || {}; |
|||
let status = 'normal'; |
|||
if (uploadStatus === UploadResultStatus.ERROR) { |
|||
status = 'exception'; |
|||
} else if (uploadStatus === UploadResultStatus.UPLOADING) { |
|||
status = 'active'; |
|||
} else if (uploadStatus === UploadResultStatus.SUCCESS) { |
|||
status = 'success'; |
|||
} |
|||
return ( |
|||
<span> |
|||
<p class="ellipsis mb-1" title={text}> |
|||
{text} |
|||
</p> |
|||
<Progress percent={percent} size="small" status={status} /> |
|||
</span> |
|||
); |
|||
}, |
|||
}, |
|||
{ |
|||
dataIndex: 'size', |
|||
title: '文件大小', |
|||
width: 100, |
|||
customRender: ({ text = 0 }) => { |
|||
return text && (text / 1024).toFixed(2) + 'KB'; |
|||
}, |
|||
}, |
|||
// {
|
|||
// dataIndex: 'type',
|
|||
// title: '文件类型',
|
|||
// width: 100,
|
|||
// },
|
|||
{ |
|||
dataIndex: 'status', |
|||
title: '状态', |
|||
width: 100, |
|||
customRender: ({ text }) => { |
|||
if (text === UploadResultStatus.SUCCESS) { |
|||
return '上传成功'; |
|||
} else if (text === UploadResultStatus.ERROR) { |
|||
return '上传失败'; |
|||
} else if (text === UploadResultStatus.UPLOADING) { |
|||
return '上传中'; |
|||
} |
|||
|
|||
return text; |
|||
}, |
|||
}, |
|||
]; |
|||
} |
|||
export function createActionColumn(handleRemove: Function, handlePreview: Function): BasicColumn { |
|||
return { |
|||
width: 120, |
|||
title: '操作', |
|||
dataIndex: 'action', |
|||
fixed: false, |
|||
customRender: ({ record }) => { |
|||
const actions: ActionItem[] = [ |
|||
{ |
|||
label: '删除', |
|||
onClick: handleRemove.bind(null, record), |
|||
}, |
|||
]; |
|||
if (checkImgType(record)) { |
|||
actions.unshift({ |
|||
label: '预览', |
|||
onClick: handlePreview.bind(null, record), |
|||
}); |
|||
} |
|||
return <TableAction actions={actions} />; |
|||
}, |
|||
}; |
|||
} |
|||
// 文件预览列表
|
|||
export function createPreviewColumns(): BasicColumn[] { |
|||
return [ |
|||
{ |
|||
dataIndex: 'url', |
|||
title: '图例', |
|||
width: 100, |
|||
customRender: ({ record }) => { |
|||
const { url, type } = (record as PreviewFileItem) || {}; |
|||
return ( |
|||
<span>{isImgTypeByName(url) ? <img src={url} style={{ width: '50px' }} /> : type}</span> |
|||
); |
|||
}, |
|||
}, |
|||
{ |
|||
dataIndex: 'name', |
|||
title: '文件名', |
|||
align: 'left', |
|||
}, |
|||
]; |
|||
} |
|||
|
|||
export function createPreviewActionColumn({ |
|||
handleRemove, |
|||
handlePreview, |
|||
handleDownload, |
|||
}: { |
|||
handleRemove: Function; |
|||
handlePreview: Function; |
|||
handleDownload: Function; |
|||
}): BasicColumn { |
|||
return { |
|||
width: 160, |
|||
title: '操作', |
|||
dataIndex: 'action', |
|||
fixed: false, |
|||
customRender: ({ record }) => { |
|||
const { url } = (record as PreviewFileItem) || {}; |
|||
|
|||
const actions: ActionItem[] = [ |
|||
{ |
|||
label: '删除', |
|||
onClick: handleRemove.bind(null, record), |
|||
}, |
|||
{ |
|||
label: '下载', |
|||
onClick: handleDownload.bind(null, record), |
|||
}, |
|||
]; |
|||
if (isImgTypeByName(url)) { |
|||
actions.unshift({ |
|||
label: '预览', |
|||
onClick: handlePreview.bind(null, record), |
|||
}); |
|||
} |
|||
return <TableAction actions={actions} />; |
|||
}, |
|||
}; |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
import type { PropType } from 'vue'; |
|||
|
|||
export const basicProps = { |
|||
helpText: { |
|||
type: String as PropType<string>, |
|||
default: '', |
|||
}, |
|||
// 文件最大多少MB
|
|||
maxSize: { |
|||
type: Number as PropType<number>, |
|||
default: 2, |
|||
}, |
|||
// 最大数量的文件,0不限制
|
|||
maxNumber: { |
|||
type: Number as PropType<number>, |
|||
default: 0, |
|||
}, |
|||
// 根据后缀,或者其他
|
|||
accept: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
multiple: { |
|||
type: Boolean, |
|||
default: true, |
|||
}, |
|||
}; |
|||
|
|||
export const uploadContainerProps = { |
|||
value: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
...basicProps, |
|||
}; |
|||
|
|||
export const priviewProps = { |
|||
value: { |
|||
type: Array as PropType<string[]>, |
|||
default: () => [], |
|||
}, |
|||
}; |
|||
@ -0,0 +1,25 @@ |
|||
import { UploadApiResult } from '/@/api/demo/model/uploadModel'; |
|||
|
|||
export enum UploadResultStatus { |
|||
SUCCESS = 'success', |
|||
ERROR = 'error', |
|||
UPLOADING = 'uploading', |
|||
} |
|||
|
|||
export interface FileItem { |
|||
thumbUrl?: string; |
|||
name: string; |
|||
size: string | number; |
|||
type?: string; |
|||
percent: number; |
|||
file: File; |
|||
status?: UploadResultStatus; |
|||
responseData?: UploadApiResult; |
|||
uuid: string; |
|||
} |
|||
|
|||
export interface PreviewFileItem { |
|||
url: string; |
|||
name: string; |
|||
type: string; |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
import { Ref, unref, computed } from 'vue'; |
|||
|
|||
export function useUploadType({ |
|||
acceptRef, |
|||
// uploadTypeRef,
|
|||
helpTextRef, |
|||
maxNumberRef, |
|||
maxSizeRef, |
|||
}: { |
|||
acceptRef: Ref<string[]>; |
|||
// uploadTypeRef: Ref<UploadTypeEnum>;
|
|||
helpTextRef: Ref<string>; |
|||
maxNumberRef: Ref<number>; |
|||
maxSizeRef: Ref<number>; |
|||
}) { |
|||
// 文件类型限制
|
|||
const getAccept = computed(() => { |
|||
// const uploadType = unref(uploadTypeRef);
|
|||
const accept = unref(acceptRef); |
|||
if (accept && accept.length > 0) { |
|||
return accept; |
|||
} |
|||
return []; |
|||
}); |
|||
const getStringAccept = computed(() => { |
|||
return unref(getAccept) |
|||
.map((item) => `.${item}`) |
|||
.join(','); |
|||
}); |
|||
// 支持jpg、jpeg、png格式,不超过2M,最多可选择10张图片,。
|
|||
const getHelpText = computed(() => { |
|||
const helpText = unref(helpTextRef); |
|||
if (helpText) { |
|||
return helpText; |
|||
} |
|||
const helpTexts: string[] = []; |
|||
|
|||
const accept = unref(acceptRef); |
|||
if (accept.length > 0) { |
|||
helpTexts.push(`支持${accept.join(',')}格式`); |
|||
} |
|||
|
|||
const maxSize = unref(maxSizeRef); |
|||
if (maxSize) { |
|||
helpTexts.push(`不超过${maxSize}MB`); |
|||
} |
|||
|
|||
const maxNumber = unref(maxNumberRef); |
|||
if (maxNumber) { |
|||
helpTexts.push(`最多可选择${maxNumber}个文件`); |
|||
} |
|||
return helpTexts.join(','); |
|||
}); |
|||
return { getAccept, getStringAccept, getHelpText }; |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
export function checkFileType(file: File, accepts: string[]) { |
|||
const newTypes = accepts.join('|'); |
|||
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
|
|||
const reg = new RegExp('\\.(' + newTypes + ')$', 'i'); |
|||
|
|||
if (!reg.test(file.name)) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
} |
|||
export function checkImgType(file: File) { |
|||
return /\.(jpg|jpeg|png|gif)$/i.test(file.name); |
|||
} |
|||
export function isImgTypeByName(name: string) { |
|||
return /\.(jpg|jpeg|png|gif)$/i.test(name); |
|||
} |
|||
export function getBase64WithFile(file: File) { |
|||
return new Promise<{ |
|||
result: string; |
|||
file: File; |
|||
}>((resolve, reject) => { |
|||
const reader = new FileReader(); |
|||
reader.readAsDataURL(file); |
|||
reader.onload = () => resolve({ result: reader.result as string, file }); |
|||
reader.onerror = (error) => reject(error); |
|||
}); |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<template> |
|||
<div class="p-4"> |
|||
<UploadContainer :maxSize="5" /> |
|||
</div> |
|||
</template> |
|||
<script lang="ts"> |
|||
import { defineComponent } from 'vue'; |
|||
import { UploadContainer } from '/@/components/Upload/index'; |
|||
|
|||
// import { Alert } from 'ant-design-vue'; |
|||
export default defineComponent({ |
|||
components: { UploadContainer }, |
|||
setup() { |
|||
return {}; |
|||
}, |
|||
}); |
|||
</script> |
|||
Loading…
Reference in new issue