feat(install): 实现带进度条的游戏安装功能
- 添加进度条组件和相关状态管理 - 实现 Rust 后端解压过程的实时进度上报 - 增加安装路径中文字符校验 -优化日志显示支持时间戳开关- 引入 zip 解压库及异步运行时依赖 - 修复安装流程中的事件通信机制 - 调整 UI 布局适配新增进度条显示
This commit is contained in:
@@ -1,17 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
let installPath = '未选择安装路径';
|
||||
// --- 1. 导入 Svelte 和 Tauri API ---
|
||||
import { onMount } from 'svelte';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
|
||||
let installPath = '';
|
||||
let isInstalling = false;
|
||||
let logContent = '';
|
||||
let logOutputElement: HTMLPreElement;
|
||||
|
||||
// --- 2. 为进度条添加新变量 ---
|
||||
let progressPercent = 0;
|
||||
|
||||
// --- 3. 定义 Rust 发送的事件结构 (可选, 但推荐) ---
|
||||
interface InstallProgress {
|
||||
message: string;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
// --- 4. 启动事件监听器 ---
|
||||
onMount(() => {
|
||||
// 监听 'install_progress' 事件
|
||||
const unlisten = listen<InstallProgress>('install_progress', (event) => {
|
||||
// 使用 Rust 发来的消息更新日志
|
||||
log(event.payload.message, false); // false = 不要添加新时间戳
|
||||
// 更新进度条
|
||||
progressPercent = event.payload.percentage;
|
||||
});
|
||||
|
||||
// 组件销毁时停止监听
|
||||
return () => {
|
||||
unlisten();
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
// 1. 打开目录选择对话框
|
||||
async function selectInstallDir() {
|
||||
|
||||
const defaultPath = 'C:\\Program Files';
|
||||
if (installPath !== '未选择安装路径'){
|
||||
log("重新选择安装目录");
|
||||
log("开始选择安装目录");
|
||||
}
|
||||
|
||||
const selected = await open({
|
||||
@@ -22,8 +52,15 @@
|
||||
});
|
||||
|
||||
if (typeof selected === 'string') {
|
||||
installPath = selected;
|
||||
log('已选择安装目录:'+selected+",点击开始安装即可开始自动安装");
|
||||
//判断安装路径是否有中文字符
|
||||
if (selected.match(/[\u4e00-\u9fa5]/)) {
|
||||
alert("安装目录不能包含中文字符");
|
||||
log("安装目录不能包含中文字符");
|
||||
installPath = '';
|
||||
return;
|
||||
}
|
||||
installPath = selected + '\\DK'; // 您的逻辑
|
||||
log('已选择安装目录:'+ installPath +",点击开始安装即可开始自动安装");
|
||||
}else if (selected === null) {
|
||||
log("未选择安装目录");
|
||||
}else{
|
||||
@@ -33,45 +70,53 @@
|
||||
|
||||
// 2. 调用 Rust 后端命令开始安装
|
||||
async function startInstallation() {
|
||||
if (installPath === '未选择安装路径') {
|
||||
if (installPath === '') {
|
||||
alert('请先选择安装路径!');
|
||||
return;
|
||||
}
|
||||
|
||||
isInstalling = true;
|
||||
// --- 5. 重置 UI ---
|
||||
logContent = ''; // 清空日志
|
||||
progressPercent = 0; // 重置进度条
|
||||
log("安装程序启动...");
|
||||
|
||||
|
||||
try {
|
||||
// 调用我们在 Rust 中定义的 `install_game` 命令
|
||||
// Tauri 会自动处理前端和后端的数据传输
|
||||
// 我们仍然调用 invoke,但现在它只负责启动
|
||||
// 真正的日志将通过 'install_progress' 事件传来
|
||||
const result: string = await invoke('install_game', {
|
||||
targetDir: installPath
|
||||
});
|
||||
|
||||
// 仅在最后显示成功弹窗
|
||||
alert(`安装完成!\n${result}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('安装失败:', error);
|
||||
log(`❌ 安装失败: ${error}`); // 将错误也记录到日志中
|
||||
alert(`安装失败:${error}`);
|
||||
} finally {
|
||||
isInstalling = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Svelte 版本的日志函数
|
||||
* 它只更新 logContent 变量,Svelte 会自动更新 DOM
|
||||
* (修改) 添加一个选项来决定是否显示时间戳
|
||||
*/
|
||||
const log = (message: string) => {
|
||||
const timestamp = new Date().toLocaleTimeString('zh-CN', { hour12: false });
|
||||
const log = (message: string, showTimestamp = false) => {
|
||||
let prefix = '';
|
||||
if (showTimestamp) {
|
||||
const timestamp = new Date().toLocaleTimeString('zh-CN', { hour12: false });
|
||||
prefix = `[${timestamp}] `;
|
||||
}
|
||||
// 更新变量,而不是直接操作 DOM
|
||||
logContent += `[${timestamp}] ${message}\n`;
|
||||
logContent += `${prefix}${message}\n`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. Svelte 响应式语句 (自动滚动)
|
||||
* * 这行代码 ( $: ... ) 意味着:
|
||||
* "每当它依赖的变量(这里是 logContent)发生变化,
|
||||
* Svelte 更新 DOM 之后,就执行这里的代码。"
|
||||
*/
|
||||
$: if (logOutputElement && logContent) {
|
||||
// 自动滚动到底部
|
||||
@@ -86,24 +131,42 @@
|
||||
<div class="flex-1 pt-10 px-5 overflow-hidden relative ">
|
||||
<h1 class="textarea-xl font-bold absolute">选择目标安装位置</h1>
|
||||
<div class="h-full pt-10">
|
||||
<pre
|
||||
class=" overflow-y-auto h-full whitespace-pre-wrap wrap-break-word "
|
||||
bind:this={logOutputElement}
|
||||
>
|
||||
<pre
|
||||
class=" overflow-y-auto h-full whitespace-pre-wrap wrap-break-word "
|
||||
bind:this={logOutputElement}
|
||||
>
|
||||
{logContent}
|
||||
</pre>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-32 shrink-0 p-4 border-base ">
|
||||
<!-- --- 6. 增加底部高度以容纳进度条 --- -->
|
||||
<div class="h-40 shrink-0 p-4 border-base ">
|
||||
|
||||
{#if isInstalling}
|
||||
|
||||
<div class="w-full bg-neutral-600 rounded-full h-2.5 mb-2">
|
||||
<div
|
||||
class="bg-blue-600 h-2.5 rounded-full transition-all duration-150"
|
||||
style="width: {progressPercent}%"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="text-center text-sm mb-2">{Math.round(progressPercent)}%</div>
|
||||
|
||||
{:else}
|
||||
|
||||
<div class="flex items-center">
|
||||
<input class="input flex-1" bind:value={installPath} placeholder="请选择安装路径" />
|
||||
|
||||
<button class="btn" on:click={selectInstallDir} disabled={isInstalling}>
|
||||
选择安装目录
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/if}
|
||||
|
||||
<div class="flex items-center">
|
||||
<input class="input flex-1" value={installPath} />
|
||||
|
||||
<button class="btn " on:click={selectInstallDir} disabled={isInstalling}>
|
||||
选择安装目录
|
||||
</button>
|
||||
</div>
|
||||
<div class="pt-4 text-center btn-primary">
|
||||
<button class="btn btn-block" on:click={startInstallation} disabled={isInstalling}>
|
||||
{isInstalling ? '正在安装...' : '开始安装'}
|
||||
@@ -113,23 +176,9 @@
|
||||
</div>
|
||||
|
||||
</main>
|
||||
<!-- <h1>游戏安装程序</h1>-->
|
||||
|
||||
<!-- <div class="path-display">-->
|
||||
<!-- <p>目标安装路径: <strong>{installPath}</strong></p>-->
|
||||
<!-- <button on:click={selectInstallDir} disabled={isInstalling}>-->
|
||||
<!-- 选择安装目录-->
|
||||
<!-- </button>-->
|
||||
<!-- </div>-->
|
||||
<!-- <button class="btn">Default</button>-->
|
||||
<!-- <button-->
|
||||
<!-- on:click={startInstallation}-->
|
||||
<!-- disabled={isInstalling || installPath === '未选择安装路径'}>-->
|
||||
<!-- {isInstalling ? '正在安装...' : '开始安装'}-->
|
||||
<!-- </button>-->
|
||||
|
||||
<style>
|
||||
|
||||
/* 您的样式 (无需更改) */
|
||||
::-webkit-scrollbar {
|
||||
/*滚动条整体样式*/
|
||||
width:5px;
|
||||
@@ -144,7 +193,4 @@
|
||||
/*滚动条里面轨道*/
|
||||
background:#e8ecf3;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user