import { useEventListener, useFileDialog } from '@vueuse/core';
|
import { type Ref } from 'vue';
|
import type { Attach } from './useAttach';
|
import { convertFileSize } from '/@/utils/file';
|
|
export type UseUploadFileOptions = {
|
pastTarget: Ref<HTMLElement | null>;
|
attachFileList: Ref<Attach<UploadFile>[]>;
|
};
|
|
const compareFiles = (file1: File, file2: File) => {
|
if (file1.type !== file2.type) return false;
|
if (file1.name !== file2.name) return false;
|
if (file1.size !== file2.size) return false;
|
if (file1.lastModified !== file2.lastModified) return false;
|
return true;
|
};
|
|
export type FileType =
|
| 'dot'
|
| 'doc'
|
| 'docx'
|
| 'pdf'
|
| 'md'
|
| 'xls'
|
| 'xlsx'
|
| 'png'
|
| 'jpg'
|
| 'jpeg'
|
| 'gif'
|
| 'json'
|
| 'txt'
|
| 'text'
|
| 'csv';
|
export type FileGroupType = 'word' | 'pdf' | 'excel' | 'image' | 'json' | 'md' | 'csv' | 'txt';
|
export type UploadFile = {
|
name: string;
|
type: FileType;
|
groupType: FileGroupType;
|
size: string;
|
file: File;
|
|
icon?: string;
|
iconClass?: string;
|
previewUrl?: string;
|
};
|
|
export const getFileGroupType = (type: FileType): FileGroupType => {
|
switch (type) {
|
case 'dot':
|
case 'doc':
|
case 'docx':
|
return 'word';
|
case 'csv':
|
return 'csv';
|
case 'txt':
|
case 'text':
|
return 'txt';
|
|
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';
|
}
|
};
|
|
export const getIconByGroupType = (groupType: FileGroupType) => {
|
switch (groupType) {
|
case 'word':
|
return 'word';
|
case 'pdf':
|
return 'pdf';
|
case 'excel':
|
return 'excel';
|
case 'csv':
|
return 'csv';
|
case 'txt':
|
return 'txt';
|
|
case 'json':
|
return 'json';
|
case 'md':
|
return 'markdown';
|
default:
|
return 'unknownfile';
|
}
|
};
|
|
export 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 'csv':
|
return 'text-green-500';
|
case 'txt':
|
return 'text-cyan-400';
|
|
case 'json':
|
return 'text-yellow-400';
|
case 'md':
|
return 'text-gray-400';
|
default:
|
return '';
|
}
|
};
|
// const supportFileType = ['doc', 'docx', 'md', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif', 'json', 'pdf','csv', 'txt'];
|
const supportFileType = ['csv', 'txt', 'text', 'dot', 'doc', 'docx', 'pdf'];
|
|
export const getFileSuffix = (name: string): FileType => {
|
if (!name) return 'txt';
|
const suffix = name.split('.').pop() as FileType;
|
return suffix;
|
};
|
export const useUploadFile = (options: UseUploadFileOptions) => {
|
const { attachFileList } = options;
|
const parseFiles = (files: FileList) => {
|
const filterFiles: UploadFile[] = [];
|
for (const file of files) {
|
if (attachFileList.value.find((item) => compareFiles(item.model.file, file))) {
|
continue;
|
}
|
const suffix = getFileSuffix(file.name);
|
if (supportFileType.includes(suffix)) {
|
const groupType = getFileGroupType(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.map(
|
(item) =>
|
({
|
get title() {
|
return item.name;
|
},
|
type: 'file',
|
model: item,
|
get icon() {
|
return item.icon;
|
},
|
get iconClass() {
|
return item.iconClass;
|
},
|
} as Attach<UploadFile>)
|
)
|
);
|
};
|
|
/**
|
* 解析粘贴板文件
|
* @param event
|
*/
|
const pasteUpload = (event) => {
|
event.stopPropagation();
|
const data = event.clipboardData || window.clipboardData;
|
const files = data.files as FileList;
|
parseFiles(files);
|
};
|
|
const {
|
files,
|
open: openFileDialog,
|
reset: resetOpenFileDialog,
|
onChange: onPickFileChange,
|
} = useFileDialog({
|
accept:
|
'text/csv,text/plain,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document', // Accept csv, txt, doc, docx and pdf files
|
reset: true,
|
});
|
|
const openFileClick = () => {
|
openFileDialog();
|
};
|
onPickFileChange((files) => {
|
if (!files) return;
|
parseFiles(files);
|
});
|
const deleteUploadFile = (file: UploadFile) => {
|
if (file.previewUrl) {
|
URL.revokeObjectURL(file.previewUrl);
|
}
|
};
|
|
useEventListener(options.pastTarget, 'paste', pasteUpload);
|
|
return {
|
attachFileList,
|
deleteUploadFile,
|
openFileClick,
|
};
|
};
|