| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- /**
- * 扫描 list-search-actions 迁移导致的 Vue 模板结构问题
- */
- const fs = require('fs')
- const path = require('path')
- const roots = process.argv.slice(2).length
- ? process.argv.slice(2)
- : [
- path.join(__dirname, '../src/views'),
- path.join(__dirname, '../../saas-mgnui/src/views'),
- path.join(__dirname, '../../adminui/src/views')
- ]
- function walk(dir, files = []) {
- if (!fs.existsSync(dir)) return files
- for (const name of fs.readdirSync(dir)) {
- const full = path.join(dir, name)
- if (fs.statSync(full).isDirectory()) walk(full, files)
- else if (name.endsWith('.vue')) files.push(full)
- }
- return files
- }
- function scanTemplate(content) {
- const issues = []
- const tplMatch = content.match(/<template>([\s\S]*?)<\/template>/)
- if (!tplMatch) return issues
- const tpl = tplMatch[1]
- // 1. list-search-actions 内嵌套 el-form-item
- const actionsRe = /<el-form-item[^>]*\blist-search-actions\b[^>]*>([\s\S]*?)<\/el-form-item>/g
- let m
- while ((m = actionsRe.exec(tpl)) !== null) {
- if (/<el-form-item\b/.test(m[1])) {
- issues.push('nested-form-item-in-actions')
- }
- if (!/<\/el-form>\s*$/.test(m[1]) && /<\/el-form>/.test(m[1])) {
- issues.push('nested-form-in-actions')
- }
- }
- // 2. list-search-actions 后直接 </el-form> 但 actions 未闭合(只有开标签到 form 结束)
- if (
- /<el-form-item[^>]*list-search-actions[^>]*>\s*<el-form-item\b/.test(tpl) &&
- /<el-form-item[^>]*list-search-actions[^>]*>[\s\S]*?<\/el-form>/.test(tpl) &&
- !/<el-form-item[^>]*list-search-actions[^>]*>[\s\S]*?<\/el-form-item>\s*\n\s*<\/el-form>/.test(tpl)
- ) {
- issues.push('actions-not-closed-before-form-end')
- }
- // 3. 多余的 </el-form-item> 紧接 list-search-actions
- if (/>\s*\n\s*<\/el-form-item>\s*\n\s*<el-form-item[^>]*list-search-actions/.test(tpl)) {
- issues.push('stray-close-before-actions')
- }
- // 4. list-search-actions 内无按钮且含查询 label
- const actionsBlocks = tpl.match(/<el-form-item[^>]*list-search-actions[^>]*>[\s\S]*?<\/el-form-item>/g) || []
- for (const block of actionsBlocks) {
- if (
- /<el-form-item\b[^>]*label=/.test(block) &&
- !/handleQuery|resetQuery|right-toolbar/.test(block)
- ) {
- issues.push('query-fields-only-in-actions-block')
- }
- }
- // 5. 未闭合的 list-search-actions(开标签后遇到 </el-form> 而无 </el-form-item>)
- if (
- /<el-form-item[^>]*list-search-actions[^>]*>[\s\S]*?<\/el-form>/.test(tpl) &&
- !/<el-form-item[^>]*list-search-actions[^>]*>[\s\S]*?<\/el-form-item>[\s\S]*?<\/el-form>/.test(tpl)
- ) {
- issues.push('unclosed-list-search-actions')
- }
- // 6. el-form 内 tag 平衡(仅 queryForm 所在 form)
- const qIdx = tpl.indexOf('ref="queryForm"')
- if (qIdx >= 0) {
- const formStart = tpl.lastIndexOf('<el-form', qIdx)
- const formEnd = tpl.indexOf('</el-form>', qIdx)
- if (formStart >= 0 && formEnd >= 0) {
- const formBody = tpl.slice(formStart, formEnd + '</el-form>'.length)
- const openFi = (formBody.match(/<el-form-item\b/g) || []).length
- const closeFi = (formBody.match(/<\/el-form-item>/g) || []).length
- if (openFi !== closeFi) {
- issues.push(`form-item-balance:${openFi}open/${closeFi}close`)
- }
- }
- }
- return [...new Set(issues)]
- }
- const results = []
- for (const root of roots) {
- for (const file of walk(root)) {
- const content = fs.readFileSync(file, 'utf8')
- const issues = scanTemplate(content)
- if (issues.length) results.push({ file, issues })
- }
- }
- console.log('Total files with issues:', results.length)
- for (const r of results) {
- console.log(r.file.replace(/\\/g, '/'))
- console.log(' ', r.issues.join(', '))
- }
|