clean-dev.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. // scripts/clean-dev.ts
  2. import fs from 'fs/promises'
  3. import path from 'path'
  4. // 现代化颜色主题
  5. const theme = {
  6. // 基础颜色
  7. reset: '\x1b[0m',
  8. bold: '\x1b[1m',
  9. dim: '\x1b[2m',
  10. // 前景色
  11. primary: '\x1b[38;5;75m', // 亮蓝色
  12. success: '\x1b[38;5;82m', // 亮绿色
  13. warning: '\x1b[38;5;220m', // 亮黄色
  14. error: '\x1b[38;5;196m', // 亮红色
  15. info: '\x1b[38;5;159m', // 青色
  16. purple: '\x1b[38;5;141m', // 紫色
  17. orange: '\x1b[38;5;208m', // 橙色
  18. gray: '\x1b[38;5;245m', // 灰色
  19. white: '\x1b[38;5;255m', // 白色
  20. // 背景色
  21. bgDark: '\x1b[48;5;235m', // 深灰背景
  22. bgBlue: '\x1b[48;5;24m', // 蓝色背景
  23. bgGreen: '\x1b[48;5;22m', // 绿色背景
  24. bgRed: '\x1b[48;5;52m' // 红色背景
  25. }
  26. // 现代化图标集
  27. const icons = {
  28. rocket: '🚀',
  29. fire: '🔥',
  30. star: '⭐',
  31. gem: '💎',
  32. crown: '👑',
  33. magic: '✨',
  34. warning: '⚠️',
  35. success: '✅',
  36. error: '❌',
  37. info: 'ℹ️',
  38. folder: '📁',
  39. file: '📄',
  40. image: '🖼️',
  41. code: '💻',
  42. data: '📊',
  43. globe: '🌐',
  44. map: '🗺️',
  45. chat: '💬',
  46. bolt: '⚡',
  47. shield: '🛡️',
  48. key: '🔑',
  49. link: '🔗',
  50. clean: '🧹',
  51. trash: '🗑️',
  52. check: '✓',
  53. cross: '✗',
  54. arrow: '→',
  55. loading: '⏳'
  56. }
  57. // 格式化工具
  58. const fmt = {
  59. title: (text: string) => `${theme.bold}${theme.primary}${text}${theme.reset}`,
  60. subtitle: (text: string) => `${theme.purple}${text}${theme.reset}`,
  61. success: (text: string) => `${theme.success}${text}${theme.reset}`,
  62. error: (text: string) => `${theme.error}${text}${theme.reset}`,
  63. warning: (text: string) => `${theme.warning}${text}${theme.reset}`,
  64. info: (text: string) => `${theme.info}${text}${theme.reset}`,
  65. highlight: (text: string) => `${theme.bold}${theme.white}${text}${theme.reset}`,
  66. dim: (text: string) => `${theme.dim}${theme.gray}${text}${theme.reset}`,
  67. orange: (text: string) => `${theme.orange}${text}${theme.reset}`,
  68. // 带背景的文本
  69. badge: (text: string, bg: string = theme.bgBlue) =>
  70. `${bg}${theme.white}${theme.bold} ${text} ${theme.reset}`,
  71. // 渐变效果模拟
  72. gradient: (text: string) => {
  73. const colors = ['\x1b[38;5;75m', '\x1b[38;5;81m', '\x1b[38;5;87m', '\x1b[38;5;159m']
  74. const chars = text.split('')
  75. return chars.map((char, i) => `${colors[i % colors.length]}${char}`).join('') + theme.reset
  76. }
  77. }
  78. // 创建现代化标题横幅
  79. function createModernBanner() {
  80. console.log()
  81. console.log(
  82. fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
  83. )
  84. console.log(
  85. fmt.gradient(' ║ ║')
  86. )
  87. console.log(
  88. ` ║ ${icons.rocket} ${fmt.title('ART DESIGN PRO')} ${fmt.subtitle('· 代码精简程序')} ${icons.magic} ║`
  89. )
  90. console.log(
  91. ` ║ ${fmt.dim('为项目移除演示数据,快速切换至开发模式')} ║`
  92. )
  93. console.log(
  94. fmt.gradient(' ║ ║')
  95. )
  96. console.log(
  97. fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
  98. )
  99. console.log()
  100. }
  101. // 创建分割线
  102. function createDivider(char = '─', color = theme.primary) {
  103. console.log(`${color}${' ' + char.repeat(66)}${theme.reset}`)
  104. }
  105. // 创建卡片样式容器
  106. function createCard(title: string, content: string[]) {
  107. console.log(` ${fmt.badge('', theme.bgBlue)} ${fmt.title(title)}`)
  108. console.log()
  109. content.forEach((line) => {
  110. console.log(` ${line}`)
  111. })
  112. console.log()
  113. }
  114. // 进度条动画
  115. function createProgressBar(current: number, total: number, text: string, width = 40) {
  116. const percentage = Math.round((current / total) * 100)
  117. const filled = Math.round((current / total) * width)
  118. const empty = width - filled
  119. const filledBar = '█'.repeat(filled)
  120. const emptyBar = '░'.repeat(empty)
  121. process.stdout.write(
  122. `\r ${fmt.info('进度')} [${theme.success}${filledBar}${theme.gray}${emptyBar}${theme.reset}] ${fmt.highlight(percentage + '%')})}`
  123. )
  124. if (current === total) {
  125. console.log()
  126. }
  127. }
  128. // 统计信息
  129. const stats = {
  130. deletedFiles: 0,
  131. deletedPaths: 0,
  132. failedPaths: 0,
  133. startTime: Date.now(),
  134. totalFiles: 0
  135. }
  136. // 清理目标
  137. const targets = [
  138. 'README.md',
  139. 'README.zh-CN.md',
  140. 'CHANGELOG.md',
  141. 'CHANGELOG.zh-CN.md',
  142. 'src/views/change',
  143. 'src/views/safeguard',
  144. 'src/views/article',
  145. 'src/views/examples',
  146. 'src/views/system/nested',
  147. 'src/views/widgets',
  148. 'src/views/template',
  149. 'src/views/dashboard/analysis',
  150. 'src/views/dashboard/ecommerce',
  151. 'src/mock/json',
  152. 'src/mock/temp/articleList.ts',
  153. 'src/mock/temp/commentDetail.ts',
  154. 'src/mock/temp/commentList.ts',
  155. 'src/assets/images/cover',
  156. 'src/assets/images/safeguard',
  157. 'src/assets/images/3d',
  158. 'src/components/core/charts/art-map-chart',
  159. 'src/components/business/comment-widget'
  160. ]
  161. // 递归统计文件数量
  162. async function countFiles(targetPath: string): Promise<number> {
  163. const fullPath = path.resolve(process.cwd(), targetPath)
  164. try {
  165. const stat = await fs.stat(fullPath)
  166. if (stat.isFile()) {
  167. return 1
  168. } else if (stat.isDirectory()) {
  169. const entries = await fs.readdir(fullPath)
  170. let count = 0
  171. for (const entry of entries) {
  172. const entryPath = path.join(targetPath, entry)
  173. count += await countFiles(entryPath)
  174. }
  175. return count
  176. }
  177. } catch {
  178. return 0
  179. }
  180. return 0
  181. }
  182. // 统计所有目标的文件数量
  183. async function countAllFiles(): Promise<number> {
  184. let totalCount = 0
  185. for (const target of targets) {
  186. const count = await countFiles(target)
  187. totalCount += count
  188. }
  189. return totalCount
  190. }
  191. // 删除文件和目录
  192. async function remove(targetPath: string, index: number) {
  193. const fullPath = path.resolve(process.cwd(), targetPath)
  194. createProgressBar(index + 1, targets.length, targetPath)
  195. try {
  196. const fileCount = await countFiles(targetPath)
  197. await fs.rm(fullPath, { recursive: true, force: true })
  198. stats.deletedFiles += fileCount
  199. stats.deletedPaths++
  200. await new Promise((resolve) => setTimeout(resolve, 50))
  201. } catch (err) {
  202. stats.failedPaths++
  203. console.log()
  204. console.log(` ${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(targetPath)}`)
  205. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  206. }
  207. }
  208. // 清理路由模块
  209. async function cleanRouteModules() {
  210. const modulesPath = path.resolve(process.cwd(), 'src/router/modules')
  211. try {
  212. // 删除演示相关的路由模块
  213. const modulesToRemove = [
  214. 'template.ts',
  215. 'widgets.ts',
  216. 'examples.ts',
  217. 'article.ts',
  218. 'safeguard.ts',
  219. 'help.ts'
  220. ]
  221. for (const module of modulesToRemove) {
  222. const modulePath = path.join(modulesPath, module)
  223. try {
  224. await fs.rm(modulePath, { force: true })
  225. } catch {
  226. // 文件不存在时忽略错误
  227. }
  228. }
  229. // 重写 dashboard.ts - 只保留 console
  230. const dashboardContent = `import { AppRouteRecord } from '@/types/router'
  231. export const dashboardRoutes: AppRouteRecord = {
  232. name: 'Dashboard',
  233. path: '/dashboard',
  234. component: '/index/index',
  235. meta: {
  236. title: 'menus.dashboard.title',
  237. icon: 'ri:pie-chart-line',
  238. roles: ['R_SUPER', 'R_ADMIN']
  239. },
  240. children: [
  241. {
  242. path: 'console',
  243. name: 'Console',
  244. component: '/dashboard/console',
  245. meta: {
  246. title: 'menus.dashboard.console',
  247. keepAlive: false,
  248. fixedTab: true
  249. }
  250. }
  251. ]
  252. }
  253. `
  254. await fs.writeFile(path.join(modulesPath, 'dashboard.ts'), dashboardContent, 'utf-8')
  255. // 重写 system.ts - 移除 nested 嵌套菜单
  256. const systemContent = `import { AppRouteRecord } from '@/types/router'
  257. export const systemRoutes: AppRouteRecord = {
  258. path: '/system',
  259. name: 'System',
  260. component: '/index/index',
  261. meta: {
  262. title: 'menus.system.title',
  263. icon: 'ri:user-3-line',
  264. roles: ['R_SUPER', 'R_ADMIN']
  265. },
  266. children: [
  267. {
  268. path: 'user',
  269. name: 'User',
  270. component: '/system/user',
  271. meta: {
  272. title: 'menus.system.user',
  273. keepAlive: true,
  274. roles: ['R_SUPER', 'R_ADMIN']
  275. }
  276. },
  277. {
  278. path: 'role',
  279. name: 'Role',
  280. component: '/system/role',
  281. meta: {
  282. title: 'menus.system.role',
  283. keepAlive: true,
  284. roles: ['R_SUPER']
  285. }
  286. },
  287. {
  288. path: 'user-center',
  289. name: 'UserCenter',
  290. component: '/system/user-center',
  291. meta: {
  292. title: 'menus.system.userCenter',
  293. isHide: true,
  294. keepAlive: true,
  295. isHideTab: true
  296. }
  297. },
  298. {
  299. path: 'menu',
  300. name: 'Menus',
  301. component: '/system/menu',
  302. meta: {
  303. title: 'menus.system.menu',
  304. keepAlive: true,
  305. roles: ['R_SUPER'],
  306. authList: [
  307. { title: '新增', authMark: 'add' },
  308. { title: '编辑', authMark: 'edit' },
  309. { title: '删除', authMark: 'delete' }
  310. ]
  311. }
  312. }
  313. ]
  314. }
  315. `
  316. await fs.writeFile(path.join(modulesPath, 'system.ts'), systemContent, 'utf-8')
  317. // 重写 index.ts - 只导入保留的模块
  318. const indexContent = `import { AppRouteRecord } from '@/types/router'
  319. import { dashboardRoutes } from './dashboard'
  320. import { systemRoutes } from './system'
  321. import { resultRoutes } from './result'
  322. import { exceptionRoutes } from './exception'
  323. /**
  324. * 导出所有模块化路由
  325. */
  326. export const routeModules: AppRouteRecord[] = [
  327. dashboardRoutes,
  328. systemRoutes,
  329. resultRoutes,
  330. exceptionRoutes
  331. ]
  332. `
  333. await fs.writeFile(path.join(modulesPath, 'index.ts'), indexContent, 'utf-8')
  334. console.log(` ${icons.success} ${fmt.success('清理路由模块完成')}`)
  335. } catch (err) {
  336. console.log(` ${icons.error} ${fmt.error('清理路由模块失败')}`)
  337. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  338. }
  339. }
  340. // 清理路由别名
  341. async function cleanRoutesAlias() {
  342. const routesAliasPath = path.resolve(process.cwd(), 'src/router/routesAlias.ts')
  343. try {
  344. const cleanedAlias = `/**
  345. * 公共路由别名
  346. # 存放系统级公共路由路径,如布局容器、登录页等
  347. */
  348. export enum RoutesAlias {
  349. Layout = '/index/index', // 布局容器
  350. Login = '/auth/login' // 登录页
  351. }
  352. `
  353. await fs.writeFile(routesAliasPath, cleanedAlias, 'utf-8')
  354. console.log(` ${icons.success} ${fmt.success('重写路由别名配置完成')}`)
  355. } catch (err) {
  356. console.log(` ${icons.error} ${fmt.error('清理路由别名失败')}`)
  357. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  358. }
  359. }
  360. // 清理变更日志
  361. async function cleanChangeLog() {
  362. const changeLogPath = path.resolve(process.cwd(), 'src/mock/upgrade/changeLog.ts')
  363. try {
  364. const cleanedChangeLog = `import { ref } from 'vue'
  365. interface UpgradeLog {
  366. version: string // 版本号
  367. title: string // 更新标题
  368. date: string // 更新日期
  369. detail?: string[] // 更新内容
  370. requireReLogin?: boolean // 是否需要重新登录
  371. remark?: string // 备注
  372. }
  373. export const upgradeLogList = ref<UpgradeLog[]>([])
  374. `
  375. await fs.writeFile(changeLogPath, cleanedChangeLog, 'utf-8')
  376. console.log(` ${icons.success} ${fmt.success('清空变更日志数据完成')}`)
  377. } catch (err) {
  378. console.log(` ${icons.error} ${fmt.error('清理变更日志失败')}`)
  379. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  380. }
  381. }
  382. // 清理语言文件
  383. async function cleanLanguageFiles() {
  384. const languageFiles = [
  385. { path: 'src/locales/langs/zh.json', name: '中文语言文件' },
  386. { path: 'src/locales/langs/en.json', name: '英文语言文件' }
  387. ]
  388. for (const { path: langPath, name } of languageFiles) {
  389. try {
  390. const fullPath = path.resolve(process.cwd(), langPath)
  391. const content = await fs.readFile(fullPath, 'utf-8')
  392. const langData = JSON.parse(content)
  393. const menusToRemove = [
  394. 'widgets',
  395. 'template',
  396. 'article',
  397. 'examples',
  398. 'safeguard',
  399. 'plan',
  400. 'help'
  401. ]
  402. if (langData.menus) {
  403. menusToRemove.forEach((menuKey) => {
  404. if (langData.menus[menuKey]) {
  405. delete langData.menus[menuKey]
  406. }
  407. })
  408. if (langData.menus.dashboard) {
  409. if (langData.menus.dashboard.analysis) {
  410. delete langData.menus.dashboard.analysis
  411. }
  412. if (langData.menus.dashboard.ecommerce) {
  413. delete langData.menus.dashboard.ecommerce
  414. }
  415. }
  416. if (langData.menus.system) {
  417. const systemKeysToRemove = [
  418. 'nested',
  419. 'menu1',
  420. 'menu2',
  421. 'menu21',
  422. 'menu3',
  423. 'menu31',
  424. 'menu32',
  425. 'menu321'
  426. ]
  427. systemKeysToRemove.forEach((key) => {
  428. if (langData.menus.system[key]) {
  429. delete langData.menus.system[key]
  430. }
  431. })
  432. }
  433. }
  434. await fs.writeFile(fullPath, JSON.stringify(langData, null, 2), 'utf-8')
  435. console.log(` ${icons.success} ${fmt.success(`清理${name}完成`)}`)
  436. } catch (err) {
  437. console.log(` ${icons.error} ${fmt.error(`清理${name}失败`)}`)
  438. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  439. }
  440. }
  441. }
  442. // 清理快速入口组件
  443. async function cleanFastEnterComponent() {
  444. const fastEnterPath = path.resolve(process.cwd(), 'src/config/fastEnter.ts')
  445. try {
  446. const cleanedFastEnter = `/**
  447. * 快速入口配置
  448. * 包含:应用列表、快速链接等配置
  449. */
  450. import { WEB_LINKS } from '@/utils/constants'
  451. import type { FastEnterConfig } from '@/types/config'
  452. const fastEnterConfig: FastEnterConfig = {
  453. // 显示条件(屏幕宽度)
  454. minWidth: 1200,
  455. // 应用列表
  456. applications: [
  457. {
  458. name: '工作台',
  459. description: '系统概览与数据统计',
  460. icon: 'ri:pie-chart-line',
  461. iconColor: '#377dff',
  462. enabled: true,
  463. order: 1,
  464. routeName: 'Console'
  465. },
  466. {
  467. name: '官方文档',
  468. description: '使用指南与开发文档',
  469. icon: 'ri:bill-line',
  470. iconColor: '#ffb100',
  471. enabled: true,
  472. order: 2,
  473. link: WEB_LINKS.DOCS
  474. },
  475. {
  476. name: '技术支持',
  477. description: '技术支持与问题反馈',
  478. icon: 'ri:user-location-line',
  479. iconColor: '#ff6b6b',
  480. enabled: true,
  481. order: 3,
  482. link: WEB_LINKS.COMMUNITY
  483. },
  484. {
  485. name: '哔哩哔哩',
  486. description: '技术分享与交流',
  487. icon: 'ri:bilibili-line',
  488. iconColor: '#FB7299',
  489. enabled: true,
  490. order: 4,
  491. link: WEB_LINKS.BILIBILI
  492. }
  493. ],
  494. // 快速链接
  495. quickLinks: [
  496. {
  497. name: '登录',
  498. enabled: true,
  499. order: 1,
  500. routeName: 'Login'
  501. },
  502. {
  503. name: '注册',
  504. enabled: true,
  505. order: 2,
  506. routeName: 'Register'
  507. },
  508. {
  509. name: '忘记密码',
  510. enabled: true,
  511. order: 3,
  512. routeName: 'ForgetPassword'
  513. },
  514. {
  515. name: '个人中心',
  516. enabled: true,
  517. order: 4,
  518. routeName: 'UserCenter'
  519. }
  520. ]
  521. }
  522. export default Object.freeze(fastEnterConfig)
  523. `
  524. await fs.writeFile(fastEnterPath, cleanedFastEnter, 'utf-8')
  525. console.log(` ${icons.success} ${fmt.success('清理快速入口配置完成')}`)
  526. } catch (err) {
  527. console.log(` ${icons.error} ${fmt.error('清理快速入口配置失败')}`)
  528. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  529. }
  530. }
  531. // 更新菜单接口
  532. async function updateMenuApi() {
  533. const apiPath = path.resolve(process.cwd(), 'src/api/system-manage.ts')
  534. try {
  535. const content = await fs.readFile(apiPath, 'utf-8')
  536. const updatedContent = content.replace(
  537. "url: '/api/v3/system/menus'",
  538. "url: '/api/v3/system/menus/simple'"
  539. )
  540. await fs.writeFile(apiPath, updatedContent, 'utf-8')
  541. console.log(` ${icons.success} ${fmt.success('更新菜单接口完成')}`)
  542. } catch (err) {
  543. console.log(` ${icons.error} ${fmt.error('更新菜单接口失败')}`)
  544. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  545. }
  546. }
  547. // 用户确认函数
  548. async function getUserConfirmation(): Promise<boolean> {
  549. const { createInterface } = await import('readline')
  550. return new Promise((resolve) => {
  551. const rl = createInterface({
  552. input: process.stdin,
  553. output: process.stdout
  554. })
  555. console.log(
  556. ` ${fmt.highlight('请输入')} ${fmt.success('yes')} ${fmt.highlight('确认执行清理操作,或按 Enter 取消')}`
  557. )
  558. console.log()
  559. process.stdout.write(` ${icons.arrow} `)
  560. rl.question('', (answer: string) => {
  561. rl.close()
  562. resolve(answer.toLowerCase().trim() === 'yes')
  563. })
  564. })
  565. }
  566. // 显示清理警告
  567. async function showCleanupWarning() {
  568. createCard('安全警告', [
  569. `${fmt.warning('此操作将永久删除以下演示内容,且无法恢复!')}`,
  570. `${fmt.dim('请仔细阅读清理列表,确认后再继续操作')}`
  571. ])
  572. const cleanupItems = [
  573. {
  574. icon: icons.image,
  575. name: '图片资源',
  576. desc: '演示用的封面图片、3D图片、运维图片等',
  577. color: theme.orange
  578. },
  579. {
  580. icon: icons.file,
  581. name: '演示页面',
  582. desc: 'widgets、template、article、examples、safeguard等页面',
  583. color: theme.purple
  584. },
  585. {
  586. icon: icons.code,
  587. name: '路由模块文件',
  588. desc: '删除演示路由模块,只保留核心模块(dashboard、system、result、exception)',
  589. color: theme.primary
  590. },
  591. {
  592. icon: icons.link,
  593. name: '路由别名',
  594. desc: '重写routesAlias.ts,移除演示路由别名',
  595. color: theme.info
  596. },
  597. {
  598. icon: icons.data,
  599. name: 'Mock数据',
  600. desc: '演示用的JSON数据、文章列表、评论数据等',
  601. color: theme.success
  602. },
  603. {
  604. icon: icons.globe,
  605. name: '多语言文件',
  606. desc: '清理中英文语言包中的演示菜单项',
  607. color: theme.warning
  608. },
  609. { icon: icons.map, name: '地图组件', desc: '移除art-map-chart地图组件', color: theme.error },
  610. { icon: icons.chat, name: '评论组件', desc: '移除comment-widget评论组件', color: theme.orange },
  611. {
  612. icon: icons.bolt,
  613. name: '快速入口',
  614. desc: '移除分析页、礼花效果、聊天、更新日志、定价、留言管理等无效项目',
  615. color: theme.purple
  616. }
  617. ]
  618. console.log(` ${fmt.badge('', theme.bgRed)} ${fmt.title('将要清理的内容')}`)
  619. console.log()
  620. cleanupItems.forEach((item, index) => {
  621. console.log(` ${item.color}${theme.reset} ${fmt.highlight(`${index + 1}. ${item.name}`)}`)
  622. console.log(` ${fmt.dim(item.desc)}`)
  623. })
  624. console.log()
  625. console.log(` ${fmt.badge('', theme.bgGreen)} ${fmt.title('保留的功能模块')}`)
  626. console.log()
  627. const preservedModules = [
  628. { name: 'Dashboard', desc: '工作台页面' },
  629. { name: 'System', desc: '系统管理模块' },
  630. { name: 'Result', desc: '结果页面' },
  631. { name: 'Exception', desc: '异常页面' },
  632. { name: 'Auth', desc: '登录注册功能' },
  633. { name: 'Core Components', desc: '核心组件库' }
  634. ]
  635. preservedModules.forEach((module) => {
  636. console.log(` ${icons.check} ${fmt.success(module.name)} ${fmt.dim(`- ${module.desc}`)}`)
  637. })
  638. console.log()
  639. createDivider()
  640. console.log()
  641. }
  642. // 显示统计信息
  643. async function showStats() {
  644. const duration = Date.now() - stats.startTime
  645. const seconds = (duration / 1000).toFixed(2)
  646. console.log()
  647. createCard('清理统计', [
  648. `${fmt.success('成功删除')}: ${fmt.highlight(stats.deletedFiles.toString())} 个文件`,
  649. `${fmt.info('涉及路径')}: ${fmt.highlight(stats.deletedPaths.toString())} 个目录/文件`,
  650. ...(stats.failedPaths > 0
  651. ? [
  652. `${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(stats.failedPaths.toString())} 个路径`
  653. ]
  654. : []),
  655. `${fmt.info('耗时')}: ${fmt.highlight(seconds)} 秒`
  656. ])
  657. }
  658. // 创建成功横幅
  659. function createSuccessBanner() {
  660. console.log()
  661. console.log(
  662. fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
  663. )
  664. console.log(
  665. fmt.gradient(' ║ ║')
  666. )
  667. console.log(
  668. ` ║ ${icons.star} ${fmt.success('清理完成!项目已准备就绪')} ${icons.rocket} ║`
  669. )
  670. console.log(
  671. ` ║ ${fmt.dim('现在可以开始您的开发之旅了!')} ║`
  672. )
  673. console.log(
  674. fmt.gradient(' ║ ║')
  675. )
  676. console.log(
  677. fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
  678. )
  679. console.log()
  680. }
  681. // 主函数
  682. async function main() {
  683. // 清屏并显示横幅
  684. console.clear()
  685. createModernBanner()
  686. // 显示清理警告
  687. await showCleanupWarning()
  688. // 统计文件数量
  689. console.log(` ${fmt.info('正在统计文件数量...')}`)
  690. stats.totalFiles = await countAllFiles()
  691. console.log(` ${fmt.info('即将清理')}: ${fmt.highlight(stats.totalFiles.toString())} 个文件`)
  692. console.log(` ${fmt.dim(`涉及 ${targets.length} 个目录/文件路径`)}`)
  693. console.log()
  694. // 用户确认
  695. const confirmed = await getUserConfirmation()
  696. if (!confirmed) {
  697. console.log(` ${fmt.warning('操作已取消,清理中止')}`)
  698. console.log()
  699. return
  700. }
  701. console.log()
  702. console.log(` ${icons.check} ${fmt.success('确认成功,开始清理...')}`)
  703. console.log()
  704. // 开始清理过程
  705. console.log(` ${fmt.badge('步骤 1/6', theme.bgBlue)} ${fmt.title('删除演示文件')}`)
  706. console.log()
  707. for (let i = 0; i < targets.length; i++) {
  708. await remove(targets[i], i)
  709. }
  710. console.log()
  711. console.log(` ${fmt.badge('步骤 2/6', theme.bgBlue)} ${fmt.title('清理路由模块')}`)
  712. console.log()
  713. await cleanRouteModules()
  714. console.log()
  715. console.log(` ${fmt.badge('步骤 3/6', theme.bgBlue)} ${fmt.title('重写路由别名')}`)
  716. console.log()
  717. await cleanRoutesAlias()
  718. console.log()
  719. console.log(` ${fmt.badge('步骤 4/6', theme.bgBlue)} ${fmt.title('清空变更日志')}`)
  720. console.log()
  721. await cleanChangeLog()
  722. console.log()
  723. console.log(` ${fmt.badge('步骤 5/6', theme.bgBlue)} ${fmt.title('清理语言文件')}`)
  724. console.log()
  725. await cleanLanguageFiles()
  726. console.log()
  727. console.log(` ${fmt.badge('步骤 6/7', theme.bgBlue)} ${fmt.title('清理快速入口')}`)
  728. console.log()
  729. await cleanFastEnterComponent()
  730. console.log()
  731. console.log(` ${fmt.badge('步骤 7/7', theme.bgBlue)} ${fmt.title('更新菜单接口')}`)
  732. console.log()
  733. await updateMenuApi()
  734. // 显示统计信息
  735. await showStats()
  736. // 显示成功横幅
  737. createSuccessBanner()
  738. }
  739. main().catch((err) => {
  740. console.log()
  741. console.log(` ${icons.error} ${fmt.error('清理脚本执行出错')}`)
  742. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  743. console.log()
  744. process.exit(1)
  745. })