feat(installer): 实现游戏安装与快捷方式创建功能- 添加禁用右键菜单和开发者工具的保护机制
- 引入GAME_CONFIG配置文件统一管理游戏信息 - 安装页面支持记录安装路径到localStorage - 成功页面增加创建桌面快捷方式选项 - 实现调用系统资源管理器打开游戏目录功能 - 集成Windows COM组件创建快捷方式的能力 - 更新UI界面展示多语言标题和版本信息 - 升级daisyui依赖至5.5.2版本- 调整窗口标题和产品名称为"游戏安装工具 - NoPJ"
This commit is contained in:
18
package-lock.json
generated
18
package-lock.json
generated
@@ -14,7 +14,7 @@
|
||||
"@tauri-apps/plugin-opener": "^2.5.2",
|
||||
"@tauri-apps/plugin-shell": "^2.3.3",
|
||||
"@tauri-apps/plugin-store": "^2.4.1",
|
||||
"daisyui": "^5.4.7"
|
||||
"daisyui": "^5.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
@@ -1204,7 +1204,6 @@
|
||||
"integrity": "sha512-TGFX1pZUt9qqY20Cv5NyYvy0iLWHf2jXi8s+eCGsig7jQMdwZWKUFMR6TbvFNhfDSUpc1sH/Y5EHv20g3HHA3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||
@@ -1244,7 +1243,6 @@
|
||||
"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",
|
||||
@@ -1842,7 +1840,6 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -1935,9 +1932,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/daisyui": {
|
||||
"version": "5.4.7",
|
||||
"resolved": "https://registry.npmmirror.com/daisyui/-/daisyui-5.4.7.tgz",
|
||||
"integrity": "sha512-2wYO61vTPCXk7xEBgnzLZAYoE0xS5IRLu/GSq0vORpB+cTrtubdx69NnA0loc0exvCY1s2fYL4lGZtFHe2ohNQ==",
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmmirror.com/daisyui/-/daisyui-5.5.2.tgz",
|
||||
"integrity": "sha512-uhEz8X1urrEhHhK51/vIQAL1fWPEJP8mTqCTEhfHfC8Dgur9XAz9SOWwl41LZgNs/fjWGvWzFcGM5WCw5ovp8g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/saadeghi/daisyui?sponsor=1"
|
||||
@@ -2572,7 +2569,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -2615,7 +2611,6 @@
|
||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -2632,7 +2627,6 @@
|
||||
"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"
|
||||
@@ -2824,7 +2818,6 @@
|
||||
"integrity": "sha512-+VUy01yfDqNmIVMd/LLKl2TTtY0ovZN0rTonh+FhKr65mFwIYgU9WzgIZKS7U9/SPCQvWTsTGx9jyt+qRm/XFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.5.0",
|
||||
"buffer-builder": "^0.2.0",
|
||||
@@ -3222,7 +3215,6 @@
|
||||
"integrity": "sha512-kjkAjCk41mJfvJZG56XcJNOdJSke94JxtcX8zFzzz2vrt47E0LnoBzU6azIZ1aBxJgUep8qegAkguSf1GjxLXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
@@ -3365,7 +3357,6 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -3387,7 +3378,6 @@
|
||||
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
||||
@@ -37,6 +37,6 @@
|
||||
"@tauri-apps/plugin-opener": "^2.5.2",
|
||||
"@tauri-apps/plugin-shell": "^2.3.3",
|
||||
"@tauri-apps/plugin-store": "^2.4.1",
|
||||
"daisyui": "^5.4.7"
|
||||
"daisyui": "^5.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
1
src-tauri/Cargo.lock
generated
1
src-tauri/Cargo.lock
generated
@@ -104,6 +104,7 @@ dependencies = [
|
||||
"tauri-plugin-shell",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"windows",
|
||||
"zip",
|
||||
]
|
||||
|
||||
|
||||
@@ -32,3 +32,4 @@ async-runtime = "0.0.0"
|
||||
tokio = { version = "1.48.0", features = ["time"] }
|
||||
tauri-plugin-shell = "2.3.3"
|
||||
tauri-plugin-opener = "2.5.2"
|
||||
windows = "0.61.3"
|
||||
|
||||
@@ -4,7 +4,8 @@ use thiserror::Error;
|
||||
use zip::ZipArchive;
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use serde::Serialize;
|
||||
use tauri::Emitter;
|
||||
|
||||
@@ -145,3 +146,20 @@ pub async fn install_game(window: tauri::Window, target_dir: String) -> Result<S
|
||||
Ok(format!("成功解压 {} 个文件到指定目录!", total_files as u32))
|
||||
}
|
||||
|
||||
|
||||
|
||||
//调用资源管理器打开游戏目录
|
||||
#[tauri::command]
|
||||
pub async fn open_game_dir(install_path:String) -> Result<String,String> {
|
||||
let game_path = Path::new(&install_path);
|
||||
if !game_path.exists() {
|
||||
return Err("游戏目录不存在".to_string());
|
||||
}
|
||||
let result = Command::new("explorer")
|
||||
.arg(game_path)
|
||||
.spawn()
|
||||
.map_err(|e| format!("打开游戏目录失败: {}", e))?;
|
||||
|
||||
println!("资源管理器进程ID: {}", result.id());
|
||||
Ok("已打开游戏目录".to_string())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod network;
|
||||
mod gameins;
|
||||
mod shortcut;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
@@ -19,7 +20,9 @@ pub fn run() {
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
network::get_network_interfaces,
|
||||
gameins::install_game
|
||||
gameins::install_game,
|
||||
gameins::open_game_dir,
|
||||
shortcut::create_shortcut,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
132
src-tauri/src/shortcut.rs
Normal file
132
src-tauri/src/shortcut.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use std::path::Path;
|
||||
use windows::{
|
||||
core::{Interface, PCWSTR, HRESULT},
|
||||
Win32::{
|
||||
System::{
|
||||
Com::{
|
||||
CoCreateInstance, CoInitializeEx, CoUninitialize,
|
||||
IPersistFile, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED
|
||||
},
|
||||
},
|
||||
UI::Shell::{IShellLinkW, ShellLink},
|
||||
},
|
||||
};
|
||||
|
||||
#[tauri::command]
|
||||
pub fn create_shortcut(
|
||||
install_path: String,
|
||||
shortcut_name: String,
|
||||
exe_name: String
|
||||
) -> Result<String, String> {
|
||||
unsafe {
|
||||
// 初始化COM库
|
||||
let com_result = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
|
||||
let needs_uninit = com_result.is_ok() || com_result == HRESULT(0x80010106u32 as i32); // S_FALSE or RPC_E_CHANGED_MODE
|
||||
|
||||
let result = create_shortcut_internal(&install_path, &shortcut_name, &exe_name);
|
||||
|
||||
if needs_uninit {
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn create_shortcut_internal(
|
||||
install_path: &str,
|
||||
shortcut_name: &str,
|
||||
exe_name: &str
|
||||
) -> Result<String, String> {
|
||||
// 获取当前用户桌面路径
|
||||
let desktop_path = get_desktop_path()?;
|
||||
let shortcut_file = format!("{}.lnk", shortcut_name);
|
||||
let shortcut_full_path = Path::new(&desktop_path).join(&shortcut_file);
|
||||
|
||||
// 构建目标程序路径
|
||||
let target_path = Path::new(install_path).join(exe_name);
|
||||
if !target_path.exists() {
|
||||
return Err(format!("目标程序不存在: {}", target_path.display()));
|
||||
}
|
||||
|
||||
// 创建IShellLink对象
|
||||
let shell_link: IShellLinkW = CoCreateInstance(
|
||||
&ShellLink,
|
||||
None,
|
||||
CLSCTX_INPROC_SERVER
|
||||
).map_err(|e| format!("创建ShellLink失败: {:?}", e))?;
|
||||
|
||||
// 设置快捷方式属性
|
||||
set_shell_link_properties(&shell_link, &target_path, install_path)?;
|
||||
|
||||
// 保存快捷方式
|
||||
save_shortcut(&shell_link, &shortcut_full_path)?;
|
||||
|
||||
Ok(format!("快捷方式创建成功: {}", shortcut_full_path.display()))
|
||||
}
|
||||
|
||||
unsafe fn get_desktop_path() -> Result<String, String> {
|
||||
std::env::var("USERPROFILE")
|
||||
.map(|profile| format!("{}\\Desktop", profile))
|
||||
.or_else(|_| {
|
||||
std::env::var("USERNAME")
|
||||
.map(|username| format!("C:\\Users\\{}\\Desktop", username))
|
||||
})
|
||||
.map_err(|_| "无法获取用户桌面路径".to_string())
|
||||
}
|
||||
|
||||
unsafe fn set_shell_link_properties(
|
||||
shell_link: &IShellLinkW,
|
||||
target_path: &Path,
|
||||
working_dir: &str
|
||||
) -> Result<(), String> {
|
||||
// 设置目标路径
|
||||
let target_path_str = target_path.to_string_lossy();
|
||||
let wide_target: Vec<u16> = to_wide_string(&target_path_str);
|
||||
|
||||
// 用 map_err + ? 处理错误并转换为 String
|
||||
shell_link
|
||||
.SetPath(PCWSTR(wide_target.as_ptr()))
|
||||
.map_err(|e| format!("设置目标路径失败: {:?}", e))?;
|
||||
|
||||
// 设置工作目录
|
||||
let wide_working_dir: Vec<u16> = to_wide_string(working_dir);
|
||||
shell_link
|
||||
.SetWorkingDirectory(PCWSTR(wide_working_dir.as_ptr()))
|
||||
.map_err(|e| format!("设置工作目录失败: {:?}", e))?;
|
||||
|
||||
// 设置描述
|
||||
let description = "NoPJ创建的快捷方式 - nopj.cn";
|
||||
let wide_desc: Vec<u16> = to_wide_string(description);
|
||||
shell_link
|
||||
.SetDescription(PCWSTR(wide_desc.as_ptr()))
|
||||
.map_err(|e| format!("设置描述失败: {:?}", e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
unsafe fn save_shortcut(
|
||||
shell_link: &IShellLinkW,
|
||||
shortcut_path: &Path
|
||||
) -> Result<(), String> {
|
||||
// 转换为 IPersistFile 接口
|
||||
let persist_file: IPersistFile = shell_link
|
||||
.cast()
|
||||
.map_err(|e| format!("接口转换失败: {:?}", e))?;
|
||||
|
||||
// 保存文件
|
||||
let path_str = shortcut_path.to_string_lossy();
|
||||
let wide_path: Vec<u16> = to_wide_string(&path_str);
|
||||
|
||||
// Save 可能返回 windows::core::Result<()>,同样用 map_err ? 处理
|
||||
persist_file
|
||||
.Save(PCWSTR(wide_path.as_ptr()), true)
|
||||
.map_err(|e| format!("保存快捷方式失败: {:?}", e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn to_wide_string(s: &str) -> Vec<u16> {
|
||||
s.encode_utf16().chain(std::iter::once(0)).collect()
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"productName": "NoPJ安装器",
|
||||
"productName": "游戏安装工具 - NoPJ",
|
||||
"version": "0.1.0",
|
||||
"identifier": "cn.nopj.gametools",
|
||||
"build": {
|
||||
@@ -12,13 +12,13 @@
|
||||
"app": {
|
||||
"windows": [
|
||||
{
|
||||
"title": "Game Install",
|
||||
"title": "游戏安装工具 - NoPJ",
|
||||
"width": 1280,
|
||||
"height": 720,
|
||||
"resizable": false,
|
||||
"fullscreen": false,
|
||||
"decorations": false
|
||||
|
||||
"decorations": false,
|
||||
"devtools": false
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
|
||||
10
src/lib/config.ts
Normal file
10
src/lib/config.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const GAME_CONFIG = {
|
||||
title: '逃离鸭科夫',
|
||||
title_rus: 'Побег из Дакова',
|
||||
title_en: 'Escape From Duckov',
|
||||
version: '1.1.6',
|
||||
description: "「逃离鸭科夫」是一款鸭子题材PVE俯视角撤离射击游戏。你要在鸭科夫的世界里搜寻物资,建造藏身处,升级装备,从一无所有到做大做强;面对虎视眈眈的敌鸭,想方设法生存下去——或者逃离。",
|
||||
pathname: '\\Duckov',
|
||||
launch: 'Duckov.exe',
|
||||
shortcut_name: "逃离鸭科夫",
|
||||
};
|
||||
@@ -12,6 +12,20 @@
|
||||
<svelte:head>
|
||||
<link rel="icon" href={favicon} />
|
||||
<Sprite />
|
||||
|
||||
<script>
|
||||
document.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault(); // 禁用右键菜单
|
||||
});
|
||||
|
||||
window.addEventListener('keydown', (event) => {
|
||||
// 禁用 F12 和 Ctrl+Shift+I
|
||||
if (event.key === 'F12' || (event.ctrlKey && event.shiftKey && event.key === 'I')) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</svelte:head>
|
||||
|
||||
<Header/>
|
||||
|
||||
@@ -1,61 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { GAME_CONFIG } from '$lib/config';
|
||||
|
||||
let isHover = false;
|
||||
|
||||
// 提取函数:处理“激活”状态
|
||||
function handleFocus() {
|
||||
isHover = true;
|
||||
}
|
||||
|
||||
// 提取函数:处理“失活”状态
|
||||
function handleBlur() {
|
||||
isHover = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<!--<div class={'relative pt-10 px-4 h-screen w-screen flex justify-center items-center transition-all ' }}-->
|
||||
<!-- class:backdrop-blur-xs={isHover}-->
|
||||
<!-->-->
|
||||
<!-- <button class="btn btn-wide" on:mouseenter={()=>{isHover = true}} on:mouseout={()=>{isHover = false}}>安装游戏</button>-->
|
||||
<!--</div>-->
|
||||
<div class="hero min-h-screen transition-all duration-300 "
|
||||
|
||||
|
||||
<div class="hero min-h-screen transition-all {isHover ? 'bg-neutral-700/30' : ''} "
|
||||
class:backdrop-blur-xs={isHover}
|
||||
|
||||
>
|
||||
<div class="hero-content text-center select-none">
|
||||
<div class="max-w-md" >
|
||||
<h1 class="text-5xl font-bold"
|
||||
on:mouseenter={()=>{isHover = true}}
|
||||
on:mouseout={()=>{isHover = false}}
|
||||
on:blur={handleBlur}
|
||||
on:focus={handleFocus}
|
||||
>逃离鸭科夫</h1>
|
||||
<p class="py-6"
|
||||
on:mouseenter={()=>{isHover = true}}
|
||||
on:mouseout={()=>{isHover = false}}
|
||||
on:blur={handleBlur}
|
||||
on:focus={handleFocus}
|
||||
>
|
||||
<span class="font-bold">《逃离鸭科夫》</span>是一款鸭子题材PVE俯视角撤离射击游戏。你要在鸭科夫的世界里搜寻物资,建造藏身处,升级装备,从一无所有到做大做强;面对虎视眈眈的敌鸭,想方设法生存下去——或者逃离。
|
||||
<div class="hero-content text-center select-none p-12 group hover:backdrop-blur hover:bg-base-100/70">
|
||||
<div class="w-xl group-hover:w-2xl transition-all duration-1000 ease-in-out ">
|
||||
<p class="text-5xl font-bold ">
|
||||
<span class="text-rotate">
|
||||
<span class="justify-items-center">
|
||||
<span>{GAME_CONFIG.title}</span>
|
||||
<span>{GAME_CONFIG.title_en}</span>
|
||||
<span>{GAME_CONFIG.title_rus}</span>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<button class="btn btn-primary btn-wide "
|
||||
on:mouseenter={()=>{isHover = true}}
|
||||
on:mouseout={()=>{isHover = false}}
|
||||
on:blur={handleBlur}
|
||||
on:focus={handleFocus}
|
||||
on:click={()=>{goto('/install')}}
|
||||
>安装游戏</button>
|
||||
<button class="btn btn-primary btn-wide "
|
||||
on:mouseenter={()=>{isHover = true}}
|
||||
on:mouseout={()=>{isHover = false}}
|
||||
on:blur={handleBlur}
|
||||
on:focus={handleFocus}
|
||||
on:click={()=>{goto('/success')}}
|
||||
>完成</button>
|
||||
<p class="pt-2">versin {GAME_CONFIG.version}</p>
|
||||
<p class="py-6 text-left">
|
||||
{GAME_CONFIG.description}
|
||||
</p>
|
||||
<!-- 事件会冒泡到父元素hero-content,因此这些按钮可以不用显式绑定事件 -->
|
||||
<div class="w-full">
|
||||
<button class="btn btn-ghost btn-wide group-hover:btn-primary "
|
||||
on:click="{() => goto('/install')}"
|
||||
>
|
||||
安装游戏
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -5,6 +5,7 @@
|
||||
import { onMount } from 'svelte';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { goto } from '$app/navigation';
|
||||
import { GAME_CONFIG } from '$lib/config';
|
||||
|
||||
let installPath = '';
|
||||
let isInstalling = false;
|
||||
@@ -30,10 +31,6 @@
|
||||
progressPercent = event.payload.percentage;
|
||||
});
|
||||
|
||||
// 组件销毁时停止监听
|
||||
return () => {
|
||||
unlisten();
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -60,7 +57,7 @@
|
||||
installPath = '';
|
||||
return;
|
||||
}
|
||||
installPath = selected + '\\DK'; // 您的逻辑
|
||||
installPath = selected +GAME_CONFIG.pathname; // 您的逻辑
|
||||
log('已选择安装目录:'+ installPath +",点击开始安装即可开始自动安装");
|
||||
}else if (selected === null) {
|
||||
log("未选择安装目录");
|
||||
@@ -82,7 +79,7 @@
|
||||
progressPercent = 0; // 重置进度条
|
||||
log("安装程序启动...");
|
||||
|
||||
|
||||
localStorage.setItem('installPath', installPath)
|
||||
try {
|
||||
// 我们仍然调用 invoke,但现在它只负责启动
|
||||
// 真正的日志将通过 'install_progress' 事件传来
|
||||
|
||||
@@ -2,10 +2,39 @@
|
||||
import tl from '$lib/assets/images/tl.png'
|
||||
import { onMount } from 'svelte';
|
||||
import { openUrl } from '@tauri-apps/plugin-opener';
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { GAME_CONFIG } from '$lib/config';
|
||||
|
||||
let data:[{attributes:{title:string, slug:string, id:string}}] = [];
|
||||
|
||||
const win = getCurrentWindow();
|
||||
|
||||
|
||||
const closeWindow = async () => {
|
||||
if (openGameDir) {
|
||||
try {
|
||||
const result = await invoke('open_game_dir', {
|
||||
installPath: installPath
|
||||
});
|
||||
console.log(result);
|
||||
} catch (error) {
|
||||
console.error('启动游戏失败:', error);
|
||||
}
|
||||
}
|
||||
await create_shortcut()
|
||||
await win.close()
|
||||
|
||||
};
|
||||
|
||||
let data:[{attributes:{title:string, slug:string, id:string}}];
|
||||
let loading = true;
|
||||
let error;
|
||||
//是否创建快捷方式变量
|
||||
let createShortcut = true;
|
||||
//是否退出后启动变量
|
||||
let openGameDir = true;
|
||||
|
||||
let installPath = localStorage.getItem('installPath');
|
||||
|
||||
const url = "https://nopj.cn/api/discussions?include=tags.parent&filter[tag]=resources&sort=-createdAt&page[offset]=0&page[limit]=5"
|
||||
|
||||
@@ -44,11 +73,68 @@
|
||||
}
|
||||
}
|
||||
|
||||
const create_shortcut = async () => {
|
||||
if (createShortcut){
|
||||
|
||||
try{
|
||||
const result = await invoke('create_shortcut', {
|
||||
installPath: localStorage.getItem('installPath'),
|
||||
shortcutName: GAME_CONFIG.shortcut_name,
|
||||
exeName: GAME_CONFIG.launch,
|
||||
})
|
||||
console.log(result);
|
||||
}catch (e){
|
||||
console.error("创建快捷方式失败:", e);
|
||||
alert(e)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="h-screen w-screen flex z-10 pt-8">
|
||||
<div class="flex-1">
|
||||
123
|
||||
<div class="h-screen w-screen flex z-10 pt-8 select-none relative">
|
||||
<div class="flex-1 flex items-center justify-center">
|
||||
<div class="w-2xl p-8 backdrop-blur-xl shadow-xl shadow-base/30">
|
||||
<div class=" text-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120" viewBox="0 0 32 32" class="m-auto">
|
||||
<g fill="none">
|
||||
<path fill="url(#SVGFnVq5bNm)" d="M30 16c0 7.732-6.268 14-14 14S2 23.732 2 16S8.268 2 16 2s14 6.268 14 14" />
|
||||
<path fill="url(#SVGcpquMdXZ)" d="M22.707 12.707a1 1 0 0 0-1.414-1.414L14.5 18.086l-3.293-3.293a1 1 0 0 0-1.414 1.414l4 4a1 1 0 0 0 1.414 0z" />
|
||||
<defs>
|
||||
<linearGradient id="SVGFnVq5bNm" x1="3" x2="22.323" y1="7.25" y2="27.326" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#52d17c" />
|
||||
<stop offset="1" stop-color="#22918b" />
|
||||
</linearGradient>
|
||||
<linearGradient id="SVGcpquMdXZ" x1="12.031" x2="14.162" y1="11.969" y2="22.66" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#fff" />
|
||||
<stop offset="1" stop-color="#e3ffd9" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<div class="font-bold text-3xl pt-2 pb-4">
|
||||
安装完成
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="fieldset bg-base-100/30 border-base-300/10 rounded-box w-full border p-4">
|
||||
<legend class="fieldset-legend">启动设置</legend>
|
||||
<label class="label">
|
||||
<input type="checkbox" checked={createShortcut} class="checkbox" />
|
||||
设置桌面快捷方式
|
||||
</label>
|
||||
<label class="label pt-4">
|
||||
<input type="checkbox" checked={openGameDir} class="checkbox" />
|
||||
打开游戏目录
|
||||
</label>
|
||||
</fieldset>
|
||||
<div class="w-full text-center pt-12">
|
||||
<button class="btn btn-primary btn-wide "
|
||||
on:click={closeWindow}
|
||||
>退出</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=" w-96 bg-base-200 bg-cover bg-center text-base-300 overflow-hidden relative" style="background-image: url({tl})">
|
||||
<div class="h-full w-full absolute top-0 z-0">
|
||||
@@ -56,12 +142,19 @@
|
||||
</div>
|
||||
<div class="z-10 relative p-4 w-full ">
|
||||
<h1 class="font-bold text-4xl text-right">NoPJ</h1>
|
||||
<p class="font-bold text-right pt-2 ">最新资源</p>
|
||||
<p class="pt-2 ">
|
||||
<span class="text-rotate font-bold text-right ">
|
||||
<span>
|
||||
<span>最新资源</span>
|
||||
<span>Latest Resources</span>
|
||||
<span>Последний ресурс</span>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<div class="pt-4">
|
||||
|
||||
<ul class="list">
|
||||
{#each data as item}
|
||||
<li class="list-row backdrop-blur-xs hover:backdrop-blur-xl hover:font-bold transition-all mt-4 font-misans">
|
||||
<li class=" list-row backdrop-blur-xs hover:backdrop-blur-xl hover:font-bold transition-all mt-4 font-misans">
|
||||
<a href="https://nopj.cn/d/{item.attributes.slug}" class=" "
|
||||
on:click={(e) => handleExternalLink(e, `https://nopj.cn/d/${item.attributes.slug}`)}
|
||||
>
|
||||
@@ -74,5 +167,11 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute bottom-3 text-center z-10 left-0 w-full">
|
||||
<p class="font-bold">Designed by Chaos & <a href="https://nopj.cn"
|
||||
on:click={(e)=>handleExternalLink(e, 'https://nopj.cn')}
|
||||
>Nopj</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user