update at 2026-02-14 11:16:40
This commit is contained in:
@@ -66,6 +66,15 @@ function getFileExtension(fileName) {
|
||||
return lowerName.slice(lastDotIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从路径提取文件名,兼容 Unix/Windows 路径分隔符。
|
||||
*/
|
||||
function getBaseNameFromPath(filePath) {
|
||||
const normalized = String(filePath || '').replace(/\\/g, '/');
|
||||
const segments = normalized.split('/');
|
||||
return segments[segments.length - 1] || '';
|
||||
}
|
||||
|
||||
const FALLBACK_THEME_COLORS = ['#9b6bc2', '#7e95f7', '#4cc9f0', '#f4a261'];
|
||||
|
||||
/**
|
||||
@@ -859,7 +868,7 @@ Page({
|
||||
*/
|
||||
readAndApplyFile(filePath, fileName, onReadFailPrefix) {
|
||||
const that = this;
|
||||
const extension = getFileExtension(fileName);
|
||||
const extension = getFileExtension(fileName) || getFileExtension(getBaseNameFromPath(filePath));
|
||||
const isCsvFile = extension === 'csv';
|
||||
const readOptions = {
|
||||
filePath,
|
||||
@@ -960,8 +969,12 @@ Page({
|
||||
if (!picked) {
|
||||
return;
|
||||
}
|
||||
const filePath = picked.path;
|
||||
const fileName = picked.name || 'unknown.csv';
|
||||
const filePath = picked.path || picked.tempFilePath || '';
|
||||
const fileName =
|
||||
picked.name ||
|
||||
getBaseNameFromPath(filePath) ||
|
||||
// 无法识别文件名时,默认按二进制读取,交由解析器做内容识别。
|
||||
'upload.bin';
|
||||
that.readAndApplyFile(filePath, fileName, '读取文件失败');
|
||||
},
|
||||
fail(err) {
|
||||
|
||||
@@ -270,6 +270,34 @@ function parseXlsxBuffer(buffer) {
|
||||
return toRawTable(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断二进制是否为 Zip 容器(xlsx)魔数:50 4B。
|
||||
*/
|
||||
function isZipMagic(bufferLike) {
|
||||
if (!bufferLike || typeof bufferLike.byteLength !== 'number' || bufferLike.byteLength < 2) {
|
||||
return false;
|
||||
}
|
||||
const bytes = new Uint8Array(bufferLike, 0, 2);
|
||||
return bytes[0] === 0x50 && bytes[1] === 0x4b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断二进制是否为 OLE 容器(老 xls)魔数:D0 CF 11 E0 A1 B1 1A E1。
|
||||
*/
|
||||
function isOleMagic(bufferLike) {
|
||||
if (!bufferLike || typeof bufferLike.byteLength !== 'number' || bufferLike.byteLength < 8) {
|
||||
return false;
|
||||
}
|
||||
const bytes = new Uint8Array(bufferLike, 0, 8);
|
||||
const signature = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1];
|
||||
for (let i = 0; i < signature.length; i += 1) {
|
||||
if (bytes[i] !== signature[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文件名后缀自动分流解析器。
|
||||
*/
|
||||
@@ -281,6 +309,13 @@ function parseTableByFileName(fileName, payload) {
|
||||
if (lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls')) {
|
||||
return parseXlsxBuffer(payload);
|
||||
}
|
||||
|
||||
// 兜底:后缀不可用时,通过文件魔数自动识别 Excel。
|
||||
if (payload && typeof payload === 'object' && typeof payload.byteLength === 'number') {
|
||||
if (isZipMagic(payload) || isOleMagic(payload)) {
|
||||
return parseXlsxBuffer(payload);
|
||||
}
|
||||
}
|
||||
throw new Error('仅支持 .csv / .xlsx / .xls 文件');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user