Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,157 @@
<link rel="icon" type="image/svg+xml" href="/codeforge.svg"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>CodeForge</title>
<style>
/* 预加载样式 */
#app-loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #f9fafb;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 9999;
}

.loading-logo {
width: 80px;
height: 80px;
margin-bottom: 2rem;
position: relative;
}

.loading-logo img {
width: 100%;
height: 100%;
animation: pulse 2s infinite;
}

.loading-spinner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 2px solid transparent;
border-top: 2px solid #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
}

.loading-title {
font-size: 2rem;
font-weight: bold;
color: #1f2937;
margin-bottom: 0.5rem;
}

.loading-subtitle {
color: #6b7280;
margin-bottom: 2rem;
}

.loading-dots {
display: flex;
gap: 0.25rem;
}

.loading-dot {
width: 12px;
height: 12px;
background-color: #3b82f6;
border-radius: 50%;
animation: bounce 1.2s infinite;
}

.loading-dot:nth-child(2) {
animation-delay: 0.1s;
}

.loading-dot:nth-child(3) {
animation-delay: 0.2s;
}

@keyframes spin {
to {
transform: rotate(360deg);
}
}

@keyframes pulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.8;
transform: scale(1.05);
}
}

@keyframes bounce {
0%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
}
</style>
</head>

<body>
<!-- 预加载动画 -->
<div id="app-loading">
<div class="loading-logo">
<img src="/codeforge.svg" alt="CodeForge"/>
<div class="loading-spinner"></div>
</div>
<h1 class="loading-title">CodeForge</h1>
<p class="loading-subtitle">轻量级代码执行器</p>
<div class="loading-dots">
<div class="loading-dot"></div>
<div class="loading-dot"></div>
<div class="loading-dot"></div>
</div>
</div>

<!-- Vue 应用 -->
<div id="app"></div>

<script type="module" src="/src/main.ts"></script>
<script>
console.log('🎬 页面脚本已加载,等待 app-ready 事件')

// 监听应用准备就绪事件
window.addEventListener('app-ready', function () {
console.log('📡 收到 app-ready 事件,开始隐藏加载动画')
const appLoading = document.getElementById('app-loading');
if (appLoading) {
console.log('🎭 开始淡出动画')
appLoading.style.opacity = '0';
appLoading.style.transition = 'opacity 0.3s ease-out';
setTimeout(() => {
console.log('✨ 预加载动画已移除')
appLoading.remove();
}, 300);
}
else {
console.log('⚠️ 找不到预加载元素')
}
});

// 超时保护,避免永远加载
setTimeout(() => {
console.log('⏰ 超时保护触发,强制隐藏加载动画')
const appLoading = document.getElementById('app-loading');
if (appLoading) {
appLoading.remove();
}
}, 10000); // 10秒超时
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ tauri-build = { version = "2", features = [] }
chrono = { version = "0.4.41", features = ["serde"] }

