import type { Component } from 'vue' import { ImageIcon, FileImageIcon, FrameIcon, QrcodeIcon, CodeIcon, TimeIcon, FileIcon, LockOnIcon, CalendarIcon, CalculatorIcon, FingerprintIcon, CreditcardIcon, LocationIcon, LinkIcon, TranslateIcon, BrowseIcon, RefreshIcon, ControlPlatformIcon, Palette1Icon, SwapIcon, FileCodeIcon, ChartIcon, MoneyIcon, InternetIcon, KeyIcon, HeartIcon, WalletIcon, UsergroupIcon, GiftIcon, AlarmIcon, TerminalIcon, GitBranchIcon, ApiIcon, BrushIcon, SoundIcon, ViewModuleIcon, SearchIcon, Table1Icon, LogoGithubIcon, ContrastIcon, Edit2Icon, ChartBarIcon, EarthIcon, GitMergeIcon, SettingIcon, CurrencyExchangeIcon, MobileIcon, WifiIcon, RocketIcon, TextboxIcon, ServerIcon, } from 'tdesign-icons-vue-next' /** * 工具注册表:网站内所有工具的“唯一数据源”。 * 侧边导航、首页卡片、命令面板、路由表均由此文件生成。 * * ⚙️ 新增工具只需三步: * 1. 在 src/views/<工具名>/ 下创建页面组件(可参考现有工具页面); * 2. 在本文件的 tools 数组中追加一条配置(path/name/desc/icon/category/component); * 3. 在 src/i18n/locales/ 的 4 个语言包中补齐 tool..name / tool..desc。 * 无需修改路由文件、首页与侧边栏,它们会自动渲染新工具。 * * 🌐 多语言约定:本文件里的 name / desc 是「简体中文原文」,同时作为翻译缺失时的兜底值; * 其它语言由 i18n 语言包提供(见 src/i18n/helpers.ts 的 toolName / toolDesc)。 * * 🗂️ 分类扩展:在 toolCategories 数组追加一条 { key/label/desc }, * 再把对应工具的 category 指向新 key 即可,导航与首页会自动出现新分组。 * 注意:没有任何工具的分类不会渲染(groupedTools 会过滤掉空分组)。 */ /** 工具分类定义(数据驱动,顺序即展示顺序) */ export interface ToolCategory { /** 分类唯一标识,与 ToolItem.category 对应 */ key: string /** 分类名称(导航分组标题、首页分区标题) */ label: string /** 一句话描述(首页分区副标题) */ desc: string } export const toolCategories: ToolCategory[] = [ { key: 'work', label: '工作效率', desc: '开发编程、办公文本与文件处理' }, { key: 'dev', label: '开发进阶', desc: '面向开发者的格式化、转换与对比工具' }, { key: 'design', label: '创意设计', desc: '生成渐变、占位图与字符画,灵感随手可得' }, { key: 'life', label: '生活助手', desc: '日常计算、查询与决策小工具' }, { key: 'fun', label: '趣味娱乐', desc: '摩斯电码等好玩的小玩具' }, { key: 'online', label: '服务端工具', desc: '调用自建后端开放接口,需要联网' }, ] export interface ToolItem { /** 路由路径(相对根路径,不含前导斜杠),同时用作 i18n 的 key */ path: string /** 工具名称(简体中文原文,翻译缺失时兜底) */ name: string /** 一句话描述(简体中文原文,翻译缺失时兜底) */ desc: string /** 菜单/卡片图标(TDesign 图标组件) */ icon: Component /** 所属分类 key(必须在 toolCategories 中存在),缺省归入第一个分类 */ category?: string /** 是否依赖后端接口(首页会打上「需联网」标记,并参与服务端工具分区) */ needsNetwork?: boolean /** 页面组件(懒加载,减小首屏体积) */ component: () => Promise } export const tools: ToolItem[] = [ /* ==================== 工作效率 ==================== */ { path: 'image-compress', name: '图片压缩', desc: '本地压缩 JPG/PNG/WebP,可调质量,压缩后直接下载', icon: ImageIcon, category: 'work', component: () => import('@/views/image-compress/ImageCompressView.vue'), }, { path: 'image-to-ico', name: '图片转 ICO', desc: 'PNG/JPG/WebP/SVG 转图标,多尺寸合成并控制输出体积', icon: FileImageIcon, category: 'work', component: () => import('@/views/image-to-ico/ImageToIcoView.vue'), }, { path: 'json-format', name: 'JSON 格式化', desc: 'JSON 格式化、压缩、校验,一键复制结果', icon: CodeIcon, category: 'work', component: () => import('@/views/json-format/JsonFormatView.vue'), }, { path: 'timestamp', name: '时间戳转换', desc: '时间戳与时间互转,支持秒/毫秒、批量转换与服务端时间校准', icon: TimeIcon, category: 'work', component: () => import('@/views/timestamp/TimestampView.vue'), }, { path: 'base64', name: 'Base64 编解码', desc: '文本 Base64 编解码,图片文件与 Base64 互转', icon: FileIcon, category: 'work', component: () => import('@/views/base64/Base64View.vue'), }, { path: 'jwt-parse', name: 'JWT 解析', desc: '解析 JWT 的 Header 与 Payload,展示过期时间', icon: LockOnIcon, category: 'work', component: () => import('@/views/jwt-parse/JwtParseView.vue'), }, { path: 'cron', name: 'Cron 表达式', desc: '解析 Cron 下次执行时间,可视化生成表达式', icon: CalendarIcon, category: 'work', component: () => import('@/views/cron/CronView.vue'), }, { path: 'radix-convert', name: '进制转换', desc: '二进制、八进制、十进制、十六进制互转', icon: CalculatorIcon, category: 'work', component: () => import('@/views/radix-convert/RadixConvertView.vue'), }, { path: 'hash', name: '哈希计算', desc: '文本/文件计算 MD5、SHA1、SHA256、SHA512,可对比服务端结果', icon: FingerprintIcon, category: 'work', component: () => import('@/views/hash/HashView.vue'), }, { path: 'url-parse', name: 'URL 解析', desc: '解析协议/域名/路径/参数,也支持构造 URL', icon: LinkIcon, category: 'work', component: () => import('@/views/url-parse/UrlParseView.vue'), }, { path: 'translate', name: '翻译', desc: '中文、英文、韩文、日文互译(免费在线接口)', icon: TranslateIcon, category: 'work', component: () => import('@/views/translate/TranslateView.vue'), }, { path: 'ocr', name: '图片 OCR 识别', desc: '本地识别图片文字,支持中英文(WASM)', icon: BrowseIcon, category: 'work', component: () => import('@/views/ocr/OcrView.vue'), }, { path: 'uuid', name: 'UUID 生成', desc: '批量生成 UUID,可选浏览器本地生成或调用服务端接口', icon: RefreshIcon, category: 'work', component: () => import('@/views/uuid/UuidView.vue'), }, { path: 'regex-test', name: '正则测试', desc: '实时测试正则匹配、分组与替换,匹配高亮显示', icon: ControlPlatformIcon, category: 'work', component: () => import('@/views/regex-test/RegexTestView.vue'), }, { path: 'case-convert', name: '命名转换', desc: '驼峰、蛇形、短横线等命名风格一键互转', icon: CodeIcon, category: 'work', component: () => import('@/views/case-convert/CaseConvertView.vue'), }, { path: 'color-convert', name: '色值转换', desc: 'HEX、RGB、HSL、HSV 互转,取色器 + 预设色板', icon: Palette1Icon, category: 'work', component: () => import('@/views/color-convert/ColorConvertView.vue'), }, { path: 'yaml-json', name: 'YAML ↔ JSON', desc: 'YAML 与 JSON 双向转换,报错定位清晰', icon: FileCodeIcon, category: 'work', component: () => import('@/views/yaml-json/YamlJsonView.vue'), }, { path: 'word-count', name: '字数统计', desc: '统计字符、汉字、单词、段落与阅读时长', icon: ChartIcon, category: 'work', component: () => import('@/views/word-count/WordCountView.vue'), }, { path: 'zh-convert', name: '简繁转换', desc: '简体与繁体中文互转(opencc 词库)', icon: TranslateIcon, category: 'work', component: () => import('@/views/zh-convert/ZhConvertView.vue'), }, /* ==================== 生活助手 ==================== */ { path: 'image-cropper', name: '图片裁剪', desc: '按比例裁剪图片,实时预览,导出 JPG/PNG', icon: FrameIcon, category: 'life', component: () => import('@/views/image-cropper/ImageCropperView.vue'), }, { path: 'qrcode', name: '二维码生成解析', desc: '文本/链接生成二维码,上传图片解析二维码内容', icon: QrcodeIcon, category: 'life', component: () => import('@/views/qrcode/QrcodeView.vue'), }, { path: 'idcard', name: '身份证解析', desc: '校验身份证合法性,解析生日、性别、年龄、地区', icon: CreditcardIcon, category: 'life', component: () => import('@/views/idcard/IdcardView.vue'), }, { path: 'address-parse', name: '地址解析', desc: '拆分中文地址的省、市、区与详细地址', icon: LocationIcon, category: 'life', component: () => import('@/views/address-parse/AddressParseView.vue'), }, { path: 'unit-convert', name: '单位换算', desc: '长度、质量、温度、数据存储等 8 类单位换算', icon: SwapIcon, category: 'life', component: () => import('@/views/unit-convert/UnitConvertView.vue'), }, { path: 'rmb-upper', name: '人民币大写', desc: '数字金额转人民币大写,处理角分与负数', icon: MoneyIcon, category: 'life', component: () => import('@/views/rmb-upper/RmbUpperView.vue'), }, { path: 'date-calc', name: '日期计算', desc: '日期差值、推算与年龄生肖星座计算', icon: CalendarIcon, category: 'life', component: () => import('@/views/date-calc/DateCalcView.vue'), }, { path: 'password-gen', name: '密码生成', desc: '随机强密码批量生成,含强度评估', icon: KeyIcon, category: 'life', component: () => import('@/views/password-gen/PasswordGenView.vue'), }, { path: 'bmi', name: 'BMI 计算器', desc: '计算身体质量指数,中国标准分级与健康体重范围', icon: HeartIcon, category: 'life', component: () => import('@/views/bmi/BmiView.vue'), }, { path: 'mortgage', name: '房贷计算器', desc: '等额本息/等额本金对比,月供、总利息一目了然', icon: WalletIcon, category: 'life', component: () => import('@/views/mortgage/MortgageView.vue'), }, { path: 'bill-split', name: '账单拆分', desc: '多人聚餐 AA 分账,自动生成转账方案', icon: UsergroupIcon, category: 'life', component: () => import('@/views/bill-split/BillSplitView.vue'), }, { path: 'random-decision', name: '随机决定', desc: '选项抽签治选择困难,随机数/骰子一键生成', icon: GiftIcon, category: 'life', component: () => import('@/views/random-decision/RandomDecisionView.vue'), }, { path: 'pomodoro', name: '番茄钟', desc: '专注与休息倒计时,记录完成轮数', icon: AlarmIcon, category: 'life', component: () => import('@/views/pomodoro/PomodoroView.vue'), }, /* ==================== 开发进阶 ==================== */ { path: 'sql-format', name: 'SQL 格式化', desc: 'SQL 语句美化:关键词换行、子句缩进,实时预览', icon: TerminalIcon, category: 'dev', component: () => import('@/views/sql-format/SqlFormatView.vue'), }, { path: 'text-diff', name: '文本对比', desc: '逐行对比两段文本,增删高亮一目了然', icon: GitBranchIcon, category: 'dev', component: () => import('@/views/text-diff/TextDiffView.vue'), }, { path: 'json-to-code', name: 'JSON 转代码', desc: 'JSON 一键生成 TypeScript 接口、Go 结构体与 Python 类', icon: ApiIcon, category: 'dev', component: () => import('@/views/json-to-code/JsonToCodeView.vue'), }, /* ==================== 创意设计 ==================== */ { path: 'gradient-generator', name: '渐变生成器', desc: '可视化调出 CSS 渐变,复制即用,内置流行配色预设', icon: BrushIcon, category: 'design', component: () => import('@/views/gradient-generator/GradientGeneratorView.vue'), }, { path: 'placeholder-image', name: '占位图生成', desc: '自定义尺寸与配色的占位图,PNG 下载 / SVG 代码复制', icon: ImageIcon, category: 'design', component: () => import('@/views/placeholder-image/PlaceholderImageView.vue'), }, { path: 'ascii-art', name: '图片转字符画', desc: '把图片转成 ASCII 字符画,可调密度与反转,酷炫复古', icon: ViewModuleIcon, category: 'design', component: () => import('@/views/ascii-art/AsciiArtView.vue'), }, /* ==================== 趣味娱乐 ==================== */ { path: 'morse-code', name: '摩斯电码', desc: '中英文与摩斯码互转,还能播放滴滴答答的电报声', icon: SoundIcon, category: 'fun', component: () => import('@/views/morse-code/MorseCodeView.vue'), }, /* ==================== 开发进阶(编程工具) ==================== */ { path: 'regex-visual', name: '正则可视化', desc: '把正则解析成结构树,附匹配测试', icon: SearchIcon, category: 'dev', component: () => import('@/views/regex-visual/RegexVisualView.vue'), }, { path: 'markdown-table', name: 'Markdown 表格', desc: '粘贴数据一键生成 Markdown / HTML 表格', icon: Table1Icon, category: 'dev', component: () => import('@/views/markdown-table/MarkdownTableView.vue'), }, { path: 'api-builder', name: 'API 请求构造器', desc: '可视化拼接请求,生成 fetch 与 curl 代码', icon: ApiIcon, category: 'dev', component: () => import('@/views/api-builder/ApiBuilderView.vue'), }, { path: 'gitignore-gen', name: '.gitignore 生成器', desc: '按技术栈勾选生成忽略规则', icon: LogoGithubIcon, category: 'dev', component: () => import('@/views/gitignore-gen/GitignoreGenView.vue'), }, { path: 'code-to-image', name: '代码转图片', desc: '代码渲染成卡片图片,支持语法高亮', icon: ImageIcon, category: 'dev', component: () => import('@/views/code-to-image/CodeToImageView.vue'), }, { path: 'color-namer', name: '颜色命名器', desc: '色值匹配最接近的 CSS 颜色名称', icon: ContrastIcon, category: 'dev', component: () => import('@/views/color-namer/ColorNamerView.vue'), }, { path: 'indent-convert', name: '缩进转换器', desc: '空格与 Tab 缩进互转,2/4/8 空格切换', icon: Edit2Icon, category: 'dev', component: () => import('@/views/indent-convert/IndentConvertView.vue'), }, { path: 'code-stats', name: '代码统计', desc: '统计总行、代码行、注释行与空白行', icon: ChartBarIcon, category: 'dev', component: () => import('@/views/code-stats/CodeStatsView.vue'), }, { path: 'hello-world', name: 'Hello World 大全', desc: '30+ 编程语言的入门代码速查', icon: EarthIcon, category: 'dev', component: () => import('@/views/hello-world/HelloWorldView.vue'), }, { path: 'json-diff', name: 'JSON 对比', desc: '逐键对比两个 JSON 的新增、删除与修改', icon: GitMergeIcon, category: 'dev', component: () => import('@/views/json-diff/JsonDiffView.vue'), }, { path: 'env-parse', name: '环境变量解析', desc: '.env 与 JSON / 键值对双向转换', icon: SettingIcon, category: 'dev', component: () => import('@/views/env-parse/EnvParseView.vue'), }, /* ==================== 服务端工具(调用自建后端开放接口) ==================== * 接口基地址由 VITE_API_BASE 配置,路径为 /api/service/open/tools/*(全部 POST)。 * needsNetwork: true 的工具在首页会打上「需联网」标记。 */ { path: 'api-status', name: '服务端接口状态', desc: '探测后端开放接口的可用性与响应耗时,确认前后端连通情况', icon: ServerIcon, category: 'online', needsNetwork: true, component: () => import('@/views/api-status/ApiStatusView.vue'), }, { path: 'random-string', name: '随机字符串', desc: '按长度与字符类型生成随机串,可选服务端密码学随机源', icon: TextboxIcon, category: 'online', needsNetwork: true, component: () => import('@/views/random-string/RandomStringView.vue'), }, { path: 'ip-info', name: 'IP 信息查询', desc: '查询服务端识别的来源 IP、是否内网地址,并展示本机环境信息', icon: InternetIcon, category: 'online', needsNetwork: true, component: () => import('@/views/ip-info/IpInfoView.vue'), }, { path: 'network-test', name: '网络测试', desc: '站点可达性检测:HTTP / Ping / TCP / DNS', icon: WifiIcon, category: 'online', needsNetwork: true, component: () => import('@/views/network-test/NetworkTestView.vue'), }, { path: 'speed-test', name: '网络测速', desc: '宽带下载/上传速度与延迟测试', icon: RocketIcon, category: 'online', needsNetwork: true, component: () => import('@/views/speed-test/SpeedTestView.vue'), }, { path: 'exchange-rate', name: '汇率换算', desc: '主流货币实时汇率换算', icon: CurrencyExchangeIcon, category: 'online', needsNetwork: true, component: () => import('@/views/exchange-rate/ExchangeRateView.vue'), }, { path: 'express-query', name: '快递查询', desc: '物流轨迹一键查询', icon: LocationIcon, category: 'online', needsNetwork: true, component: () => import('@/views/express-query/ExpressQueryView.vue'), }, { path: 'phone-locate', name: '手机号归属地', desc: '归属地与运营商查询', icon: MobileIcon, category: 'online', needsNetwork: true, component: () => import('@/views/phone-locate/PhoneLocateView.vue'), }, ] /** 工具默认分类:未填写 category 时归入第一个分类 */ export function toolCategoryKey(tool: ToolItem): string { return tool.category ?? toolCategories[0].key } /** * 按分类分组返回工具(按 toolCategories 声明顺序)。 * 侧边导航、首页分区、命令面板统一使用该函数,新增分类零改动。 * * 注意:这里会过滤掉「没有任何工具的分类」。历史上 toolCategories 里 * 有 health / study / travel 三个只声明未使用的分类,导致首页渲染出 * 标题下方空白的分区、侧栏出现空分组标题。过滤后新增分类也不会再复现。 */ export function groupedTools(): Array<{ category: ToolCategory; items: ToolItem[] }> { return toolCategories .map((category) => ({ category, items: tools.filter((t) => toolCategoryKey(t) === category.key), })) .filter((group) => group.items.length > 0) } /** 依赖后端接口的工具(首页做区分展示,命令面板加联网标记) */ export function networkTools(): ToolItem[] { return tools.filter((t) => t.needsNetwork) } /** * 工具搜索:名称、描述、路由 path 三者任一命中即算匹配。 * 同时把 i18n 翻译结果一起纳入匹配,保证英文/日文/韩文界面下 * 用对应语言的关键词也能搜到(例如 "compress" / "압축")。 */ export function searchTools(keyword: string, resolve: (tool: ToolItem) => string[]): ToolItem[] { const kw = keyword.trim().toLowerCase() if (!kw) return tools return tools.filter((tool) => { const haystack = [tool.path, tool.name, tool.desc, ...resolve(tool)] .join(' ') .toLowerCase() return haystack.includes(kw) }) }