barneo-file-service
Version:
Комплексная библиотека Vue 3 для работы с файлами в приложениях Barneo. Предоставляет мощную функциональность для загрузки, управления и обработки файлов с валидацией, отслеживанием прогресса и поддержкой localStorage.
212 lines (175 loc) • 5.65 kB
text/typescript
import { ref, computed } from "vue";
import type {
FileUploadResponse,
FileUploadOptions,
AppName,
FileUploadState,
FileUploaderOptions,
} from "../types";
import { FileUploadService } from "../services/FileUploadService";
export function useFileUploader(options: FileUploaderOptions) {
const uploadService = new FileUploadService({
apiUrl: options.apiUrl,
appName: options.appName,
headers: options.headers,
timeout: options.timeout,
});
// Состояние загрузок
const uploads = ref<Map<string, FileUploadState>>(new Map());
const isUploading = ref(false);
const totalProgress = ref(0);
// Computed свойства
const pendingUploads = computed(() =>
Array.from(uploads.value.values()).filter(
(upload) => upload.status === "pending"
)
);
const uploadingFiles = computed(() =>
Array.from(uploads.value.values()).filter(
(upload) => upload.status === "uploading"
)
);
const completedUploads = computed(() =>
Array.from(uploads.value.values()).filter(
(upload) => upload.status === "success"
)
);
const failedUploads = computed(() =>
Array.from(uploads.value.values()).filter(
(upload) => upload.status === "error"
)
);
const hasUploads = computed(() => uploads.value.size > 0);
const hasErrors = computed(() => failedUploads.value.length > 0);
// Методы
const createUploadState = (file: File): FileUploadState => ({
id: generateId(),
file,
status: "pending",
progress: 0,
});
const uploadFile = async (file: File): Promise<FileUploadResponse[]> => {
const uploadState = createUploadState(file);
uploads.value.set(uploadState.id, uploadState);
try {
uploadState.status = "uploading";
uploadState.progress = 0;
isUploading.value = true;
// Принудительно обновляем Map для реактивности
uploads.value = new Map(uploads.value);
const response = await uploadService.uploadFile(file, {
appName: options.appName,
onProgress: (progress) => {
uploadState.progress = progress;
updateTotalProgress();
},
onError: (error) => {
uploadState.status = "error";
uploadState.error = error.message;
if (options.onError) {
options.onError(error);
}
},
});
uploadState.status = "success";
uploadState.response = response;
uploadState.progress = 100;
updateTotalProgress();
// Принудительно обновляем Map для реактивности
uploads.value = new Map(uploads.value);
return response;
} catch (error) {
uploadState.status = "error";
uploadState.error =
error instanceof Error ? error.message : "Unknown error occurred";
// Принудительно обновляем Map для реактивности
uploads.value = new Map(uploads.value);
throw error;
} finally {
isUploading.value = false;
}
};
const uploadFiles = async (files: File[]): Promise<FileUploadResponse[]> => {
try {
isUploading.value = true;
// Загружаем все файлы параллельно
const uploadPromises = files.map((file) => uploadFile(file));
const results = await Promise.all(uploadPromises);
return results.flat();
} finally {
isUploading.value = false;
}
};
const retryUpload = async (
uploadId: string
): Promise<FileUploadResponse[]> => {
const uploadState = uploads.value.get(uploadId);
if (!uploadState || uploadState.status !== "error") {
throw new Error("Upload not found or not in error state");
}
// Очищаем предыдущую ошибку
uploadState.error = undefined;
return await uploadFile(uploadState.file);
};
const removeUpload = (uploadId: string) => {
uploads.value.delete(uploadId);
updateTotalProgress();
};
const clearUploads = () => {
uploads.value.clear();
totalProgress.value = 0;
isUploading.value = false;
};
const clearCompletedUploads = () => {
for (const [id, upload] of uploads.value.entries()) {
if (upload.status === "success") {
uploads.value.delete(id);
}
}
updateTotalProgress();
};
const clearFailedUploads = () => {
for (const [id, upload] of uploads.value.entries()) {
if (upload.status === "error") {
uploads.value.delete(id);
}
}
updateTotalProgress();
};
const updateTotalProgress = () => {
if (uploads.value.size === 0) {
totalProgress.value = 0;
return;
}
const total = Array.from(uploads.value.values()).reduce((sum, upload) => {
return sum + upload.progress;
}, 0);
totalProgress.value = Math.round(total / uploads.value.size);
};
const generateId = (): string => {
return Math.random().toString(36).substr(2, 9);
};
return {
// Состояние
uploads,
isUploading,
totalProgress,
// Computed
pendingUploads,
uploadingFiles,
completedUploads,
failedUploads,
hasUploads,
hasErrors,
// Методы
uploadFile,
uploadFiles,
retryUpload,
removeUpload,
clearUploads,
clearCompletedUploads,
clearFailedUploads,
// Сервис
uploadService,
};
}