2025-03-28 13:50:14 +08:00
|
|
|
import { useEffect, useMemo } from "react";
|
2025-03-03 17:54:00 +08:00
|
|
|
import { filesize } from "filesize";
|
|
|
|
|
import { X } from "lucide-react";
|
2025-03-28 13:50:14 +08:00
|
|
|
import { useAsyncEffect } from "ahooks";
|
|
|
|
|
import { useTranslation } from "react-i18next";
|
2025-03-03 17:54:00 +08:00
|
|
|
|
2025-03-17 16:24:18 +08:00
|
|
|
import { useChatStore } from "@/stores/chatStore";
|
|
|
|
|
import { isImage } from "@/utils";
|
2025-03-28 13:50:14 +08:00
|
|
|
import { useConnectStore } from "@/stores/connectStore";
|
|
|
|
|
import { deleteAttachment, uploadAttachment } from "@/api/attachment";
|
|
|
|
|
import FileIcon from "../Common/Icons/FileIcon";
|
2025-03-17 16:24:18 +08:00
|
|
|
|
|
|
|
|
interface FileListProps {
|
2025-03-28 13:50:14 +08:00
|
|
|
sessionId: string;
|
2025-03-17 16:24:18 +08:00
|
|
|
getFileUrl: (path: string) => string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-28 13:50:14 +08:00
|
|
|
const FileList = (props: FileListProps) => {
|
|
|
|
|
const { sessionId } = props;
|
|
|
|
|
const { t } = useTranslation();
|
2025-03-03 17:54:00 +08:00
|
|
|
const uploadFiles = useChatStore((state) => state.uploadFiles);
|
|
|
|
|
const setUploadFiles = useChatStore((state) => state.setUploadFiles);
|
2025-03-28 13:50:14 +08:00
|
|
|
const currentService = useConnectStore((state) => state.currentService);
|
2025-03-03 17:54:00 +08:00
|
|
|
|
2025-03-28 13:50:14 +08:00
|
|
|
const serverId = useMemo(() => {
|
|
|
|
|
return currentService.id;
|
|
|
|
|
}, [currentService]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
return () => {
|
|
|
|
|
setUploadFiles([]);
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useAsyncEffect(async () => {
|
|
|
|
|
if (uploadFiles.length === 0) return;
|
|
|
|
|
|
|
|
|
|
for await (const item of uploadFiles) {
|
|
|
|
|
const { uploaded, path } = item;
|
|
|
|
|
|
|
|
|
|
if (uploaded) continue;
|
|
|
|
|
|
|
|
|
|
const attachmentIds = await uploadAttachment({
|
|
|
|
|
serverId,
|
|
|
|
|
sessionId,
|
|
|
|
|
filePaths: [path],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!attachmentIds) continue;
|
|
|
|
|
|
|
|
|
|
Object.assign(item, {
|
|
|
|
|
uploaded: true,
|
|
|
|
|
attachmentId: attachmentIds[0],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setUploadFiles(uploadFiles);
|
|
|
|
|
}
|
|
|
|
|
}, [uploadFiles]);
|
|
|
|
|
|
|
|
|
|
const deleteFile = async (id: string, attachmentId: string) => {
|
2025-03-03 17:54:00 +08:00
|
|
|
setUploadFiles(uploadFiles.filter((file) => file.id !== id));
|
2025-03-28 13:50:14 +08:00
|
|
|
|
|
|
|
|
deleteAttachment({ serverId, id: attachmentId });
|
2025-03-03 17:54:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex flex-wrap gap-y-2 -mx-1 text-sm">
|
|
|
|
|
{uploadFiles.map((file) => {
|
2025-03-28 13:50:14 +08:00
|
|
|
const { id, name, extname, size, uploaded, attachmentId } = file;
|
2025-03-03 17:54:00 +08:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div key={id} className="w-1/3 px-1">
|
2025-03-04 20:09:58 +08:00
|
|
|
<div className="relative group flex items-center gap-1 p-1 rounded-[4px] bg-[#dedede] dark:bg-[#202126]">
|
2025-03-28 13:50:14 +08:00
|
|
|
{attachmentId && (
|
|
|
|
|
<div
|
|
|
|
|
className="absolute flex justify-center items-center size-[14px] bg-red-600 top-0 right-0 rounded-full cursor-pointer translate-x-[5px] -translate-y-[5px] transition opacity-0 group-hover:opacity-100 "
|
|
|
|
|
onClick={() => {
|
|
|
|
|
deleteFile(id, attachmentId);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<X className="size-[10px] text-white" />
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-03-03 17:54:00 +08:00
|
|
|
|
2025-03-28 13:50:14 +08:00
|
|
|
<FileIcon extname={extname} />
|
2025-03-03 17:54:00 +08:00
|
|
|
|
2025-03-03 22:13:32 +08:00
|
|
|
<div className="flex flex-col justify-between overflow-hidden">
|
2025-03-04 12:43:24 +08:00
|
|
|
<div className="truncate text-[#333333] dark:text-[#D8D8D8]">
|
|
|
|
|
{name}
|
|
|
|
|
</div>
|
2025-03-03 17:54:00 +08:00
|
|
|
|
2025-03-04 12:43:24 +08:00
|
|
|
<div className="text-xs text-[#999999]">
|
2025-03-28 13:50:14 +08:00
|
|
|
{uploaded ? (
|
|
|
|
|
<div className="flex gap-2">
|
|
|
|
|
{extname && <span>{extname}</span>}
|
|
|
|
|
<span>
|
|
|
|
|
{filesize(size, { standard: "jedec", spacer: "" })}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<span>{t("assistant.fileList.uploading")}</span>
|
|
|
|
|
)}
|
2025-03-03 17:54:00 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default FileList;
|