- 新增 WindowsCredential 模型和控制器,用于管理 Windows 凭据 - 新增 RemoteAccessToken 模型,支持生成可分享的远程访问链接 - 更新 RemoteDesktopController,添加 Token 生成、验证、撤销等 API - 更新前端 RemoteDesktopModal,支持4种连接方式:快速连接、生成分享链接、手动输入、链接管理 - 新增 WindowsCredentialManager 组件用于管理 Windows 凭据 - 新增 RemoteAccessPage 用于通过 Token 访问远程桌面 - 添加 Vue Router 支持 /remote/:token 路由 - 更新数据库迁移,添加 WindowsCredentials 和 RemoteAccessTokens 表
839 lines
23 KiB
TypeScript
839 lines
23 KiB
TypeScript
// scripts/clean-dev.ts
|
||
import fs from 'fs/promises'
|
||
import path from 'path'
|
||
|
||
// 现代化颜色主题
|
||
const theme = {
|
||
// 基础颜色
|
||
reset: '\x1b[0m',
|
||
bold: '\x1b[1m',
|
||
dim: '\x1b[2m',
|
||
|
||
// 前景色
|
||
primary: '\x1b[38;5;75m', // 亮蓝色
|
||
success: '\x1b[38;5;82m', // 亮绿色
|
||
warning: '\x1b[38;5;220m', // 亮黄色
|
||
error: '\x1b[38;5;196m', // 亮红色
|
||
info: '\x1b[38;5;159m', // 青色
|
||
purple: '\x1b[38;5;141m', // 紫色
|
||
orange: '\x1b[38;5;208m', // 橙色
|
||
gray: '\x1b[38;5;245m', // 灰色
|
||
white: '\x1b[38;5;255m', // 白色
|
||
|
||
// 背景色
|
||
bgDark: '\x1b[48;5;235m', // 深灰背景
|
||
bgBlue: '\x1b[48;5;24m', // 蓝色背景
|
||
bgGreen: '\x1b[48;5;22m', // 绿色背景
|
||
bgRed: '\x1b[48;5;52m' // 红色背景
|
||
}
|
||
|
||
// 现代化图标集
|
||
const icons = {
|
||
rocket: '🚀',
|
||
fire: '🔥',
|
||
star: '⭐',
|
||
gem: '💎',
|
||
crown: '👑',
|
||
magic: '✨',
|
||
warning: '⚠️',
|
||
success: '✅',
|
||
error: '❌',
|
||
info: 'ℹ️',
|
||
folder: '📁',
|
||
file: '📄',
|
||
image: '🖼️',
|
||
code: '💻',
|
||
data: '📊',
|
||
globe: '🌐',
|
||
map: '🗺️',
|
||
chat: '💬',
|
||
bolt: '⚡',
|
||
shield: '🛡️',
|
||
key: '🔑',
|
||
link: '🔗',
|
||
clean: '🧹',
|
||
trash: '🗑️',
|
||
check: '✓',
|
||
cross: '✗',
|
||
arrow: '→',
|
||
loading: '⏳'
|
||
}
|
||
|
||
// 格式化工具
|
||
const fmt = {
|
||
title: (text: string) => `${theme.bold}${theme.primary}${text}${theme.reset}`,
|
||
subtitle: (text: string) => `${theme.purple}${text}${theme.reset}`,
|
||
success: (text: string) => `${theme.success}${text}${theme.reset}`,
|
||
error: (text: string) => `${theme.error}${text}${theme.reset}`,
|
||
warning: (text: string) => `${theme.warning}${text}${theme.reset}`,
|
||
info: (text: string) => `${theme.info}${text}${theme.reset}`,
|
||
highlight: (text: string) => `${theme.bold}${theme.white}${text}${theme.reset}`,
|
||
dim: (text: string) => `${theme.dim}${theme.gray}${text}${theme.reset}`,
|
||
orange: (text: string) => `${theme.orange}${text}${theme.reset}`,
|
||
|
||
// 带背景的文本
|
||
badge: (text: string, bg: string = theme.bgBlue) =>
|
||
`${bg}${theme.white}${theme.bold} ${text} ${theme.reset}`,
|
||
|
||
// 渐变效果模拟
|
||
gradient: (text: string) => {
|
||
const colors = ['\x1b[38;5;75m', '\x1b[38;5;81m', '\x1b[38;5;87m', '\x1b[38;5;159m']
|
||
const chars = text.split('')
|
||
return chars.map((char, i) => `${colors[i % colors.length]}${char}`).join('') + theme.reset
|
||
}
|
||
}
|
||
|
||
// 创建现代化标题横幅
|
||
function createModernBanner() {
|
||
console.log()
|
||
console.log(
|
||
fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
|
||
)
|
||
console.log(
|
||
fmt.gradient(' ║ ║')
|
||
)
|
||
console.log(
|
||
` ║ ${icons.rocket} ${fmt.title('ART DESIGN PRO')} ${fmt.subtitle('· 代码精简程序')} ${icons.magic} ║`
|
||
)
|
||
console.log(
|
||
` ║ ${fmt.dim('为项目移除演示数据,快速切换至开发模式')} ║`
|
||
)
|
||
console.log(
|
||
fmt.gradient(' ║ ║')
|
||
)
|
||
console.log(
|
||
fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
|
||
)
|
||
console.log()
|
||
}
|
||
|
||
// 创建分割线
|
||
function createDivider(char = '─', color = theme.primary) {
|
||
console.log(`${color}${' ' + char.repeat(66)}${theme.reset}`)
|
||
}
|
||
|
||
// 创建卡片样式容器
|
||
function createCard(title: string, content: string[]) {
|
||
console.log(` ${fmt.badge('', theme.bgBlue)} ${fmt.title(title)}`)
|
||
console.log()
|
||
content.forEach((line) => {
|
||
console.log(` ${line}`)
|
||
})
|
||
console.log()
|
||
}
|
||
|
||
// 进度条动画
|
||
function createProgressBar(current: number, total: number, text: string, width = 40) {
|
||
const percentage = Math.round((current / total) * 100)
|
||
const filled = Math.round((current / total) * width)
|
||
const empty = width - filled
|
||
|
||
const filledBar = '█'.repeat(filled)
|
||
const emptyBar = '░'.repeat(empty)
|
||
|
||
process.stdout.write(
|
||
`\r ${fmt.info('进度')} [${theme.success}${filledBar}${theme.gray}${emptyBar}${theme.reset}] ${fmt.highlight(percentage + '%')})}`
|
||
)
|
||
|
||
if (current === total) {
|
||
console.log()
|
||
}
|
||
}
|
||
|
||
// 统计信息
|
||
const stats = {
|
||
deletedFiles: 0,
|
||
deletedPaths: 0,
|
||
failedPaths: 0,
|
||
startTime: Date.now(),
|
||
totalFiles: 0
|
||
}
|
||
|
||
// 清理目标
|
||
const targets = [
|
||
'README.md',
|
||
'README.zh-CN.md',
|
||
'CHANGELOG.md',
|
||
'CHANGELOG.zh-CN.md',
|
||
'src/views/change',
|
||
'src/views/safeguard',
|
||
'src/views/article',
|
||
'src/views/examples',
|
||
'src/views/system/nested',
|
||
'src/views/widgets',
|
||
'src/views/template',
|
||
'src/views/dashboard/analysis',
|
||
'src/views/dashboard/ecommerce',
|
||
'src/mock/json',
|
||
'src/mock/temp/articleList.ts',
|
||
'src/mock/temp/commentDetail.ts',
|
||
'src/mock/temp/commentList.ts',
|
||
'src/assets/images/cover',
|
||
'src/assets/images/safeguard',
|
||
'src/assets/images/3d',
|
||
'src/components/core/charts/art-map-chart',
|
||
'src/components/business/comment-widget'
|
||
]
|
||
|
||
// 递归统计文件数量
|
||
async function countFiles(targetPath: string): Promise<number> {
|
||
const fullPath = path.resolve(process.cwd(), targetPath)
|
||
|
||
try {
|
||
const stat = await fs.stat(fullPath)
|
||
|
||
if (stat.isFile()) {
|
||
return 1
|
||
} else if (stat.isDirectory()) {
|
||
const entries = await fs.readdir(fullPath)
|
||
let count = 0
|
||
|
||
for (const entry of entries) {
|
||
const entryPath = path.join(targetPath, entry)
|
||
count += await countFiles(entryPath)
|
||
}
|
||
|
||
return count
|
||
}
|
||
} catch {
|
||
return 0
|
||
}
|
||
|
||
return 0
|
||
}
|
||
|
||
// 统计所有目标的文件数量
|
||
async function countAllFiles(): Promise<number> {
|
||
let totalCount = 0
|
||
|
||
for (const target of targets) {
|
||
const count = await countFiles(target)
|
||
totalCount += count
|
||
}
|
||
|
||
return totalCount
|
||
}
|
||
|
||
// 删除文件和目录
|
||
async function remove(targetPath: string, index: number) {
|
||
const fullPath = path.resolve(process.cwd(), targetPath)
|
||
|
||
createProgressBar(index + 1, targets.length, targetPath)
|
||
|
||
try {
|
||
const fileCount = await countFiles(targetPath)
|
||
await fs.rm(fullPath, { recursive: true, force: true })
|
||
stats.deletedFiles += fileCount
|
||
stats.deletedPaths++
|
||
await new Promise((resolve) => setTimeout(resolve, 50))
|
||
} catch (err) {
|
||
stats.failedPaths++
|
||
console.log()
|
||
console.log(` ${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(targetPath)}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
|
||
// 清理路由模块
|
||
async function cleanRouteModules() {
|
||
const modulesPath = path.resolve(process.cwd(), 'src/router/modules')
|
||
|
||
try {
|
||
// 删除演示相关的路由模块
|
||
const modulesToRemove = [
|
||
'template.ts',
|
||
'widgets.ts',
|
||
'examples.ts',
|
||
'article.ts',
|
||
'safeguard.ts',
|
||
'help.ts'
|
||
]
|
||
|
||
for (const module of modulesToRemove) {
|
||
const modulePath = path.join(modulesPath, module)
|
||
try {
|
||
await fs.rm(modulePath, { force: true })
|
||
} catch {
|
||
// 文件不存在时忽略错误
|
||
}
|
||
}
|
||
|
||
// 重写 dashboard.ts - 只保留 console
|
||
const dashboardContent = `import { AppRouteRecord } from '@/types/router'
|
||
|
||
export const dashboardRoutes: AppRouteRecord = {
|
||
name: 'Dashboard',
|
||
path: '/dashboard',
|
||
component: '/index/index',
|
||
meta: {
|
||
title: 'menus.dashboard.title',
|
||
icon: 'ri:pie-chart-line',
|
||
roles: ['R_SUPER', 'R_ADMIN']
|
||
},
|
||
children: [
|
||
{
|
||
path: 'console',
|
||
name: 'Console',
|
||
component: '/dashboard/console',
|
||
meta: {
|
||
title: 'menus.dashboard.console',
|
||
keepAlive: false,
|
||
fixedTab: true
|
||
}
|
||
}
|
||
]
|
||
}
|
||
`
|
||
await fs.writeFile(path.join(modulesPath, 'dashboard.ts'), dashboardContent, 'utf-8')
|
||
|
||
// 重写 system.ts - 移除 nested 嵌套菜单
|
||
const systemContent = `import { AppRouteRecord } from '@/types/router'
|
||
|
||
export const systemRoutes: AppRouteRecord = {
|
||
path: '/system',
|
||
name: 'System',
|
||
component: '/index/index',
|
||
meta: {
|
||
title: 'menus.system.title',
|
||
icon: 'ri:user-3-line',
|
||
roles: ['R_SUPER', 'R_ADMIN']
|
||
},
|
||
children: [
|
||
{
|
||
path: 'user',
|
||
name: 'User',
|
||
component: '/system/user',
|
||
meta: {
|
||
title: 'menus.system.user',
|
||
keepAlive: true,
|
||
roles: ['R_SUPER', 'R_ADMIN']
|
||
}
|
||
},
|
||
{
|
||
path: 'role',
|
||
name: 'Role',
|
||
component: '/system/role',
|
||
meta: {
|
||
title: 'menus.system.role',
|
||
keepAlive: true,
|
||
roles: ['R_SUPER']
|
||
}
|
||
},
|
||
{
|
||
path: 'user-center',
|
||
name: 'UserCenter',
|
||
component: '/system/user-center',
|
||
meta: {
|
||
title: 'menus.system.userCenter',
|
||
isHide: true,
|
||
keepAlive: true,
|
||
isHideTab: true
|
||
}
|
||
},
|
||
{
|
||
path: 'menu',
|
||
name: 'Menus',
|
||
component: '/system/menu',
|
||
meta: {
|
||
title: 'menus.system.menu',
|
||
keepAlive: true,
|
||
roles: ['R_SUPER'],
|
||
authList: [
|
||
{ title: '新增', authMark: 'add' },
|
||
{ title: '编辑', authMark: 'edit' },
|
||
{ title: '删除', authMark: 'delete' }
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
`
|
||
await fs.writeFile(path.join(modulesPath, 'system.ts'), systemContent, 'utf-8')
|
||
|
||
// 重写 index.ts - 只导入保留的模块
|
||
const indexContent = `import { AppRouteRecord } from '@/types/router'
|
||
import { dashboardRoutes } from './dashboard'
|
||
import { systemRoutes } from './system'
|
||
import { resultRoutes } from './result'
|
||
import { exceptionRoutes } from './exception'
|
||
|
||
/**
|
||
* 导出所有模块化路由
|
||
*/
|
||
export const routeModules: AppRouteRecord[] = [
|
||
dashboardRoutes,
|
||
systemRoutes,
|
||
resultRoutes,
|
||
exceptionRoutes
|
||
]
|
||
`
|
||
await fs.writeFile(path.join(modulesPath, 'index.ts'), indexContent, 'utf-8')
|
||
|
||
console.log(` ${icons.success} ${fmt.success('清理路由模块完成')}`)
|
||
} catch (err) {
|
||
console.log(` ${icons.error} ${fmt.error('清理路由模块失败')}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
|
||
// 清理路由别名
|
||
async function cleanRoutesAlias() {
|
||
const routesAliasPath = path.resolve(process.cwd(), 'src/router/routesAlias.ts')
|
||
|
||
try {
|
||
const cleanedAlias = `/**
|
||
* 公共路由别名
|
||
# 存放系统级公共路由路径,如布局容器、登录页等
|
||
*/
|
||
export enum RoutesAlias {
|
||
Layout = '/index/index', // 布局容器
|
||
Login = '/auth/login' // 登录页
|
||
}
|
||
`
|
||
|
||
await fs.writeFile(routesAliasPath, cleanedAlias, 'utf-8')
|
||
console.log(` ${icons.success} ${fmt.success('重写路由别名配置完成')}`)
|
||
} catch (err) {
|
||
console.log(` ${icons.error} ${fmt.error('清理路由别名失败')}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
|
||
// 清理变更日志
|
||
async function cleanChangeLog() {
|
||
const changeLogPath = path.resolve(process.cwd(), 'src/mock/upgrade/changeLog.ts')
|
||
|
||
try {
|
||
const cleanedChangeLog = `import { ref } from 'vue'
|
||
|
||
interface UpgradeLog {
|
||
version: string // 版本号
|
||
title: string // 更新标题
|
||
date: string // 更新日期
|
||
detail?: string[] // 更新内容
|
||
requireReLogin?: boolean // 是否需要重新登录
|
||
remark?: string // 备注
|
||
}
|
||
|
||
export const upgradeLogList = ref<UpgradeLog[]>([])
|
||
`
|
||
|
||
await fs.writeFile(changeLogPath, cleanedChangeLog, 'utf-8')
|
||
console.log(` ${icons.success} ${fmt.success('清空变更日志数据完成')}`)
|
||
} catch (err) {
|
||
console.log(` ${icons.error} ${fmt.error('清理变更日志失败')}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
|
||
// 清理语言文件
|
||
async function cleanLanguageFiles() {
|
||
const languageFiles = [
|
||
{ path: 'src/locales/langs/zh.json', name: '中文语言文件' },
|
||
{ path: 'src/locales/langs/en.json', name: '英文语言文件' }
|
||
]
|
||
|
||
for (const { path: langPath, name } of languageFiles) {
|
||
try {
|
||
const fullPath = path.resolve(process.cwd(), langPath)
|
||
const content = await fs.readFile(fullPath, 'utf-8')
|
||
const langData = JSON.parse(content)
|
||
|
||
const menusToRemove = [
|
||
'widgets',
|
||
'template',
|
||
'article',
|
||
'examples',
|
||
'safeguard',
|
||
'plan',
|
||
'help'
|
||
]
|
||
|
||
if (langData.menus) {
|
||
menusToRemove.forEach((menuKey) => {
|
||
if (langData.menus[menuKey]) {
|
||
delete langData.menus[menuKey]
|
||
}
|
||
})
|
||
|
||
if (langData.menus.dashboard) {
|
||
if (langData.menus.dashboard.analysis) {
|
||
delete langData.menus.dashboard.analysis
|
||
}
|
||
if (langData.menus.dashboard.ecommerce) {
|
||
delete langData.menus.dashboard.ecommerce
|
||
}
|
||
}
|
||
|
||
if (langData.menus.system) {
|
||
const systemKeysToRemove = [
|
||
'nested',
|
||
'menu1',
|
||
'menu2',
|
||
'menu21',
|
||
'menu3',
|
||
'menu31',
|
||
'menu32',
|
||
'menu321'
|
||
]
|
||
systemKeysToRemove.forEach((key) => {
|
||
if (langData.menus.system[key]) {
|
||
delete langData.menus.system[key]
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
await fs.writeFile(fullPath, JSON.stringify(langData, null, 2), 'utf-8')
|
||
console.log(` ${icons.success} ${fmt.success(`清理${name}完成`)}`)
|
||
} catch (err) {
|
||
console.log(` ${icons.error} ${fmt.error(`清理${name}失败`)}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清理快速入口组件
|
||
async function cleanFastEnterComponent() {
|
||
const fastEnterPath = path.resolve(process.cwd(), 'src/config/fastEnter.ts')
|
||
|
||
try {
|
||
const cleanedFastEnter = `/**
|
||
* 快速入口配置
|
||
* 包含:应用列表、快速链接等配置
|
||
*/
|
||
import { WEB_LINKS } from '@/utils/constants'
|
||
import type { FastEnterConfig } from '@/types/config'
|
||
|
||
const fastEnterConfig: FastEnterConfig = {
|
||
// 显示条件(屏幕宽度)
|
||
minWidth: 1200,
|
||
// 应用列表
|
||
applications: [
|
||
{
|
||
name: '工作台',
|
||
description: '系统概览与数据统计',
|
||
icon: 'ri:pie-chart-line',
|
||
iconColor: '#377dff',
|
||
enabled: true,
|
||
order: 1,
|
||
routeName: 'Console'
|
||
},
|
||
{
|
||
name: '官方文档',
|
||
description: '使用指南与开发文档',
|
||
icon: 'ri:bill-line',
|
||
iconColor: '#ffb100',
|
||
enabled: true,
|
||
order: 2,
|
||
link: WEB_LINKS.DOCS
|
||
},
|
||
{
|
||
name: '技术支持',
|
||
description: '技术支持与问题反馈',
|
||
icon: 'ri:user-location-line',
|
||
iconColor: '#ff6b6b',
|
||
enabled: true,
|
||
order: 3,
|
||
link: WEB_LINKS.COMMUNITY
|
||
},
|
||
{
|
||
name: '哔哩哔哩',
|
||
description: '技术分享与交流',
|
||
icon: 'ri:bilibili-line',
|
||
iconColor: '#FB7299',
|
||
enabled: true,
|
||
order: 4,
|
||
link: WEB_LINKS.BILIBILI
|
||
}
|
||
],
|
||
// 快速链接
|
||
quickLinks: [
|
||
{
|
||
name: '登录',
|
||
enabled: true,
|
||
order: 1,
|
||
routeName: 'Login'
|
||
},
|
||
{
|
||
name: '注册',
|
||
enabled: true,
|
||
order: 2,
|
||
routeName: 'Register'
|
||
},
|
||
{
|
||
name: '忘记密码',
|
||
enabled: true,
|
||
order: 3,
|
||
routeName: 'ForgetPassword'
|
||
},
|
||
{
|
||
name: '个人中心',
|
||
enabled: true,
|
||
order: 4,
|
||
routeName: 'UserCenter'
|
||
}
|
||
]
|
||
}
|
||
|
||
export default Object.freeze(fastEnterConfig)
|
||
`
|
||
|
||
await fs.writeFile(fastEnterPath, cleanedFastEnter, 'utf-8')
|
||
console.log(` ${icons.success} ${fmt.success('清理快速入口配置完成')}`)
|
||
} catch (err) {
|
||
console.log(` ${icons.error} ${fmt.error('清理快速入口配置失败')}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
|
||
// 更新菜单接口
|
||
async function updateMenuApi() {
|
||
const apiPath = path.resolve(process.cwd(), 'src/api/system-manage.ts')
|
||
|
||
try {
|
||
const content = await fs.readFile(apiPath, 'utf-8')
|
||
const updatedContent = content.replace(
|
||
"url: '/api/v3/system/menus'",
|
||
"url: '/api/v3/system/menus/simple'"
|
||
)
|
||
|
||
await fs.writeFile(apiPath, updatedContent, 'utf-8')
|
||
console.log(` ${icons.success} ${fmt.success('更新菜单接口完成')}`)
|
||
} catch (err) {
|
||
console.log(` ${icons.error} ${fmt.error('更新菜单接口失败')}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
}
|
||
}
|
||
|
||
// 用户确认函数
|
||
async function getUserConfirmation(): Promise<boolean> {
|
||
const { createInterface } = await import('readline')
|
||
|
||
return new Promise((resolve) => {
|
||
const rl = createInterface({
|
||
input: process.stdin,
|
||
output: process.stdout
|
||
})
|
||
|
||
console.log(
|
||
` ${fmt.highlight('请输入')} ${fmt.success('yes')} ${fmt.highlight('确认执行清理操作,或按 Enter 取消')}`
|
||
)
|
||
console.log()
|
||
process.stdout.write(` ${icons.arrow} `)
|
||
|
||
rl.question('', (answer: string) => {
|
||
rl.close()
|
||
resolve(answer.toLowerCase().trim() === 'yes')
|
||
})
|
||
})
|
||
}
|
||
|
||
// 显示清理警告
|
||
async function showCleanupWarning() {
|
||
createCard('安全警告', [
|
||
`${fmt.warning('此操作将永久删除以下演示内容,且无法恢复!')}`,
|
||
`${fmt.dim('请仔细阅读清理列表,确认后再继续操作')}`
|
||
])
|
||
|
||
const cleanupItems = [
|
||
{
|
||
icon: icons.image,
|
||
name: '图片资源',
|
||
desc: '演示用的封面图片、3D图片、运维图片等',
|
||
color: theme.orange
|
||
},
|
||
{
|
||
icon: icons.file,
|
||
name: '演示页面',
|
||
desc: 'widgets、template、article、examples、safeguard等页面',
|
||
color: theme.purple
|
||
},
|
||
{
|
||
icon: icons.code,
|
||
name: '路由模块文件',
|
||
desc: '删除演示路由模块,只保留核心模块(dashboard、system、result、exception)',
|
||
color: theme.primary
|
||
},
|
||
{
|
||
icon: icons.link,
|
||
name: '路由别名',
|
||
desc: '重写routesAlias.ts,移除演示路由别名',
|
||
color: theme.info
|
||
},
|
||
{
|
||
icon: icons.data,
|
||
name: 'Mock数据',
|
||
desc: '演示用的JSON数据、文章列表、评论数据等',
|
||
color: theme.success
|
||
},
|
||
{
|
||
icon: icons.globe,
|
||
name: '多语言文件',
|
||
desc: '清理中英文语言包中的演示菜单项',
|
||
color: theme.warning
|
||
},
|
||
{ icon: icons.map, name: '地图组件', desc: '移除art-map-chart地图组件', color: theme.error },
|
||
{ icon: icons.chat, name: '评论组件', desc: '移除comment-widget评论组件', color: theme.orange },
|
||
{
|
||
icon: icons.bolt,
|
||
name: '快速入口',
|
||
desc: '移除分析页、礼花效果、聊天、更新日志、定价、留言管理等无效项目',
|
||
color: theme.purple
|
||
}
|
||
]
|
||
|
||
console.log(` ${fmt.badge('', theme.bgRed)} ${fmt.title('将要清理的内容')}`)
|
||
console.log()
|
||
|
||
cleanupItems.forEach((item, index) => {
|
||
console.log(` ${item.color}${theme.reset} ${fmt.highlight(`${index + 1}. ${item.name}`)}`)
|
||
console.log(` ${fmt.dim(item.desc)}`)
|
||
})
|
||
|
||
console.log()
|
||
console.log(` ${fmt.badge('', theme.bgGreen)} ${fmt.title('保留的功能模块')}`)
|
||
console.log()
|
||
|
||
const preservedModules = [
|
||
{ name: 'Dashboard', desc: '工作台页面' },
|
||
{ name: 'System', desc: '系统管理模块' },
|
||
{ name: 'Result', desc: '结果页面' },
|
||
{ name: 'Exception', desc: '异常页面' },
|
||
{ name: 'Auth', desc: '登录注册功能' },
|
||
{ name: 'Core Components', desc: '核心组件库' }
|
||
]
|
||
|
||
preservedModules.forEach((module) => {
|
||
console.log(` ${icons.check} ${fmt.success(module.name)} ${fmt.dim(`- ${module.desc}`)}`)
|
||
})
|
||
|
||
console.log()
|
||
createDivider()
|
||
console.log()
|
||
}
|
||
|
||
// 显示统计信息
|
||
async function showStats() {
|
||
const duration = Date.now() - stats.startTime
|
||
const seconds = (duration / 1000).toFixed(2)
|
||
|
||
console.log()
|
||
createCard('清理统计', [
|
||
`${fmt.success('成功删除')}: ${fmt.highlight(stats.deletedFiles.toString())} 个文件`,
|
||
`${fmt.info('涉及路径')}: ${fmt.highlight(stats.deletedPaths.toString())} 个目录/文件`,
|
||
...(stats.failedPaths > 0
|
||
? [
|
||
`${icons.error} ${fmt.error('删除失败')}: ${fmt.highlight(stats.failedPaths.toString())} 个路径`
|
||
]
|
||
: []),
|
||
`${fmt.info('耗时')}: ${fmt.highlight(seconds)} 秒`
|
||
])
|
||
}
|
||
|
||
// 创建成功横幅
|
||
function createSuccessBanner() {
|
||
console.log()
|
||
console.log(
|
||
fmt.gradient(' ╔══════════════════════════════════════════════════════════════════╗')
|
||
)
|
||
console.log(
|
||
fmt.gradient(' ║ ║')
|
||
)
|
||
console.log(
|
||
` ║ ${icons.star} ${fmt.success('清理完成!项目已准备就绪')} ${icons.rocket} ║`
|
||
)
|
||
console.log(
|
||
` ║ ${fmt.dim('现在可以开始您的开发之旅了!')} ║`
|
||
)
|
||
console.log(
|
||
fmt.gradient(' ║ ║')
|
||
)
|
||
console.log(
|
||
fmt.gradient(' ╚══════════════════════════════════════════════════════════════════╝')
|
||
)
|
||
console.log()
|
||
}
|
||
|
||
// 主函数
|
||
async function main() {
|
||
// 清屏并显示横幅
|
||
console.clear()
|
||
createModernBanner()
|
||
|
||
// 显示清理警告
|
||
await showCleanupWarning()
|
||
|
||
// 统计文件数量
|
||
console.log(` ${fmt.info('正在统计文件数量...')}`)
|
||
stats.totalFiles = await countAllFiles()
|
||
|
||
console.log(` ${fmt.info('即将清理')}: ${fmt.highlight(stats.totalFiles.toString())} 个文件`)
|
||
console.log(` ${fmt.dim(`涉及 ${targets.length} 个目录/文件路径`)}`)
|
||
console.log()
|
||
|
||
// 用户确认
|
||
const confirmed = await getUserConfirmation()
|
||
|
||
if (!confirmed) {
|
||
console.log(` ${fmt.warning('操作已取消,清理中止')}`)
|
||
console.log()
|
||
return
|
||
}
|
||
|
||
console.log()
|
||
console.log(` ${icons.check} ${fmt.success('确认成功,开始清理...')}`)
|
||
console.log()
|
||
|
||
// 开始清理过程
|
||
console.log(` ${fmt.badge('步骤 1/6', theme.bgBlue)} ${fmt.title('删除演示文件')}`)
|
||
console.log()
|
||
for (let i = 0; i < targets.length; i++) {
|
||
await remove(targets[i], i)
|
||
}
|
||
console.log()
|
||
|
||
console.log(` ${fmt.badge('步骤 2/6', theme.bgBlue)} ${fmt.title('清理路由模块')}`)
|
||
console.log()
|
||
await cleanRouteModules()
|
||
console.log()
|
||
|
||
console.log(` ${fmt.badge('步骤 3/6', theme.bgBlue)} ${fmt.title('重写路由别名')}`)
|
||
console.log()
|
||
await cleanRoutesAlias()
|
||
console.log()
|
||
|
||
console.log(` ${fmt.badge('步骤 4/6', theme.bgBlue)} ${fmt.title('清空变更日志')}`)
|
||
console.log()
|
||
await cleanChangeLog()
|
||
console.log()
|
||
|
||
console.log(` ${fmt.badge('步骤 5/6', theme.bgBlue)} ${fmt.title('清理语言文件')}`)
|
||
console.log()
|
||
await cleanLanguageFiles()
|
||
console.log()
|
||
|
||
console.log(` ${fmt.badge('步骤 6/7', theme.bgBlue)} ${fmt.title('清理快速入口')}`)
|
||
console.log()
|
||
await cleanFastEnterComponent()
|
||
console.log()
|
||
|
||
console.log(` ${fmt.badge('步骤 7/7', theme.bgBlue)} ${fmt.title('更新菜单接口')}`)
|
||
console.log()
|
||
await updateMenuApi()
|
||
|
||
// 显示统计信息
|
||
await showStats()
|
||
|
||
// 显示成功横幅
|
||
createSuccessBanner()
|
||
}
|
||
|
||
main().catch((err) => {
|
||
console.log()
|
||
console.log(` ${icons.error} ${fmt.error('清理脚本执行出错')}`)
|
||
console.log(` ${fmt.dim('错误详情: ' + err)}`)
|
||
console.log()
|
||
process.exit(1)
|
||
})
|