[dependencies]
tauri = { version = "2", features = [] }
tauri = { version = "2", features = ["devtools"] }
tauri-plugin-opener = "2"
tauri-plugin-shell = "2.0"
tauri-plugin-dialog = "2.0"
Expand Down
14 changes: 14 additions & 0 deletions src-tauri/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,20 @@ pub async fn execute_code(

let _ = plugin.post_execute_hook(&mut result);

if result.success
&& result.stdout == *"END-NO-OUTPUT"
&& result.stderr == *"END-NO-OUTPUT"
{
let _ = app.emit(
"code-output",
serde_json::json!({
"type": "stdout",
"content": "代码执行成功 (无输出)",
"language": request.language
}),
);
}

let _ = app.emit(
"code-execution-complete",
serde_json::json!({
Expand Down
12 changes: 11 additions & 1 deletion src-tauri/src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,20 @@ pub trait LanguagePlugin: Send + Sync {

// 后执行钩子
fn post_execute_hook(&self, result: &mut ExecutionResult) -> Result<(), String> {
info!(
"执行代码 -> 插件 [ {} ] 处理 post_execute_hook 开始",
self.get_language_key()
);

if result.success && result.stdout.is_empty() && result.stderr.is_empty() {
result.stdout = "代码执行成功 (无输出)".to_string();
result.stdout = String::from("END-NO-OUTPUT");
result.stderr = String::from("END-NO-OUTPUT");
}

info!(
"执行代码 -> 插件 [ {} ] 处理 post_execute_hook 结束",
self.get_language_key()
);
Ok(())
}
}
Expand Down
6 changes: 5 additions & 1 deletion src-tauri/src/setup/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ pub fn create_menu(app: &AppHandle) -> tauri::Result<Menu<tauri::Wry>> {
// 编辑菜单
let edit_submenu = menus::edit::create_edit_submenu(app)?;

// 开发者菜单
let developer_submenu = menus::developer::create_developer_submenu(app)?;

let menu = MenuBuilder::new(app)
.items(&[&app_submenu, &edit_submenu])
.items(&[&app_submenu, &edit_submenu, &developer_submenu])
.build()?;

Ok(menu)
Expand All @@ -23,5 +26,6 @@ pub fn setup_menu_handler(app: &AppHandle) {
app.on_menu_event(move |app, event| {
menus::app::handle_app_menu_event(app, event.id().as_ref());
menus::edit::handle_edit_menu_event(app, event.id().as_ref());
menus::developer::handle_developer_menu_event(app, event.id().as_ref());
});
}
20 changes: 15 additions & 5 deletions src-tauri/src/setup/menus/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,27 @@ pub fn create_app_submenu(app: &AppHandle) -> tauri::Result<Submenu<tauri::Wry>>
.id("about")
.build(app)?;

let quit_item = MenuItemBuilder::new("退出 CodeForge")
.id("quit")
.accelerator("CmdOrCtrl+Q")
.build(app)?;

let settings_item = MenuItemBuilder::new("设置")
.id("settings")
.accelerator("CmdOrCtrl+,")
.build(app)?;

let restart_item = MenuItemBuilder::new("重启 CodeForge")
.id("restart")
.accelerator("CmdOrCtrl+R")
.build(app)?;

let quit_item = MenuItemBuilder::new("退出 CodeForge")
.id("quit")
.accelerator("CmdOrCtrl+Q")
.build(app)?;

let app_submenu = SubmenuBuilder::new(app, "CodeForge")
.item(&about_item)
.separator()
.item(&settings_item)
.separator()
.item(&restart_item)
.item(&quit_item)
.build()?;

Expand All @@ -38,6 +44,10 @@ pub fn handle_app_menu_event(app: &AppHandle, event_id: &str) {
"settings" => {
let _event = app.emit("show-settings", ());
}
"restart" => {
info!("CodeForge 应用重启");
app.restart();
}
"quit" => {
info!("CodeForge 应用关闭");
app.exit(0);
Expand Down
42 changes: 42 additions & 0 deletions src-tauri/src/setup/menus/developer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use log::info;
use tauri::{
AppHandle, Manager,
menu::{MenuItemBuilder, Submenu, SubmenuBuilder},
};

pub fn create_developer_submenu(app: &AppHandle) -> tauri::Result<Submenu<tauri::Wry>> {
let reload_item = MenuItemBuilder::new("重新加载")
.id("reload-window")
.accelerator("CmdOrCtrl+Shift+R")
.build(app)?;

let devtools_item = MenuItemBuilder::new("打开调试器")
.id("open-devtools")
.accelerator("CmdOrCtrl+Shift+I")
.build(app)?;

let developer_submenu = SubmenuBuilder::new(app, "开发者模式")
.item(&reload_item)
.item(&devtools_item)
.build()?;

Ok(developer_submenu)
}

pub fn handle_developer_menu_event(app: &AppHandle, event_id: &str) {
match event_id {
"reload-window" => {
info!("开发者 -> 重新加载");
if let Some(window) = app.get_webview_window("main") {
let _ = window.reload();
}
}
"open-devtools" => {
info!("开发者 -> 打开调试器");
if let Some(window) = app.get_webview_window("main") {
window.open_devtools();
}
}
_ => {}
}
}
1 change: 1 addition & 0 deletions src-tauri/src/setup/menus/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod app;
pub mod developer;
pub mod edit;
39 changes: 33 additions & 6 deletions src-tauri/src/utils/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub async fn reset_log_directory(_app: AppHandle) -> Result<(), String> {
}

// 获取日志文件列表
#[command]
#[tauri::command]
pub async fn get_log_files(app: AppHandle) -> Result<Vec<String>, String> {
let log_dir = {
let guard = LOG_DIRECTORY.lock().unwrap();
Expand All @@ -106,22 +106,49 @@ pub async fn get_log_files(app: AppHandle) -> Result<Vec<String>, String> {
};
info!("获取日志 -> 日志目录为: {}", log_dir.display());

// 获取今天的日期字符串
let today = chrono::Local::now().format("%Y-%m-%d").to_string();
info!("获取日志 -> 查找今天({})的日志文件", today);

let mut log_files = Vec::new();

if let Ok(entries) = std::fs::read_dir(&log_dir) {
for entry in entries.flatten() {
if let Some(filename) = entry.file_name().to_str() {
if filename.ends_with(".log") && filename.starts_with("codeforge-") {
if filename.ends_with(".log")
&& filename.starts_with("codeforge-")
&& filename.contains(&today)
{
log_files.push(filename.to_string());
info!("获取日志 -> 发现日志文件: {}", filename);
info!("获取日志 -> 发现今天的日志文件: {}", filename);
}
}
}
}

info!("获取日志 -> 找到 {} 个日志文件", log_files.len());
log_files.sort();
log_files.reverse(); // 最新的在前面
info!("获取日志 -> 找到 {} 个今天的日志文件", log_files.len());

// 按日志级别排序:error -> warn -> info -> debug -> 普通日志
log_files.sort_by(|a, b| {
let get_priority = |filename: &str| -> u8 {
if filename.contains("-info-") {
1
} else if filename.contains("-warn-") {
2
} else if filename.contains("-error-") {
3
} else if filename.contains("-debug-") {
4
} else {
0
}
};

let priority_a = get_priority(a);
let priority_b = get_priority(b);

priority_a.cmp(&priority_b).then_with(|| a.cmp(b))
});

Ok(log_files)
}
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"minHeight": 600,
"width": 1800,
"height": 1200,
"center": true,
"devtools": true,
"additionalBrowserArgs": "--disable-context-menu"
}
],
Expand Down
Loading
Loading