// 扫描 ZF/ruoyi-ui 中残留的小虎租房旧色值,输出「色值 -> 出现次数 / 文件数」清单 // 仅统计,不修改任何文件 // 用法: node _design-test/scan-old-colors.js const fs = require('fs'); const path = require('path'); const ROOT = 'e:/KF_7/ZhenOS-ZF/ruoyi-ui/src'; const EXT = new Set(['.vue', '.scss', '.css', '.js', '.ts']); // 小虎租房旧色板(品牌橙 + 暖中性 + 语义 + 业务梯度) const CAND = new Set([ '#ff7a1a', '#e86a0c', '#d96408', '#ff8a3d', '#ffc48a', '#ffe8d1', '#fff6ec', '#f6ead8', '#faf7f2', '#e9d3b0', '#efe7dc', '#8a7f73', '#c9beb0', '#2a2118', '#3a322a', '#756a5e', '#9a8e80', '#b8ac9e', '#2f2820', '#4a4036', '#ffb31a', '#fff6e0', '#d9481c', '#fdeee8', '#2e9e5b', '#ecf7f0', '#f08060', '#fbbf24', '#1f8a5b', '#fbf5ea', '#d3dce6', '#99a9bf' ]); const stats = new Map(); // hex -> { n, files:Set } const rgbStats = new Map(); function walk(dir) { for (const e of fs.readdirSync(dir, { withFileTypes: true })) { const p = path.join(dir, e.name); if (e.isDirectory()) { walk(p); continue; } if (!EXT.has(path.extname(e.name).toLowerCase())) continue; const txt = fs.readFileSync(p, 'utf8'); const rel = path.relative(ROOT, p).replace(/\\/g, '/'); // 十六进制 const re = /#([0-9a-fA-F]{6})\b/g; let m; while ((m = re.exec(txt))) { const hex = '#' + m[1].toLowerCase(); if (!CAND.has(hex)) continue; if (!stats.has(hex)) stats.set(hex, { n: 0, files: new Set() }); const s = stats.get(hex); s.n++; s.files.add(rel); } // rgb()/rgba() 三元组 const re2 = /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/g; while ((m = re2.exec(txt))) { const key = [m[1], m[2], m[3]].join(','); const hex = '#' + [m[1], m[2], m[3]].map(v => (+v).toString(16).padStart(2, '0')).join(''); if (!CAND.has(hex) && !['255,122,26', '255,179,26', '255,138,61'].includes(key)) continue; if (!rgbStats.has(key)) rgbStats.set(key, { n: 0, files: new Set(), hex }); const s = rgbStats.get(key); s.n++; s.files.add(rel); } } } walk(ROOT); const rows = [...stats.entries()].map(([hex, s]) => ({ hex, n: s.n, f: s.files.size })) .sort((a, b) => b.n - a.n); const rgbRows = [...rgbStats.entries()].map(([k, s]) => ({ k, hex: s.hex, n: s.n, f: s.files.size })) .sort((a, b) => b.n - a.n); console.log('=== 十六进制旧色值(' + rows.length + ' 种)==='); let sum = 0, filesMax = 0; rows.forEach(r => { sum += r.n; filesMax = Math.max(filesMax, r.f); console.log(' ' + r.hex + ' ' + String(r.n).padStart(4) + ' 次 ' + String(r.f).padStart(3) + ' 文件'); }); console.log(' 小计 ' + sum + ' 次'); console.log('\n=== rgb()/rgba() 旧三元组(' + rgbRows.length + ' 种)==='); let sum2 = 0; rgbRows.forEach(r => { sum2 += r.n; console.log(' rgb(' + r.k + ') ' + String(r.n).padStart(4) + ' 次 ' + String(r.f).padStart(3) + ' 文件'); }); console.log(' 小计 ' + sum2 + ' 次'); console.log('\n合计 ' + (sum + sum2) + ' 处');