Compare commits
2 Commits
a024c4a043
...
daed
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
514c025caf | ||
|
|
cacb25a2ca |
9
package-lock.json
generated
9
package-lock.json
generated
@@ -867,6 +867,7 @@
|
||||
"integrity": "sha512-TGFX1pZUt9qqY20Cv5NyYvy0iLWHf2jXi8s+eCGsig7jQMdwZWKUFMR6TbvFNhfDSUpc1sH/Y5EHv20g3HHA3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||
@@ -906,6 +907,7 @@
|
||||
"integrity": "sha512-YZs/OSKOQAQCnJvM/P+F1URotNnYNeU3P2s4oIpzm1uFaqUEqRxUB0g5ejMjEb5Gjb9/PiBI5Ktrq4rUUF8UVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte-inspector": "^5.0.0",
|
||||
"debug": "^4.4.1",
|
||||
@@ -1467,6 +1469,7 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -2055,6 +2058,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -2097,6 +2101,7 @@
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -2113,6 +2118,7 @@
|
||||
"integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"prettier": "^3.0.0",
|
||||
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
|
||||
@@ -2304,6 +2310,7 @@
|
||||
"integrity": "sha512-kjkAjCk41mJfvJZG56XcJNOdJSke94JxtcX8zFzzz2vrt47E0LnoBzU6azIZ1aBxJgUep8qegAkguSf1GjxLXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
@@ -2402,6 +2409,7 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -2416,6 +2424,7 @@
|
||||
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
||||
8
src-tauri/.idea/.gitignore
generated
vendored
Normal file
8
src-tauri/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
src-tauri/.idea/modules.xml
generated
Normal file
8
src-tauri/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/src-tauri.iml" filepath="$PROJECT_DIR$/.idea/src-tauri.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
11
src-tauri/.idea/src-tauri.iml
generated
Normal file
11
src-tauri/.idea/src-tauri.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
src-tauri/.idea/vcs.xml
generated
Normal file
6
src-tauri/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
13
src-tauri/Cargo.lock
generated
13
src-tauri/Cargo.lock
generated
@@ -80,6 +80,7 @@ name = "app"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"network-interface",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
@@ -1904,6 +1905,18 @@ dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "network-interface"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07709a6d4eba90ab10ec170a0530b3aafc81cb8a2d380e4423ae41fc55fe5745"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"thiserror 2.0.17",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
|
||||
@@ -19,7 +19,8 @@ tauri-build = { version = "2.5.1", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0.228" }
|
||||
log = "0.4"
|
||||
tauri = { version = "2.9.2", features = [] }
|
||||
tauri-plugin-log = "2"
|
||||
network-interface = "2.0.3"
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
mod network;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
@@ -11,6 +13,9 @@ pub fn run() {
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
network::get_network_interfaces
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
app_lib::run();
|
||||
}
|
||||
|
||||
37
src-tauri/src/network.rs
Normal file
37
src-tauri/src/network.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use network_interface::{NetworkInterface, NetworkInterfaceConfig};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct InterfaceInfo {
|
||||
pub name: String,
|
||||
pub addr: String, // IP 地址
|
||||
pub mac: Option<String>, // MAC 地址,可能不存在
|
||||
}
|
||||
|
||||
|
||||
fn map_interface_to_info(interface: &NetworkInterface) -> InterfaceInfo {
|
||||
let mac_address = interface.mac_addr.as_ref().map(|mac| mac.to_string());
|
||||
let ip_addr = interface.addr.iter().find(|addr| addr.ip().is_ipv4())
|
||||
.map(|addr| addr.ip().to_string())
|
||||
.unwrap_or_else(|| "N/A".to_string());
|
||||
|
||||
InterfaceInfo {
|
||||
name: interface.name.clone(),
|
||||
addr: ip_addr,
|
||||
mac: mac_address,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_network_interfaces() -> Result<Vec<InterfaceInfo>, String> {
|
||||
match NetworkInterface::show() {
|
||||
Ok(interfaces) => {
|
||||
let info_list: Vec<InterfaceInfo> = interfaces.into_iter()
|
||||
.map(|interface| map_interface_to_info(&interface))
|
||||
.collect();
|
||||
Ok(info_list)
|
||||
}
|
||||
Err(e) => Err(format!("无法获取网络接口信息: {}", e)),
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
:root{
|
||||
--main-bg-color: #1f1f1f;
|
||||
--main-border-shadow:1px 0 3px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" >
|
||||
<symbol id="home" viewBox="0 0 20 20">
|
||||
<g fill="none">
|
||||
<path fill="url(#home-SVGDx0DLj5H)" d="M13.18 2H10.5C8.768 7.023 6.823 12.62 6.823 18h6.483a1.75 1.75 0 0 0 1.485-.825l3.998-6.42a1.43 1.43 0 0 0 0-1.51L14.98 3.13A2 2 0 0 0 13.18 2"/>
|
||||
|
||||
<path fill="url(#home-SVGpR69Vbpe)" fill-opacity="0.5" d="M13.18 2H10.5C8.768 7.023 6.823 12.62 6.823 18h6.483a1.75 1.75 0 0 0 1.485-.825l3.998-6.42a1.43 1.43 0 0 0 0-1.51L14.98 3.13A2 2 0 0 0 13.18 2"/>
|
||||
|
||||
<path fill="url(#home-SVGFEeptdiY)" d="M13.25 2.001H6.69c-.601 0-1.16.308-1.48.816l-3.942 6.25a1.75 1.75 0 0 0 0 1.867L5.13 17.06c.354.56.96.91 1.619.938l.067.002h.006a2 2 0 0 0 1.969-1.662l.003-.002L11.18 3.953a2 2 0 0 1 2.069-1.952"/>
|
||||
|
||||
<path fill="url(#home-SVGIBIxBcZq)" fill-opacity="0.4" d="M13.25 2.001H6.69c-.601 0-1.16.308-1.48.816l-3.942 6.25a1.75 1.75 0 0 0 0 1.867L5.13 17.06c.354.56.96.91 1.619.938l.067.002h.006a2 2 0 0 0 1.969-1.662l.003-.002L11.18 3.953a2 2 0 0 1 2.069-1.952"/>
|
||||
|
||||
<defs>
|
||||
<radialGradient id="home-SVGDx0DLj5H" cx="0" cy="0" r="1" gradientTransform="rotate(-87.881 17.698 4.836)scale(23.3302 18.6978)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffc470"/><stop offset=".251" stop-color="#ff835c"/><stop offset=".584" stop-color="#f24a9d"/><stop offset=".871" stop-color="#b339f0"/><stop offset="1" stop-color="#c354ff"/></radialGradient>
|
||||
<radialGradient id="home-SVGpR69Vbpe" cx="0" cy="0" r="1" gradientTransform="matrix(-9.9932 -9.83058 9.94854 -10.1131 11.777 16.154)" gradientUnits="userSpaceOnUse"><stop offset=".709" stop-color="#ffb357" stop-opacity="0"/><stop offset=".942" stop-color="#ffb357"/></radialGradient>
|
||||
<radialGradient id="home-SVGFEeptdiY" cx="0" cy="0" r="1" gradientTransform="rotate(-160.247 10.243 6.665)scale(22.9945 19.4416)" gradientUnits="userSpaceOnUse"><stop offset=".222" stop-color="#4e46e2"/><stop offset=".578" stop-color="#625df6"/><stop offset=".955" stop-color="#e37dff"/></radialGradient>
|
||||
<linearGradient id="home-SVGIBIxBcZq" x1="4.823" x2="10.254" y1="8.629" y2="9.914" gradientUnits="userSpaceOnUse"><stop stop-color="#7563f7" stop-opacity="0"/><stop offset=".986" stop-color="#4916ae"/></linearGradient>
|
||||
</defs>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="network" viewBox="0 0 24 24"><path fill="currentColor" d="M7 7H5V6H4V4h1V3h2v1h1v2H7zm-2 4h1v3H5v1H2v-1H1v-3h1v-1h3zm4-3h1v1H9zm6 7h1v1h-1zm2-7h1v1h-1zM8 7h1v1H8zm-1 5h1v1H7z"/><path fill="currentColor" d="M16 14v-3h-1v-1h-1V9h-3v1h-1v1H9v3h1v1h1v1h3v-1h1v-1zm-5 0v-3h3v3zm5-5h1v1h-1zm0 7h1v1h-1zm5 2h1v3h-1v1h-3v-1h-1v-3h1v-1h3zm1-13v2h-1v1h-2V7h-1V5h1V4h2v1z"/></symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 70 B After Width: | Height: | Size: 2.7 KiB |
36
src/lib/components/Icon.svelte
Normal file
36
src/lib/components/Icon.svelte
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import type { IconId } from '$lib/types/icon-ids';
|
||||
|
||||
export let id: IconId;
|
||||
export let size: number | string ;
|
||||
export let className: string = '';
|
||||
$: dimensions = typeof size === 'number' ? `${size}px` : size;
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<svg {...$$restProps}
|
||||
role="img"
|
||||
class={className}
|
||||
aria-hidden="true"
|
||||
width={dimensions?dimensions:24}
|
||||
height={dimensions?dimensions:24}
|
||||
>
|
||||
<use href={`#${id}`} />
|
||||
</svg>
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
.app-icon {
|
||||
/* 确保图标与文本基线对齐 */
|
||||
vertical-align: middle;
|
||||
/* 防止用户选择图标,提高用户体验 */
|
||||
user-select: none;
|
||||
/* 默认显示为行内块级元素 */
|
||||
display: inline-block;
|
||||
/* 确保它能响应 CSS 动画 */
|
||||
transition: color 0.2s, transform 0.2s;
|
||||
}
|
||||
</style>
|
||||
|
||||
23
src/lib/components/icon/HomeIcon.svelte
Normal file
23
src/lib/components/icon/HomeIcon.svelte
Normal file
@@ -0,0 +1,23 @@
|
||||
<script>
|
||||
</script>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" {...$$restProps}>
|
||||
<g fill="none">
|
||||
<path fill="url(#SVGkm4eqcHj)" d="M6 9h4v5H6z" />
|
||||
<path fill="url(#SVG4sqiUdhg)" d="M8.687 2.273a1 1 0 0 0-1.374 0l-4.844 4.58A1.5 1.5 0 0 0 2 7.943v4.569a1.5 1.5 0 0 0 1.5 1.5h3v-4a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v4h3a1.5 1.5 0 0 0 1.5-1.5v-4.57a1.5 1.5 0 0 0-.47-1.09z" />
|
||||
<path fill="url(#SVGbhYexcuE)" fill-rule="evenodd" d="m8.004 2.636l5.731 5.41a.75.75 0 1 0 1.03-1.091L8.86 1.382a1.25 1.25 0 0 0-1.724.007L1.23 7.059a.75.75 0 0 0 1.038 1.082z" clip-rule="evenodd" />
|
||||
<defs>
|
||||
<linearGradient id="SVGkm4eqcHj" x1="8" x2="4.796" y1="9" y2="14.698" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#944600" />
|
||||
<stop offset="1" stop-color="#cd8e02" />
|
||||
</linearGradient>
|
||||
<linearGradient id="SVG4sqiUdhg" x1="3.145" x2="14.93" y1="1.413" y2="10.981" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#ffd394" />
|
||||
<stop offset="1" stop-color="#ffb357" />
|
||||
</linearGradient>
|
||||
<linearGradient id="SVGbhYexcuE" x1="10.262" x2="6.945" y1="-.696" y2="7.895" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#ff921f" />
|
||||
<stop offset="1" stop-color="#eb4824" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -11,22 +11,21 @@
|
||||
</script>
|
||||
|
||||
<header class="custom-titlebar" data-tauri-drag-region>
|
||||
<div class="app-title" data-tauri-drag-region>
|
||||
|
||||
</div>
|
||||
<div class="app-title" data-tauri-drag-region></div>
|
||||
|
||||
<div class="window-controls">
|
||||
<button type="button" aria-label="最小化窗口" data-tauri-drag-region="false" class="h-btn btn-minimize" on:click={minimize}></button>
|
||||
<button type="button" title="最小化窗口" data-tauri-drag-region="false" class="h-btn btn-minimize" on:click={minimize}></button>
|
||||
<button
|
||||
type="button"
|
||||
data-tauri-drag-region="false"
|
||||
class="h-btn btn-max"
|
||||
aria-label="最大化窗口"
|
||||
title="最大化窗口"
|
||||
on:click={maximize}></button>
|
||||
<button type="button"
|
||||
data-tauri-drag-region="false"
|
||||
class="h-btn btn-close"
|
||||
aria-label="关闭窗口"
|
||||
title="关闭应用"
|
||||
on:click={closeWindow}></button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -4,26 +4,34 @@
|
||||
|
||||
// 模拟导航项数据
|
||||
// 确保对象字面量语法正确无误
|
||||
const navItems = [
|
||||
{ icon: '🏠', label: '主页', path: '/' },
|
||||
{ icon: '⭐', label: '收藏', path: '/favorites' },
|
||||
{ icon: '💬', label: '聊天', path: '/chat' },
|
||||
{ icon: '⚙️', label: '设置', path: '/settings' },
|
||||
import { goto } from '$app/navigation';
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import type { IconId } from '$lib/types/icon-ids';
|
||||
import HomeIcon from '$lib/components/icon/HomeIcon.svelte';
|
||||
|
||||
const navItems:[{icon: IconId, label: string, path: string}] = [
|
||||
{ icon: 'network', label: 'IP工具', path: '/iptools' },
|
||||
];
|
||||
|
||||
let activePath: string = '/'; // 明确声明类型
|
||||
|
||||
function navigate(path: string) {
|
||||
activePath = path;
|
||||
// goto(path); // 实际应用中使用 SvelteKit 的导航
|
||||
goto(path);
|
||||
console.log(`导航到: ${path}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
<nav class="sidebar">
|
||||
<!-- 顶部图标/Logo -->
|
||||
<div class="sidebar-logo">
|
||||
<span role="img" aria-label="App Logo">⚛️</span>
|
||||
<div class="sidebar-logo pt-2 pb-2">
|
||||
<button type="button"
|
||||
class="cursor-pointer"
|
||||
title="回到主页"
|
||||
on:click={() => navigate('/')}>
|
||||
<HomeIcon width="24" height="24" />
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 中间导航图标 -->
|
||||
@@ -35,7 +43,7 @@
|
||||
on:click={() => navigate(item.path)}
|
||||
title={item.label}
|
||||
>
|
||||
{item.icon}
|
||||
<Icon id={item.icon} className="hover:text-neutral-400 transition-all duration-1000" size="24" />
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -51,7 +59,7 @@
|
||||
/* 侧边栏的基础样式 */
|
||||
.sidebar {
|
||||
/* 根据图片,侧边栏宽度较窄,可能在 60px 左右 */
|
||||
width: 25px;
|
||||
width: 35px;
|
||||
min-width: 35px; /* 确保它不会收缩 */
|
||||
height: 100%;
|
||||
background-color: var(--main-bg-color); /* 比主背景稍亮 */
|
||||
@@ -59,14 +67,12 @@
|
||||
flex-direction: column; /* 垂直排列内容 */
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
box-shadow: 1px 0 3px rgba(255, 255, 255, 0.1);
|
||||
box-shadow: var(--main-border-shadow);
|
||||
user-select: none; /* 阻止文本选择 */
|
||||
}
|
||||
|
||||
/* Logo/顶部区域 */
|
||||
.sidebar-logo {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
16
src/lib/components/ui/Sprite.svelte
Normal file
16
src/lib/components/ui/Sprite.svelte
Normal file
@@ -0,0 +1,16 @@
|
||||
<script>
|
||||
</script>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display:none" >
|
||||
|
||||
<symbol id="network" viewBox="0 0 24 24">
|
||||
<g fill="none">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 7.96c2.59-.125 4.379.274 4.625 1.193c.429 1.6-3.98 4.172-9.849 5.745c-5.868 1.572-10.972 1.55-11.401-.051c-.254-.948 1.188-2.236 3.625-3.455" />
|
||||
<path fill="currentColor" fill-rule="evenodd" d="M4 12a8 8 0 1 1 15.985.491c-1.653.879-3.904 1.754-6.467 2.44c-2.874.77-5.526 1.14-7.478 1.131a12 12 0 0 1-.956-.039A7.96 7.96 0 0 1 4 12m2.766 6.05a8.003 8.003 0 0 0 12.658-3.065c-1.561.697-3.4 1.346-5.389 1.879c-2.668.715-5.208 1.115-7.269 1.186" clip-rule="evenodd" />
|
||||
</g>
|
||||
</symbol>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</svg>
|
||||
3
src/lib/types/icon-ids.ts
Normal file
3
src/lib/types/icon-ids.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export type IconId =
|
||||
| 'home'
|
||||
| 'network' ;
|
||||
@@ -3,23 +3,20 @@
|
||||
import favicon from '$lib/assets/favicon.svg';
|
||||
import Header from '$lib/components/layout/Header.svelte';
|
||||
import Sidebar from '$lib/components/layout/Sidebar.svelte';
|
||||
import Sprite from '$lib/components/ui/Sprite.svelte';
|
||||
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<link rel="icon" href={favicon} />
|
||||
<Sprite />
|
||||
</svelte:head>
|
||||
<Header/>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 1. 侧边栏: 固定宽度,全高 -->
|
||||
<Sidebar />
|
||||
<!-- 2. 主内容区域: 占据剩余所有空间 (flex-1) -->
|
||||
<main class="main-content">
|
||||
<!-- 渲染子路由的内容 (+page.svelte 或下级 +layout.svelte)
|
||||
使用标准的 <slot /> 替换了 {@render children()} -->
|
||||
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
79
src/routes/iptools/+page.svelte
Normal file
79
src/routes/iptools/+page.svelte
Normal file
@@ -0,0 +1,79 @@
|
||||
<script lang="ts">
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
// 定义与 Rust 端 InterfaceInfo 匹配的 TypeScript 类型
|
||||
interface InterfaceInfo {
|
||||
name: string;
|
||||
addr: string;
|
||||
mac?: string;
|
||||
}
|
||||
|
||||
let interfaces: InterfaceInfo[] = [];
|
||||
let loading: boolean = true;
|
||||
let error: string | null = null;
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
// 调用 Rust 后端命令
|
||||
interfaces = await invoke<InterfaceInfo[]>("get_network_interfaces");
|
||||
console.log("Network interfaces:", interfaces);
|
||||
} catch (err) {
|
||||
console.error("Failed to get network interfaces:", err);
|
||||
// 错误处理,将错误信息展示给用户
|
||||
error = (err as string) || "未知错误";
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="network-info">
|
||||
<h2>🌐 网络接口信息</h2>
|
||||
|
||||
{#if loading}
|
||||
<p>正在加载...</p>
|
||||
{:else if error}
|
||||
<p class="error-message">错误: {error}</p>
|
||||
{:else}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>IP 地址 (IPv4)</th>
|
||||
<th>MAC 地址</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each interfaces as iface (iface.name)}
|
||||
<tr>
|
||||
<td><strong>{iface.name}</strong></td>
|
||||
<td>{iface.addr}</td>
|
||||
<td>{iface.mac || 'N/A'}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 简单的 Svelte 样式 */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 1em;
|
||||
}
|
||||
th, td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: var(--main-bg-color);
|
||||
}
|
||||
.error-message {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user