import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import assert from 'node:assert/strict'; // Change navigation only; keep the current multi-round manual and report bodies. const root = 'docs/workshop-quality-r13-20261110'; const out = 'docs/workshop-dialogue-guide-20261111/site-navigation'; const manual = 'final-康师傅工作坊操作手册.html'; const sha = value => crypto.createHash('sha256').update(value).digest('hex'); const read = file => fs.readFileSync(path.join(root, file), 'utf8'); const write = (file, text) => fs.writeFileSync(path.join(root, file), text); const walk = dir => fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => { const file = path.join(dir, entry.name); return entry.isDirectory() ? walk(file) : [file]; }); fs.mkdirSync(out, { recursive: true }); const articleHashes = {}; const reportPages = []; for (const file of walk(root).filter(file => file.endsWith('.html'))) { const rel = path.relative(root, file).replaceAll('\\', '/'); let html = read(rel); if (!html.includes('
') || rel === 'index.html') continue; const articles = [...html.matchAll(//g)].map(match => match[0]); articles.forEach((article, index) => { articleHashes[`${rel}#${index}`] = sha(article); }); const base = rel.includes('/') ? '../' : ''; const header = `
产品创新工作坊
`; assert.equal([...html.matchAll(/
/g)].length, 1, rel); html = html.replace(/
[\s\S]*?<\/header>/, () => header) .replaceAll(`href="${base}index.html"`, `href="${base}${manual}"`) .replaceAll('>工作坊首页', '>操作手册'); assert.deepEqual([...html.matchAll(//g)].map(match => match[0]), articles); write(rel, html); reportPages.push(rel); } let css = read('assets/workshop-reports.css'); css = css.replace('justify-content:space-between;gap:18px;align-items:center;padding:14px 28px;z-index:20', 'gap:18px;align-items:center;height:51px;padding:0 28px;z-index:20') .replace('.site-links{display:flex;align-items:center;gap:20px}', '.site-links{display:flex;align-items:center;justify-content:flex-end;margin-left:auto;gap:20px}') .replace('.site-topbar{padding:14px 22px}', '.site-topbar{padding:0 22px}') .replace('html{scroll-padding-top:24px}.site-layout{display:block}', 'html{scroll-padding-top:70px}.site-layout{display:block;padding-top:51px}') .replace('.site-topbar{position:static;padding:11px 16px}', '.site-topbar{position:fixed;top:0;left:0;right:0;height:51px;padding:0 16px}') .replace('.site-links{width:100%;gap:18px}.site-links a:last-child{margin-left:auto}', '.site-links{gap:18px}') .replace('.source-item{scroll-margin-top:16px}', '.source-item{scroll-margin-top:70px}'); write('assets/workshop-reports.css', css); let html = read(manual); html = html.replace('.topbar>span{margin-right:auto;font-size:11px}.topbar>a{font-size:11px}', '.topbar>span{display:none}.top-links{gap:18px}') .replace('.topbar>span{font-size:10px}.topbar>a{font-size:10px}', '.top-links{gap:16px}'); write(manual, html); function redirect(target) { return ` 康师傅 · 产品创新工作坊操作手册

打开康师傅工作坊操作手册

`; } write('index.html', redirect(manual)); write('manual/index.html', redirect('../' + manual)); const routes = JSON.parse(read('site-routes.json')); routes.home = manual; routes.manual = manual; routes.redirects = { 'index.html': manual, 'manual/index.html': manual }; routes.navigation = [ { label: '操作手册', path: manual }, { label: '报告案例', path: '案例报告合集.html' }, { label: '成果看板', url: 'https://kangshifu.fmode.cn/' } ]; write('site-routes.json', JSON.stringify(routes, null, 2) + '\n'); const dataHashes = Object.fromEntries(walk(path.join(root, 'data')).map(file => [path.relative(root, file).replaceAll('\\', '/'), sha(fs.readFileSync(file))])); const beforeFile = path.join(out, 'before.json'); if (!fs.existsSync(beforeFile)) fs.writeFileSync(beforeFile, JSON.stringify({ reportPages, articleHashes, dataHashes }, null, 2) + '\n'); console.log(JSON.stringify({ ok: true, reportPagesUpdated: reportPages.length, home: manual, navigationLinks: 3 }));