优化文档结构,整合内外网访问和钉钉登录相关信息,删除冗余内容,提升可读性
This commit is contained in:
parent
0368cf8f62
commit
562b7c6cdb
240
scripts/analyze-external-file-sizes.ts
Normal file
240
scripts/analyze-external-file-sizes.ts
Normal file
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* 分析外网服务器上存在的老素材源文件大小
|
||||
*/
|
||||
|
||||
import { readFile, writeFile } from 'fs/promises'
|
||||
|
||||
interface ExternalCheckRow {
|
||||
素材ID: string
|
||||
素材类型: string
|
||||
产品型号: string
|
||||
作者: string
|
||||
使用店铺: string
|
||||
源文件路径: string
|
||||
外网服务器URL: string
|
||||
文件是否存在: string
|
||||
源文件大小: string
|
||||
创建时间: string
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('='.repeat(60))
|
||||
console.log('分析外网服务器上存在的老素材源文件大小')
|
||||
console.log('='.repeat(60))
|
||||
console.log()
|
||||
|
||||
// 读取外网服务器检查报告
|
||||
console.log('📋 读取外网服务器检查报告...')
|
||||
let externalCheckData: ExternalCheckRow[] = []
|
||||
try {
|
||||
const externalCheckContent = await readFile('老素材外网服务器检查报告.csv', 'utf-8')
|
||||
const lines = externalCheckContent.split('\n').filter(line => line.trim())
|
||||
if (lines.length < 2) {
|
||||
throw new Error('CSV文件格式错误')
|
||||
}
|
||||
|
||||
// 简单的CSV解析(处理带引号的字段)
|
||||
function parseCSVLine(line: string): string[] {
|
||||
const result: string[] = []
|
||||
let current = ''
|
||||
let inQuotes = false
|
||||
|
||||
for (let i = 0; i < line.length; i++) {
|
||||
const char = line[i]
|
||||
if (char === '"') {
|
||||
if (inQuotes && line[i + 1] === '"') {
|
||||
current += '"'
|
||||
i++ // 跳过下一个引号
|
||||
} else {
|
||||
inQuotes = !inQuotes
|
||||
}
|
||||
} else if (char === ',' && !inQuotes) {
|
||||
result.push(current)
|
||||
current = ''
|
||||
} else {
|
||||
current += char
|
||||
}
|
||||
}
|
||||
result.push(current)
|
||||
return result
|
||||
}
|
||||
|
||||
const headers = parseCSVLine(lines[0]).map(h => h.trim())
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const values = parseCSVLine(lines[i])
|
||||
const row: any = {}
|
||||
headers.forEach((header, index) => {
|
||||
row[header] = (values[index] || '').trim()
|
||||
})
|
||||
externalCheckData.push(row as ExternalCheckRow)
|
||||
}
|
||||
console.log(` 读取到 ${externalCheckData.length} 条记录`)
|
||||
} catch (error) {
|
||||
console.error('❌ 无法读取外网服务器检查报告:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// 筛选出存在的文件
|
||||
const existingFiles = externalCheckData.filter(row => row['文件是否存在'] === '是')
|
||||
const missingFiles = externalCheckData.filter(row => row['文件是否存在'] === '否')
|
||||
|
||||
console.log(` 外网服务器存在: ${existingFiles.length} 个`)
|
||||
console.log(` 外网服务器缺失: ${missingFiles.length} 个`)
|
||||
console.log()
|
||||
|
||||
// 分析文件大小
|
||||
console.log('📊 分析文件大小...')
|
||||
|
||||
let totalSize = 0
|
||||
let totalSizeGB = 0
|
||||
const sizeStats: Array<{
|
||||
materialId: string
|
||||
materialType: string
|
||||
productModel: string
|
||||
authorName: string
|
||||
categoryName: string
|
||||
zipFilePath: string
|
||||
externalUrl: string
|
||||
fileSize: number
|
||||
fileSizeMB: number
|
||||
fileSizeGB: number
|
||||
createdAt: string
|
||||
}> = []
|
||||
|
||||
for (const row of existingFiles) {
|
||||
const fileSizeStr = (row['源文件大小(字节)'] || row['源文件大小'] || '0').trim()
|
||||
const fileSize = parseInt(fileSizeStr, 10)
|
||||
if (!isNaN(fileSize) && fileSize > 0) {
|
||||
totalSize += fileSize
|
||||
const fileSizeMB = fileSize / (1024 * 1024)
|
||||
const fileSizeGB = fileSize / (1024 * 1024 * 1024)
|
||||
|
||||
sizeStats.push({
|
||||
materialId: row['素材ID'],
|
||||
materialType: row['素材类型'],
|
||||
productModel: row['产品型号'],
|
||||
authorName: row['作者'],
|
||||
categoryName: row['使用店铺'],
|
||||
zipFilePath: row['源文件路径'],
|
||||
externalUrl: row['外网服务器URL'],
|
||||
fileSize,
|
||||
fileSizeMB: Math.round(fileSizeMB * 100) / 100,
|
||||
fileSizeGB: Math.round(fileSizeGB * 1000) / 1000,
|
||||
createdAt: row['创建时间'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
totalSizeGB = totalSize / (1024 * 1024 * 1024)
|
||||
|
||||
console.log(` 总文件数: ${sizeStats.length} 个`)
|
||||
console.log(` 总大小: ${(totalSizeGB).toFixed(2)} GB (${totalSize} 字节)`)
|
||||
console.log()
|
||||
|
||||
// 按大小排序
|
||||
sizeStats.sort((a, b) => b.fileSize - a.fileSize)
|
||||
|
||||
// 统计信息
|
||||
const avgSize = totalSize / sizeStats.length
|
||||
const avgSizeMB = avgSize / (1024 * 1024)
|
||||
const maxSize = sizeStats[0]?.fileSize || 0
|
||||
const minSize = sizeStats[sizeStats.length - 1]?.fileSize || 0
|
||||
|
||||
console.log('📈 大小统计:')
|
||||
console.log(` 平均大小: ${(avgSizeMB).toFixed(2)} MB`)
|
||||
console.log(` 最大文件: ${(maxSize / (1024 * 1024)).toFixed(2)} MB (${sizeStats[0]?.productModel || 'N/A'})`)
|
||||
console.log(` 最小文件: ${(minSize / (1024 * 1024)).toFixed(2)} MB (${sizeStats[sizeStats.length - 1]?.productModel || 'N/A'})`)
|
||||
console.log()
|
||||
|
||||
// 按素材类型统计
|
||||
const typeStats: Record<string, { count: number; totalSize: number; avgSize: number }> = {}
|
||||
for (const stat of sizeStats) {
|
||||
if (!typeStats[stat.materialType]) {
|
||||
typeStats[stat.materialType] = { count: 0, totalSize: 0, avgSize: 0 }
|
||||
}
|
||||
typeStats[stat.materialType].count++
|
||||
typeStats[stat.materialType].totalSize += stat.fileSize
|
||||
}
|
||||
|
||||
for (const type in typeStats) {
|
||||
typeStats[type].avgSize = typeStats[type].totalSize / typeStats[type].count
|
||||
}
|
||||
|
||||
console.log('📦 按素材类型统计:')
|
||||
for (const [type, stats] of Object.entries(typeStats).sort((a, b) => b[1].totalSize - a[1].totalSize)) {
|
||||
const totalGB = stats.totalSize / (1024 * 1024 * 1024)
|
||||
const avgMB = stats.avgSize / (1024 * 1024)
|
||||
console.log(` ${type}: ${stats.count} 个, 总计 ${totalGB.toFixed(2)} GB, 平均 ${avgMB.toFixed(2)} MB`)
|
||||
}
|
||||
console.log()
|
||||
|
||||
// 生成详细报告
|
||||
console.log('💾 生成详细报告...')
|
||||
|
||||
const reportRows: string[] = []
|
||||
reportRows.push('素材ID,素材类型,产品型号,作者,使用店铺,源文件路径,外网服务器URL,文件大小(字节),文件大小(MB),文件大小(GB),创建时间')
|
||||
|
||||
for (const stat of sizeStats) {
|
||||
const row = [
|
||||
stat.materialId,
|
||||
stat.materialType,
|
||||
stat.productModel,
|
||||
stat.authorName,
|
||||
stat.categoryName,
|
||||
stat.zipFilePath,
|
||||
stat.externalUrl,
|
||||
stat.fileSize.toString(),
|
||||
stat.fileSizeMB.toFixed(2),
|
||||
stat.fileSizeGB.toFixed(3),
|
||||
stat.createdAt,
|
||||
]
|
||||
reportRows.push(row.map(field => {
|
||||
if (field === null || field === undefined) return ''
|
||||
const str = String(field)
|
||||
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
||||
return `"${str.replace(/"/g, '""')}"`
|
||||
}
|
||||
return str
|
||||
}).join(','))
|
||||
}
|
||||
|
||||
const csvContent = reportRows.join('\n')
|
||||
const outputDir = process.env.IS_IN_CONTAINER === 'true' ? '/tmp' : '.'
|
||||
const statsFile = `${outputDir}/老素材外网服务器源文件大小统计.csv`
|
||||
const summaryFile = `${outputDir}/老素材外网服务器源文件大小汇总.csv`
|
||||
|
||||
await writeFile(statsFile, csvContent, 'utf-8')
|
||||
|
||||
console.log(`✅ 报告已生成: ${statsFile}`)
|
||||
console.log(` 包含 ${sizeStats.length} 个存在文件的大小信息`)
|
||||
console.log()
|
||||
|
||||
// 生成汇总报告
|
||||
const summaryRows: string[] = []
|
||||
summaryRows.push('统计项,数值')
|
||||
summaryRows.push(`总文件数,${sizeStats.length}`)
|
||||
summaryRows.push(`总大小(字节),${totalSize}`)
|
||||
summaryRows.push(`总大小(MB),${(totalSize / (1024 * 1024)).toFixed(2)}`)
|
||||
summaryRows.push(`总大小(GB),${totalSizeGB.toFixed(2)}`)
|
||||
summaryRows.push(`平均大小(MB),${avgSizeMB.toFixed(2)}`)
|
||||
summaryRows.push(`最大文件(MB),${(maxSize / (1024 * 1024)).toFixed(2)}`)
|
||||
summaryRows.push(`最小文件(MB),${(minSize / (1024 * 1024)).toFixed(2)}`)
|
||||
summaryRows.push('')
|
||||
summaryRows.push('素材类型,文件数,总大小(GB),平均大小(MB)')
|
||||
|
||||
for (const [type, stats] of Object.entries(typeStats).sort((a, b) => b[1].totalSize - a[1].totalSize)) {
|
||||
const totalGB = stats.totalSize / (1024 * 1024 * 1024)
|
||||
const avgMB = stats.avgSize / (1024 * 1024)
|
||||
summaryRows.push(`${type},${stats.count},${totalGB.toFixed(2)},${avgMB.toFixed(2)}`)
|
||||
}
|
||||
|
||||
await writeFile(summaryFile, summaryRows.join('\n'), 'utf-8')
|
||||
|
||||
console.log(`✅ 汇总报告已生成: ${summaryFile}`)
|
||||
console.log()
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('执行失败:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user