按要求删除导航栏「教程」及整个教程模块。
删除内容
- 导航项「教程」(/guide/videos) 及其 activeMatch
- 侧边栏「教程中心」条目
- pages/guide/videos.md(教程中心页,76 行)
- pages/projects/{iotlcm,xiu-dtu,xiu-admin}/guide/tutorial.md(三份教程视频页,共 251 行)
- data/projects.ts 里三个项目的「教程视频」子页面登记
同步清理的引用(避免 404)
- pages/projects/iotlcm/index.md:“下一步”表格里的教程视频行
- pages/projects/iotlcm/guide/quickstart.md:“下一步”里的教程链接
- 4 个审计脚本里的教程路径:
audit-band-offset.mjs / audit-layout.mjs / audit-sidebar-footer.mjs / render-check.mjs
- 注释里「教程等」的措辞
保留的内容(与本次无关,未动)
- DemoVideo.vue 及其 data/demo.ts 里的 demoVideos:
那是「系统演示」页里的 BV 号外链卡片,不是教程栏目
- compare.md 里「录屏教程」对比维度:属于竞品对比表的正常描述
验证
- 导航实测 8 项:首页/系统演示/产品功能/核心能力/界面预览/项目/官方文档/联系我们,无「教程」
- 侧边栏实测仅「门户部署」
- 干净副本构建成功,产物中无 tutorial/videos 文件
- 断链检查:失效项里无一条与教程相关
- check-registry 与 check-nav-brand 通过
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { chromium } from 'playwright'
|
||||
import { createServer } from 'http'
|
||||
import { stat, readFile } from 'fs/promises'
|
||||
import { extname, join, normalize } from 'path'
|
||||
|
||||
const ROOT = process.argv[2]
|
||||
if (!ROOT) { console.error('用法: node render-check.mjs <distDir>'); process.exit(1) }
|
||||
|
||||
const MIME = { '.html':'text/html', '.js':'text/javascript', '.css':'text/css', '.svg':'image/svg+xml', '.png':'image/png', '.jpg':'image/jpeg', '.json':'application/json', '.woff2':'font/woff2', '.woff':'font/woff', '.ico':'image/x-icon' }
|
||||
|
||||
const server = createServer(async (req, res) => {
|
||||
try {
|
||||
let p = decodeURIComponent(req.url.split('?')[0])
|
||||
if (!p.startsWith('/')) p = '/' + p
|
||||
let fp = normalize(join(ROOT, p))
|
||||
try { await stat(fp) } catch {
|
||||
try { await stat(fp + '.html'); fp = fp + '.html' }
|
||||
catch { try { await stat(join(fp, 'index.html')); fp = join(fp, 'index.html') } catch { fp = join(ROOT, '404.html') } }
|
||||
}
|
||||
if ((await stat(fp)).isDirectory()) fp = join(fp, 'index.html')
|
||||
const buf = await readFile(fp)
|
||||
res.writeHead(200, { 'content-type': MIME[extname(fp)] || 'application/octet-stream' })
|
||||
res.end(buf)
|
||||
} catch { res.writeHead(404); res.end('nf') }
|
||||
})
|
||||
await new Promise(r => server.listen(0, r))
|
||||
const port = server.address().port
|
||||
|
||||
const browser = await chromium.launch({ channel: 'chrome', args: ['--no-sandbox'] })
|
||||
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, javaScriptEnabled: false })
|
||||
const page = await ctx.newPage()
|
||||
|
||||
const pages = ['', 'demo', 'about', 'projects/', 'projects/iotlcm/', 'projects/xiu-dtu/', 'projects/xiu-admin/', 'guide/portal-deploy', 'projects/iotlcm/compare', 'projects/iotlcm/guide/deploy', 'projects/iotlcm/guide/quickstart']
|
||||
const results = []
|
||||
for (const p of pages) {
|
||||
const resp = await page.goto(`http://127.0.0.1:${port}/${p}`, { waitUntil: 'load' })
|
||||
const info = await page.evaluate(() => ({
|
||||
is404: !!document.querySelector('.NotFound'),
|
||||
h1: (document.querySelector('h1')?.textContent || '').trim().slice(0, 36),
|
||||
hasNav: !!document.querySelector('.VPNav'),
|
||||
hasFooter: !!document.querySelector('.pf-foot'),
|
||||
}))
|
||||
results.push({ p: p || '(home)', status: resp.status(), ...info })
|
||||
}
|
||||
console.log(`\n=== ${ROOT} 渲染验收 ===`)
|
||||
let ok = 0, fail = 0
|
||||
for (const r of results) {
|
||||
const bad = r.is404 || r.status >= 400 || !r.hasNav
|
||||
if (bad) fail++; else ok++
|
||||
console.log(`${bad ? '❌' : '✅'} ${String(r.status).padEnd(4)} ${r.p.padEnd(34)} ${r.is404 ? '[404页]' : ''} ${r.h1}`)
|
||||
}
|
||||
console.log(`\n通过 ${ok} / 失败 ${fail}`)
|
||||
await browser.close()
|
||||
server.close()
|
||||
process.exit(fail ? 1 : 0)
|
||||
Reference in New Issue
Block a user