clean-dev.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  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. isFullPage: true
  361. }
  362. },
  363. {
  364. path: '404',
  365. name: '404',
  366. component: RoutesAlias.Exception404,
  367. meta: {
  368. title: 'menus.exception.notFound',
  369. keepAlive: true,
  370. isFullPage: true
  371. }
  372. },
  373. {
  374. path: '500',
  375. name: '500',
  376. component: RoutesAlias.Exception500,
  377. meta: {
  378. title: 'menus.exception.serverError',
  379. keepAlive: true,
  380. isFullPage: true
  381. }
  382. }
  383. ]
  384. }
  385. ]
  386. `
  387. await fs.writeFile(asyncRoutesPath, cleanedRoutes, 'utf-8')
  388. console.log(` ${icons.success} ${fmt.success('重写异步路由配置完成')}`)
  389. } catch (err) {
  390. console.log(` ${icons.error} ${fmt.error('清理异步路由失败')}`)
  391. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  392. }
  393. }
  394. // 清理路由别名
  395. async function cleanRoutesAlias() {
  396. const routesAliasPath = path.resolve(process.cwd(), 'src/router/routesAlias.ts')
  397. try {
  398. const cleanedAlias = `/**
  399. * 路由别名,方便快速找到页面,同时可以用作路由跳转
  400. */
  401. export enum RoutesAlias {
  402. // 布局和认证
  403. Layout = '/index/index', // 布局容器
  404. Login = '/auth/login', // 登录
  405. Register = '/auth/register', // 注册
  406. ForgetPassword = '/auth/forget-password', // 忘记密码
  407. // 异常页面
  408. Exception403 = '/exception/403', // 403
  409. Exception404 = '/exception/404', // 404
  410. Exception500 = '/exception/500', // 500
  411. // 结果页面
  412. Success = '/result/success', // 成功
  413. Fail = '/result/fail', // 失败
  414. // 仪表板
  415. Dashboard = '/dashboard/console', // 工作台
  416. // 系统管理
  417. User = '/system/user', // 账户
  418. Role = '/system/role', // 角色
  419. UserCenter = '/system/user-center', // 用户中心
  420. Menu = '/system/menu' // 菜单
  421. }
  422. `
  423. await fs.writeFile(routesAliasPath, cleanedAlias, 'utf-8')
  424. console.log(` ${icons.success} ${fmt.success('重写路由别名配置完成')}`)
  425. } catch (err) {
  426. console.log(` ${icons.error} ${fmt.error('清理路由别名失败')}`)
  427. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  428. }
  429. }
  430. // 清理变更日志
  431. async function cleanChangeLog() {
  432. const changeLogPath = path.resolve(process.cwd(), 'src/mock/upgrade/changeLog.ts')
  433. try {
  434. const cleanedChangeLog = `import { ref } from 'vue'
  435. interface UpgradeLog {
  436. version: string // 版本号
  437. title: string // 更新标题
  438. date: string // 更新日期
  439. detail?: string[] // 更新内容
  440. requireReLogin?: boolean // 是否需要重新登录
  441. remark?: string // 备注
  442. }
  443. export const upgradeLogList = ref<UpgradeLog[]>([])
  444. `
  445. await fs.writeFile(changeLogPath, cleanedChangeLog, 'utf-8')
  446. console.log(` ${icons.success} ${fmt.success('清空变更日志数据完成')}`)
  447. } catch (err) {
  448. console.log(` ${icons.error} ${fmt.error('清理变更日志失败')}`)
  449. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  450. }
  451. }
  452. // 清理语言文件
  453. async function cleanLanguageFiles() {
  454. const languageFiles = [
  455. { path: 'src/locales/langs/zh.json', name: '中文语言文件' },
  456. { path: 'src/locales/langs/en.json', name: '英文语言文件' }
  457. ]
  458. for (const { path: langPath, name } of languageFiles) {
  459. try {
  460. const fullPath = path.resolve(process.cwd(), langPath)
  461. const content = await fs.readFile(fullPath, 'utf-8')
  462. const langData = JSON.parse(content)
  463. const menusToRemove = [
  464. 'widgets',
  465. 'template',
  466. 'article',
  467. 'examples',
  468. 'safeguard',
  469. 'plan',
  470. 'help'
  471. ]
  472. if (langData.menus) {
  473. menusToRemove.forEach((menuKey) => {
  474. if (langData.menus[menuKey]) {
  475. delete langData.menus[menuKey]
  476. }
  477. })
  478. if (langData.menus.dashboard) {
  479. if (langData.menus.dashboard.analysis) {
  480. delete langData.menus.dashboard.analysis
  481. }
  482. if (langData.menus.dashboard.ecommerce) {
  483. delete langData.menus.dashboard.ecommerce
  484. }
  485. }
  486. if (langData.menus.system) {
  487. const systemKeysToRemove = [
  488. 'nested',
  489. 'menu1',
  490. 'menu2',
  491. 'menu21',
  492. 'menu3',
  493. 'menu31',
  494. 'menu32',
  495. 'menu321'
  496. ]
  497. systemKeysToRemove.forEach((key) => {
  498. if (langData.menus.system[key]) {
  499. delete langData.menus.system[key]
  500. }
  501. })
  502. }
  503. }
  504. await fs.writeFile(fullPath, JSON.stringify(langData, null, 2), 'utf-8')
  505. console.log(` ${icons.success} ${fmt.success(`清理${name}完成`)}`)
  506. } catch (err) {
  507. console.log(` ${icons.error} ${fmt.error(`清理${name}失败`)}`)
  508. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  509. }
  510. }
  511. }
  512. // 清理快速入口组件
  513. async function cleanFastEnterComponent() {
  514. const fastEnterPath = path.resolve(process.cwd(), 'src/config/fastEnter.ts')
  515. try {
  516. const cleanedFastEnter = `/**
  517. * 快速入口配置
  518. * 包含:应用列表、快速链接等配置
  519. */
  520. import { RoutesAlias } from '@/router/routesAlias'
  521. import { WEB_LINKS } from '@/utils/constants'
  522. import type { FastEnterConfig } from '@/types/config'
  523. const fastEnterConfig: FastEnterConfig = {
  524. // 显示条件(屏幕宽度)
  525. minWidth: 1200,
  526. // 应用列表
  527. applications: [
  528. {
  529. name: '工作台',
  530. description: '系统概览与数据统计',
  531. icon: '&#xe721;',
  532. iconColor: '#377dff',
  533. path: RoutesAlias.Dashboard,
  534. enabled: true,
  535. order: 1
  536. },
  537. {
  538. name: '官方文档',
  539. description: '使用指南与开发文档',
  540. icon: '&#xe788;',
  541. iconColor: '#ffb100',
  542. path: WEB_LINKS.DOCS,
  543. enabled: true,
  544. order: 2
  545. },
  546. {
  547. name: '技术支持',
  548. description: '技术支持与问题反馈',
  549. icon: '&#xe86e;',
  550. iconColor: '#ff6b6b',
  551. path: WEB_LINKS.COMMUNITY,
  552. enabled: true,
  553. order: 3
  554. },
  555. {
  556. name: '哔哩哔哩',
  557. description: '技术分享与交流',
  558. icon: '&#xe6b4;',
  559. iconColor: '#FB7299',
  560. path: WEB_LINKS.BILIBILI,
  561. enabled: true,
  562. order: 4
  563. }
  564. ],
  565. // 快速链接
  566. quickLinks: [
  567. {
  568. name: '登录',
  569. path: RoutesAlias.Login,
  570. enabled: true,
  571. order: 1
  572. },
  573. {
  574. name: '注册',
  575. path: RoutesAlias.Register,
  576. enabled: true,
  577. order: 2
  578. },
  579. {
  580. name: '忘记密码',
  581. path: RoutesAlias.ForgetPassword,
  582. enabled: true,
  583. order: 3
  584. },
  585. {
  586. name: '个人中心',
  587. path: RoutesAlias.UserCenter,
  588. enabled: true,
  589. order: 4
  590. }
  591. ]
  592. }
  593. export default Object.freeze(fastEnterConfig)
  594. `
  595. await fs.writeFile(fastEnterPath, cleanedFastEnter, 'utf-8')
  596. console.log(` ${icons.success} ${fmt.success('清理快速入口配置完成')}`)
  597. } catch (err) {
  598. console.log(` ${icons.error} ${fmt.error('清理快速入口配置失败')}`)
  599. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  600. }
  601. }
  602. // 用户确认函数
  603. async function getUserConfirmation(): Promise<boolean> {
  604. const { createInterface } = await import('readline')
  605. return new Promise((resolve) => {
  606. const rl = createInterface({
  607. input: process.stdin,
  608. output: process.stdout
  609. })
  610. console.log(
  611. ` ${fmt.highlight('请输入')} ${fmt.success('yes')} ${fmt.highlight('确认执行清理操作,或按 Enter 取消')}`
  612. )
  613. console.log()
  614. process.stdout.write(` ${icons.arrow} `)
  615. rl.question('', (answer: string) => {
  616. rl.close()
  617. resolve(answer.toLowerCase().trim() === 'yes')
  618. })
  619. })
  620. }
  621. // 显示清理警告
  622. async function showCleanupWarning() {
  623. createCard('安全警告', [
  624. `${fmt.warning('此操作将永久删除以下演示内容,且无法恢复!')}`,
  625. `${fmt.dim('请仔细阅读清理列表,确认后再继续操作')}`
  626. ])
  627. const cleanupItems = [
  628. {
  629. icon: icons.image,
  630. name: '图片资源',
  631. desc: '演示用的封面图片、3D图片、运维图片等',
  632. color: theme.orange
  633. },
  634. {
  635. icon: icons.file,
  636. name: '演示页面',
  637. desc: 'widgets、template、article、examples、safeguard等页面',
  638. color: theme.purple
  639. },
  640. {
  641. icon: icons.code,
  642. name: '动态路由文件',
  643. desc: '重写asyncRoutes.ts,只保留核心路由',
  644. color: theme.primary
  645. },
  646. {
  647. icon: icons.link,
  648. name: '路由别名',
  649. desc: '重写routesAlias.ts,移除演示路由别名',
  650. color: theme.info
  651. },
  652. {
  653. icon: icons.data,
  654. name: 'Mock数据',
  655. desc: '演示用的JSON数据、文章列表、评论数据等',
  656. color: theme.success
  657. },
  658. {
  659. icon: icons.globe,
  660. name: '多语言文件',
  661. desc: '清理中英文语言包中的演示菜单项',
  662. color: theme.warning
  663. },
  664. { icon: icons.map, name: '地图组件', desc: '移除art-map-chart地图组件', color: theme.error },
  665. { icon: icons.chat, name: '评论组件', desc: '移除comment-widget评论组件', color: theme.orange },
  666. {
  667. icon: icons.bolt,
  668. name: '快速入口',
  669. desc: '移除分析页、礼花效果、聊天、更新日志、定价、留言管理等无效项目',
  670. color: theme.purple
  671. }
  672. ]
  673. console.log(` ${fmt.badge('', theme.bgRed)} ${fmt.title('将要清理的内容')}`)
  674. console.log()
  675. cleanupItems.forEach((item, index) => {
  676. console.log(` ${item.color}${theme.reset} ${fmt.highlight(`${index + 1}. ${item.name}`)}`)
  677. console.log(` ${fmt.dim(item.desc)}`)
  678. })
  679. console.log()
  680. console.log(` ${fmt.badge('', theme.bgGreen)} ${fmt.title('保留的功能模块')}`)
  681. console.log()
  682. const preservedModules = [
  683. { name: 'Dashboard', desc: '工作台页面' },
  684. { name: 'System', desc: '系统管理模块' },
  685. { name: 'Result', desc: '结果页面' },
  686. { name: 'Exception', desc: '异常页面' },
  687. { name: 'Auth', desc: '登录注册功能' },
  688. { name: 'Core Components', desc: '核心组件库' }
  689. ]
  690. preservedModules.forEach((module) => {
  691. console.log(` ${icons.check} ${fmt.success(module.name)} ${fmt.dim(`- ${module.desc}`)}`)
  692. })
  693. console.log()
  694. createDivider()
  695. console.log()
  696. }
  697. // 显示统计信息
  698. async function showStats() {
  699. const duration = Date.now() - stats.startTime
  700. const seconds = (duration / 1000).toFixed(2)
  701. console.log()
  702. createCard('清理统计', [
  703. `${fmt.success('成功删除')}: ${fmt.highlight(stats.deletedFiles.toString())} 个文件`,
  704. `${fmt.info('涉及路径')}: ${fmt.highlight(stats.deletedPaths.toString())} 个目录/文件`,
  705. ...(stats.failedPaths > 0
  706. ? [
  707. `${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(stats.failedPaths.toString())} 个路径`
  708. ]
  709. : []),
  710. `${fmt.info('耗时')}: ${fmt.highlight(seconds)} 秒`
  711. ])
  712. }
  713. // 创建成功横幅
  714. function createSuccessBanner() {
  715. console.log()
  716. console.log(
  717. fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
  718. )
  719. console.log(
  720. fmt.gradient(' ║ ║')
  721. )
  722. console.log(
  723. ` ║ ${icons.star} ${fmt.success('清理完成!项目已准备就绪')} ${icons.rocket} ║`
  724. )
  725. console.log(
  726. ` ║ ${fmt.dim('现在可以开始您的开发之旅了!')} ║`
  727. )
  728. console.log(
  729. fmt.gradient(' ║ ║')
  730. )
  731. console.log(
  732. fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
  733. )
  734. console.log()
  735. }
  736. // 主函数
  737. async function main() {
  738. // 清屏并显示横幅
  739. console.clear()
  740. createModernBanner()
  741. // 显示清理警告
  742. await showCleanupWarning()
  743. // 统计文件数量
  744. console.log(` ${fmt.info('正在统计文件数量...')}`)
  745. stats.totalFiles = await countAllFiles()
  746. console.log(` ${fmt.info('即将清理')}: ${fmt.highlight(stats.totalFiles.toString())} 个文件`)
  747. console.log(` ${fmt.dim(`涉及 ${targets.length} 个目录/文件路径`)}`)
  748. console.log()
  749. // 用户确认
  750. const confirmed = await getUserConfirmation()
  751. if (!confirmed) {
  752. console.log(` ${fmt.warning('操作已取消,清理中止')}`)
  753. console.log()
  754. return
  755. }
  756. console.log()
  757. console.log(` ${icons.check} ${fmt.success('确认成功,开始清理...')}`)
  758. console.log()
  759. // 开始清理过程
  760. console.log(` ${fmt.badge('步骤 1/6', theme.bgBlue)} ${fmt.title('删除演示文件')}`)
  761. console.log()
  762. for (let i = 0; i < targets.length; i++) {
  763. await remove(targets[i], i)
  764. }
  765. console.log()
  766. console.log(` ${fmt.badge('步骤 2/6', theme.bgBlue)} ${fmt.title('重写路由配置')}`)
  767. console.log()
  768. await cleanAsyncRoutes()
  769. console.log()
  770. console.log(` ${fmt.badge('步骤 3/6', theme.bgBlue)} ${fmt.title('重写路由别名')}`)
  771. console.log()
  772. await cleanRoutesAlias()
  773. console.log()
  774. console.log(` ${fmt.badge('步骤 4/6', theme.bgBlue)} ${fmt.title('清空变更日志')}`)
  775. console.log()
  776. await cleanChangeLog()
  777. console.log()
  778. console.log(` ${fmt.badge('步骤 5/6', theme.bgBlue)} ${fmt.title('清理语言文件')}`)
  779. console.log()
  780. await cleanLanguageFiles()
  781. console.log()
  782. console.log(` ${fmt.badge('步骤 6/6', theme.bgBlue)} ${fmt.title('清理快速入口')}`)
  783. console.log()
  784. await cleanFastEnterComponent()
  785. // 显示统计信息
  786. await showStats()
  787. // 显示成功横幅
  788. createSuccessBanner()
  789. }
  790. main().catch((err) => {
  791. console.log()
  792. console.log(` ${icons.error} ${fmt.error('清理脚本执行出错')}`)
  793. console.log(` ${fmt.dim('错误详情: ' + err)}`)
  794. console.log()
  795. process.exit(1)
  796. })