All checks were successful
Build and Deploy (tool.xpcool.com) / build-and-deploy (push) Successful in 1m6s
视觉体系(核心是「令牌 → TDesign 桥接」) - 新增 tokens.scss:--tk-* 设计令牌(青玉 Jade 单一强调色、冷调中性色阶、 圆角/间距/字号/z-index/动效规范、按语言切换字体栈) - 新增 tdesign-theme.scss:--tk-* → --td-* 桥接(含完整冷调灰阶 1-14) → 60+ 个未改动的存量工具页零成本继承新配色与圆角 - index.scss 重写:只过渡颜色、统一 focus-visible、reduced-motion 降级 - 新增 v-reveal 滚动进入指令 布局与交互 - MainLayout 重写:毛玻璃 sticky 顶栏 + 三区布局 + 页脚(含备案号) - 新增 CommandPalette(⌘K/Ctrl+K)、LocaleSwitch(显示语言代码不用国旗)、 ThemeSwitch(三态;图标显示生效 mode、菜单勾选用户偏好 preference) - SideNav 重写:内联筛选、可折叠分组持久化、活动态指示条、需联网标记 - HomeView 重写:左对齐 Hero + 真实可用搜索 + 概览数字条 + 服务端工具专区 国际化与主题 - vue-i18n 11 + zh-CN/en-US/ja-JP/ko-KR 完整语言包(58 个工具名与描述全译) - helpers 取词带中文兜底;index.html 防闪烁内联脚本与 store 三处同步 - 主题三态 light/dark/auto,preference 与 mode 分离 服务端对接(service.xpcool.com /api/service/open/tools/*) - 新增 openTools.ts:接口元数据与调用函数共用同一份路径定义 - 改造/新建 6 页:ip-info、uuid、hash(服务端 MD5 两端口径对比)、 timestamp(服务端时钟 + 时钟偏移)、random-string、api-status - 均为「本机 / 服务端」双模式,默认本机、不自动打网络请求 - 后端未实现的 5 个接口用 BackendPending 如实标注,不伪装可用 修复 - 空分类渲染缺陷(health/study/travel 无工具却渲染空区块),分类 9 → 6 - UnoCSS panel 快捷类补内边距;IpInfoView 漏 onBeforeUnmount; SideNav 末尾 import;HomeView 错误导入 SUPPORTED_LOCALES 其他 - 新增 src/config.ts 集中站点常量,页脚展示备案号并链工信部核验 - docs/api-contract.md 按线上实际重写;PROJECT_STATE.md 全面更新 - 构建通过:vue-tsc --noEmit + vite build
642 lines
20 KiB
TypeScript
642 lines
20 KiB
TypeScript
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.<path>.name / tool.<path>.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<Component>
|
||
}
|
||
|
||
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)
|
||
})
|
||
}
|