35 lines
1.7 KiB
JavaScript
35 lines
1.7 KiB
JavaScript
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
import { existsSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
const root = process.cwd();
|
|
const reportsRoot = path.join(root, 'reports');
|
|
const output = path.join(root, 'data', 'reports.json');
|
|
const categoryNames = { daily: '每日复盘', intraday: '盘中项目', sector: '行业观察', stock: '个股跟踪' };
|
|
const files = [];
|
|
async function walk(dir) {
|
|
if (!existsSync(dir)) return;
|
|
for (const item of await readdir(dir, { withFileTypes: true })) {
|
|
const full = path.join(dir, item.name);
|
|
if (item.isDirectory()) await walk(full);
|
|
else if (item.name.endsWith('.html')) files.push(full);
|
|
}
|
|
}
|
|
await walk(reportsRoot);
|
|
const records = [];
|
|
for (const file of files) {
|
|
const rel = path.relative(root, file).split(path.sep).join('/');
|
|
const parts = rel.split('/');
|
|
const category = parts[1];
|
|
const match = parts.at(-1).match(/^(\d{4}-\d{2}-\d{2})-(.+)\.html$/);
|
|
if (!match) { console.warn(`Skipped (expected YYYY-MM-DD-slug.html): ${rel}`); continue; }
|
|
const [, date, slug] = match;
|
|
const html = await readFile(file, 'utf8');
|
|
const title = html.match(/<title>(.*?)<\/title>/i)?.[1]?.trim() || slug.replaceAll('-', ' ');
|
|
const summary = html.match(/<meta\s+name=["']description["']\s+content=["'](.*?)["']/i)?.[1] || '打开查看详细研究内容';
|
|
records.push({ id: `${category}-${date}-${slug}`, category, categoryName: categoryNames[category] || category, date, title, summary, tags: [category.toUpperCase()], path: rel });
|
|
}
|
|
records.sort((a, b) => b.date.localeCompare(a.date) || a.title.localeCompare(b.title));
|
|
await writeFile(output, `${JSON.stringify(records, null, 2)}\n`);
|
|
console.log(`Indexed ${records.length} report(s) → ${path.relative(root, output)}`);
|