import { useEventListener, useFileDialog } from '@vueuse/core';
|
import { ref, type Ref } from 'vue';
|
import { convertFileSize } from '/@/utils/file';
|
|
export type UseUploadFileOptions = {
|
pastTarget: Ref<HTMLElement | null>;
|
};
|
|
export type FileType = 'doc' | 'docx' | 'pdf' | 'md' | 'xls' | 'xlsx' | 'png' | 'jpg' | 'jpeg' | 'gif' | 'json';
|
export type FileGroupType = 'word' | 'pdf' | 'excel' | 'image' | 'json' | 'md';
|
export type UploadFile = {
|
name: string;
|
type: FileType;
|
groupType: FileGroupType;
|
size: string;
|
file: File;
|
icon?: string;
|
iconClass?: string;
|
previewUrl?: string;
|
};
|
|
const getGroupType = (type: FileType): FileGroupType => {
|
switch (type) {
|
case 'doc':
|
case 'docx':
|
return 'word';
|
|
case 'md':
|
return 'md';
|
case 'pdf':
|
return 'pdf';
|
case 'xls':
|
case 'xlsx':
|
return 'excel';
|
case 'png':
|
case 'jpg':
|
case 'jpeg':
|
case 'gif':
|
return 'image';
|
case 'json':
|
return 'json';
|
default:
|
return 'md';
|
}
|
};
|
|
const getIconByGroupType = (groupType: FileGroupType) => {
|
switch (groupType) {
|
case 'word':
|
return 'word';
|
case 'pdf':
|
return 'pdf';
|
case 'excel':
|
return 'excel';
|
|
case 'json':
|
return 'json';
|
case 'md':
|
return 'markdown';
|
default:
|
return 'unknownfile';
|
}
|
};
|
|
const getIconClassByGroupType = (groupType: FileGroupType) => {
|
switch (groupType) {
|
case 'word':
|
return 'text-blue-400';
|
case 'pdf':
|
return 'text-red-400';
|
case 'excel':
|
return 'text-green-400';
|
|
case 'json':
|
return 'text-yellow-400';
|
case 'md':
|
return 'text-gray-400';
|
default:
|
return '';
|
}
|
};
|
|
export const useUploadFile = (options: UseUploadFileOptions) => {
|
const supportFileType = ['doc', 'docx', 'md', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif', 'json', 'pdf'];
|
const attachFileList = ref<UploadFile[]>([]);
|
|
const parseFiles = (files:FileList) => {
|
const filterFiles: UploadFile[] = [];
|
for (const file of files) {
|
const suffix = file.name.split('.').pop() as FileType;
|
if (supportFileType.includes(suffix)) {
|
const groupType = getGroupType(suffix);
|
const uploadFile: UploadFile = {
|
type: suffix,
|
groupType: groupType,
|
file,
|
get name() {
|
return this.file.name;
|
},
|
get size() {
|
return convertFileSize(this.file.size);
|
},
|
};
|
|
// Generate preview URL for image files
|
if (groupType === 'image') {
|
uploadFile.previewUrl = URL.createObjectURL(file);
|
} else {
|
uploadFile.icon = getIconByGroupType(groupType);
|
uploadFile.iconClass = getIconClassByGroupType(groupType);
|
}
|
|
filterFiles.push(uploadFile);
|
}
|
}
|
attachFileList.value.push(...filterFiles);
|
}
|
|
/**
|
* 解析粘贴板文件
|
* @param event
|
*/
|
const pasteUpload = (event) => {
|
event.stopPropagation();
|
const data = event.clipboardData || window.clipboardData;
|
const files = data.files as FileList;
|
parseFiles(files)
|
};
|
|
const clearFileList = () => {
|
attachFileList.value = [];
|
};
|
const {
|
files,
|
open:openFileDialog,
|
reset:resetOpenFileDialog,
|
onChange: onPickFileChange,
|
} = useFileDialog({
|
accept:
|
'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/markdown,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,image/png,image/jpeg,image/gif,application/json,application/pdf', // Set to accept only image files
|
reset:true
|
});
|
|
|
const openFileClick = () =>{
|
openFileDialog();
|
}
|
onPickFileChange((files) => {
|
if(!files) return;
|
parseFiles(files)
|
});
|
const deleteIndexFile = (index) => {
|
const file = attachFileList.value[index];
|
// Revoke object URL for image files
|
if (file.previewUrl) {
|
URL.revokeObjectURL(file.previewUrl);
|
}
|
attachFileList.value.splice(index, 1);
|
};
|
|
useEventListener(options.pastTarget, 'paste', pasteUpload);
|
|
return {
|
attachFileList,
|
clearFileList,
|
deleteIndexFile,
|
openFileClick
|
};
|
};
|