You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

880 lines
24 KiB

1 week ago
  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. 'src/views/change',
  141. 'src/views/safeguard',
  142. 'src/views/article',
  143. 'src/views/examples',
  144. 'src/views/system/nested',
  145. 'src/views/widgets',
  146. 'src/views/template',
  147. 'src/views/dashboard/analysis',
  148. 'src/views/dashboard/ecommerce',
  149. 'src/mock/json',
  150. 'src/mock/temp/articleList.ts',
  151. 'src/mock/temp/commentDetail.ts',
  152. 'src/mock/temp/commentList.ts',
  153. 'src/assets/img/cover',
  154. 'src/assets/img/safeguard',
  155. 'src/assets/img/3d',
  156. 'src/components/core/charts/art-map-chart',
  157. 'src/components/custom/comment-widget'
  158. ]
  159. // 递归统计文件数量
  160. async function countFiles(targetPath: string): Promise<number> {
  161. const fullPath = path.resolve(process.cwd(), targetPath)
  162. try {
  163. const stat = await fs.stat(fullPath)
  164. if (stat.isFile()) {
  165. return 1
  166. } else if (stat.isDirectory()) {
  167. const entries = await fs.readdir(fullPath)
  168. let count = 0
  169. for (const entry of entries) {
  170. const entryPath = path.join(targetPath, entry)
  171. count += await countFiles(entryPath)
  172. }
  173. return count
  174. }
  175. } catch {
  176. return 0
  177. }
  178. return 0
  179. }
  180. // 统计所有目标的文件数量
  181. async function countAllFiles(): Promise<number> {
  182. let totalCount = 0
  183. for (const target of targets) {
  184. const count = await countFiles(target)
  185. totalCount += count
  186. }
  187. return totalCount
  188. }
  189. // 删除文件和目录
  190. async function remove(targetPath: string, index: number) {
  191. const fullPath = path.resolve(process.cwd(), targetPath)
  192. createProgressBar(index + 1, targets.length, targetPath)
  193. try {
  194. const fileCount = await countFiles(targetPath)
  195. await fs.rm(fullPath, { recursive: true, force: true })
  196. stats.deletedFiles += fileCount
  197. stats.deletedPaths++
  198. await new Promise((resolve) => setTimeout(resolve, 50))
  199. } catch (err) {
  200. stats.failedPaths++
  201. console.log()
  202. console.log(` ${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(targetPath)}`)
  203. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  204. }
  205. }
  206. // 清理异步路由
  207. async function cleanAsyncRoutes() {
  208. const asyncRoutesPath = path.resolve(process.cwd(), 'src/router/routes/asyncRoutes.ts')
  209. try {
  210. const cleanedRoutes = `import { RoutesAlias } from '../routesAlias'
  211. import { AppRouteRecord } from '@/types/router'
  212. /**
  213. *
  214. *
  215. * :
  216. * - 使
  217. * -
  218. *
  219. * title:
  220. * i18n key'用户列表'
  221. *
  222. * RoutesAlias.Layout component /index/index
  223. * meta asyncRoutes staticRoutes
  224. */
  225. export const asyncRoutes: AppRouteRecord[] = [
  226. {
  227. name: 'Dashboard',
  228. path: '/dashboard',
  229. component: RoutesAlias.Layout,
  230. meta: {
  231. title: 'menus.dashboard.title',
  232. icon: '&#xe721;',
  233. roles: ['R_SUPER', 'R_ADMIN']
  234. },
  235. children: [
  236. {
  237. path: 'console',
  238. name: 'Console',
  239. component: RoutesAlias.Dashboard,
  240. meta: {
  241. title: 'menus.dashboard.console',
  242. keepAlive: false,
  243. fixedTab: true
  244. }
  245. }
  246. ]
  247. },
  248. {
  249. path: '/system',
  250. name: 'System',
  251. component: RoutesAlias.Layout,
  252. meta: {
  253. title: 'menus.system.title',
  254. icon: '&#xe7b9;',
  255. roles: ['R_SUPER', 'R_ADMIN']
  256. },
  257. children: [
  258. {
  259. path: 'user',
  260. name: 'User',
  261. component: RoutesAlias.User,
  262. meta: {
  263. title: 'menus.system.user',
  264. keepAlive: true,
  265. roles: ['R_SUPER', 'R_ADMIN']
  266. }
  267. },
  268. {
  269. path: 'role',
  270. name: 'Role',
  271. component: RoutesAlias.Role,
  272. meta: {
  273. title: 'menus.system.role',
  274. keepAlive: true,
  275. roles: ['R_SUPER']
  276. }
  277. },
  278. {
  279. path: 'user-center',
  280. name: 'UserCenter',
  281. component: RoutesAlias.UserCenter,
  282. meta: {
  283. title: 'menus.system.userCenter',
  284. isHide: true,
  285. keepAlive: true,
  286. isHideTab: true
  287. }
  288. },
  289. {
  290. path: 'menu',
  291. name: 'Menus',
  292. component: RoutesAlias.Menu,
  293. meta: {
  294. title: 'menus.system.menu',
  295. keepAlive: true,
  296. roles: ['R_SUPER'],
  297. authList: [
  298. {
  299. title: '新增',
  300. authMark: 'add'
  301. },
  302. {
  303. title: '编辑',
  304. authMark: 'edit'
  305. },
  306. {
  307. title: '删除',
  308. authMark: 'delete'
  309. }
  310. ]
  311. }
  312. }
  313. ]
  314. },
  315. {
  316. path: '/result',
  317. name: 'Result',
  318. component: RoutesAlias.Layout,
  319. meta: {
  320. title: 'menus.result.title',
  321. icon: '&#xe715;'
  322. },
  323. children: [
  324. {
  325. path: 'success',
  326. name: 'ResultSuccess',
  327. component: RoutesAlias.Success,
  328. meta: {
  329. title: 'menus.result.success',
  330. keepAlive: true
  331. }
  332. },
  333. {
  334. path: 'fail',
  335. name: 'ResultFail',
  336. component: RoutesAlias.Fail,
  337. meta: {
  338. title: 'menus.result.fail',
  339. keepAlive: true
  340. }
  341. }
  342. ]
  343. },
  344. {
  345. path: '/exception',
  346. name: 'Exception',
  347. component: RoutesAlias.Layout,
  348. meta: {
  349. title: 'menus.exception.title',
  350. icon: '&#xe820;'
  351. },
  352. children: [
  353. {
  354. path: '403',
  355. name: '403',
  356. component: RoutesAlias.Exception403,
  357. meta: {
  358. title: 'menus.exception.forbidden',
  359. keepAlive: true
  360. }
  361. },
  362. {
  363. path: '404',
  364. name: '404',
  365. component: RoutesAlias.Exception404,
  366. meta: {
  367. title: 'menus.exception.notFound',
  368. keepAlive: true
  369. }
  370. },
  371. {
  372. path: '500',
  373. name: '500',
  374. component: RoutesAlias.Exception500,
  375. meta: {
  376. title: 'menus.exception.serverError',
  377. keepAlive: true
  378. }
  379. }
  380. ]
  381. }
  382. ]
  383. `
  384. await fs.writeFile(asyncRoutesPath, cleanedRoutes, 'utf-8')
  385. console.log(` ${icons.success} ${fmt.success('重写异步路由配置完成')}`)
  386. } catch (err) {
  387. console.log(` ${icons.error} ${fmt.error('清理异步路由失败')}`)
  388. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  389. }
  390. }
  391. // 清理路由别名
  392. async function cleanRoutesAlias() {
  393. const routesAliasPath = path.resolve(process.cwd(), 'src/router/routesAlias.ts')
  394. try {
  395. const cleanedAlias = `/**
  396. * 便
  397. */
  398. export enum RoutesAlias {
  399. // 布局和认证
  400. Layout = '/index/index', // 布局容器
  401. Login = '/auth/login', // 登录
  402. Register = '/auth/register', // 注册
  403. ForgetPassword = '/auth/forget-password', // 忘记密码
  404. // 异常页面
  405. Exception403 = '/exception/403', // 403
  406. Exception404 = '/exception/404', // 404
  407. Exception500 = '/exception/500', // 500
  408. // 结果页面
  409. Success = '/result/success', // 成功
  410. Fail = '/result/fail', // 失败
  411. // 仪表板
  412. Dashboard = '/dashboard/console', // 工作台
  413. // 系统管理
  414. User = '/system/user', // 账户
  415. Role = '/system/role', // 角色
  416. UserCenter = '/system/user-center', // 用户中心
  417. Menu = '/system/menu' // 菜单
  418. }
  419. `
  420. await fs.writeFile(routesAliasPath, cleanedAlias, 'utf-8')
  421. console.log(` ${icons.success} ${fmt.success('重写路由别名配置完成')}`)
  422. } catch (err) {
  423. console.log(` ${icons.error} ${fmt.error('清理路由别名失败')}`)
  424. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  425. }
  426. }
  427. // 清理变更日志
  428. async function cleanChangeLog() {
  429. const changeLogPath = path.resolve(process.cwd(), 'src/mock/upgrade/changeLog.ts')
  430. try {
  431. const cleanedChangeLog = `import { ref } from 'vue'
  432. interface UpgradeLog {
  433. version: string // 版本号
  434. title: string // 更新标题
  435. date: string // 更新日期
  436. detail?: string[] // 更新内容
  437. requireReLogin?: boolean // 是否需要重新登录
  438. remark?: string // 备注
  439. }
  440. export const upgradeLogList = ref<UpgradeLog[]>([])
  441. `
  442. await fs.writeFile(changeLogPath, cleanedChangeLog, 'utf-8')
  443. console.log(` ${icons.success} ${fmt.success('清空变更日志数据完成')}`)
  444. } catch (err) {
  445. console.log(` ${icons.error} ${fmt.error('清理变更日志失败')}`)
  446. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  447. }
  448. }
  449. // 清理语言文件
  450. async function cleanLanguageFiles() {
  451. const languageFiles = [
  452. { path: 'src/locales/langs/zh.json', name: '中文语言文件' },
  453. { path: 'src/locales/langs/en.json', name: '英文语言文件' }
  454. ]
  455. for (const { path: langPath, name } of languageFiles) {
  456. try {
  457. const fullPath = path.resolve(process.cwd(), langPath)
  458. const content = await fs.readFile(fullPath, 'utf-8')
  459. const langData = JSON.parse(content)
  460. const menusToRemove = [
  461. 'widgets',
  462. 'template',
  463. 'article',
  464. 'examples',
  465. 'safeguard',
  466. 'plan',
  467. 'help'
  468. ]
  469. if (langData.menus) {
  470. menusToRemove.forEach((menuKey) => {
  471. if (langData.menus[menuKey]) {
  472. delete langData.menus[menuKey]
  473. }
  474. })
  475. if (langData.menus.dashboard) {
  476. if (langData.menus.dashboard.analysis) {
  477. delete langData.menus.dashboard.analysis
  478. }
  479. if (langData.menus.dashboard.ecommerce) {
  480. delete langData.menus.dashboard.ecommerce
  481. }
  482. }
  483. if (langData.menus.system) {
  484. const systemKeysToRemove = [
  485. 'nested',
  486. 'menu1',
  487. 'menu2',
  488. 'menu21',
  489. 'menu3',
  490. 'menu31',
  491. 'menu32',
  492. 'menu321'
  493. ]
  494. systemKeysToRemove.forEach((key) => {
  495. if (langData.menus.system[key]) {
  496. delete langData.menus.system[key]
  497. }
  498. })
  499. }
  500. }
  501. await fs.writeFile(fullPath, JSON.stringify(langData, null, 2), 'utf-8')
  502. console.log(` ${icons.success} ${fmt.success(`清理${name}完成`)}`)
  503. } catch (err) {
  504. console.log(` ${icons.error} ${fmt.error(`清理${name}失败`)}`)
  505. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  506. }
  507. }
  508. }
  509. // 清理快速入口组件
  510. async function cleanFastEnterComponent() {
  511. const fastEnterPath = path.resolve(process.cwd(), 'src/config/fastEnter.ts')
  512. try {
  513. const cleanedFastEnter = `/**
  514. *
  515. *
  516. */
  517. import { RoutesAlias } from '@/router/routesAlias'
  518. import { WEB_LINKS } from '@/utils/constants'
  519. import type { FastEnterConfig } from '@/types/config'
  520. const fastEnterConfig: FastEnterConfig = {
  521. // 显示条件(屏幕宽度)
  522. minWidth: 1200,
  523. // 应用列表
  524. applications: [
  525. {
  526. name: '工作台',
  527. description: '系统概览与数据统计',
  528. icon: '&#xe721;',
  529. iconColor: '#377dff',
  530. path: RoutesAlias.Dashboard,
  531. enabled: true,
  532. order: 1
  533. },
  534. {
  535. name: '官方文档',
  536. description: '使用指南与开发文档',
  537. icon: '&#xe788;',
  538. iconColor: '#ffb100',
  539. path: WEB_LINKS.DOCS,
  540. enabled: true,
  541. order: 2
  542. },
  543. {
  544. name: '技术支持',
  545. description: '技术支持与问题反馈',
  546. icon: '&#xe86e;',
  547. iconColor: '#ff6b6b',
  548. path: WEB_LINKS.COMMUNITY,
  549. enabled: true,
  550. order: 3
  551. },
  552. {
  553. name: '哔哩哔哩',
  554. description: '技术分享与交流',
  555. icon: '&#xe6b4;',
  556. iconColor: '#FB7299',
  557. path: WEB_LINKS.BILIBILI,
  558. enabled: true,
  559. order: 4
  560. }
  561. ],
  562. // 快速链接
  563. quickLinks: [
  564. {
  565. name: '登录',
  566. path: RoutesAlias.Login,
  567. enabled: true,
  568. order: 1
  569. },
  570. {
  571. name: '注册',
  572. path: RoutesAlias.Register,
  573. enabled: true,
  574. order: 2
  575. },
  576. {
  577. name: '忘记密码',
  578. path: RoutesAlias.ForgetPassword,
  579. enabled: true,
  580. order: 3
  581. },
  582. {
  583. name: '个人中心',
  584. path: RoutesAlias.UserCenter,
  585. enabled: true,
  586. order: 4
  587. }
  588. ]
  589. }
  590. export default Object.freeze(fastEnterConfig)
  591. `
  592. await fs.writeFile(fastEnterPath, cleanedFastEnter, 'utf-8')
  593. console.log(` ${icons.success} ${fmt.success('清理快速入口配置完成')}`)
  594. } catch (err) {
  595. console.log(` ${icons.error} ${fmt.error('清理快速入口配置失败')}`)
  596. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  597. }
  598. }
  599. // 用户确认函数
  600. async function getUserConfirmation(): Promise<boolean> {
  601. const { createInterface } = await import('readline')
  602. return new Promise((resolve) => {
  603. const rl = createInterface({
  604. input: process.stdin,
  605. output: process.stdout
  606. })
  607. console.log(
  608. ` ${fmt.highlight('请输入')} ${fmt.success('yes')} ${fmt.highlight('确认执行清理操作,或按 Enter 取消')}`
  609. )
  610. console.log()
  611. process.stdout.write(` ${icons.arrow} `)
  612. rl.question('', (answer: string) => {
  613. rl.close()
  614. resolve(answer.toLowerCase().trim() === 'yes')
  615. })
  616. })
  617. }
  618. // 显示清理警告
  619. async function showCleanupWarning() {
  620. createCard('安全警告', [
  621. `${fmt.warning('此操作将永久删除以下演示内容,且无法恢复!')}`,
  622. `${fmt.dim('请仔细阅读清理列表,确认后再继续操作')}`
  623. ])
  624. const cleanupItems = [
  625. {
  626. icon: icons.image,
  627. name: '图片资源',
  628. desc: '演示用的封面图片、3D图片、运维图片等',
  629. color: theme.orange
  630. },
  631. {
  632. icon: icons.file,
  633. name: '演示页面',
  634. desc: 'widgets、template、article、examples、safeguard等页面',
  635. color: theme.purple
  636. },
  637. {
  638. icon: icons.code,
  639. name: '动态路由文件',
  640. desc: '重写asyncRoutes.ts,只保留核心路由',
  641. color: theme.primary
  642. },
  643. {
  644. icon: icons.link,
  645. name: '路由别名',
  646. desc: '重写routesAlias.ts,移除演示路由别名',
  647. color: theme.info
  648. },
  649. {
  650. icon: icons.data,
  651. name: 'Mock数据',
  652. desc: '演示用的JSON数据、文章列表、评论数据等',
  653. color: theme.success
  654. },
  655. {
  656. icon: icons.globe,
  657. name: '多语言文件',
  658. desc: '清理中英文语言包中的演示菜单项',
  659. color: theme.warning
  660. },
  661. { icon: icons.map, name: '地图组件', desc: '移除art-map-chart地图组件', color: theme.error },
  662. { icon: icons.chat, name: '评论组件', desc: '移除comment-widget评论组件', color: theme.orange },
  663. {
  664. icon: icons.bolt,
  665. name: '快速入口',
  666. desc: '移除分析页、礼花效果、聊天、更新日志、定价、留言管理等无效项目',
  667. color: theme.purple
  668. }
  669. ]
  670. console.log(` ${fmt.badge('', theme.bgRed)} ${fmt.title('将要清理的内容')}`)
  671. console.log()
  672. cleanupItems.forEach((item, index) => {
  673. console.log(` ${item.color}${theme.reset} ${fmt.highlight(`${index + 1}. ${item.name}`)}`)
  674. console.log(` ${fmt.dim(item.desc)}`)
  675. })
  676. console.log()
  677. console.log(` ${fmt.badge('', theme.bgGreen)} ${fmt.title('保留的功能模块')}`)
  678. console.log()
  679. const preservedModules = [
  680. { name: 'Dashboard', desc: '工作台页面' },
  681. { name: 'System', desc: '系统管理模块' },
  682. { name: 'Result', desc: '结果页面' },
  683. { name: 'Exception', desc: '异常页面' },
  684. { name: 'Auth', desc: '登录注册功能' },
  685. { name: 'Core Components', desc: '核心组件库' }
  686. ]
  687. preservedModules.forEach((module) => {
  688. console.log(` ${icons.check} ${fmt.success(module.name)} ${fmt.dim(`- ${module.desc}`)}`)
  689. })
  690. console.log()
  691. createDivider()
  692. console.log()
  693. }
  694. // 显示统计信息
  695. async function showStats() {
  696. const duration = Date.now() - stats.startTime
  697. const seconds = (duration / 1000).toFixed(2)
  698. console.log()
  699. createCard('清理统计', [
  700. `${fmt.success('成功删除')}: ${fmt.highlight(stats.deletedFiles.toString())} 个文件`,
  701. `${fmt.info('涉及路径')}: ${fmt.highlight(stats.deletedPaths.toString())} 个目录/文件`,
  702. ...(stats.failedPaths > 0
  703. ? [
  704. `${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(stats.failedPaths.toString())} 个路径`
  705. ]
  706. : []),
  707. `${fmt.info('耗时')}: ${fmt.highlight(seconds)}`
  708. ])
  709. }
  710. // 创建成功横幅
  711. function createSuccessBanner() {
  712. console.log()
  713. console.log(
  714. fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
  715. )
  716. console.log(
  717. fmt.gradient(' ║ ║')
  718. )
  719. console.log(
  720. `${icons.star} ${fmt.success('清理完成!项目已准备就绪')} ${icons.rocket}`
  721. )
  722. console.log(
  723. `${fmt.dim('现在可以开始您的开发之旅了!')}`
  724. )
  725. console.log(
  726. fmt.gradient(' ║ ║')
  727. )
  728. console.log(
  729. fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
  730. )
  731. console.log()
  732. }
  733. // 主函数
  734. async function main() {
  735. // 清屏并显示横幅
  736. console.clear()
  737. createModernBanner()
  738. // 显示清理警告
  739. await showCleanupWarning()
  740. // 统计文件数量
  741. console.log(` ${fmt.info('正在统计文件数量...')}`)
  742. stats.totalFiles = await countAllFiles()
  743. console.log(` ${fmt.info('即将清理')}: ${fmt.highlight(stats.totalFiles.toString())} 个文件`)
  744. console.log(` ${fmt.dim(`涉及 ${targets.length} 个目录/文件路径`)}`)
  745. console.log()
  746. // 用户确认
  747. const confirmed = await getUserConfirmation()
  748. if (!confirmed) {
  749. console.log(` ${fmt.warning('操作已取消,清理中止')}`)
  750. console.log()
  751. return
  752. }
  753. console.log()
  754. console.log(` ${icons.check} ${fmt.success('确认成功,开始清理...')}`)
  755. console.log()
  756. // 开始清理过程
  757. console.log(` ${fmt.badge('步骤 1/6', theme.bgBlue)} ${fmt.title('删除演示文件')}`)
  758. console.log()
  759. for (let i = 0; i < targets.length; i++) {
  760. await remove(targets[i], i)
  761. }
  762. console.log()
  763. console.log(` ${fmt.badge('步骤 2/6', theme.bgBlue)} ${fmt.title('重写路由配置')}`)
  764. console.log()
  765. await cleanAsyncRoutes()
  766. console.log()
  767. console.log(` ${fmt.badge('步骤 3/6', theme.bgBlue)} ${fmt.title('重写路由别名')}`)
  768. console.log()
  769. await cleanRoutesAlias()
  770. console.log()
  771. console.log(` ${fmt.badge('步骤 4/6', theme.bgBlue)} ${fmt.title('清空变更日志')}`)
  772. console.log()
  773. await cleanChangeLog()
  774. console.log()
  775. console.log(` ${fmt.badge('步骤 5/6', theme.bgBlue)} ${fmt.title('清理语言文件')}`)
  776. console.log()
  777. await cleanLanguageFiles()
  778. console.log()
  779. console.log(` ${fmt.badge('步骤 6/6', theme.bgBlue)} ${fmt.title('清理快速入口')}`)
  780. console.log()
  781. await cleanFastEnterComponent()
  782. // 显示统计信息
  783. await showStats()
  784. // 显示成功横幅
  785. createSuccessBanner()
  786. }
  787. main().catch((err) => {
  788. console.log()
  789. console.log(` ${icons.error} ${fmt.error('清理脚本执行出错')}`)
  790. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  791. console.log()
  792. process.exit(1)
  793. })