const fs = require('fs') const path = require('path') const root = path.resolve(__dirname, '..') const menuPath = path.join(root, 'work', 'menu_inventory_role1.csv') const rows = parseCsv(fs.readFileSync(menuPath, 'utf8')) function parseCsv(text) { const lines = text.replace(/^\uFEFF/, '').trim().split(/\r?\n/) const parseLine = line => { const values = [] let value = '' let quoted = false for (let i = 0; i < line.length; i++) { const char = line[i] if (char === '"') { if (quoted && line[i + 1] === '"') { value += '"'; i++ } else quoted = !quoted } else if (char === ',' && !quoted) { values.push(value); value = '' } else value += char } values.push(value) return values } const headers = parseLine(lines.shift()) return lines.map(line => { const values = parseLine(line) return Object.fromEntries(headers.map((header, i) => [header, values[i] || ''])) }) } function cleanText(value) { return String(value || '') .replace(/<[^>]+>/g, ' ') .replace(/\{\{[^}]+\}\}/g, ' ') .replace(/\s+/g, ' ') .trim() } function unique(values) { return [...new Set(values.map(value => cleanText(value)).filter(Boolean))] } function csv(value) { return `"${String(value == null ? '' : value).replace(/"/g, '""')}"` } const pageRows = [] for (const row of rows) { if (!row.componet || row.pid === '0') continue const relativeView = `${row.componet.replace(/^\//, '')}.vue` const sourcePath = path.join(root, 'src', 'views', relativeView) const exists = fs.existsSync(sourcePath) const source = exists ? fs.readFileSync(sourcePath, 'utf8') : '' const buttons = [] const buttonPattern = /]*>([\s\S]*?)<\/el-button>/g let match while ((match = buttonPattern.exec(source)) !== null) buttons.push(match[1]) const tabs = [] const tabPattern = /]*\blabel\s*=\s*(['"])(.*?)\1/g while ((match = tabPattern.exec(source)) !== null) tabs.push(match[2]) const columns = [] const columnPattern = /]*\blabel\s*=\s*(['"])(.*?)\1/g while ((match = columnPattern.exec(source)) !== null) columns.push(match[2]) const methods = [] const methodPattern = /^\s{4,8}([A-Za-z_$][\w$]*)\s*\([^)]*\)\s*\{/gm while ((match = methodPattern.exec(source)) !== null) methods.push(match[1]) const procedures = [] const procedurePattern = /\bCreateData\s*\(\s*(['"])(.*?)\1\s*,\s*(['"])(.*?)\3/gms while ((match = procedurePattern.exec(source)) !== null) procedures.push(match[4]) const b1 = { get: (source.match(/\bgetB1\s*\(/g) || []).length, post: (source.match(/\bpostB1\s*\(/g) || []).length, patch: (source.match(/\bpatchB1\s*\(/g) || []).length } const tm = { get: (source.match(/\bgettm\s*\(/g) || []).length, post: (source.match(/\bposttm\s*\(/g) || []).length, patch: (source.match(/\bpatchtm\s*\(/g) || []).length } pageRows.push({ module: row.componet.split('/')[1] || '', title: row.title, path: row.componet, component: row.componet, source: relativeView, exists, buttons: unique(buttons).join(' | '), tabs: unique(tabs).join(' | '), columns: unique(columns).join(' | '), methods: unique(methods).join(' | '), procedures: unique(procedures).join(' | '), b1GetPostPatch: `${b1.get}/${b1.post}/${b1.patch}`, tmGetPostPatch: `${tm.get}/${tm.post}/${tm.patch}` }) } const headers = ['module', 'title', 'path', 'component', 'source', 'exists', 'buttons', 'tabs', 'columns', 'methods', 'procedures', 'b1GetPostPatch', 'tmGetPostPatch'] const output = [headers, ...pageRows.map(row => headers.map(header => row[header]))].map(row => row.map(csv).join(',')).join('\n') + '\n' fs.writeFileSync(path.join(root, 'work', 'page_ui_inventory_role1_20260725.csv'), output, 'utf8') const missing = pageRows.filter(row => !row.exists) console.log(JSON.stringify({ menuLeaves: pageRows.length, sourceFilesFound: pageRows.filter(row => row.exists).length, sourceFilesMissing: missing.length, missingComponents: missing.map(row => row.component) }))