/** * Abaqus CSV viewer (feature ⑤) — an enhanced grid for result exports. * * - RFC4180-ish parser (quoted fields, escaped quotes, CRLF) * - 数值列自动检测(整列可解析为有限数) * - 表头点击排序(数值/字符串分别比较,升降切换) * - 列显示开关(勾选显隐列) * - 分页(默认 50 行/页,替代旧的"只显示前 200 行") * - 选中数值列时渲染 inline SVG sparkline 趋势 * - 主题走 theme.ts CSS 变量 */ import { useMemo, useState, type CSSProperties } from 'react' import type { FileViewerProps } from 'dsh-better-sidebar' import { ensureCaeStyles } from './theme.js' import { IconChevron } from './icons.js' /** Parse CSV text into rows (RFC4180-ish; enough for Abaqus result exports). */ function parseCsv(text: string): string[][] { if (!text) return [] const rows: string[][] = [] let row: string[] = [] let field = '' let inQuotes = false for (let i = 0; i < text.length; i++) { const c = text[i] if (inQuotes) { if (c === '"') { if (text[i + 1] === '"') { field += '"' i++ } else inQuotes = false } else field += c } else if (c === '"') { inQuotes = true } else if (c === ',') { row.push(field) field = '' } else if (c === '\n' || c === '\r') { if (c === '\r' && text[i + 1] === '\n') i++ row.push(field) field = '' if (row.some((x) => x !== '')) rows.push(row) row = [] } else field += c } row.push(field) if (row.some((x) => x !== '')) rows.push(row) return rows } function isNum(s: string): boolean { if (s === '') return false const n = Number(s) return Number.isFinite(n) } function Sparkline({ values, width = 240, height = 44 }: { values: number[]; width?: number; height?: number }) { if (values.length < 2) return
| toggleSort(ci)} title="点击排序"> {header[ci] || `col${ci}`} {numeric[ci] && ( )} {sortCol === ci && {sortDir === 'asc' ? '▲' : '▼'}} | ))}
|---|
| {r[ci]} | ))}