import { ref } from 'vue'; import dayjs from 'dayjs'; import { message } from 'ant-design-vue'; import type { AttachedFile } from '/@/views/ventAI/manageAssistent/types/index'; import { isAudioFile, isCsvFile, isDxfFile, isExcelFile, isTextFile, isVideoFile, isWordFile } from '/@/views/ventAI/manageAssistent/lib/index'; import type ChatInputArea from '/@/views/ventAI/manageAssistent/components/chat/ChatInputArea.vue'; /** * 输入区附件:文件选择 / 拖拽 / 粘贴三条入口统一走 addFile —— 校验 → 按类型读取(文本/二进制/预览) * → 落到待发送状态。三条入口的差别只在「文件从哪来」,校验与分流必须共用一份,否则会各自漂移。 */ export const useChatFiles = (getChatInput: () => InstanceType | undefined) => { const pendingFile = ref(null); const activeFileReader = ref(null); const triggerFileUpload = () => { getChatInput()?.fileInputRef?.click(); }; /** * 校验并读入一个文件作为待发送附件。 * 待发附件是单值(pendingFile),多选/多文件场景由调用方取第一个后再进来。 */ const addFile = (file: File): void => { // 剪贴板里取到的文件可能没有文件名(部分浏览器的截图项),补一个仅用于展示与分流的名字 const name = file.name || `粘贴附件_${dayjs().format('HHmmss')}`; if (isVideoFile(name) || isAudioFile(name)) { message.warning('不支持上传音频和视频文件'); return; } try { const newFile: AttachedFile = { id: `file-${Date.now()}`, name, size: file.size, type: file.type, uploadTime: dayjs().format('YYYY-MM-DD HH:mm'), originalFile: file, }; // 换附件时中断上一次仍在读取的 FileReader if (activeFileReader.value) { activeFileReader.value.abort(); activeFileReader.value = null; } const reader = new FileReader(); activeFileReader.value = reader; // 读取方式只判断一次:onload 与 readAs* 两处各写一遍条件容易走偏。 // .dxf 必须在此显式分流到文本:否则会落到 dataURL 分支,附件里只有 preview、拿不到 content, // DXF 预览面板只能显示空白。 const readMode = isTextFile(name) || isCsvFile(name) || isDxfFile(name) ? 'text' : isWordFile(name) || isExcelFile(name) ? 'binary' : 'dataurl'; reader.onload = (e) => { activeFileReader.value = null; if (readMode === 'text') { newFile.content = e.target?.result as string; } else if (readMode === 'binary') { newFile.arrayBuffer = e.target?.result as ArrayBuffer; } else { newFile.preview = e.target?.result as string; } }; if (readMode === 'text') { reader.readAsText(file); } else if (readMode === 'binary') { reader.readAsArrayBuffer(file); } else { reader.readAsDataURL(file); } pendingFile.value = newFile; message.success(`文件 "${name}" 已添加,点击发送按钮提交`); } catch (error) { console.error('文件处理失败:', error); message.error('文件处理失败,请重试'); } }; const handleFileUpload = (event: Event) => { const target = event.target as HTMLInputElement; const file = target.files?.[0]; // 无论是否取到文件都复位,否则再次选择同一个文件不会再触发 change target.value = ''; if (!file) return; addFile(file); }; const removePendingFile = () => { pendingFile.value = null; }; return { pendingFile, activeFileReader, triggerFileUpload, handleFileUpload, addFile, removePendingFile }; };