127 lines
4.1 KiB
TypeScript
127 lines
4.1 KiB
TypeScript
// 上传相关的工具函数
|
||
import { isVideoMaterialType } from '@/lib/video-material-types'
|
||
|
||
/**
|
||
* 格式化文件大小
|
||
*/
|
||
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]
|
||
}
|
||
|
||
/**
|
||
* 格式化上传速度(字节/秒 -> 用户友好单位)
|
||
* 使用字节单位(B/s、KB/s、MB/s),而非比特单位
|
||
*/
|
||
export function formatSpeed(bytesPerSecond: number): string {
|
||
if (bytesPerSecond < 1024) {
|
||
return `${bytesPerSecond.toFixed(0)} B/s`
|
||
}
|
||
if (bytesPerSecond < 1024 * 1024) {
|
||
return `${(bytesPerSecond / 1024).toFixed(2)} KB/s`
|
||
}
|
||
return `${(bytesPerSecond / 1024 / 1024).toFixed(2)} MB/s`
|
||
}
|
||
|
||
/**
|
||
* 计算剩余时间
|
||
*/
|
||
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 (isVideoMaterialType(materialType)) return videoExts.includes(ext)
|
||
|
||
// 品牌VI灵感:只能是 PDF,展示图在单独的展示图字段里上传
|
||
if (materialType === '品牌VI灵感') return ext === '.pdf'
|
||
|
||
// 详情模板:支持直接上传 PSD/TIF/PSB 文件或压缩包
|
||
if (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 (isVideoMaterialType(materialType))
|
||
return '.mp4,.mov,.avi,.mkv,.mts,.m4v'
|
||
if (materialType === '品牌VI灵感') return '.pdf'
|
||
// 详情模板:支持直接上传 PSD/TIF/PSB 文件或压缩包
|
||
if (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
|
||
}
|