From fa2288c4972b5c1d6079873ad96004803c90a91f Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 6 Sep 2026 13:47:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BE=A4=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E4=B8=8D=E4=BC=A0file=5Ftype=EF=BC=8C?= =?UTF-8?q?=E5=9B=BE=E7=89=87/=E8=A7=86=E9=A2=91/=E8=AF=AD=E9=9F=B3?= =?UTF-8?q?=E7=BE=A4=E6=96=87=E4=BB=B6=E5=85=A8=E9=83=A8=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=88=90=E9=80=9A=E7=94=A8=E6=96=87=E4=BB=B6=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:POST /groups/{topic}/files 的 file_type 是客户端登记时自己声明的字段(im-api.js的 addGroupFile早就留了这个参数),不是服务端拿mime_type反推的——实测:上传一张mime_type 正确记成"image/png"的图片,只要请求体不带file_type,服务端就把它落成字面量"file"(不是 留空)。GroupFiles的onFile上传流程一直没传这个字段,导致FILE_TYPE_META准备好的 image/video/audio/document四种彩色图标从未被真正用上,所有群文件不分类型清一色显示灰色 通用文件图标。 修复:新增fileTypeFromMime辅助函数(与content-library-view.jsx的同名函数用同一套mime前缀 优先、扩展名兜底文档类型的判断口径),上传时算出分类一起传给addGroupFile。 验证:真实浏览器上传一张PNG,接口返回file_type从"file"变成"image",列表图标从灰色通用 文件图标变成绿色图片图标;对照同一会话里upload-fix之前的旧文件,图标仍是灰色(存量数据 不受影响,符合预期,不需要也没有接口能批量回填旧记录)。 --- src/views/group-management-view.jsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/views/group-management-view.jsx b/src/views/group-management-view.jsx index 6188e4de..01616c2c 100644 --- a/src/views/group-management-view.jsx +++ b/src/views/group-management-view.jsx @@ -967,6 +967,21 @@ const FILE_TYPE_META = { image: ['image', '#3ba55c'], video: ['videocam', '#3b82c4'], audio: ['audiotrack', '#8b5cf6'], document: ['description', '#e05d44'], file: ['insert_drive_file', '#8a8f98'] }; +const DOCUMENT_EXT = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']; +// POST /groups/{topic}/files 的 file_type 字段是客户端在登记时自己声明的(addGroupFile 的 +// im-api.js 签名早就留了这个参数),不是服务端拿 mime_type 反推的——实测:即使 mime_type 正确 +// 存成 "image/png",只要请求体没带 file_type,服务端就把它落成字面量 "file"(不是留空)。这里 +// 的 onFile 上传流程原来完全没传这个字段,导致真实是图片/视频/语音的群文件在列表里全部显示成 +// 灰色通用文件图标,跟 FILE_TYPE_META 已经准备好的 image/video/audio/document 四种彩色图标从未 +// 对应起来过。跟 content-library-view.jsx 的 fileTypeFromMime 用的是同一套判断(mime 前缀优先, +// 帶附件扩展名兜底文档类型),保持两处"什么算图片/视频/文档"的口径一致。 +function fileTypeFromMime(mime, name) { + const prefix = (mime || '').split('/')[0]; + if (prefix === 'image' || prefix === 'video' || prefix === 'audio') return prefix; + const ext = (/\.([a-zA-Z0-9]+)$/.exec(name || '') || [])[1]; + if (mime === 'application/pdf' || DOCUMENT_EXT.includes((ext || '').toLowerCase())) return 'document'; + return 'file'; +} function GroupFiles({topic, tinode, onToast}) { const [queryInput, setQueryInput] = React.useState(''); @@ -1016,7 +1031,8 @@ function GroupFiles({topic, tinode, onToast}) { if (!file || !tinode) return; setUploading({name: file.name, progress: 0}); uploadLargeFile(tinode, file, frac => setUploading(u => u ? {...u, progress: Math.round(frac * 100)} : u)) - .then(({fileId}) => addGroupFile(topic, {fileId, fileName: file.name, mimeType: file.type, fileSize: file.size})) + .then(({fileId}) => addGroupFile(topic, {fileId, fileName: file.name, mimeType: file.type, fileSize: file.size, + fileType: fileTypeFromMime(file.type, file.name)})) .then(() => { setUploading(null); load(); }) .catch(err => { setUploading(null); onToast(err.message || '上传失败'); }); };