/** * 全平台原型完成情况汇总页生成脚本 * * 用法:node scripts/generate-overview.js [输出目录] * 默认输出到:C:\Users\lenovo\Desktop\数字味道\蚁熊SAAS项目\产品\已完成\全平台 * * 由 git post-merge hook 在 git pull 后自动触发 */ const fs = require('fs'); const path = require('path'); // ===== 配置 ===== const PROJECT_ROOT = path.resolve(__dirname, '..'); const INDEX_HTML = path.join(PROJECT_ROOT, 'index.html'); const OUTPUT_DIR = process.argv[2] || 'C:\\Users\\lenovo\\Desktop\\数字味道\\蚁熊SAAS项目\\产品\\已完成\\全平台'; // ===== 从 index.html 提取 SITE_MAP 数据 ===== function extractSiteMap(html) { // 找到 const SITE_MAP = [ 开始的位置 const startMarker = 'const SITE_MAP = ['; const startIdx = html.indexOf(startMarker); if (startIdx === -1) throw new Error('未找到 SITE_MAP 定义'); // 从 SITE_MAP 开始,数括号匹配找到结束的 ]; let depth = 0; let inString = false; let stringChar = ''; let i = startIdx + startMarker.length - 1; // -1 因为 [ 已经包含在 marker 中 for (; i < html.length; i++) { const ch = html[i]; if (inString) { if (ch === '\\') { i++; continue; } if (ch === stringChar) { inString = false; } continue; } if (ch === '"' || ch === "'" || ch === '`') { inString = true; stringChar = ch; continue; } if (ch === '[' || ch === '{') { depth++; } else if (ch === ']' || ch === '}') { depth--; if (depth === 0) { // 找到了闭合的 ] const jsCode = html.substring(startIdx + startMarker.indexOf('['), i + 1); // 处理 JS 中的尾逗号(JSON 不允许) const cleanedCode = jsCode .replace(/,(\s*[}\]])/g, '$1') // 移除尾逗号 .replace(/\/\*[\s\S]*?\*\//g, '') // 移除块注释 .replace(/\/\/.*$/gm, ''); // 移除行注释 try { return eval('(' + cleanedCode + ')'); } catch (e) { throw new Error('SITE_MAP 解析失败: ' + e.message); } } } } throw new Error('SITE_MAP 未正确闭合'); } // ===== 提取 ICONS SVG 定义 ===== function extractIcons(html) { const match = html.match(/const ICONS = (\{[\s\S]*?\n\};)/); if (!match) return {}; try { const cleaned = match[1].replace(/,(\s*\})/g, '$1'); return eval('(' + cleaned + ')'); } catch (e) { return {}; } } // ===== 计算模块状态 ===== function getModuleStatus(mod) { const hasPages = mod.pages && mod.pages.length > 0; if (!hasPages) return { status: 'pending', label: '待设计', cls: 'pending' }; if (mod.done) return { status: 'done', label: '已完成', cls: 'done' }; return { status: 'wip', label: '设计中', cls: 'wip' }; } // ===== 统计各端数据 ===== function buildTabStats(tab) { if (tab.roles) { // 健康应急 APP 特殊结构:roles + shared const roleModules = []; tab.roles.forEach(role => { role.modules.forEach(mod => { const st = getModuleStatus(mod); roleModules.push({ name: role.role + ' - ' + mod.name, dir: mod.dir, pages: mod.pages || [], pageCount: (mod.pages || []).length, status: st.status, statusLabel: st.label, statusCls: st.cls, prd: mod.prd || null }); }); }); if (tab.shared) { tab.shared.forEach(mod => { const st = getModuleStatus(mod); roleModules.push({ name: '共享 - ' + mod.name, dir: mod.dir, pages: mod.pages || [], pageCount: (mod.pages || []).length, status: st.status, statusLabel: st.label, statusCls: st.cls, prd: null }); }); } return { id: tab.id, label: tab.label, modules: roleModules, totalPages: roleModules.reduce((s, m) => s + m.pageCount, 0), doneModules: roleModules.filter(m => m.status === 'done').length, wipModules: roleModules.filter(m => m.status === 'wip').length, pendingModules: roleModules.filter(m => m.status === 'pending').length, totalModules: roleModules.length }; } // 标准结构:modules[] const modules = (tab.modules || []).map(mod => { const st = getModuleStatus(mod); return { name: mod.name, dir: mod.dir, pages: mod.pages || [], pageCount: (mod.pages || []).length, status: st.status, statusLabel: st.label, statusCls: st.cls, prd: mod.prd || null, entry: mod.entry || 'index.html' }; }); return { id: tab.id, label: tab.label, modules, totalPages: modules.reduce((s, m) => s + m.pageCount, 0), doneModules: modules.filter(m => m.status === 'done').length, wipModules: modules.filter(m => m.status === 'wip').length, pendingModules: modules.filter(m => m.status === 'pending').length, totalModules: modules.length }; } // ===== 生成 HTML ===== function generateHTML(tabStats, generatedAt) { const grandTotalPages = tabStats.reduce((s, t) => s + t.totalPages, 0); const grandTotalModules = tabStats.reduce((s, t) => s + t.totalModules, 0); const grandDoneModules = tabStats.reduce((s, t) => s + t.doneModules, 0); const platformColors = { 'web-admin': '#69b1ff', 'employee-app': '#95de64', 'emergency-app': '#ffc069', 'other-terminals': '#b37feb' }; const platformIcons = { 'web-admin': '💻', 'employee-app': '📱', 'emergency-app': '🎥', 'other-terminals': '🌐' }; const platformLabels = { 'web-admin': 'Web 管理端', 'employee-app': '员工端 APP', 'emergency-app': '健康应急 APP', 'other-terminals': '其他终端' }; function renderModuleCard(mod) { const statusConfig = { done: { cls: 'card--done', badge: '已完成', badgeCls: 'badge--done' }, wip: { cls: 'card--wip', badge: '设计中', badgeCls: 'badge--wip' }, pending: { cls: 'card--pending', badge: '待设计', badgeCls: 'badge--pending' } }; const sc = statusConfig[mod.status]; const pageLabel = mod.pageCount > 0 ? `${mod.pageCount} 页` : '暂无页面'; const prdLink = mod.prd ? `PRD` : ''; return `
自动生成于 ${generatedAt} | 数据来源:git pull 后最新 SITE_MAP