gongxiangp2/components/upload/upload-utils.ts

130 lines
4.2 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.

// 上传相关的工具函数
/**
* 格式化文件大小
*/
export function formatBytes(bytes: number): string {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]
}
/**
* 格式化上传速度(字节/秒 -> Mbps,网络带宽标准单位)
* 1 MB/s = 8 Mbps (1字节 = 8比特)
*/
export function formatSpeed(bytesPerSecond: number): string {
// 转换为比特/秒
const bitsPerSecond = bytesPerSecond * 8
if (bitsPerSecond < 1000) {
return `${bitsPerSecond.toFixed(0)} bps`
}
if (bitsPerSecond < 1000 * 1000) {
return `${(bitsPerSecond / 1000).toFixed(2)} Kbps`
}
return `${(bitsPerSecond / 1000 / 1000).toFixed(2)} Mbps`
}
/**
* 计算剩余时间
*/
export function calculateRemainingTime(remainingBytes: number, speed: number): string {
if (speed <= 0) return '计算中...'
const seconds = Math.ceil(remainingBytes / speed)
if (seconds < 60) return `${seconds}秒`
const minutes = Math.floor(seconds / 60)
const secs = seconds % 60
return `${minutes}分${secs}秒`
}
/**
* 获取文件扩展名
*/
export function getFileExtension(filename: string): string {
const idx = filename.lastIndexOf('.')
return idx >= 0 ? filename.slice(idx).toLowerCase() : ''
}
/**
* 验证主文件类型是否有效
*/
export function isValidMainFileType(file: File, materialType: string): boolean {
const ext = getFileExtension(file.name)
const archiveExts = ['.zip', '.rar', '.7z']
const videoExts = ['.mp4', '.mov', '.avi', '.mkv', '.mts', '.m4v']
const audioExts = ['.mp3', '.wav', '.flac', '.m4a', '.aac', '.ogg']
const psdExts = ['.psd', '.tif', '.tiff', '.psb'] // 详情页/详情模板支持 PSD、TIF、PSB
// 音乐:只能是音频文件
if (materialType === '音乐') return audioExts.includes(ext)
// 视频类:只能是视频文件
if (['主图视频', '安装视频', '种草视频'].includes(materialType)) return videoExts.includes(ext)
// 品牌VI灵感:只能是 PDF,展示图在单独的展示图字段里上传
if (materialType === '品牌VI灵感') return ext === '.pdf'
// 详情页和详情模板:支持直接上传 PSD/TIF/PSB 文件或压缩包
if (materialType === '详情页' || materialType === '详情模板') {
return psdExts.includes(ext) || archiveExts.includes(ext)
}
// 其他类型(3D场景/模特等):仍然按旧逻辑走压缩包
return archiveExts.includes(ext)
}
/**
* 获取主文件接受的类型
*/
export function getMainFileAccept(materialType: string): string {
if (materialType === '音乐') return '.mp3,.wav,.flac,.m4a,.aac,.ogg'
if (['主图视频', '安装视频', '种草视频'].includes(materialType))
return '.mp4,.mov,.avi,.mkv,.mts,.m4v'
if (materialType === '品牌VI灵感') return '.pdf'
// 详情页和详情模板:支持直接上传 PSD/TIF/PSB 文件或压缩包
if (materialType === '详情页' || materialType === '详情模板') {
return '.psd,.tif,.tiff,.psb,.zip,.rar,.7z'
}
return '.zip,.rar,.7z'
}
/**
* 从文件名提取SPU(简单逻辑:提取文件名中的大写字母和数字组合)
*/
export function extractSpuFromFileName(filename: string): string {
// 移除扩展名
const nameWithoutExt = filename.replace(/\.[^/.]+$/, '')
// 尝试提取类似 "XY-2024-001" 的格式
const spuMatch = nameWithoutExt.match(/[A-Z]{2,}-?\d{4}-?\d{3,}/i)
if (spuMatch) {
return spuMatch[0].toUpperCase()
}
// 如果没有匹配到,返回文件名(去除扩展名和特殊字符)
return nameWithoutExt.replace(/[^a-zA-Z0-9\-_]/g, '').toUpperCase()
}
/**
* 将File转换为base64格式(用于批量上传中的预览图)
*/
export async function convertFileToBase64(file: File): Promise<{ name: string; data: number[]; type: string }> {
const arrayBuffer = await file.arrayBuffer()
return {
name: file.name,
data: Array.from(new Uint8Array(arrayBuffer)),
type: file.type,
}
}
/**
* 检测素材类型(从文件名)
*/
export function detectMaterialType(filename: string): string | null {
// 不再根据文件扩展名自动检测素材类型
// 用户需要手动选择素材类型
return null
}