性能优化
This commit is contained in:
@@ -0,0 +1,484 @@
|
||||
// This file has been generated by Tauri Specta. Do not edit this file manually.
|
||||
|
||||
import { invoke as __TAURI_INVOKE } from "@tauri-apps/api/core";
|
||||
|
||||
/** Commands */
|
||||
export const commands = {
|
||||
proxyActivateProfile: (id: string) => __TAURI_INVOKE<null>("proxy_activate_profile", { id }),
|
||||
proxyCheckKernelUpdate: () => __TAURI_INVOKE<KernelUpdateInfo>("proxy_check_kernel_update"),
|
||||
proxyClearSystemProxy: () => __TAURI_INVOKE<null>("proxy_clear_system_proxy"),
|
||||
proxyCloseConnection: (id: string) => __TAURI_INVOKE<null>("proxy_close_connection", { id }),
|
||||
proxyDeleteProfile: (id: string) => __TAURI_INVOKE<null>("proxy_delete_profile", { id }),
|
||||
proxyGetSettings: () => __TAURI_INVOKE<ProxySettings>("proxy_get_settings"),
|
||||
proxyGetSystemProxy: () => __TAURI_INVOKE<boolean>("proxy_get_system_proxy"),
|
||||
proxyImportProfile: (url: string, name: string) => __TAURI_INVOKE<ProfileMeta>("proxy_import_profile", { url, name }),
|
||||
/** 首次安装内核(与 update_kernel 共用 install_kernel 实现,语义独立便于前端区分场景) */
|
||||
proxyInstallKernel: (mirrorPrefix: string | null) => __TAURI_INVOKE<KernelInfo>("proxy_install_kernel", { mirrorPrefix }),
|
||||
proxyKernelInfo: () => __TAURI_INVOKE<KernelInfo>("proxy_kernel_info"),
|
||||
proxyRestart: () => __TAURI_INVOKE<ProcessInfo>("proxy_restart"),
|
||||
proxySaveSettings: (settings: ProxySettings) => __TAURI_INVOKE<null>("proxy_save_settings", { settings }),
|
||||
proxySelectProxy: (group: string, name: string) => __TAURI_INVOKE<null>("proxy_select_proxy", { group, name }),
|
||||
proxySetSystemProxy: () => __TAURI_INVOKE<null>("proxy_set_system_proxy"),
|
||||
proxyStart: () => __TAURI_INVOKE<ProcessInfo>("proxy_start"),
|
||||
proxyStatus: () => __TAURI_INVOKE<ProxyStatus>("proxy_status"),
|
||||
proxyStop: () => __TAURI_INVOKE<null>("proxy_stop"),
|
||||
proxyTestDelay: (name: string, url: string | null, timeout: number | null) => __TAURI_INVOKE<number>("proxy_test_delay", { name, url, timeout }),
|
||||
proxyUpdateKernel: (mirrorPrefix: string | null) => __TAURI_INVOKE<KernelInfo>("proxy_update_kernel", { mirrorPrefix }),
|
||||
proxyUpdateProfile: (id: string) => __TAURI_INVOKE<ProfileMeta>("proxy_update_profile", { id }),
|
||||
/** 读取快速面板设置(快捷键等) */
|
||||
quickpanelGetSettings: () => __TAURI_INVOKE<QuickPanelSettings>("quickpanel_get_settings"),
|
||||
/** 保存快速面板设置;快捷键变化时自动重新注册 + 预创建窗口 */
|
||||
quickpanelSaveSettings: (settings: QuickPanelSettings) => __TAURI_INVOKE<null>("quickpanel_save_settings", { settings }),
|
||||
/** 注册(或切换)快速面板全局快捷键 */
|
||||
quickpanelRegisterShortcut: (shortcut: string) => __TAURI_INVOKE<null>("quickpanel_register_shortcut", { shortcut }),
|
||||
/** 注销快速面板全局快捷键 */
|
||||
quickpanelUnregisterShortcut: () => __TAURI_INVOKE<null>("quickpanel_unregister_shortcut"),
|
||||
/** 手动触发显示快速面板(供 UI 按钮调用) */
|
||||
quickpanelShowPopup: () => __TAURI_INVOKE<null>("quickpanel_show_popup"),
|
||||
/** 隐藏快速面板 */
|
||||
quickpanelHidePopup: () => __TAURI_INVOKE<null>("quickpanel_hide_popup"),
|
||||
/** 显示已创建的弹窗窗口(前端 onMounted 后调用) */
|
||||
quickpanelShowWindow: () => __TAURI_INVOKE<null>("quickpanel_show_window"),
|
||||
/** 锁定屏幕(Windows: rundll32 user32.dll,LockWorkStation,CREATE_NO_WINDOW 避免黑窗) */
|
||||
quickpanelLockScreen: () => __TAURI_INVOKE<null>("quickpanel_lock_screen"),
|
||||
/** 初始化文件索引数据库(应用启动时调用) */
|
||||
quickpanelInitFileIndex: () => __TAURI_INVOKE<null>("quickpanel_init_file_index"),
|
||||
/** 构建文件索引(全量重建,阻塞操作建议在 spawn_blocking 调用) */
|
||||
quickpanelBuildFileIndex: () => __TAURI_INVOKE<number>("quickpanel_build_file_index"),
|
||||
/** 搜索文件索引(SQLite 查询移出主线程) */
|
||||
quickpanelSearchFiles: (query: string, limit: number | null) => __TAURI_INVOKE<FileRecord[]>("quickpanel_search_files", { query, limit }),
|
||||
/** 获取索引状态 */
|
||||
quickpanelFileIndexStats: () => __TAURI_INVOKE<IndexStats>("quickpanel_file_index_stats"),
|
||||
/** 扫描已安装应用(遍历开始菜单/桌面/磁盘,移出主线程) */
|
||||
quickpanelScanApps: () => __TAURI_INVOKE<AppRecord[]>("quickpanel_scan_apps"),
|
||||
/**
|
||||
* 获取应用图标(data URL)。命中内存/磁盘缓存时零 Windows API 调用。
|
||||
* 前端按需为可见项调用,避免一次性加载全部图标。
|
||||
* 未命中缓存时 SHGetFileInfoW + 编码 + 落盘为阻塞操作,移出主线程。
|
||||
*/
|
||||
quickpanelGetAppIcon: (path: string) => __TAURI_INVOKE<string | null>("quickpanel_get_app_icon", { path }),
|
||||
/** 清理图标缓存(磁盘 + 内存) */
|
||||
quickpanelClearAppIconCache: () => __TAURI_INVOKE<null>("quickpanel_clear_app_icon_cache"),
|
||||
/** 在资源管理器中显示文件(选中) */
|
||||
quickpanelRevealInExplorer: (path: string) => __TAURI_INVOKE<null>("quickpanel_reveal_in_explorer", { path }),
|
||||
/**
|
||||
* 用系统默认程序打开文件/文件夹。
|
||||
* - 目录:explorer.exe 直接打开(修复索引目录点击后未打开的问题)
|
||||
* - 文件:ShellExecuteW open,无关联应用时自动 fallback 到「打开方式」对话框(verb: openas)
|
||||
*/
|
||||
quickpanelOpenFile: (path: string) => __TAURI_INVOKE<null>("quickpanel_open_file", { path }),
|
||||
/** 获取 Windows 常用快捷位置(hosts、回收站、此电脑、用户目录、系统管理工具等) */
|
||||
quickpanelGetSpecialLocations: () => __TAURI_INVOKE<SpecialLocation[]>("quickpanel_get_special_locations"),
|
||||
/** 打开快捷位置(kind: file | shell | cmd) */
|
||||
quickpanelOpenSpecial: (kind: string, target: string, args: string[]) => __TAURI_INVOKE<null>("quickpanel_open_special", { kind, target, args }),
|
||||
/** 删除文件(移到回收站,PowerShell 阻塞等待移出主线程) */
|
||||
quickpanelDeleteFile: (path: string) => __TAURI_INVOKE<null>("quickpanel_delete_file", { path }),
|
||||
/**
|
||||
* 运行自定义命令(执行可执行文件 + 参数)
|
||||
* .lnk 快捷方式不能直接 spawn(os error 193),需通过 cmd /C 启动
|
||||
*/
|
||||
quickpanelRunCustomCommand: (command: string, args: string[]) => __TAURI_INVOKE<null>("quickpanel_run_custom_command", { command, args }),
|
||||
/**
|
||||
* 运行系统命令(不设置 CREATE_NO_WINDOW,使 cmd/powershell/regedit 等显示自身窗口)
|
||||
* 适用于内置系统工具:regedit、shutdown、cmd、powershell、taskmgr 等。
|
||||
*/
|
||||
quickpanelRunSystemCommand: (command: string, args: string[]) => __TAURI_INVOKE<null>("quickpanel_run_system_command", { command, args }),
|
||||
clipboardGetHistory: (limit: number | null, offset: number | null, kind: string | null) => __TAURI_INVOKE<HistoryPage>("clipboard_get_history", { limit, offset, kind }),
|
||||
clipboardGetPinned: () => __TAURI_INVOKE<ClipboardItem[]>("clipboard_get_pinned"),
|
||||
clipboardSearch: (query: string, limit: number | null, offset: number | null) => __TAURI_INVOKE<HistoryPage>("clipboard_search", { query, limit, offset }),
|
||||
clipboardGetItem: (id: number) => __TAURI_INVOKE<({
|
||||
/** 文本内容 / 文件列表 JSON */
|
||||
content: string | null,
|
||||
/** 图片 PNG base64(仅 image 类型) */
|
||||
imageBase64: string | null,
|
||||
}) & (ClipboardItem) | null>("clipboard_get_item", { id }),
|
||||
clipboardSetPinned: (id: number, pinned: boolean) => __TAURI_INVOKE<boolean>("clipboard_set_pinned", { id, pinned }),
|
||||
clipboardDelete: (id: number) => __TAURI_INVOKE<boolean>("clipboard_delete", { id }),
|
||||
clipboardClear: () => __TAURI_INVOKE<boolean>("clipboard_clear"),
|
||||
clipboardCopyBack: (id: number) => __TAURI_INVOKE<null>("clipboard_copy_back", { id }),
|
||||
clipboardCount: () => __TAURI_INVOKE<number>("clipboard_count"),
|
||||
clipboardGetSettings: () => __TAURI_INVOKE<ClipboardSettings>("clipboard_get_settings"),
|
||||
clipboardSaveSettings: (settings: ClipboardSettings) => __TAURI_INVOKE<null>("clipboard_save_settings", { settings }),
|
||||
clipboardStatus: () => __TAURI_INVOKE<ClipboardStatus>("clipboard_status"),
|
||||
clipboardStart: () => __TAURI_INVOKE<null>("clipboard_start"),
|
||||
clipboardStop: () => __TAURI_INVOKE<null>("clipboard_stop"),
|
||||
/** 注册(或切换)快捷弹窗全局快捷键 */
|
||||
clipboardRegisterShortcut: (shortcut: string) => __TAURI_INVOKE<null>("clipboard_register_shortcut", { shortcut }),
|
||||
/** 注销快捷弹窗全局快捷键 */
|
||||
clipboardUnregisterShortcut: () => __TAURI_INVOKE<null>("clipboard_unregister_shortcut"),
|
||||
/** 手动触发显示快捷弹窗(供 UI 按钮调用) */
|
||||
clipboardShowPopup: () => __TAURI_INVOKE<null>("clipboard_show_popup"),
|
||||
/** 隐藏快捷弹窗 */
|
||||
clipboardHidePopup: () => __TAURI_INVOKE<null>("clipboard_hide_popup"),
|
||||
/** 显示已创建的弹窗窗口(前端 onMounted 后调用) */
|
||||
clipboardShowWindow: () => __TAURI_INVOKE<null>("clipboard_show_window"),
|
||||
/** 隐藏弹窗并模拟 Ctrl+V 粘贴到原窗口 */
|
||||
clipboardPasteToTarget: () => __TAURI_INVOKE<null>("clipboard_paste_to_target"),
|
||||
/** 获取所有任务 */
|
||||
downloaderGetTasks: () => __TAURI_INVOKE<DownloadTask[]>("downloader_get_tasks"),
|
||||
/** 检查 URL 重复性并探测文件信息(添加下载前调用) */
|
||||
downloaderCheckUrl: (url: string, dir: string | null, headers: { [key in string]: string } | null) => __TAURI_INVOKE<CheckUrlResult>("downloader_check_url", { url, dir, headers }),
|
||||
/** 添加下载任务 */
|
||||
downloaderAddTask: (url: string, filename: string | null, dir: string | null, headers: { [key in string]: string } | null, autoRename: boolean | null) => __TAURI_INVOKE<string>("downloader_add_task", { url, filename, dir, headers, autoRename }),
|
||||
/** 暂停任务 */
|
||||
downloaderPauseTask: (id: string) => __TAURI_INVOKE<null>("downloader_pause_task", { id }),
|
||||
/** 恢复任务 */
|
||||
downloaderResumeTask: (id: string) => __TAURI_INVOKE<null>("downloader_resume_task", { id }),
|
||||
/** 移除任务 */
|
||||
downloaderRemoveTask: (id: string, deleteFiles: boolean | null) => __TAURI_INVOKE<null>("downloader_remove_task", { id, deleteFiles }),
|
||||
/** 获取设置 */
|
||||
downloaderGetSettings: () => __TAURI_INVOKE<DownloaderSettings>("downloader_get_settings"),
|
||||
/** 保存设置 */
|
||||
downloaderSaveSettings: (settings: DownloaderSettings) => __TAURI_INVOKE<null>("downloader_save_settings", { settings }),
|
||||
/** 用系统资源管理器打开目录 */
|
||||
downloaderOpenDir: (path: string) => __TAURI_INVOKE<null>("downloader_open_dir", { path }),
|
||||
/** 用系统默认浏览器打开 URL */
|
||||
downloaderOpenUrl: (url: string) => __TAURI_INVOKE<null>("downloader_open_url", { url }),
|
||||
/** 禁用指定窗口(按 label 查找)的显示/隐藏过渡动画,消除覆盖层出现/消失时的缩放动画 */
|
||||
screenshotDisableTransitions: (label: string) => __TAURI_INVOKE<null>("screenshot_disable_transitions", { label }),
|
||||
/** 注册(或切换)截图全局快捷键。传入空字符串则禁用快捷键。 */
|
||||
screenshotRegisterShortcut: (shortcut: string) => __TAURI_INVOKE<null>("screenshot_register_shortcut", { shortcut }),
|
||||
/** 注销截图全局快捷键 */
|
||||
screenshotUnregisterShortcut: () => __TAURI_INVOKE<null>("screenshot_unregister_shortcut"),
|
||||
/** 捕获整个虚拟屏(多显示器拼接)存入静态,不做 PNG 编码 */
|
||||
screenshotCaptureFullscreen: () => __TAURI_INVOKE<null>("screenshot_capture_fullscreen"),
|
||||
/** 全屏捕获编码为 PNG base64 并清除(全屏截图直接进编辑器) */
|
||||
screenshotFullscreenPng: () => __TAURI_INVOKE<CaptureData>("screenshot_fullscreen_png"),
|
||||
/** 清除静态全屏捕获(覆盖层关闭/取消时释放内存) */
|
||||
screenshotClearFullscreen: () => __TAURI_INVOKE<null>("screenshot_clear_fullscreen"),
|
||||
/** 按物理像素坐标裁剪已存储的全屏捕获 */
|
||||
screenshotCropStored: (x: number, y: number, w: number, h: number) => __TAURI_INVOKE<CaptureData>("screenshot_crop_stored", { x, y, w, h }),
|
||||
/** 裁剪已存储的全屏捕获并直接写入剪贴板(一次 IPC 完成"裁剪+复制") */
|
||||
screenshotCropCopyStored: (x: number, y: number, w: number, h: number) => __TAURI_INVOKE<CaptureData>("screenshot_crop_copy_stored", { x, y, w, h }),
|
||||
/** 拾取指定物理屏幕坐标下的顶层窗口 */
|
||||
screenshotWindowFromPoint: (x: number, y: number) => __TAURI_INVOKE<{
|
||||
hwnd: number,
|
||||
title: string,
|
||||
rect: ScreenRect,
|
||||
/** DWM 扩展边框矩形(视觉边界,去掉最大化窗口的隐形缩放边框),命中测试用 rect,高亮用 visual_rect */
|
||||
visualRect: ScreenRect | null,
|
||||
} | null>("screenshot_window_from_point", { x, y }),
|
||||
/** 获取当前鼠标物理屏幕坐标(覆盖层打开时定位初始悬停窗口) */
|
||||
screenshotCursorPos: () => __TAURI_INVOKE<[number, number]>("screenshot_cursor_pos"),
|
||||
/** 枚举所有可见顶层窗口 */
|
||||
screenshotEnumWindows: () => __TAURI_INVOKE<WindowInfo[]>("screenshot_enum_windows"),
|
||||
/** 按 hwnd 捕获指定窗口 */
|
||||
screenshotCaptureWindow: (hwnd: number) => __TAURI_INVOKE<CaptureData>("screenshot_capture_window", { hwnd }),
|
||||
/** 存入编辑器图片(base64 PNG) */
|
||||
screenshotSetEditorImage: (pngBase64: string) => __TAURI_INVOKE<null>("screenshot_set_editor_image", { pngBase64 }),
|
||||
/** 取出编辑器图片(编辑器窗口加载时调用,取出即清除) */
|
||||
screenshotGetEditorImage: () => __TAURI_INVOKE<string | null>("screenshot_get_editor_image"),
|
||||
/** 将 PNG base64 写入系统剪贴板(转 CF_DIB) */
|
||||
screenshotCopyImage: (pngBase64: string) => __TAURI_INVOKE<null>("screenshot_copy_image", { pngBase64 }),
|
||||
/** 将 PNG base64 写入文件 */
|
||||
screenshotSavePng: (pngBase64: string, path: string) => __TAURI_INVOKE<null>("screenshot_save_png", { pngBase64, path }),
|
||||
/** 将完整 PNG 写入历史缓存目录,返回文件路径 */
|
||||
screenshotSaveCache: (pngBase64: string) => __TAURI_INVOKE<string>("screenshot_save_cache", { pngBase64 }),
|
||||
/** 从历史缓存目录读取 PNG 并返回 base64(点击历史项复制/保存时一次性加载,不常驻内存) */
|
||||
screenshotLoadCache: (path: string) => __TAURI_INVOKE<string>("screenshot_load_cache", { path }),
|
||||
/** 删除历史缓存文件(历史项移除/清空时调用,静默忽略不存在文件) */
|
||||
screenshotDeleteCache: (path: string) => __TAURI_INVOKE<null>("screenshot_delete_cache", { path }),
|
||||
};
|
||||
|
||||
/* Types */
|
||||
export type AppRecord = {
|
||||
name: string,
|
||||
path: string,
|
||||
};
|
||||
|
||||
/** 前端可见的捕获数据 */
|
||||
export type CaptureData = {
|
||||
pngBase64: string,
|
||||
width: number,
|
||||
height: number,
|
||||
};
|
||||
|
||||
/** check_url 命令返回的结果 */
|
||||
export type CheckUrlResult = {
|
||||
/** 探测是否成功 */
|
||||
ok: boolean,
|
||||
/** 错误信息(探测失败时) */
|
||||
error: string | null,
|
||||
/** 文件名(探测成功时) */
|
||||
filename: string | null,
|
||||
/** 文件大小(字节) */
|
||||
totalSize: number | null,
|
||||
/** 是否支持断点续传 */
|
||||
supportsResume: boolean,
|
||||
/** 重复类型 */
|
||||
duplicate: DuplicateKind,
|
||||
/** 已存在的任务信息 */
|
||||
existing: ExistingTaskInfo | null,
|
||||
};
|
||||
|
||||
/** 列表项(不含大字段,用于历史/搜索结果) */
|
||||
export type ClipboardItem = {
|
||||
id: number,
|
||||
kind: string,
|
||||
preview: string,
|
||||
size: number,
|
||||
pinned: boolean,
|
||||
pinnedOrder: number | null,
|
||||
createdAt: number,
|
||||
};
|
||||
|
||||
/** 详情(含文本内容或图片 base64) */
|
||||
export type ClipboardItemDetail = {
|
||||
/** 文本内容 / 文件列表 JSON */
|
||||
content: string | null,
|
||||
/** 图片 PNG base64(仅 image 类型) */
|
||||
imageBase64: string | null,
|
||||
} & ClipboardItem;
|
||||
|
||||
/** 剪贴板设置(持久化到 clipboard/settings.json) */
|
||||
export type ClipboardSettings = {
|
||||
/** 监听是否启用 */
|
||||
enabled?: boolean,
|
||||
/** 非固定历史最大条数 */
|
||||
maxItems?: number,
|
||||
/** 图片大小上限(KB),0 表示不限 */
|
||||
maxImageKb?: number,
|
||||
recordText?: boolean,
|
||||
recordImage?: boolean,
|
||||
recordFiles?: boolean,
|
||||
/** 去重(相同内容更新时间而非新增) */
|
||||
dedup?: boolean,
|
||||
/** 快捷弹窗全局快捷键(如 "Alt+V",空字符串表示禁用) */
|
||||
shortcut?: string,
|
||||
};
|
||||
|
||||
export type ClipboardStatus = {
|
||||
running: boolean,
|
||||
count: number,
|
||||
};
|
||||
|
||||
/** 自定义命令 */
|
||||
export type CustomCommand = {
|
||||
id: string,
|
||||
title: string,
|
||||
command: string,
|
||||
args?: string[],
|
||||
};
|
||||
|
||||
/** 下载任务 */
|
||||
export type DownloadTask = {
|
||||
/** 任务 ID(自增 hex 字符串) */
|
||||
id: string,
|
||||
/** 下载地址 */
|
||||
url: string,
|
||||
/** 文件名 */
|
||||
filename: string,
|
||||
/** 保存目录(绝对路径) */
|
||||
dir: string,
|
||||
/** 状态 */
|
||||
status: TaskStatus,
|
||||
/** 文件总大小(字节),0=未知 */
|
||||
totalSize: number,
|
||||
/** 已下载字节 */
|
||||
completedSize: number,
|
||||
/** 当前下载速度 bytes/s */
|
||||
speed: number,
|
||||
/** 服务器是否支持断点续传 */
|
||||
supportsResume: boolean,
|
||||
/** 分段信息 */
|
||||
segments?: Segment[],
|
||||
/** 错误信息 */
|
||||
error?: string | null,
|
||||
/** 创建时间(Unix 时间戳,毫秒) */
|
||||
createdAt: number,
|
||||
/** 自定义请求头(Cookie / Referer 等) */
|
||||
headers?: { [key in string]: string },
|
||||
};
|
||||
|
||||
/** 下载设置 */
|
||||
export type DownloaderSettings = {
|
||||
/** 下载目录 */
|
||||
downloadDir?: string,
|
||||
/** 最大同时下载数 */
|
||||
maxConcurrent?: number,
|
||||
/** 单任务最大连接数(多线程分段数) */
|
||||
maxConnections?: number,
|
||||
/** 断点续传 */
|
||||
continueDownload?: boolean,
|
||||
/** 全局速度限制 KB/s(0=不限) */
|
||||
globalSpeedLimit?: number,
|
||||
/** 扩展 HTTP API 端口 */
|
||||
extensionPort?: number,
|
||||
/** 扩展认证密钥(空=不认证) */
|
||||
extensionSecret?: string,
|
||||
/** 删除任务时是否同时删除已下载的文件 */
|
||||
deleteFilesOnRemove?: boolean,
|
||||
/** 添加下载前检查重复(URL 或文件名重复时询问) */
|
||||
checkDuplicate?: boolean,
|
||||
};
|
||||
|
||||
/** 重复类型 */
|
||||
export type DuplicateKind =
|
||||
/** 无重复 */
|
||||
"none" |
|
||||
/** URL 重复(已有相同链接的任务) */
|
||||
"url" |
|
||||
/** 文件名重复(已有同名任务下载到同一目录) */
|
||||
"filename" |
|
||||
/** 磁盘文件已存在 */
|
||||
"fileExists";
|
||||
|
||||
/** 已存在的任务信息(用于前端展示) */
|
||||
export type ExistingTaskInfo = {
|
||||
id: string,
|
||||
filename: string,
|
||||
status: TaskStatus,
|
||||
};
|
||||
|
||||
/** 单个文件记录(返回给前端) */
|
||||
export type FileRecord = {
|
||||
path: string,
|
||||
name: string,
|
||||
ext: string,
|
||||
size: number,
|
||||
isDir: boolean,
|
||||
};
|
||||
|
||||
/** 历史查询结果(含总数,用于分页) */
|
||||
export type HistoryPage = {
|
||||
items: ClipboardItem[],
|
||||
total: number,
|
||||
};
|
||||
|
||||
/** 索引状态(返回给前端) */
|
||||
export type IndexStats = {
|
||||
total: number,
|
||||
lastBuiltAt: number,
|
||||
lastBuiltDirs: string[],
|
||||
};
|
||||
|
||||
export type KernelInfo = {
|
||||
path: string,
|
||||
exists: boolean,
|
||||
version: string | null,
|
||||
};
|
||||
|
||||
export type KernelUpdateInfo = {
|
||||
currentVersion: string | null,
|
||||
latestVersion: string,
|
||||
downloadUrl: string,
|
||||
hasUpdate: boolean,
|
||||
};
|
||||
|
||||
/** 进程信息(返回给前端) */
|
||||
export type ProcessInfo = {
|
||||
id: string,
|
||||
name: string,
|
||||
status: ProcessStatus,
|
||||
pid: number | null,
|
||||
restartCount: number,
|
||||
};
|
||||
|
||||
/** 进程状态枚举 */
|
||||
export type ProcessStatus = "running" | "stopped" | "crashed" | "starting";
|
||||
|
||||
export type ProfileMeta = {
|
||||
id?: string,
|
||||
name?: string,
|
||||
url?: string,
|
||||
addedAt?: string,
|
||||
updatedAt?: string,
|
||||
size?: number | null,
|
||||
};
|
||||
|
||||
export type ProxySettings = {
|
||||
mixedPort?: number,
|
||||
externalController?: string,
|
||||
secret?: string,
|
||||
mode?: string,
|
||||
logLevel?: string,
|
||||
allowLan?: boolean,
|
||||
systemProxy?: boolean,
|
||||
autoStart?: boolean,
|
||||
autoSystemProxy?: boolean,
|
||||
currentProfile?: string | null,
|
||||
profiles?: ProfileMeta[],
|
||||
autoSwitchEnabled?: boolean,
|
||||
autoSwitchInterval?: number,
|
||||
autoSwitchGroup?: string,
|
||||
autoSwitchRegion?: string,
|
||||
/**
|
||||
* 内核下载镜像源列表(前缀拼接到 GitHub URL 前)。
|
||||
* 空字符串 = 直连 GitHub,其余为镜像站前缀(含尾斜杠)。
|
||||
*/
|
||||
kernelMirrors?: string[],
|
||||
};
|
||||
|
||||
export type ProxyStatus = {
|
||||
running: boolean,
|
||||
pid: number | null,
|
||||
restartCount: number,
|
||||
};
|
||||
|
||||
/** 快速面板设置 */
|
||||
export type QuickPanelSettings = {
|
||||
/** 全局快捷键(如 "Alt+Space"),空字符串表示不注册。 */
|
||||
shortcut?: string,
|
||||
/** 唤起位置:center(鼠标所在显示器中央)| cursor(鼠标位置) */
|
||||
popupPosition?: string,
|
||||
/** 默认搜索引擎:google | bing | baidu */
|
||||
searchEngine?: string,
|
||||
/** 文件索引目录列表(空列表表示使用默认:桌面/文档/下载) */
|
||||
indexDirs?: string[],
|
||||
/** 自定义命令列表 */
|
||||
customCommands?: CustomCommand[],
|
||||
};
|
||||
|
||||
export type ScreenRect = {
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
};
|
||||
|
||||
/** 下载分段(多线程 Range 下载 / 断点续传用) */
|
||||
export type Segment = {
|
||||
/** 分段索引 */
|
||||
index: number,
|
||||
/** 起始字节(含) */
|
||||
start: number,
|
||||
/** 结束字节(含) */
|
||||
end: number,
|
||||
/** 已下载字节 */
|
||||
completed: number,
|
||||
};
|
||||
|
||||
/** 快捷位置条目 */
|
||||
export type SpecialLocation = {
|
||||
id: string,
|
||||
title: string,
|
||||
subtitle: string,
|
||||
keywords: string[],
|
||||
/** file: 真实文件/文件夹路径;shell: explorer 打开的 shell 路径;cmd: 可执行命令 */
|
||||
kind: string,
|
||||
target: string,
|
||||
args: string[],
|
||||
};
|
||||
|
||||
/** 任务状态 */
|
||||
export type TaskStatus =
|
||||
/** 排队等待(并发数已满) */
|
||||
"queued" |
|
||||
/** 下载中 */
|
||||
"active" |
|
||||
/** 已暂停 */
|
||||
"paused" |
|
||||
/** 已完成 */
|
||||
"complete" |
|
||||
/** 错误 */
|
||||
"error";
|
||||
|
||||
/** 窗口信息(窗口拾取 / 枚举) */
|
||||
export type WindowInfo = {
|
||||
hwnd: number,
|
||||
title: string,
|
||||
rect: ScreenRect,
|
||||
/** DWM 扩展边框矩形(视觉边界,去掉最大化窗口的隐形缩放边框),命中测试用 rect,高亮用 visual_rect */
|
||||
visualRect: ScreenRect | null,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 表达式求值器单测(Node 内置 test runner)。
|
||||
*/
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { evaluateExpression } from './calc.ts'
|
||||
|
||||
test('四则运算与优先级', () => {
|
||||
assert.equal(evaluateExpression('1+2*3'), 7)
|
||||
assert.equal(evaluateExpression('2*(3+4)'), 14)
|
||||
assert.equal(evaluateExpression('10-2-3'), 5)
|
||||
})
|
||||
|
||||
test('除法与取模', () => {
|
||||
assert.equal(evaluateExpression('10/4'), 2.5)
|
||||
assert.equal(evaluateExpression('10%3'), 1)
|
||||
})
|
||||
|
||||
test('小数与边界写法', () => {
|
||||
assert.equal(evaluateExpression('0.1+0.2'), 0.30000000000000004)
|
||||
assert.equal(evaluateExpression('.5+.5'), 1)
|
||||
assert.equal(evaluateExpression('5.'), 5)
|
||||
})
|
||||
|
||||
test('一元正负号', () => {
|
||||
assert.equal(evaluateExpression('-5+3'), -2)
|
||||
assert.equal(evaluateExpression('-(2+3)'), -5)
|
||||
assert.equal(evaluateExpression('2*-3'), -6)
|
||||
assert.equal(evaluateExpression('+5'), 5)
|
||||
assert.equal(evaluateExpression('--5'), 5)
|
||||
})
|
||||
|
||||
test('括号嵌套', () => {
|
||||
assert.equal(evaluateExpression('(1+2)*(3+4)'), 21)
|
||||
assert.equal(evaluateExpression('((1+2))'), 3)
|
||||
})
|
||||
|
||||
test('空白容忍', () => {
|
||||
assert.equal(evaluateExpression(' 1 + 2 '), 3)
|
||||
assert.equal(evaluateExpression(' '), null)
|
||||
})
|
||||
|
||||
test('非法输入返回 null', () => {
|
||||
assert.equal(evaluateExpression(''), null)
|
||||
assert.equal(evaluateExpression('abc'), null)
|
||||
assert.equal(evaluateExpression('1/'), null)
|
||||
assert.equal(evaluateExpression('((1+2)'), null)
|
||||
assert.equal(evaluateExpression('1+2)'), null)
|
||||
assert.equal(evaluateExpression('1 2'), null)
|
||||
assert.equal(evaluateExpression('%3'), null)
|
||||
assert.equal(evaluateExpression('1.2.3'), null)
|
||||
})
|
||||
|
||||
test('非有限结果返回 null(除零)', () => {
|
||||
assert.equal(evaluateExpression('1/0'), null)
|
||||
assert.equal(evaluateExpression('5%0'), null)
|
||||
})
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 表达式求值器(CSP 安全,替代 Function/eval)。
|
||||
* 支持:十进制小数、+ - * / %、括号、一元正负号。
|
||||
* 非法输入或结果为非有限值返回 null。
|
||||
*
|
||||
* 语义差异说明:原 Function 实现下 `1++2` / `1--2` 属语法错误;
|
||||
* 此处解析器将连续正负号按一元运算符处理(`1++2` → 3),更宽松且无安全隐患。
|
||||
*/
|
||||
|
||||
type Token =
|
||||
| { kind: 'num'; value: number }
|
||||
| { kind: 'op'; value: string }
|
||||
| { kind: 'end' }
|
||||
|
||||
/** 数字 token:`12.5` / `12.` / `.5` */
|
||||
const NUM_RE = /^\d+(\.\d*)?|^\.\d+/
|
||||
|
||||
function tokenize(input: string): Token[] | null {
|
||||
const tokens: Token[] = []
|
||||
let i = 0
|
||||
while (i < input.length) {
|
||||
const ch = input[i]
|
||||
if (/\s/.test(ch)) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (/[0-9.]/.test(ch)) {
|
||||
const m = NUM_RE.exec(input.slice(i))
|
||||
if (!m) return null
|
||||
const value = Number(m[0])
|
||||
if (!Number.isFinite(value)) return null
|
||||
tokens.push({ kind: 'num', value })
|
||||
i += m[0].length
|
||||
continue
|
||||
}
|
||||
if ('+-*/%()'.includes(ch)) {
|
||||
tokens.push({ kind: 'op', value: ch })
|
||||
i++
|
||||
continue
|
||||
}
|
||||
return null
|
||||
}
|
||||
tokens.push({ kind: 'end' })
|
||||
return tokens
|
||||
}
|
||||
|
||||
/** 递归下降解析器:expr → term → factor(支持优先级与括号) */
|
||||
class Parser {
|
||||
private pos = 0
|
||||
private tokens: Token[]
|
||||
|
||||
constructor(tokens: Token[]) {
|
||||
this.tokens = tokens
|
||||
}
|
||||
|
||||
/** 完整解析:要求消费全部 token 且成功 */
|
||||
parse(): number | null {
|
||||
const v = this.parseExpr()
|
||||
if (v === null) return null
|
||||
if (this.peek().kind !== 'end') return null
|
||||
return v
|
||||
}
|
||||
|
||||
private peek(): Token {
|
||||
return this.tokens[this.pos]
|
||||
}
|
||||
|
||||
private next(): Token {
|
||||
return this.tokens[this.pos++]
|
||||
}
|
||||
|
||||
/** expr := term (('+' | '-') term)* */
|
||||
private parseExpr(): number | null {
|
||||
let left = this.parseTerm()
|
||||
if (left === null) return null
|
||||
while (true) {
|
||||
const tok = this.peek()
|
||||
if (tok.kind !== 'op' || (tok.value !== '+' && tok.value !== '-')) break
|
||||
this.next()
|
||||
const right = this.parseTerm()
|
||||
if (right === null) return null
|
||||
left = tok.value === '+' ? left + right : left - right
|
||||
}
|
||||
return left
|
||||
}
|
||||
|
||||
/** term := factor (('*' | '/' | '%') factor)* */
|
||||
private parseTerm(): number | null {
|
||||
let left = this.parseFactor()
|
||||
if (left === null) return null
|
||||
while (true) {
|
||||
const tok = this.peek()
|
||||
if (tok.kind !== 'op' || (tok.value !== '*' && tok.value !== '/' && tok.value !== '%')) {
|
||||
break
|
||||
}
|
||||
this.next()
|
||||
const right = this.parseFactor()
|
||||
if (right === null) return null
|
||||
left = tok.value === '*' ? left * right : tok.value === '/' ? left / right : left % right
|
||||
}
|
||||
return left
|
||||
}
|
||||
|
||||
/** factor := ('+' | '-') factor | '(' expr ')' | number */
|
||||
private parseFactor(): number | null {
|
||||
const tok = this.peek()
|
||||
if (tok.kind === 'op' && (tok.value === '+' || tok.value === '-')) {
|
||||
this.next()
|
||||
const v = this.parseFactor()
|
||||
if (v === null) return null
|
||||
return tok.value === '-' ? -v : v
|
||||
}
|
||||
if (tok.kind === 'num') {
|
||||
this.next()
|
||||
return tok.value
|
||||
}
|
||||
if (tok.kind === 'op' && tok.value === '(') {
|
||||
this.next()
|
||||
const v = this.parseExpr()
|
||||
if (v === null) return null
|
||||
const close = this.next()
|
||||
if (close.kind !== 'op' || close.value !== ')') return null
|
||||
return v
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** 求值表达式,非法输入或结果为非有限值返回 null */
|
||||
export function evaluateExpression(input: string): number | null {
|
||||
const tokens = tokenize(input)
|
||||
if (!tokens) return null
|
||||
const result = new Parser(tokens).parse()
|
||||
if (result === null || !Number.isFinite(result)) return null
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 全局常量集中定义。
|
||||
* 窗口 label / Tauri 事件名 / localStorage 存储键,避免魔法字符串散布各处。
|
||||
* 与 Rust 侧 `src-tauri/src/constants.rs` 保持对应。
|
||||
*/
|
||||
|
||||
/** 窗口 label(对应 Rust constants::windows 与 capabilities/*.json) */
|
||||
export const WINDOWS = {
|
||||
main: 'main',
|
||||
osdOverlay: 'osd-overlay',
|
||||
screenshotOverlay: 'screenshot-overlay',
|
||||
} as const
|
||||
|
||||
/** Tauri 事件名(前端 emit / listen 与 Rust constants::events 对应) */
|
||||
export const EVENTS = {
|
||||
// 托盘菜单
|
||||
trayMenuShow: 'tray-menu-show',
|
||||
trayMenuStateUpdated: 'tray-menu-state-updated',
|
||||
trayToggleOsd: 'tray:toggle-osd',
|
||||
trayNewDownload: 'tray:new-download',
|
||||
trayOpenSettings: 'tray:open-settings',
|
||||
// 剪贴板
|
||||
clipboardChanged: 'clipboard-changed',
|
||||
clipboardPopupShow: 'clipboard-popup-show',
|
||||
clipboardPopupHide: 'clipboard-popup-hide',
|
||||
// 快速面板
|
||||
quickpanelShow: 'quickpanel-show',
|
||||
quickpanelHide: 'quickpanel-hide',
|
||||
quickpanelExecuteCommand: 'quickpanel-execute-command',
|
||||
// 截图
|
||||
screenshotBegin: 'screenshot-begin',
|
||||
screenshotOverlayReady: 'screenshot-overlay-ready',
|
||||
screenshotShortcut: 'screenshot-shortcut',
|
||||
screenshotExported: 'screenshot-exported',
|
||||
// 内核安装进度
|
||||
kernelInstallProgress: 'kernel-install-progress',
|
||||
// 监控 OSD
|
||||
osdStateUpdate: 'osd-state-update',
|
||||
osdContentSize: 'osd-content-size',
|
||||
osdSystemUiActive: 'osd-system-ui-active',
|
||||
osdSystemUiInactive: 'osd-system-ui-inactive',
|
||||
osdStartDrag: 'osd-start-drag',
|
||||
osdEndDrag: 'osd-end-drag',
|
||||
monitorReady: 'monitor-ready',
|
||||
monitorLoading: 'monitor-loading',
|
||||
monitorDisconnected: 'monitor-disconnected',
|
||||
monitorError: 'monitor-error',
|
||||
monitorData: 'monitor-data',
|
||||
monitorNetwork: 'monitor-network',
|
||||
// 其他
|
||||
processStatusChanged: 'process-status-changed',
|
||||
downloadAdded: 'download-added',
|
||||
} as const
|
||||
|
||||
/** localStorage 存储键 */
|
||||
export const STORAGE_KEYS = {
|
||||
appSettings: 'thing_app_settings',
|
||||
lastModule: 'thing_last_module',
|
||||
quickpanelCommands: 'thing_quickpanel_commands',
|
||||
quickpanelSettings: 'thing_quickpanel_settings',
|
||||
quickpanelHistory: 'thing_quickpanel_history',
|
||||
quickpanelHistoryItems: 'thing_quickpanel_history_items',
|
||||
currencyRates: 'thing_quickpanel_currency_rates',
|
||||
monitorOsdConfig: 'thing_monitor_osd_config',
|
||||
} as const
|
||||
+3
-3
@@ -86,19 +86,19 @@ export async function getLogs(
|
||||
level?: LogLevel,
|
||||
limit?: number,
|
||||
): Promise<LogEntry[]> {
|
||||
return invoke('get_logs', { module, level, limit })
|
||||
return invoke('log_list', { module, level, limit })
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有日志文件。
|
||||
*/
|
||||
export async function clearLogs(): Promise<void> {
|
||||
return invoke('clear_logs')
|
||||
return invoke('log_clear')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日志系统信息(目录、文件列表、空间占用)。
|
||||
*/
|
||||
export async function getLogInfo(): Promise<LogInfo> {
|
||||
return invoke('get_log_info')
|
||||
return invoke('log_info_state')
|
||||
}
|
||||
|
||||
@@ -10,6 +10,3 @@ import { ref } from 'vue'
|
||||
|
||||
/** 待打开新建下载对话框(由托盘"新建下载"触发) */
|
||||
export const pendingNewDownload = ref(false)
|
||||
|
||||
/** 待切换到设置模块(由托盘"常规设置"触发) */
|
||||
export const pendingOpenSettings = ref(false)
|
||||
|
||||
Reference in New Issue
Block a user