You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
4.2 KiB
97 lines
4.2 KiB
|
1 week ago
|
// 票 01:生成 pages-index.md(sitemap 树 + 每页文本量 + 重点标注)
|
||
|
|
import fs from 'node:fs';
|
||
|
|
import path from 'node:path';
|
||
|
|
|
||
|
|
const ROOT = 'e:/code/crm-backend-matt';
|
||
|
|
const IN_JSON = `${ROOT}/.scratch/lanhu-latest/axure-v29.json`;
|
||
|
|
const OUT_DIR = `${ROOT}/.scratch/opportunity-bugfix/lanhu-pages`;
|
||
|
|
const OUT = `${ROOT}/.scratch/lanhu-latest/pages-index.md`;
|
||
|
|
|
||
|
|
const data = JSON.parse(fs.readFileSync(IN_JSON, 'utf8'));
|
||
|
|
|
||
|
|
// sitemap walk,保持树形结构输出
|
||
|
|
const lines = [];
|
||
|
|
const stats = { total: 0, withFile: 0, noText: 0 };
|
||
|
|
const focus = { a1x: [], a3: [], a4: [], notes: [] };
|
||
|
|
|
||
|
|
function mdOf(pageName) {
|
||
|
|
// 与 fetch-all-pages.mjs 相同的 safeName 规则
|
||
|
|
return pageName.replace(/[\\/:*?"<>|\s]+/g, '_') + '.md';
|
||
|
|
}
|
||
|
|
|
||
|
|
const walk = (nodes, depth, folder) => {
|
||
|
|
for (const n of nodes || []) {
|
||
|
|
const hasKids = Array.isArray(n.children) && n.children.length > 0;
|
||
|
|
// 带 url 的 Folder:自身也算页面,再递归 children(Axure sitemap 常见形态)
|
||
|
|
if (n.url) {
|
||
|
|
stats.total++;
|
||
|
|
const file = path.join(OUT_DIR, mdOf(n.pageName));
|
||
|
|
let texts = -1, exists = fs.existsSync(file) && fs.statSync(file).size > 100;
|
||
|
|
if (exists) {
|
||
|
|
stats.withFile++;
|
||
|
|
const head = fs.readFileSync(file, 'utf8').split('\n').slice(0, 6).join('\n');
|
||
|
|
const m = head.match(/有文本: (\d+)/);
|
||
|
|
texts = m ? +m[1] : -1;
|
||
|
|
if (texts === 0) stats.noText++;
|
||
|
|
}
|
||
|
|
const mark = !exists ? ' ⚠缺失' : texts === 0 ? ' (空页)' : '';
|
||
|
|
const isNote = exists && texts >= 0 && (() => {
|
||
|
|
const c = fs.readFileSync(file, 'utf8');
|
||
|
|
return c.includes('开发说明') || c.includes('变更记录');
|
||
|
|
})();
|
||
|
|
lines.push(`${' '.repeat(depth)}- ${n.pageName}${mark}${isNote ? ' 〔含批注〕' : ''} ${texts >= 0 ? `(${texts})` : ''}`);
|
||
|
|
// 重点标注
|
||
|
|
const url = n.url;
|
||
|
|
if (/^a1x/i.test(n.pageName) || url.toLowerCase().startsWith('a1x')) focus.a1x.push(n.pageName);
|
||
|
|
if (/^a3/i.test(n.pageName) || url.toLowerCase().startsWith('a3')) focus.a3.push(n.pageName);
|
||
|
|
if (/^a4/i.test(n.pageName) || url.toLowerCase().startsWith('a4')) focus.a4.push(n.pageName);
|
||
|
|
if (/暂缓|关闭/.test(n.pageName)) focus.notes.push(n.pageName);
|
||
|
|
}
|
||
|
|
if (hasKids) {
|
||
|
|
if (!n.url) lines.push(`${' '.repeat(depth)}- **${n.pageName}/**`);
|
||
|
|
walk(n.children, n.url ? depth + 1 : depth, [...folder, n.pageName]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
walk(data.sitemap.rootNodes, 0, []);
|
||
|
|
|
||
|
|
// sitemap 没覆盖的 pages key(兜底页)
|
||
|
|
const inTree = new Set();
|
||
|
|
const collect = (nodes) => (nodes || []).forEach(n => {
|
||
|
|
if (n.url) inTree.add(n.url);
|
||
|
|
if (n.children) collect(n.children);
|
||
|
|
});
|
||
|
|
collect(data.sitemap.rootNodes);
|
||
|
|
const orphan = Object.keys(data.pages).filter(u => !inTree.has(u));
|
||
|
|
|
||
|
|
const out = [
|
||
|
|
'# v29 原型页面索引(182 页文本库)',
|
||
|
|
'',
|
||
|
|
`- 清单: .scratch/lanhu-latest/axure-v29.json(web 端 v29, 2026-08-28)`,
|
||
|
|
`- 文本库: .scratch/opportunity-bugfix/lanhu-pages/*.md(id | 类型 | 名称 | 文本,含需求批注区)`,
|
||
|
|
`- 括号数字 = 该页有文本控件数;〔含批注〕= 含开发说明/变更记录批注;⚠缺失 = 文本库无对应文件`,
|
||
|
|
`- 拉取日志: .scratch/opportunity-bugfix/fetch-all.log`,
|
||
|
|
'',
|
||
|
|
`## 统计:sitemap 页 ${stats.total},已落盘 ${stats.withFile},空页 ${stats.noText},孤儿清单页 ${orphan.length}`,
|
||
|
|
'',
|
||
|
|
'## 重点页(票 02/07/08 输入)',
|
||
|
|
'',
|
||
|
|
`### A1X 工作计划(${focus.a1x.length} 页,票 07 可行性)`,
|
||
|
|
...focus.a1x.map(s => `- ${s}`), '',
|
||
|
|
`### A4 客户管理(${focus.a4.length} 页,票 08 可行性)`,
|
||
|
|
...focus.a4.map(s => `- ${s}`), '',
|
||
|
|
`### A3 商机全族(${focus.a3.length} 页,票 02 复测)`,
|
||
|
|
...focus.a3.map(s => `- ${s}`), '',
|
||
|
|
`### 暂缓/关闭相关页(D-14 等裁决线索)`,
|
||
|
|
...focus.notes.map(s => `- ${s}`), '',
|
||
|
|
'## Sitemap 树',
|
||
|
|
'',
|
||
|
|
...lines,
|
||
|
|
'',
|
||
|
|
];
|
||
|
|
if (orphan.length) out.push('## 清单里有但 sitemap 树没有的页', '', ...orphan.map(u => `- ${u} → ${mdOf(u.replace(/\.html$/, '').replace(/[\\/:*?"<>|\s]+/g, '_'))}`), '');
|
||
|
|
fs.writeFileSync(OUT, out.join('\n'), 'utf8');
|
||
|
|
console.log(`index written: ${OUT}`);
|
||
|
|
console.log(JSON.stringify(stats));
|
||
|
|
console.log('focus counts:', Object.fromEntries(Object.entries(focus).map(([k, v]) => [k, v.length])));
|