update at 2026-02-13 17:44:25

This commit is contained in:
douboer@gmail.com
2026-02-13 17:44:25 +08:00
parent b98da08f83
commit 2fe45888ba
6 changed files with 660 additions and 124 deletions

View File

@@ -31,6 +31,34 @@ function parseNumericValue(text: string): number | null {
return parsed;
}
/**
* 将单元格值格式化为可读文本,用于告警输出。
* 空字符串会明确展示为“(空)”,便于定位“看起来没填值”的问题行。
*/
function formatCellValueForWarning(value: string): string {
if (value.length === 0) {
return '(空)';
}
return value;
}
/**
* 组装“列位置 + 列名 + 原始值”的告警片段,便于用户快速定位问题字段。
*/
function buildColumnDebugText(row: string[], headers: string[], columns: number[]): string {
if (columns.length === 0) {
return '未选择列';
}
return columns
.map((columnIndex) => {
const headerName = headers[columnIndex] ?? `${columnIndex + 1}`;
const rawValue = row[columnIndex] ?? '';
return `${columnIndex + 1} 列(${headerName}="${formatCellValueForWarning(rawValue)}"`;
})
.join('');
}
/**
* 按照配置生成 source 名称。
* 若未选择描述列,则回退为数据列文本。
@@ -87,30 +115,48 @@ export function buildSankeyData(table: RawTable, config: MappingConfig): SankeyB
const linkValueMap = new Map<string, number>();
const warnings: string[] = [];
let droppedRows = 0;
const sourceDataColumnIndex = config.sourceDataColumn;
const sourceDataColumnName =
table.headers[sourceDataColumnIndex] ?? `${sourceDataColumnIndex + 1}`;
const lastNonEmptyTargetValueByColumn = new Map<number, string>();
table.rows.forEach((row, rowIndex) => {
const excelRow = rowIndex + 2;
const sourceRaw = normalizeText(row[config.sourceDataColumn as number] ?? '');
const sourceCellRaw = row[sourceDataColumnIndex] ?? '';
const sourceRaw = normalizeText(sourceCellRaw);
const sourceValue = parseNumericValue(sourceRaw);
if (sourceValue === null) {
warnings.push(`${excelRow} 行: 源数据不是有效数字,已跳过`);
warnings.push(
`${excelRow} 行, 第 ${sourceDataColumnIndex + 1} 列(${sourceDataColumnName}: 源数据不是有效数字,原始值="${formatCellValueForWarning(sourceCellRaw)}",已跳过`
);
droppedRows += 1;
return;
}
const sourceName = buildSourceName(row, config);
if (!sourceName) {
warnings.push(`${excelRow} 行: 源描述为空,已跳过`);
const sourceDescDebugText = buildColumnDebugText(
row,
table.headers,
config.sourceDescriptionColumns
);
warnings.push(`${excelRow} 行: 源描述为空,字段=${sourceDescDebugText},已跳过`);
droppedRows += 1;
return;
}
const targetName = buildTargetName(row, config, lastNonEmptyTargetValueByColumn);
if (!targetName) {
warnings.push(`${excelRow} 行: 目标描述为空,已跳过`);
const targetDescDebugText = buildColumnDebugText(
row,
table.headers,
config.targetDescriptionColumns
);
warnings.push(
`${excelRow} 行: 目标描述为空,字段=${targetDescDebugText},且无可继承的上方值,已跳过`
);
droppedRows += 1;
return;
}