docs: add project README and initialize repository
@@ -0,0 +1,25 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
src-tauri/target
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
version: 43
|
||||||
|
jobs:
|
||||||
|
- name: 构建部署 PortFlow
|
||||||
|
steps:
|
||||||
|
# ========== 步骤1:拉取代码 ==========
|
||||||
|
- type: CheckoutStep
|
||||||
|
name: 拉取最新代码
|
||||||
|
cloneCredential:
|
||||||
|
type: DefaultCredential
|
||||||
|
withLfs: false
|
||||||
|
withSubmodules: false
|
||||||
|
checkoutPath: '@project_path@'
|
||||||
|
condition: SUCCESSFUL
|
||||||
|
optional: false
|
||||||
|
|
||||||
|
# ========== 步骤2:执行 Tauri 编译打包 ==========
|
||||||
|
- type: CommandStep
|
||||||
|
name: 安装前端依赖并离线打包exe
|
||||||
|
# 💡 使用集成了 Rust 1.80+ 稳定版和 Node 环境的公共基础镜像
|
||||||
|
image: rust:1.80-slim
|
||||||
|
commands:
|
||||||
|
# 1. 安装构建所需的依赖环境 (C++ 编译器、Node 环境等)
|
||||||
|
- apt-get update && apt-get install -y curl libwebkit2gtk-4.1-dev build-essential libssl-dev libgtk-3-dev libayumu-dev libsoup-3.0-dev
|
||||||
|
- curl -fsSL https://bun.sh/install | bash
|
||||||
|
- export PATH="$HOME/.bun/bin:$PATH"
|
||||||
|
|
||||||
|
# 2. 切换到项目根目录安装前端并编译
|
||||||
|
- cd @project_path@
|
||||||
|
- bun install
|
||||||
|
|
||||||
|
# 3. 强行执行离线打包,直接吐出绿色 exe
|
||||||
|
- bun tauri build -- --offline
|
||||||
|
condition: SUCCESSFUL
|
||||||
|
optional: false
|
||||||
|
|
||||||
|
# ========== 任务级别配置 ==========
|
||||||
|
jobExecutor: docker
|
||||||
|
# 💡 关键配置:告诉 OneDev 将打包出来的 exe 作为流水线成果留存
|
||||||
|
artifacts: src-tauri/target/release/PortFlow.exe
|
||||||
|
triggers:
|
||||||
|
- type: BranchUpdateTrigger
|
||||||
|
branches: main
|
||||||
|
userMatch: anyone
|
||||||
|
projects: PortFlow # 💡 别忘了同步你在 OneDev 里的最新项目名
|
||||||
|
retryCondition: never
|
||||||
|
maxRetries: 3
|
||||||
|
retryDelay: 30
|
||||||
|
timeout: 3600 # 缩短超时时间到 1 小时
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
# PortFlow
|
||||||
|
|
||||||
|
PortFlow 是一个基于 Tauri 2 + TypeScript 的桌面端口管理工具,用于查看系统网络端口占用并按 PID 结束进程。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 实时读取系统端口(TCP/UDP)及进程信息
|
||||||
|
- 展示端口、进程名、PID、连接状态等字段
|
||||||
|
- 支持关键词过滤(端口、进程名、PID、状态)
|
||||||
|
- 支持按 PID 强制结束进程(Windows 使用 `taskkill`,类 Unix 使用 `kill -9`)
|
||||||
|
- 桌面端原生窗口(Tauri)
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- 前端:TypeScript + Vite + HTML/CSS
|
||||||
|
- 桌面容器:Tauri 2
|
||||||
|
- 后端:Rust(`sysinfo` + 系统命令)
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- Node.js 18+
|
||||||
|
- Bun(项目的 Tauri 构建命令使用 `bun run ...`)
|
||||||
|
- Rust stable(建议与 Tauri 2 兼容版本)
|
||||||
|
- Windows 平台需要可用的 `netstat` 与 `taskkill`
|
||||||
|
|
||||||
|
## 本地开发
|
||||||
|
|
||||||
|
安装依赖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
启动前端开发服务器:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
启动 Tauri 开发模式:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm tauri dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建打包
|
||||||
|
|
||||||
|
构建前端静态资源:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建桌面应用:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm tauri build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├─ src/ # 前端 TS 入口与样式
|
||||||
|
├─ src-tauri/ # Tauri / Rust 代码
|
||||||
|
│ ├─ src/main.rs # 端口扫描与进程结束命令
|
||||||
|
│ └─ tauri.conf.json # 应用窗口与构建配置
|
||||||
|
├─ index.html # 前端主页面
|
||||||
|
├─ package.json
|
||||||
|
└─ README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 说明
|
||||||
|
|
||||||
|
- 当前仓库中同时存在 Tauri 模板默认 `src/main.ts` 与自定义 `index.html` 页面逻辑,实际功能以 `index.html` + `src-tauri/src/main.rs` 为主。
|
||||||
|
- 如需在生产环境中稳定使用,请以管理员权限运行应用,以确保获取完整端口数据并执行进程结束操作。
|
||||||
@@ -0,0 +1,468 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>PortFlow - 系统进程与网络监视器</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after {
|
||||||
|
transition: background-color 0.15s ease, border-color 0.15s ease;
|
||||||
|
}
|
||||||
|
.custom-scrollbar::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-track {
|
||||||
|
background: #020617;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
background: #1e293b;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #334155;
|
||||||
|
}
|
||||||
|
@keyframes radar-pulse {
|
||||||
|
0% { transform: scale(0.95); opacity: 0.8; box-shadow: 0 0 30px rgba(79, 70, 229, 0.15); }
|
||||||
|
50% { transform: scale(1.05); opacity: 0.5; box-shadow: 0 0 50px rgba(79, 70, 229, 0.3); }
|
||||||
|
100% { transform: scale(0.95); opacity: 0.8; box-shadow: 0 0 30px rgba(79, 70, 229, 0.15); }
|
||||||
|
}
|
||||||
|
.radar-animate {
|
||||||
|
animation: radar-pulse 2s infinite ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-slate-50 text-slate-800 dark:bg-slate-950 dark:text-slate-100 h-screen w-screen overflow-hidden font-sans select-none flex flex-col border border-slate-200 dark:border-slate-800 rounded-lg">
|
||||||
|
|
||||||
|
<div id="splash-screen" data-tauri-drag-region class="absolute inset-0 z-50 bg-slate-100 flex flex-col items-center justify-center text-slate-800 transition-all duration-500 ease-in-out">
|
||||||
|
<div class="flex flex-col items-center pointer-events-none">
|
||||||
|
<div class="relative w-20 h-20 bg-white rounded-full flex items-center justify-center border border-slate-200 shadow-md mb-6 radar-animate">
|
||||||
|
<i class="fa-solid fa-network-wired text-3xl text-indigo-500 animate-pulse"></i>
|
||||||
|
<div class="absolute inset-0 border-2 border-dashed border-indigo-500/20 rounded-full animate-spin" style="animation-duration: 8s;"></div>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-2xl font-black tracking-widest text-slate-800 font-sans uppercase" id="splash-app-name">PORTFLOW</h1>
|
||||||
|
<p class="text-xs text-indigo-600 font-medium mt-2 tracking-wider">系统端口与映像进程分析内核</p>
|
||||||
|
<div class="w-48 h-1 bg-slate-200 rounded-full mt-8 overflow-hidden">
|
||||||
|
<div class="h-full w-1/2 bg-gradient-to-r from-indigo-500 to-indigo-400 rounded-full animate-[shimmer_1.5s_infinite_linear]" style="animation-name: progress-shimmer;">
|
||||||
|
<style>
|
||||||
|
@keyframes progress-shimmer {
|
||||||
|
0% { transform: translateX(-100%); }
|
||||||
|
100% { transform: translateX(200%); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-[11px] text-slate-400 font-medium mt-3" id="splash-status">正在下钻底层网络套接字,映射物理端口映像...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="custom-titlebar" data-tauri-drag-region class="h-10 w-full bg-slate-100 dark:bg-slate-900 border-b border-slate-200 dark:border-slate-800 flex justify-between items-center pl-4 shrink-0 select-none cursor-default">
|
||||||
|
<div class="flex items-center space-x-2 text-xs font-medium text-slate-500 dark:text-slate-400 pointer-events-none">
|
||||||
|
<i class="fa-solid fa-network-wired text-indigo-500"></i>
|
||||||
|
<span id="titlebar-app-name">PortFlow 进程管理器</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center h-full text-slate-500 dark:text-slate-400 text-xs">
|
||||||
|
<button onclick="windowMinimize()" class="w-12 h-full hover:bg-slate-200 dark:hover:bg-slate-800 flex items-center justify-center transition-colors duration-75 cursor-pointer" title="最小化">
|
||||||
|
<i class="fa-solid fa-minus"></i>
|
||||||
|
</button>
|
||||||
|
<button onclick="windowMaximize()" class="w-12 h-full hover:bg-slate-200 dark:hover:bg-slate-800 flex items-center justify-center transition-colors duration-75 cursor-pointer" title="最大化">
|
||||||
|
<i id="max-icon" class="fa-regular fa-square"></i>
|
||||||
|
</button>
|
||||||
|
<button onclick="windowClose()" class="w-12 h-full hover:bg-rose-600 hover:text-white flex items-center justify-center transition-colors duration-75 cursor-pointer" title="关闭">
|
||||||
|
<i class="fa-solid fa-xmark text-sm"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<header class="border-b border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900/50 px-6 py-3.5 flex justify-between items-center shrink-0 shadow-xs">
|
||||||
|
<div class="flex items-center space-x-3">
|
||||||
|
<div class="bg-slate-800 dark:bg-indigo-600 p-2 rounded-lg text-white">
|
||||||
|
<i class="fa-solid fa-chart-pie text-lg"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-lg font-bold tracking-tight text-slate-900 dark:text-white flex items-center gap-2" id="header-app-name">PortFlow 进程管理器</h1>
|
||||||
|
<p class="text-xs text-slate-400 dark:text-slate-500">实时监控系统端口与映像进程分析</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-3">
|
||||||
|
<button onclick="toggleTheme()" class="w-9 h-9 rounded-lg border border-slate-200 bg-white hover:bg-slate-50 dark:border-slate-800 dark:bg-slate-900 dark:hover:bg-slate-800 flex items-center justify-center cursor-pointer shadow-2xs" title="切换主题">
|
||||||
|
<i id="theme-icon" class="fa-solid fa-sun text-amber-500"></i>
|
||||||
|
</button>
|
||||||
|
<span class="flex items-center text-xs bg-indigo-500/10 text-indigo-600 dark:text-indigo-400 px-2.5 py-1 rounded border border-indigo-500/20 font-mono" id="app-version-badge">
|
||||||
|
<span class="w-1.5 h-1.5 bg-indigo-500 rounded-full mr-2 animate-pulse"></span>版本: 获取中...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="max-w-7xl w-full mx-auto p-4 flex-1 min-h-0 flex flex-col space-y-4 overflow-hidden">
|
||||||
|
<section class="grid grid-cols-2 md:grid-cols-4 gap-3 shrink-0">
|
||||||
|
<div class="bg-white dark:bg-slate-900 p-3 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-slate-400 dark:text-slate-500">网络套接字总数</p>
|
||||||
|
<p class="text-xl font-bold mt-0.5 text-slate-900 dark:text-white" id="total-ports">0</p>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-chart-line text-indigo-500 opacity-30 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white dark:bg-slate-900 p-3 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-slate-400 dark:text-slate-500">TCP 监听级</p>
|
||||||
|
<p class="text-xl font-bold mt-0.5 text-blue-600 dark:text-blue-400" id="tcp-count">0</p>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-arrow-right-arrows-left text-blue-500 opacity-30 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white dark:bg-slate-900 p-3 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-slate-400 dark:text-slate-500">UDP 数据报</p>
|
||||||
|
<p class="text-xl font-bold mt-0.5 text-purple-600 dark:text-purple-400" id="udp-count">0</p>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-bolt text-purple-500 opacity-30 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white dark:bg-slate-900 p-3 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-slate-400 dark:text-slate-500">已终止进程数</p>
|
||||||
|
<p class="text-xl font-bold mt-0.5 text-rose-600 dark:text-rose-400" id="killed-count">0</p>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-ban text-rose-500 opacity-30 text-xl"></i>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4 flex-1 min-h-0 items-stretch">
|
||||||
|
<div class="lg:col-span-2 flex flex-col space-y-4 min-h-0" id="left-panel">
|
||||||
|
<div class="bg-white dark:bg-slate-900 p-4 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs shrink-0 flex gap-2 items-center">
|
||||||
|
<div class="relative flex-1">
|
||||||
|
<i class="fa-solid fa-filter absolute left-3 top-3 text-slate-400 text-xs"></i>
|
||||||
|
<input id="search-input" type="text" placeholder="输入端口号或进程名称过滤 (例如: 8080 或 node)..." class="w-full bg-slate-50 border border-slate-200 dark:bg-slate-950 dark:border-slate-800 rounded-md pl-9 pr-4 py-1.5 text-sm placeholder-slate-400 focus:outline-none focus:border-indigo-500 transition-all">
|
||||||
|
</div>
|
||||||
|
<button onclick="throttledLoadPorts()" class="text-xs bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 px-3 py-2 border border-slate-200 dark:border-slate-700 rounded-md font-medium cursor-pointer flex items-center gap-1.5 shrink-0 transition-all active:scale-95">
|
||||||
|
<i id="refresh-icon" class="fa-solid fa-arrows-rotate transition-transform duration-500"></i>
|
||||||
|
<span>刷新列表</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-slate-900 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs flex-1 flex flex-col min-h-0 overflow-hidden">
|
||||||
|
<div class="overflow-y-auto flex-1 custom-scrollbar">
|
||||||
|
<table class="w-full text-left border-collapse table-fixed">
|
||||||
|
<thead class="sticky top-0 bg-slate-100 dark:bg-slate-800 z-10 border-b border-slate-200 dark:border-slate-700 shadow-xs">
|
||||||
|
<tr class="text-slate-600 dark:text-slate-300 text-xs font-semibold">
|
||||||
|
<th class="py-2.5 px-4 w-20">类型</th>
|
||||||
|
<th class="py-2.5 px-4 w-28">本地端口</th>
|
||||||
|
<th class="py-2.5 px-4">关联映像名称 (Process)</th>
|
||||||
|
<th class="py-2.5 px-4 w-24">PID</th>
|
||||||
|
<th class="py-2.5 px-4 w-32">状态</th>
|
||||||
|
<th class="py-2.5 px-4 w-24 text-center">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="port-table-body" class="divide-y divide-slate-100 dark:divide-slate-800/60 text-xs font-mono"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="right-log-card" class="bg-white dark:bg-slate-900 p-4 rounded-lg border border-slate-200 dark:border-slate-800 shadow-2xs flex flex-col min-h-0">
|
||||||
|
<div class="flex items-center justify-between mb-2 shrink-0">
|
||||||
|
<h3 class="text-xs font-bold text-slate-700 dark:text-slate-300 uppercase tracking-wider flex items-center">
|
||||||
|
<i class="fa-solid fa-terminal mr-1.5 text-indigo-500"></i> 事件与诊断日志
|
||||||
|
</h3>
|
||||||
|
<button onclick="clearLogs()" class="text-[10px] text-slate-400 hover:text-slate-600 transition-colors cursor-pointer">清空</button>
|
||||||
|
</div>
|
||||||
|
<div id="terminal-log" class="bg-slate-950 border border-slate-900 rounded p-3 text-[11px] font-mono text-slate-400 flex-1 overflow-y-auto space-y-1.5 shadow-inner custom-scrollbar">
|
||||||
|
<div class="text-slate-600">[内核层] 初始化高级视口与多线程异步引擎就绪。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="text-center py-2 text-[11px] text-slate-400 dark:text-slate-600 border-t border-slate-200 dark:border-slate-900 shrink-0 bg-white dark:bg-slate-900/50" id="footer-app-name">
|
||||||
|
PortFlow 进程管理器
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const invoke = window.__TAURI__ ? (window.__TAURI__.core ? window.__TAURI__.core.invoke : window.__TAURI__.invoke) : null;
|
||||||
|
|
||||||
|
let appWindow = null;
|
||||||
|
if (window.__TAURI__ && window.__TAURI__.window) {
|
||||||
|
appWindow = window.__TAURI__.window.getCurrentWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
let allPortsData = [];
|
||||||
|
let killedCount = 0;
|
||||||
|
let isInitialLoad = true; // 💡 控制全屏 Loading 仅执行一次
|
||||||
|
|
||||||
|
const stateTranslation = {
|
||||||
|
'LISTENING': '监听中 (Listening)',
|
||||||
|
'ESTABLISHED': '已建立连接',
|
||||||
|
'CLOSE_WAIT': '等待关闭',
|
||||||
|
'TIME_WAIT': '等待被动关闭',
|
||||||
|
'SYN_SENT': '正在请求连接',
|
||||||
|
'SYN_RECEIVED': '已收到连接请求',
|
||||||
|
'FIN_WAIT_1': '等待远端确认关闭',
|
||||||
|
'FIN_WAIT_2': '等待远端关闭请求',
|
||||||
|
'LAST_ACK': '等待最后确认',
|
||||||
|
'CLOSING': '正在关闭',
|
||||||
|
'UNKNOWN': '未知状态'
|
||||||
|
};
|
||||||
|
|
||||||
|
function getChineseState(stateStr) {
|
||||||
|
if (!stateStr) return '活动中';
|
||||||
|
const upperState = stateStr.toUpperCase();
|
||||||
|
return stateTranslation[upperState] || stateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步配置元数据
|
||||||
|
async function syncAppMetadata() {
|
||||||
|
if (window.__TAURI__) {
|
||||||
|
try {
|
||||||
|
const version = await window.__TAURI__.core.invoke("plugin:app|version");
|
||||||
|
const name = await window.__TAURI__.core.invoke("plugin:app|name");
|
||||||
|
|
||||||
|
document.getElementById('app-version-badge').innerHTML = `<span class="w-1.5 h-1.5 bg-indigo-500 rounded-full mr-2 animate-pulse"></span>版本: V${version}`;
|
||||||
|
document.getElementById('splash-app-name').innerText = name;
|
||||||
|
document.getElementById('titlebar-app-name').innerText = `${name} 进程管理器`;
|
||||||
|
document.getElementById('header-app-name').innerText = `${name} 进程管理器`;
|
||||||
|
document.getElementById('footer-app-name').innerText = `${name} 进程管理器`;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("元数据同步权限受限:", e);
|
||||||
|
document.getElementById('app-version-badge').innerText = "版本: 内置环境";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.getElementById('app-version-badge').innerText = "版本: 演示模式";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initWindowDrag() {
|
||||||
|
const titlebar = document.getElementById('custom-titlebar');
|
||||||
|
const splash = document.getElementById('splash-screen');
|
||||||
|
|
||||||
|
const attachDrag = (element) => {
|
||||||
|
if (element && appWindow) {
|
||||||
|
element.addEventListener('mousedown', (e) => {
|
||||||
|
if (!e.target.closest('button')) {
|
||||||
|
appWindow.startDragging();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
attachDrag(titlebar);
|
||||||
|
attachDrag(splash);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function windowMinimize() { if (appWindow) await appWindow.minimize(); }
|
||||||
|
async function windowMaximize() {
|
||||||
|
if (appWindow) {
|
||||||
|
try {
|
||||||
|
const isMax = await appWindow.isMaximized();
|
||||||
|
if (isMax) {
|
||||||
|
await appWindow.unmaximize();
|
||||||
|
document.getElementById('max-icon').className = 'fa-regular fa-square';
|
||||||
|
} else {
|
||||||
|
await appWindow.maximize();
|
||||||
|
document.getElementById('max-icon').className = 'fa-regular fa-clone';
|
||||||
|
}
|
||||||
|
} catch (err) { console.error(err); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function windowClose() { if (appWindow) await appWindow.close(); }
|
||||||
|
|
||||||
|
function matchHeight() {
|
||||||
|
const leftPanel = document.getElementById('left-panel');
|
||||||
|
const rightCard = document.getElementById('right-log-card');
|
||||||
|
if (window.innerWidth >= 1024) {
|
||||||
|
const leftHeight = leftPanel.offsetHeight;
|
||||||
|
if (leftHeight > 0) rightCard.style.height = `${leftHeight}px`;
|
||||||
|
} else { rightCard.style.height = 'auto'; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleTheme() {
|
||||||
|
const isDark = document.documentElement.classList.toggle('dark');
|
||||||
|
document.getElementById('theme-icon').className = isDark ? 'fa-solid fa-moon text-indigo-400' : 'fa-solid fa-sun text-amber-500';
|
||||||
|
localStorage.setItem('theme', isDark ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
if (localStorage.getItem('theme') === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
document.getElementById('theme-icon').className = 'fa-solid fa-moon text-indigo-400';
|
||||||
|
}
|
||||||
|
|
||||||
|
function logToTerminal(message, type = 'info') {
|
||||||
|
const container = document.getElementById('terminal-log');
|
||||||
|
const time = new Date().toLocaleTimeString();
|
||||||
|
let colorClass = 'text-slate-400';
|
||||||
|
if (type === 'success') colorClass = 'text-emerald-400';
|
||||||
|
if (type === 'error') colorClass = 'text-rose-400';
|
||||||
|
if (type === 'cmd') colorClass = 'text-indigo-400 font-bold';
|
||||||
|
container.innerHTML += `<div class="${colorClass}">[${time}] ${message}</div>`;
|
||||||
|
container.scrollTop = container.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearLogs() { document.getElementById('terminal-log').innerHTML = ''; }
|
||||||
|
|
||||||
|
function getProcessIcon(name) {
|
||||||
|
if (!name) return '<i class="fa-solid fa-circle-question text-slate-400 mr-2 text-xs w-4 text-center"></i>';
|
||||||
|
const lower = name.toLowerCase();
|
||||||
|
if (lower.includes('node')) return '<i class="fa-brands fa-node-js text-emerald-500 mr-2 text-sm w-4 text-center"></i>';
|
||||||
|
if (lower.includes('java')) return '<i class="fa-brands fa-java text-orange-500 mr-2 text-sm w-4 text-center"></i>';
|
||||||
|
if (lower.includes('python')) return '<i class="fa-brands fa-python text-blue-400 mr-2 text-sm w-4 text-center"></i>';
|
||||||
|
if (lower.includes('nginx') || lower.includes('apache')) return '<i class="fa-solid fa-server text-teal-500 mr-2 text-xs w-4 text-center"></i>';
|
||||||
|
if (lower.includes('chrome') || lower.includes('edge') || lower.includes('browser')) return '<i class="fa-brands fa-chrome text-amber-500 mr-2 text-xs w-4 text-center"></i>';
|
||||||
|
if (lower.includes('unknown') || lower.includes('已结束')) return '<i class="fa-solid fa-circle-question text-slate-400 mr-2 text-xs w-4 text-center"></i>';
|
||||||
|
return '<i class="fa-solid fa-window-maximize text-indigo-400/80 mr-2 text-xs w-4 text-center"></i>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 💡 优化:带精准区分首次与二次反馈机制的加载函数
|
||||||
|
async function loadRealPorts() {
|
||||||
|
logToTerminal(`$ sys_diagnostic --get-network-mapping`, 'cmd');
|
||||||
|
const refreshIcon = document.getElementById('refresh-icon');
|
||||||
|
|
||||||
|
if (isInitialLoad) {
|
||||||
|
const splash = document.getElementById('splash-screen');
|
||||||
|
if (splash) {
|
||||||
|
splash.style.display = 'flex';
|
||||||
|
splash.classList.remove('opacity-0', 'pointer-events-none');
|
||||||
|
}
|
||||||
|
} else if (refreshIcon) {
|
||||||
|
refreshIcon.classList.add('animate-spin'); // 仅让按钮旋转
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!invoke) {
|
||||||
|
logToTerminal(`未检测到原生外壳,载入任务管理器级模拟排布。`, 'error');
|
||||||
|
allPortsData = [
|
||||||
|
{ protocol: 'TCP', port: 8080, name: 'nginx.exe', pid: 4120, state: 'LISTENING' },
|
||||||
|
{ protocol: 'TCP', port: 3000, name: 'node.exe', pid: 10424, state: 'LISTENING' },
|
||||||
|
{ protocol: 'TCP', port: 9000, name: 'java.exe', pid: 8840, state: 'CLOSE_WAIT' },
|
||||||
|
{ protocol: 'UDP', port: 5353, name: 'chrome.exe', pid: 1402, state: 'ESTABLISHED' },
|
||||||
|
{ protocol: 'TCP', port: 5432, name: 'postgres.exe', pid: 2112, state: 'LISTENING' }
|
||||||
|
];
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
renderTable(allPortsData);
|
||||||
|
if (isInitialLoad) { hideSplashScreen(); isInitialLoad = false; }
|
||||||
|
else if (refreshIcon) refreshIcon.classList.remove('animate-spin');
|
||||||
|
}, 800);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 执行已经解耦、不会产生界面锁死假死的异步命令
|
||||||
|
allPortsData = await invoke('get_active_ports');
|
||||||
|
renderTable(allPortsData);
|
||||||
|
logToTerminal(`核心映射成功:已提取出 ${allPortsData.length} 个物理网络映射映像。`, 'success');
|
||||||
|
|
||||||
|
if (isInitialLoad) { hideSplashScreen(); isInitialLoad = false; }
|
||||||
|
else if (refreshIcon) refreshIcon.classList.remove('animate-spin');
|
||||||
|
} catch (err) {
|
||||||
|
logToTerminal(`提取进程映像失败: ${err}`, 'error');
|
||||||
|
if (isInitialLoad) {
|
||||||
|
document.getElementById('splash-status').innerText = "加载失败,请确保使用管理员身份运行: " + err;
|
||||||
|
} else if (refreshIcon) refreshIcon.classList.remove('animate-spin');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideSplashScreen() {
|
||||||
|
const splash = document.getElementById('splash-screen');
|
||||||
|
if (splash) {
|
||||||
|
splash.classList.add('opacity-0', 'pointer-events-none');
|
||||||
|
setTimeout(() => { splash.style.display = 'none'; }, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterPorts() {
|
||||||
|
const query = document.getElementById('search-input').value.toLowerCase().trim();
|
||||||
|
if (!query) { renderTable(allPortsData); return; }
|
||||||
|
const filtered = allPortsData.filter(item =>
|
||||||
|
item.port.toString().includes(query) ||
|
||||||
|
item.name.toLowerCase().includes(query) ||
|
||||||
|
item.pid.toString().includes(query) ||
|
||||||
|
getChineseState(item.state).includes(query)
|
||||||
|
);
|
||||||
|
renderTable(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
function debounce(fn, delay) {
|
||||||
|
let timer = null;
|
||||||
|
return function (...args) {
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => { fn.apply(this, args); }, delay);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function throttle(fn, limit) {
|
||||||
|
let lastFunc = null, lastRan = null;
|
||||||
|
return function (...args) {
|
||||||
|
const context = this;
|
||||||
|
if (!lastRan) { fn.apply(context, args); lastRan = Date.now(); }
|
||||||
|
else {
|
||||||
|
if (lastFunc) clearTimeout(lastFunc);
|
||||||
|
lastFunc = setTimeout(function () {
|
||||||
|
if ((Date.now() - lastRan) >= limit) { fn.apply(context, args); lastRan = Date.now(); }
|
||||||
|
}, limit - (Date.now() - lastRan));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const debouncedFilter = debounce(filterPorts, 200);
|
||||||
|
const throttledLoadPorts = throttle(() => { loadRealPorts(); }, 1500);
|
||||||
|
|
||||||
|
function renderTable(ports) {
|
||||||
|
const tbody = document.getElementById('port-table-body');
|
||||||
|
document.getElementById('total-ports').innerText = allPortsData.length;
|
||||||
|
document.getElementById('tcp-count').innerText = allPortsData.filter(p=>p.protocol==='TCP').length;
|
||||||
|
document.getElementById('udp-count').innerText = allPortsData.filter(p=>p.protocol==='UDP').length;
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
if (ports.length === 0) {
|
||||||
|
tbody.innerHTML = `<tr><td colspan="6" class="text-center py-8 text-slate-400 italic">没有匹配的系统映像活动条目</td></tr>`;
|
||||||
|
matchHeight();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ports.forEach(item => {
|
||||||
|
const isTcp = item.protocol === 'TCP';
|
||||||
|
const typeBadge = isTcp ? '<span class="text-blue-600 bg-blue-500/10 border border-blue-500/20 px-1.5 rounded text-[10px]">TCP</span>' : '<span class="text-purple-600 bg-purple-500/10 border border-purple-500/20 px-1.5 rounded text-[10px]">UDP</span>';
|
||||||
|
const cnState = getChineseState(item.state);
|
||||||
|
const itemName = item.name || "未知映像";
|
||||||
|
|
||||||
|
tbody.innerHTML += `
|
||||||
|
<tr class="hover:bg-slate-100 dark:hover:bg-slate-800/40 border-b border-slate-100 dark:border-slate-800/40 transition-colors">
|
||||||
|
<td class="py-2 px-4 font-semibold">${typeBadge}</td>
|
||||||
|
<td class="py-2 px-4 text-indigo-600 dark:text-indigo-400 font-bold text-sm">:${item.port}</td>
|
||||||
|
<td class="py-2 px-4 text-slate-700 dark:text-slate-200 flex items-center overflow-hidden text-ellipsis whitespace-nowrap">
|
||||||
|
${getProcessIcon(itemName)}
|
||||||
|
<span class="truncate" title="${itemName}">${itemName}</span>
|
||||||
|
</td>
|
||||||
|
<td class="py-2 px-4 text-slate-500 dark:text-slate-400">${item.pid}</td>
|
||||||
|
<td class="py-2 px-4"><span class="text-[11px] text-emerald-600 font-medium whitespace-nowrap"><span class="w-1 h-1 inline-block bg-emerald-500 rounded-full mr-1.5 mb-0.5"></span>${cnState}</span></td>
|
||||||
|
<td class="py-2 px-4 text-center whitespace-nowrap"><button onclick="killRealProcess(${item.pid}, '${itemName}')" class="bg-rose-600 hover:bg-rose-700 text-white font-sans px-2.5 py-0.5 rounded text-[11px] transition-all cursor-pointer shadow-3xs whitespace-nowrap inline-block">结束任务</button></td>
|
||||||
|
</tr>`;
|
||||||
|
});
|
||||||
|
matchHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function killRealProcess(pid, name) {
|
||||||
|
if (confirm(`【Windows 任务管理器核心警告】\n\n确定要强行终止映像进程 "${name}" (PID: ${pid}) 吗?\n结束该进程会导致关联的物理端口立即释放,未保存的更改会直接丢失。`)) {
|
||||||
|
logToTerminal(`$ taskkill /F /PID ${pid}`, 'cmd');
|
||||||
|
if (!invoke) {
|
||||||
|
allPortsData = allPortsData.filter(p => p.pid !== pid); renderTable(allPortsData); return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const successMsg = await invoke('kill_process_by_pid', { pid: pid });
|
||||||
|
logToTerminal(successMsg, 'success');
|
||||||
|
killedCount++; document.getElementById('killed-count').innerText = killedCount;
|
||||||
|
await loadRealPorts();
|
||||||
|
document.getElementById('search-input').value = '';
|
||||||
|
} catch (err) {
|
||||||
|
logToTerminal(`进程销毁遭遇拒绝: ${err}`, 'error');
|
||||||
|
alert(`拒绝访问:强杀此系统核心或高权限进程需要以管理员权限重新启动软件。\n\n${err}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', matchHeight);
|
||||||
|
window.onload = async () => {
|
||||||
|
initWindowDrag();
|
||||||
|
await syncAppMetadata();
|
||||||
|
await loadRealPorts();
|
||||||
|
document.getElementById('search-input').addEventListener('input', debouncedFilter);
|
||||||
|
setTimeout(matchHeight, 150);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "port_killer",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"tauri": "tauri"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^2",
|
||||||
|
"@tauri-apps/plugin-opener": "^2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tauri-apps/cli": "^2",
|
||||||
|
"vite": "^6.0.3",
|
||||||
|
"typescript": "~5.6.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,809 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
dependencies:
|
||||||
|
'@tauri-apps/api':
|
||||||
|
specifier: ^2
|
||||||
|
version: 2.11.0
|
||||||
|
'@tauri-apps/plugin-opener':
|
||||||
|
specifier: ^2
|
||||||
|
version: 2.5.4
|
||||||
|
devDependencies:
|
||||||
|
'@tauri-apps/cli':
|
||||||
|
specifier: ^2
|
||||||
|
version: 2.11.2
|
||||||
|
typescript:
|
||||||
|
specifier: ~5.6.2
|
||||||
|
version: 5.6.3
|
||||||
|
vite:
|
||||||
|
specifier: ^6.0.3
|
||||||
|
version: 6.4.2
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [aix]
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.25.12':
|
||||||
|
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.25.12':
|
||||||
|
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.25.12':
|
||||||
|
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.25.12':
|
||||||
|
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [mips64el]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.25.12':
|
||||||
|
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [netbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [sunos]
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.25.12':
|
||||||
|
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.25.12':
|
||||||
|
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.60.4':
|
||||||
|
resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.60.4':
|
||||||
|
resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.60.4':
|
||||||
|
resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.60.4':
|
||||||
|
resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-musl@4.60.4':
|
||||||
|
resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-musl@4.60.4':
|
||||||
|
resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.60.4':
|
||||||
|
resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.60.4':
|
||||||
|
resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-openbsd-x64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.60.4':
|
||||||
|
resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.60.4':
|
||||||
|
resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.60.4':
|
||||||
|
resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.60.4':
|
||||||
|
resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.60.4':
|
||||||
|
resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tauri-apps/api@2.11.0':
|
||||||
|
resolution: {integrity: sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==}
|
||||||
|
|
||||||
|
'@tauri-apps/cli-darwin-arm64@2.11.2':
|
||||||
|
resolution: {integrity: sha512-+4UZzLt+eOAEQCwgd+TqKgyUJMrvx+BgdXLLaqJYmPqzP+nE6YZr/hY6CWLYGQb8jFn99jEkmC6uA3tNvamA1w==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-darwin-x64@2.11.2':
|
||||||
|
resolution: {integrity: sha512-VjYYtZUPqDMLutSfJEyxFE3Bz+DPi7c8wC3imckgvciLDZLq4qwKJxBicg0BXGhXjJsl8vKWgWRFNMPELQ+Xyg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-arm-gnueabihf@2.11.2':
|
||||||
|
resolution: {integrity: sha512-yMemD6f4i95AQriS8EazyOFzbE34yjnP16i3IOzpHGQvBoy2DjypFMFBq0NtPuITURv/cOGguRtHR5d79/9CSA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-arm64-gnu@2.11.2':
|
||||||
|
resolution: {integrity: sha512-cgI91D2wL8GSgoWwZXDqt+DwnuZCP2/bz03QAE4TrhgAKIsrB4hX26W/H1EONPUUNkqrsgeCD0wU6pcNjV/5kw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-arm64-musl@2.11.2':
|
||||||
|
resolution: {integrity: sha512-X1rm0BERqAAggtYTESSgXrS3sz4Sb/OiPiz54UqISlXW+GkR3vNIGnsy/lejNmoXGVqri3Q53BCfQiclOIyRPw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-riscv64-gnu@2.11.2':
|
||||||
|
resolution: {integrity: sha512-usbMLJbT3KtkOrBMDVeGYNM35aTHXx38SJSzTMSqqjeUIOQ+iVPjb2yAGNAE+KqmBbAx4FOFIyMeKXx2M/JKGQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-x64-gnu@2.11.2':
|
||||||
|
resolution: {integrity: sha512-Ru4gwJKPG0ctVGchRGpRup4Y4lW2SSfFnrbQcyHhCliKy4g8Qz97TrUgCur4CbWyAgKxvGh3SjrkA0LDYzDGiw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-x64-musl@2.11.2':
|
||||||
|
resolution: {integrity: sha512-eUm7T6clN1MMmNSRQ9gaWsQdyehQx2Gmn5hht/QUlqZQI/qcP2OJK5dnaxqwFzCr2HdsEo9ydxaqcS1oJzMvUw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-win32-arm64-msvc@2.11.2':
|
||||||
|
resolution: {integrity: sha512-HeeZW80jU+gVTOEX4X/hC6NVSAdDVXajwP5fxIZ/3z9WvUC7qrudX2GMTilYq6Dg0e0sk0XgsAJD1hZ5wPBXUA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-win32-ia32-msvc@2.11.2':
|
||||||
|
resolution: {integrity: sha512-YhjQNZcXfbkCLyazSv1nPnJ9iRFE1wm6kc51FDbU10/Dk09io+6PAGMLjkxnX2GdM0qMnDmTjstY8mTDVvtKeA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tauri-apps/cli-win32-x64-msvc@2.11.2':
|
||||||
|
resolution: {integrity: sha512-d2JchlFIpZevZVReyqhQOekJmb1UH3rhZ5VX6sH3ty9ETE0TKQavpihvoScUXfKKpW6HZC0MrFGRU0ZtD+w3gA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tauri-apps/cli@2.11.2':
|
||||||
|
resolution: {integrity: sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-opener@2.5.4':
|
||||||
|
resolution: {integrity: sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==}
|
||||||
|
|
||||||
|
'@types/estree@1.0.8':
|
||||||
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
esbuild@0.25.12:
|
||||||
|
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
fdir@6.5.0:
|
||||||
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
picomatch: ^3 || ^4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
picomatch:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
nanoid@3.3.12:
|
||||||
|
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
|
||||||
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
|
picomatch@4.0.4:
|
||||||
|
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
postcss@8.5.15:
|
||||||
|
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
rollup@4.60.4:
|
||||||
|
resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==}
|
||||||
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
source-map-js@1.2.1:
|
||||||
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
tinyglobby@0.2.16:
|
||||||
|
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
typescript@5.6.3:
|
||||||
|
resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
vite@6.4.2:
|
||||||
|
resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==}
|
||||||
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
|
||||||
|
jiti: '>=1.21.0'
|
||||||
|
less: '*'
|
||||||
|
lightningcss: ^1.21.0
|
||||||
|
sass: '*'
|
||||||
|
sass-embedded: '*'
|
||||||
|
stylus: '*'
|
||||||
|
sugarss: '*'
|
||||||
|
terser: ^5.16.0
|
||||||
|
tsx: ^4.8.1
|
||||||
|
yaml: ^2.4.2
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/node':
|
||||||
|
optional: true
|
||||||
|
jiti:
|
||||||
|
optional: true
|
||||||
|
less:
|
||||||
|
optional: true
|
||||||
|
lightningcss:
|
||||||
|
optional: true
|
||||||
|
sass:
|
||||||
|
optional: true
|
||||||
|
sass-embedded:
|
||||||
|
optional: true
|
||||||
|
stylus:
|
||||||
|
optional: true
|
||||||
|
sugarss:
|
||||||
|
optional: true
|
||||||
|
terser:
|
||||||
|
optional: true
|
||||||
|
tsx:
|
||||||
|
optional: true
|
||||||
|
yaml:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@esbuild/aix-ppc64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-arm@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/android-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/darwin-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/freebsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-arm@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ia32@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-loong64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-mips64el@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-ppc64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-riscv64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-s390x@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/linux-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/netbsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openbsd-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/openharmony-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/sunos-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-arm64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-ia32@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@esbuild/win32-x64@0.25.12':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-musl@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-musl@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openbsd-x64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.60.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/api@2.11.0': {}
|
||||||
|
|
||||||
|
'@tauri-apps/cli-darwin-arm64@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-darwin-x64@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-arm-gnueabihf@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-arm64-gnu@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-arm64-musl@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-riscv64-gnu@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-x64-gnu@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-linux-x64-musl@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-win32-arm64-msvc@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-win32-ia32-msvc@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli-win32-x64-msvc@2.11.2':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tauri-apps/cli@2.11.2':
|
||||||
|
optionalDependencies:
|
||||||
|
'@tauri-apps/cli-darwin-arm64': 2.11.2
|
||||||
|
'@tauri-apps/cli-darwin-x64': 2.11.2
|
||||||
|
'@tauri-apps/cli-linux-arm-gnueabihf': 2.11.2
|
||||||
|
'@tauri-apps/cli-linux-arm64-gnu': 2.11.2
|
||||||
|
'@tauri-apps/cli-linux-arm64-musl': 2.11.2
|
||||||
|
'@tauri-apps/cli-linux-riscv64-gnu': 2.11.2
|
||||||
|
'@tauri-apps/cli-linux-x64-gnu': 2.11.2
|
||||||
|
'@tauri-apps/cli-linux-x64-musl': 2.11.2
|
||||||
|
'@tauri-apps/cli-win32-arm64-msvc': 2.11.2
|
||||||
|
'@tauri-apps/cli-win32-ia32-msvc': 2.11.2
|
||||||
|
'@tauri-apps/cli-win32-x64-msvc': 2.11.2
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-opener@2.5.4':
|
||||||
|
dependencies:
|
||||||
|
'@tauri-apps/api': 2.11.0
|
||||||
|
|
||||||
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
esbuild@0.25.12:
|
||||||
|
optionalDependencies:
|
||||||
|
'@esbuild/aix-ppc64': 0.25.12
|
||||||
|
'@esbuild/android-arm': 0.25.12
|
||||||
|
'@esbuild/android-arm64': 0.25.12
|
||||||
|
'@esbuild/android-x64': 0.25.12
|
||||||
|
'@esbuild/darwin-arm64': 0.25.12
|
||||||
|
'@esbuild/darwin-x64': 0.25.12
|
||||||
|
'@esbuild/freebsd-arm64': 0.25.12
|
||||||
|
'@esbuild/freebsd-x64': 0.25.12
|
||||||
|
'@esbuild/linux-arm': 0.25.12
|
||||||
|
'@esbuild/linux-arm64': 0.25.12
|
||||||
|
'@esbuild/linux-ia32': 0.25.12
|
||||||
|
'@esbuild/linux-loong64': 0.25.12
|
||||||
|
'@esbuild/linux-mips64el': 0.25.12
|
||||||
|
'@esbuild/linux-ppc64': 0.25.12
|
||||||
|
'@esbuild/linux-riscv64': 0.25.12
|
||||||
|
'@esbuild/linux-s390x': 0.25.12
|
||||||
|
'@esbuild/linux-x64': 0.25.12
|
||||||
|
'@esbuild/netbsd-arm64': 0.25.12
|
||||||
|
'@esbuild/netbsd-x64': 0.25.12
|
||||||
|
'@esbuild/openbsd-arm64': 0.25.12
|
||||||
|
'@esbuild/openbsd-x64': 0.25.12
|
||||||
|
'@esbuild/openharmony-arm64': 0.25.12
|
||||||
|
'@esbuild/sunos-x64': 0.25.12
|
||||||
|
'@esbuild/win32-arm64': 0.25.12
|
||||||
|
'@esbuild/win32-ia32': 0.25.12
|
||||||
|
'@esbuild/win32-x64': 0.25.12
|
||||||
|
|
||||||
|
fdir@6.5.0(picomatch@4.0.4):
|
||||||
|
optionalDependencies:
|
||||||
|
picomatch: 4.0.4
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
nanoid@3.3.12: {}
|
||||||
|
|
||||||
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
|
picomatch@4.0.4: {}
|
||||||
|
|
||||||
|
postcss@8.5.15:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.12
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
rollup@4.60.4:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
optionalDependencies:
|
||||||
|
'@rollup/rollup-android-arm-eabi': 4.60.4
|
||||||
|
'@rollup/rollup-android-arm64': 4.60.4
|
||||||
|
'@rollup/rollup-darwin-arm64': 4.60.4
|
||||||
|
'@rollup/rollup-darwin-x64': 4.60.4
|
||||||
|
'@rollup/rollup-freebsd-arm64': 4.60.4
|
||||||
|
'@rollup/rollup-freebsd-x64': 4.60.4
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf': 4.60.4
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf': 4.60.4
|
||||||
|
'@rollup/rollup-linux-arm64-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-linux-arm64-musl': 4.60.4
|
||||||
|
'@rollup/rollup-linux-loong64-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-linux-loong64-musl': 4.60.4
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-linux-ppc64-musl': 4.60.4
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-linux-riscv64-musl': 4.60.4
|
||||||
|
'@rollup/rollup-linux-s390x-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-linux-x64-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-linux-x64-musl': 4.60.4
|
||||||
|
'@rollup/rollup-openbsd-x64': 4.60.4
|
||||||
|
'@rollup/rollup-openharmony-arm64': 4.60.4
|
||||||
|
'@rollup/rollup-win32-arm64-msvc': 4.60.4
|
||||||
|
'@rollup/rollup-win32-ia32-msvc': 4.60.4
|
||||||
|
'@rollup/rollup-win32-x64-gnu': 4.60.4
|
||||||
|
'@rollup/rollup-win32-x64-msvc': 4.60.4
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
tinyglobby@0.2.16:
|
||||||
|
dependencies:
|
||||||
|
fdir: 6.5.0(picomatch@4.0.4)
|
||||||
|
picomatch: 4.0.4
|
||||||
|
|
||||||
|
typescript@5.6.3: {}
|
||||||
|
|
||||||
|
vite@6.4.2:
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.25.12
|
||||||
|
fdir: 6.5.0(picomatch@4.0.4)
|
||||||
|
picomatch: 4.0.4
|
||||||
|
postcss: 8.5.15
|
||||||
|
rollup: 4.60.4
|
||||||
|
tinyglobby: 0.2.16
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.3
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
allowBuilds:
|
||||||
|
esbuild: true
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
|
||||||
|
# Generated by Tauri
|
||||||
|
# will have schema files for capabilities auto-completion
|
||||||
|
/gen/schemas
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "PortFlow"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "一个基于 Tauri 的端口管理工具"
|
||||||
|
authors = ["寒寒"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
# The `_lib` suffix may seem redundant but it is necessary
|
||||||
|
# to make the lib name unique and wouldn't conflict with the bin name.
|
||||||
|
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||||
|
name = "port_flow_lib"
|
||||||
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tauri-build = { version = "2", features = [] }
|
||||||
|
winres = "0.1"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tauri = { version = "2", features = [] }
|
||||||
|
tauri-plugin-opener = "2"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
sysinfo = "0.30"
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
fn main() {
|
||||||
|
// 💡 仅在 Windows 平台下注入管理员清单
|
||||||
|
if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" {
|
||||||
|
let mut res = winres::WindowsResource::new();
|
||||||
|
// 强行写入 UAC 清单,要求最高管理员权限
|
||||||
|
res.set_manifest(r#"
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
||||||
|
"#);
|
||||||
|
res.compile().unwrap();
|
||||||
|
}
|
||||||
|
tauri_build::build();
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "default",
|
||||||
|
"description": "Capability for the main window",
|
||||||
|
"windows": ["main"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"opener:default",
|
||||||
|
"core:window:allow-start-dragging",
|
||||||
|
"core:window:allow-minimize",
|
||||||
|
"core:window:allow-maximize",
|
||||||
|
"core:window:allow-unmaximize",
|
||||||
|
"core:window:allow-close",
|
||||||
|
"core:app:allow-version",
|
||||||
|
"core:app:allow-name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 974 B |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 903 B |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||||
|
#[tauri::command]
|
||||||
|
fn greet(name: &str) -> String {
|
||||||
|
format!("Hello, {}! You've been greeted from Rust!", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
|
pub fn run() {
|
||||||
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_opener::init())
|
||||||
|
.invoke_handler(tauri::generate_handler![greet])
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application");
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
// Prevents additional console window on Windows in release
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::process::Command;
|
||||||
|
use sysinfo::{Pid, System};
|
||||||
|
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
struct PortInfo {
|
||||||
|
protocol: String,
|
||||||
|
port: u16,
|
||||||
|
name: String,
|
||||||
|
pid: u32,
|
||||||
|
state: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 💡 异步处理命令,使用 spawn_blocking 将耗时任务抛给专用后台线程池
|
||||||
|
#[tauri::command]
|
||||||
|
async fn get_active_ports() -> Result<Vec<PortInfo>, String> {
|
||||||
|
tauri::async_runtime::spawn_blocking(move || {
|
||||||
|
let mut ports = Vec::new();
|
||||||
|
|
||||||
|
// 在后台线程中初始化系统进程快照
|
||||||
|
let mut sys = System::new_all();
|
||||||
|
sys.refresh_processes();
|
||||||
|
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
// Windows 环境下执行 netstat -ano
|
||||||
|
let output = Command::new("cmd")
|
||||||
|
.args(&["/C", "netstat -ano"])
|
||||||
|
.output()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
|
for line in stdout.lines() {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 5 && (parts[0] == "TCP" || parts[0] == "UDP") {
|
||||||
|
let local_addr = parts[1];
|
||||||
|
let state = parts[3].to_string();
|
||||||
|
let pid_str = parts[4];
|
||||||
|
|
||||||
|
if let Some(port_str) = local_addr.split(':').last() {
|
||||||
|
if let (Ok(port), Ok(pid_val)) = (port_str.parse::<u16>(), pid_str.parse::<u32>()) {
|
||||||
|
let process_name = if let Some(proc) = sys.process(Pid::from(pid_val as usize)) {
|
||||||
|
proc.name().to_string()
|
||||||
|
} else {
|
||||||
|
"未知进程 (已结束)".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
ports.push(PortInfo {
|
||||||
|
protocol: parts[0].to_string(),
|
||||||
|
port,
|
||||||
|
name: process_name,
|
||||||
|
pid: pid_val,
|
||||||
|
state,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// macOS / Linux 降级兼容处理
|
||||||
|
let output = Command::new("sh")
|
||||||
|
.args(&["-c", "lsof -i -P -n | grep LISTEN"])
|
||||||
|
.output()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
|
for line in stdout.lines() {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 9 {
|
||||||
|
let pid_str = parts[1];
|
||||||
|
let protocol = if parts[7].contains("UDP") { "UDP" } else { "TCP" };
|
||||||
|
let local_addr = parts[8];
|
||||||
|
|
||||||
|
if let Some(port_str) = local_addr.split(':').last() {
|
||||||
|
if let (Ok(port), Ok(pid_val)) = (port_str.parse::<u16>(), pid_str.parse::<u32>()) {
|
||||||
|
let process_name = if let Some(proc) = sys.process(Pid::from(pid_val as usize)) {
|
||||||
|
proc.name().to_string()
|
||||||
|
} else {
|
||||||
|
parts[0].to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
ports.push(PortInfo {
|
||||||
|
protocol: protocol.to_string(),
|
||||||
|
port,
|
||||||
|
name: process_name,
|
||||||
|
pid: pid_val,
|
||||||
|
state: "LISTENING".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ports)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("进程同步线程崩溃: {}", e))?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn kill_process_by_pid(pid: u32) -> Result<String, String> {
|
||||||
|
let output = if cfg!(target_os = "windows") {
|
||||||
|
Command::new("taskkill")
|
||||||
|
.args(&["/F", "/PID", &pid.to_string()])
|
||||||
|
.output()
|
||||||
|
} else {
|
||||||
|
Command::new("kill")
|
||||||
|
.args(&["-9", &pid.to_string()])
|
||||||
|
.output()
|
||||||
|
};
|
||||||
|
|
||||||
|
match output {
|
||||||
|
Ok(out) => {
|
||||||
|
if out.status.success() {
|
||||||
|
Ok(format!("成功结束 PID: {} 的进程", pid))
|
||||||
|
} else {
|
||||||
|
Err(String::from_utf8_lossy(&out.stderr).to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
tauri::Builder::default()
|
||||||
|
.invoke_handler(tauri::generate_handler![get_active_ports, kill_process_by_pid])
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running tauri application");
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
|
"productName": "PortFlow",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"identifier": "com.administrator.portflow",
|
||||||
|
"build": {
|
||||||
|
"beforeDevCommand": "bun run dev",
|
||||||
|
"devUrl": "http://localhost:1420",
|
||||||
|
"beforeBuildCommand": "bun run build",
|
||||||
|
"frontendDist": "../dist"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"withGlobalTauri": true,
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"label": "main",
|
||||||
|
"title": "PortFlow - 端口管理控制台",
|
||||||
|
"width": 1150,
|
||||||
|
"height": 760,
|
||||||
|
"minWidth": 980,
|
||||||
|
"minHeight": 600,
|
||||||
|
"resizable": true,
|
||||||
|
"fullscreen": false,
|
||||||
|
"decorations": false,
|
||||||
|
"center": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": {
|
||||||
|
"csp": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bundle": {
|
||||||
|
"active": true,
|
||||||
|
"targets": ["nsis"],
|
||||||
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
|
||||||
|
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#2D79C7" stroke="none">
|
||||||
|
<path d="M430 5109 c-130 -19 -248 -88 -325 -191 -53 -71 -83 -147 -96 -247
|
||||||
|
-6 -49 -9 -813 -7 -2166 l3 -2090 22 -65 c54 -159 170 -273 328 -323 l70 -22
|
||||||
|
2140 0 2140 0 66 23 c160 55 272 169 322 327 l22 70 0 2135 0 2135 -22 70
|
||||||
|
c-49 157 -155 265 -319 327 l-59 23 -2115 1 c-1163 1 -2140 -2 -2170 -7z
|
||||||
|
m3931 -2383 c48 -9 120 -26 160 -39 l74 -23 3 -237 c1 -130 0 -237 -2 -237 -3
|
||||||
|
0 -26 14 -53 30 -61 38 -197 84 -310 106 -110 20 -293 15 -368 -12 -111 -39
|
||||||
|
-175 -110 -175 -193 0 -110 97 -197 335 -300 140 -61 309 -146 375 -189 30
|
||||||
|
-20 87 -68 126 -107 119 -117 164 -234 164 -426 0 -310 -145 -518 -430 -613
|
||||||
|
-131 -43 -248 -59 -445 -60 -243 -1 -405 24 -577 90 l-68 26 0 242 c0 175 -3
|
||||||
|
245 -12 254 -9 9 -9 12 0 12 7 0 12 -4 12 -9 0 -17 139 -102 223 -138 136 -57
|
||||||
|
233 -77 382 -76 145 0 224 19 295 68 75 52 100 156 59 242 -41 84 -135 148
|
||||||
|
-374 253 -367 161 -522 300 -581 520 -23 86 -23 253 -1 337 73 275 312 448
|
||||||
|
682 492 109 13 401 6 506 -13z m-1391 -241 l0 -205 -320 0 -320 0 0 -915 0
|
||||||
|
-915 -255 0 -255 0 0 915 0 915 -320 0 -320 0 0 205 0 205 895 0 895 0 0 -205z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,22 @@
|
|||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
|
||||||
|
let greetInputEl: HTMLInputElement | null;
|
||||||
|
let greetMsgEl: HTMLElement | null;
|
||||||
|
|
||||||
|
async function greet() {
|
||||||
|
if (greetMsgEl && greetInputEl) {
|
||||||
|
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||||
|
greetMsgEl.textContent = await invoke("greet", {
|
||||||
|
name: greetInputEl.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
greetInputEl = document.querySelector("#greet-input");
|
||||||
|
greetMsgEl = document.querySelector("#greet-msg");
|
||||||
|
document.querySelector("#greet-form")?.addEventListener("submit", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
greet();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
.logo.vite:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #747bff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo.typescript:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #2d79c7);
|
||||||
|
}
|
||||||
|
:root {
|
||||||
|
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
color: #0f0f0f;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin: 0;
|
||||||
|
padding-top: 10vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 6em;
|
||||||
|
padding: 1.5em;
|
||||||
|
will-change: filter;
|
||||||
|
transition: 0.75s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo.tauri:hover {
|
||||||
|
filter: drop-shadow(0 0 2em #24c8db);
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #646cff;
|
||||||
|
text-decoration: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #535bf2;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.6em 1.2em;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: inherit;
|
||||||
|
color: #0f0f0f;
|
||||||
|
background-color: #ffffff;
|
||||||
|
transition: border-color 0.25s;
|
||||||
|
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
border-color: #396cd8;
|
||||||
|
}
|
||||||
|
button:active {
|
||||||
|
border-color: #396cd8;
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#greet-input {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
color: #f6f6f6;
|
||||||
|
background-color: #2f2f2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #24c8db;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #0f0f0f98;
|
||||||
|
}
|
||||||
|
button:active {
|
||||||
|
background-color: #0f0f0f69;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
|
// @ts-expect-error process is a nodejs global
|
||||||
|
const host = process.env.TAURI_DEV_HOST;
|
||||||
|
|
||||||
|
// https://vite.dev/config/
|
||||||
|
export default defineConfig(async () => ({
|
||||||
|
|
||||||
|
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||||
|
//
|
||||||
|
// 1. prevent Vite from obscuring rust errors
|
||||||
|
clearScreen: false,
|
||||||
|
// 2. tauri expects a fixed port, fail if that port is not available
|
||||||
|
server: {
|
||||||
|
port: 1420,
|
||||||
|
strictPort: true,
|
||||||
|
host: host || false,
|
||||||
|
hmr: host
|
||||||
|
? {
|
||||||
|
protocol: "ws",
|
||||||
|
host,
|
||||||
|
port: 1421,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
watch: {
|
||||||
|
// 3. tell Vite to ignore watching `src-tauri`
|
||||||
|
ignored: ["**/src-tauri/**"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||