Files
jinshen-website/app/utils/parseTable.ts
R2m1liA c860621e7a
All checks were successful
deploy to server / build-and-deploy (push) Successful in 6m51s
feat!: 将QuestionList的内容渲染由Markdown改为HTML
- 后端CMS字段由Markdown改为WYSIWYG因此前端做出对应修改
2025-11-14 00:00:05 +08:00

91 lines
2.4 KiB
TypeScript
Raw Permalink 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.

import type { Element, Node } from 'domhandler';
export interface ParsedTable {
headers: string[];
rows: Record<string, string>[];
}
const isElement = (n: Node): n is Element => n.type === 'tag';
export function parseHtmlTable(table: Element): ParsedTable {
if (table.name !== 'table') {
throw new Error('parseHtmlTable: node is not <table>');
}
// 获取 table 下的所有 tag 子节点
const getChildren = (node: Node): Element[] =>
isElement(node) ? node.children.filter(isElement) : [];
// ---- 找 thead / tbody ----
const children = getChildren(table);
const thead = children.find((n) => n.name === 'thead');
const tbody = children.find((n) => n.name === 'tbody');
if (!tbody) {
return { headers: [], rows: [] };
}
const bodyRows = getChildren(tbody).filter((n) => n.name === 'tr');
if (bodyRows.length === 0) {
return { headers: [], rows: [] };
}
// ---- 1. 表头 ----
let headerCells: Element[] = [];
if (thead) {
// 如果 Directus 有 thead一般不会
const headerRow = getChildren(thead).find((n) => n.name === 'tr');
headerCells = headerRow
? getChildren(headerRow).filter((n) => n.name === 'th' || n.name === 'td')
: [];
} else {
// Directus 情况:没有 thead → 用 tbody 第一行作为 header
headerCells = getChildren(bodyRows[0]).filter(
(n) => n.name === 'th' || n.name === 'td'
);
}
logger.info(headerCells);
const headers = headerCells.map((cell, i) => {
const text = cell.children
.filter((c) => c.type === 'text')
.map((t) => t.data.trim())
.filter(Boolean)
.join('');
return text || `${i + 1}`;
});
// ---- 2. 数据行 ----
// 如果没有 thead则跳过第一行它是 header
const dataRows = thead ? bodyRows : bodyRows.slice(1);
const rows = dataRows.map((row) => {
const cells = getChildren(row).filter(
(n) => n.name === 'td' || n.name === 'th'
);
const record: Record<string, string> = {};
headers.forEach((header, i) => {
const cell = cells[i];
if (!cell) {
record[header] = '';
} else {
const text = cell.children
.filter((c) => c.type === 'text')
.map((t) => t.data.trim())
.filter(Boolean)
.join('');
record[header] = text;
}
});
return record;
});
logger.info(headers, rows);
return { headers, rows };
}