Files
cz-web/src/utils/filePreview.ts
2026-09-30 08:04:16 +08:00

53 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 预览类型判定(纯函数,无副作用,便于单测与复用)。
*
* <p>为什么集中在一个文件:前端多处 `FileList` 预览都按「后缀 → 渲染方式」分流,
* 统一这里避免每个页面各写一套正则 / 后缀表。后端同源预览端点(`/web/workOrderDraft/preview/{ossId}`)
* 按后缀纠正 Content-Type,这里与之后端口径保持一致的归类。</p>
*/
export type PreviewKind = 'image' | 'pdf' | 'video' | 'audio' | 'text' | 'unsupported'
const IMAGE_SUFFIXES = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp']
const PDF_SUFFIXES = ['pdf']
const VIDEO_SUFFIXES = ['mp4', 'webm', 'mov', 'avi', 'm4v']
const AUDIO_SUFFIXES = ['mp3', 'wav', 'ogg', 'm4a']
// 文本类:含 html/htm/svg —— 统一按纯文本展示源码,避免内联渲染触发存储型 XSS
const TEXT_SUFFIXES = ['txt', 'sql', 'log', 'csv', 'json', 'xml', 'md', 'yml', 'yaml', 'html', 'htm', 'svg']
/** 取小写字尾(不含点);无点返回空串 */
export function getSuffix(name: string): string {
const idx = name.lastIndexOf('.')
return idx >= 0 ? name.slice(idx + 1).toLowerCase() : ''
}
/** 按文件名判定预览类型;office / 未知后缀一律 unsupported(前端不内联,给下载) */
export function resolvePreviewKind(name: string): PreviewKind {
const ext = getSuffix(name)
if (IMAGE_SUFFIXES.includes(ext)) return 'image'
if (PDF_SUFFIXES.includes(ext)) return 'pdf'
if (VIDEO_SUFFIXES.includes(ext)) return 'video'
if (AUDIO_SUFFIXES.includes(ext)) return 'audio'
if (TEXT_SUFFIXES.includes(ext)) return 'text'
return 'unsupported'
}
/** 是否可被前端内联预览(true = image/pdf/video/audio/text) */
export function isPreviewable(name: string): boolean {
return resolvePreviewKind(name) !== 'unsupported'
}
/**
* 文本内联预览上限(1MB)。
* 整文件塞进 `<pre>` 会卡死浏览器(如 5MB+ 的 .sql/.log),故只读取前 1MB 渲染,超出截断并提示下载。
*/
export const PREVIEW_TEXT_MAX_BYTES = 1024 * 1024
/** 人类可读体积(B/KB/MB/GB) */
export function formatBytes(bytes: number): string {
if (!bytes || bytes < 0) return '0 B'
const units = ['B', 'KB', 'MB', 'GB']
const i = Math.min(units.length - 1, Math.floor(Math.log(bytes) / Math.log(1024)))
const val = bytes / Math.pow(1024, i)
return `${i === 0 ? val : val.toFixed(1)} ${units[i]}`
}