Skip to content

Commit 3b6afca

Browse files
authored
Merge pull request #19 from qianmoQ/dev-25.0.1
feat (core): 增加多个功能
2 parents c2a1858 + 4fcc0f9 commit 3b6afca

11 files changed

Lines changed: 275 additions & 14 deletions

File tree

index.html

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,157 @@
55
<link rel="icon" type="image/svg+xml" href="/codeforge.svg"/>
66
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
77
<title>CodeForge</title>
8+
<style>
9+
/* 预加载样式 */
10+
#app-loading {
11+
position: fixed;
12+
top: 0;
13+
left: 0;
14+
width: 100%;
15+
height: 100%;
16+
background-color: #f9fafb;
17+
display: flex;
18+
flex-direction: column;
19+
align-items: center;
20+
justify-content: center;
21+
z-index: 9999;
22+
}
23+
24+
.loading-logo {
25+
width: 80px;
26+
height: 80px;
27+
margin-bottom: 2rem;
28+
position: relative;
29+
}
30+
31+
.loading-logo img {
32+
width: 100%;
33+
height: 100%;
34+
animation: pulse 2s infinite;
35+
}
36+
37+
.loading-spinner {
38+
position: absolute;
39+
top: 0;
40+
left: 0;
41+
width: 100%;
42+
height: 100%;
43+
border: 2px solid transparent;
44+
border-top: 2px solid #3b82f6;
45+
border-radius: 50%;
46+
animation: spin 1s linear infinite;
47+
}
48+
49+
.loading-title {
50+
font-size: 2rem;
51+
font-weight: bold;
52+
color: #1f2937;
53+
margin-bottom: 0.5rem;
54+
}
55+
56+
.loading-subtitle {
57+
color: #6b7280;
58+
margin-bottom: 2rem;
59+
}
60+
61+
.loading-dots {
62+
display: flex;
63+
gap: 0.25rem;
64+
}
65+
66+
.loading-dot {
67+
width: 12px;
68+
height: 12px;
69+
background-color: #3b82f6;
70+
border-radius: 50%;
71+
animation: bounce 1.2s infinite;
72+
}
73+
74+
.loading-dot:nth-child(2) {
75+
animation-delay: 0.1s;
76+
}
77+
78+
.loading-dot:nth-child(3) {
79+
animation-delay: 0.2s;
80+
}
81+
82+
@keyframes spin {
83+
to {
84+
transform: rotate(360deg);
85+
}
86+
}
87+
88+
@keyframes pulse {
89+
0%, 100% {
90+
opacity: 1;
91+
transform: scale(1);
92+
}
93+
50% {
94+
opacity: 0.8;
95+
transform: scale(1.05);
96+
}
97+
}
98+
99+
@keyframes bounce {
100+
0%, 80%, 100% {
101+
transform: translateY(0);
102+
}
103+
40% {
104+
transform: translateY(-10px);
105+
}
106+
}
107+
</style>
8108
</head>
9109

10110
<body>
111+
<!-- 预加载动画 -->
112+
<div id="app-loading">
113+
<div class="loading-logo">
114+
<img src="/codeforge.svg" alt="CodeForge"/>
115+
<div class="loading-spinner"></div>
116+
</div>
117+
<h1 class="loading-title">CodeForge</h1>
118+
<p class="loading-subtitle">轻量级代码执行器</p>
119+
<div class="loading-dots">
120+
<div class="loading-dot"></div>
121+
<div class="loading-dot"></div>
122+
<div class="loading-dot"></div>
123+
</div>
124+
</div>
125+
126+
<!-- Vue 应用 -->
11127
<div id="app"></div>
128+
12129
<script type="module" src="/src/main.ts"></script>
130+
<script>
131+
console.log('🎬 页面脚本已加载,等待 app-ready 事件')
132+
133+
// 监听应用准备就绪事件
134+
window.addEventListener('app-ready', function () {
135+
console.log('📡 收到 app-ready 事件,开始隐藏加载动画')
136+
const appLoading = document.getElementById('app-loading');
137+
if (appLoading) {
138+
console.log('🎭 开始淡出动画')
139+
appLoading.style.opacity = '0';
140+
appLoading.style.transition = 'opacity 0.3s ease-out';
141+
setTimeout(() => {
142+
console.log('✨ 预加载动画已移除')
143+
appLoading.remove();
144+
}, 300);
145+
}
146+
else {
147+
console.log('⚠️ 找不到预加载元素')
148+
}
149+
});
150+
151+
// 超时保护,避免永远加载
152+
setTimeout(() => {
153+
console.log('⏰ 超时保护触发,强制隐藏加载动画')
154+
const appLoading = document.getElementById('app-loading');
155+
if (appLoading) {
156+
appLoading.remove();
157+
}
158+
}, 10000); // 10秒超时
159+
</script>
13160
</body>
14161
</html>

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ tauri-build = { version = "2", features = [] }
1414
chrono = { version = "0.4.41", features = ["serde"] }
1515

1616
[dependencies]
17-
tauri = { version = "2", features = [] }
17+
tauri = { version = "2", features = ["devtools"] }
1818
tauri-plugin-opener = "2"
1919
tauri-plugin-shell = "2.0"
2020
tauri-plugin-dialog = "2.0"

src-tauri/src/execution.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,20 @@ pub async fn execute_code(
343343

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

346+
if result.success
347+
&& result.stdout == *"END-NO-OUTPUT"
348+
&& result.stderr == *"END-NO-OUTPUT"
349+
{
350+
let _ = app.emit(
351+
"code-output",
352+
serde_json::json!({
353+
"type": "stdout",
354+
"content": "代码执行成功 (无输出)",
355+
"language": request.language
356+
}),
357+
);
358+
}
359+
346360
let _ = app.emit(
347361
"code-execution-complete",
348362
serde_json::json!({

src-tauri/src/plugins/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,20 @@ pub trait LanguagePlugin: Send + Sync {
295295

296296
// 后执行钩子
297297
fn post_execute_hook(&self, result: &mut ExecutionResult) -> Result<(), String> {
298+
info!(
299+
"执行代码 -> 插件 [ {} ] 处理 post_execute_hook 开始",
300+
self.get_language_key()
301+
);
302+
298303
if result.success && result.stdout.is_empty() && result.stderr.is_empty() {
299-
result.stdout = "代码执行成功 (无输出)".to_string();
304+
result.stdout = String::from("END-NO-OUTPUT");
305+
result.stderr = String::from("END-NO-OUTPUT");
300306
}
301307

308+
info!(
309+
"执行代码 -> 插件 [ {} ] 处理 post_execute_hook 结束",
310+
self.get_language_key()
311+
);
302312
Ok(())
303313
}
304314
}

src-tauri/src/setup/menu.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ pub fn create_menu(app: &AppHandle) -> tauri::Result<Menu<tauri::Wry>> {
1212
// 编辑菜单
1313
let edit_submenu = menus::edit::create_edit_submenu(app)?;
1414

15+
// 开发者菜单
16+
let developer_submenu = menus::developer::create_developer_submenu(app)?;
17+
1518
let menu = MenuBuilder::new(app)
16-
.items(&[&app_submenu, &edit_submenu])
19+
.items(&[&app_submenu, &edit_submenu, &developer_submenu])
1720
.build()?;
1821

1922
Ok(menu)
@@ -23,5 +26,6 @@ pub fn setup_menu_handler(app: &AppHandle) {
2326
app.on_menu_event(move |app, event| {
2427
menus::app::handle_app_menu_event(app, event.id().as_ref());
2528
menus::edit::handle_edit_menu_event(app, event.id().as_ref());
29+
menus::developer::handle_developer_menu_event(app, event.id().as_ref());
2630
});
2731
}

src-tauri/src/setup/menus/app.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,27 @@ pub fn create_app_submenu(app: &AppHandle) -> tauri::Result<Submenu<tauri::Wry>>
99
.id("about")
1010
.build(app)?;
1111

12-
let quit_item = MenuItemBuilder::new("退出 CodeForge")
13-
.id("quit")
14-
.accelerator("CmdOrCtrl+Q")
15-
.build(app)?;
16-
1712
let settings_item = MenuItemBuilder::new("设置")
1813
.id("settings")
1914
.accelerator("CmdOrCtrl+,")
2015
.build(app)?;
2116

17+
let restart_item = MenuItemBuilder::new("重启 CodeForge")
18+
.id("restart")
19+
.accelerator("CmdOrCtrl+R")
20+
.build(app)?;
21+
22+
let quit_item = MenuItemBuilder::new("退出 CodeForge")
23+
.id("quit")
24+
.accelerator("CmdOrCtrl+Q")
25+
.build(app)?;
26+
2227
let app_submenu = SubmenuBuilder::new(app, "CodeForge")
2328
.item(&about_item)
2429
.separator()
2530
.item(&settings_item)
2631
.separator()
32+
.item(&restart_item)
2733
.item(&quit_item)
2834
.build()?;
2935

@@ -38,6 +44,10 @@ pub fn handle_app_menu_event(app: &AppHandle, event_id: &str) {
3844
"settings" => {
3945
let _event = app.emit("show-settings", ());
4046
}
47+
"restart" => {
48+
info!("CodeForge 应用重启");
49+
app.restart();
50+
}
4151
"quit" => {
4252
info!("CodeForge 应用关闭");
4353
app.exit(0);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use log::info;
2+
use tauri::{
3+
AppHandle, Manager,
4+
menu::{MenuItemBuilder, Submenu, SubmenuBuilder},
5+
};
6+
7+
pub fn create_developer_submenu(app: &AppHandle) -> tauri::Result<Submenu<tauri::Wry>> {
8+
let reload_item = MenuItemBuilder::new("重新加载")
9+
.id("reload-window")
10+
.accelerator("CmdOrCtrl+Shift+R")
11+
.build(app)?;
12+
13+
let devtools_item = MenuItemBuilder::new("打开调试器")
14+
.id("open-devtools")
15+
.accelerator("CmdOrCtrl+Shift+I")
16+
.build(app)?;
17+
18+
let developer_submenu = SubmenuBuilder::new(app, "开发者模式")
19+
.item(&reload_item)
20+
.item(&devtools_item)
21+
.build()?;
22+
23+
Ok(developer_submenu)
24+
}
25+
26+
pub fn handle_developer_menu_event(app: &AppHandle, event_id: &str) {
27+
match event_id {
28+
"reload-window" => {
29+
info!("开发者 -> 重新加载");
30+
if let Some(window) = app.get_webview_window("main") {
31+
let _ = window.reload();
32+
}
33+
}
34+
"open-devtools" => {
35+
info!("开发者 -> 打开调试器");
36+
if let Some(window) = app.get_webview_window("main") {
37+
window.open_devtools();
38+
}
39+
}
40+
_ => {}
41+
}
42+
}

src-tauri/src/setup/menus/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub mod app;
2+
pub mod developer;
23
pub mod edit;

src-tauri/src/utils/logger.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub async fn reset_log_directory(_app: AppHandle) -> Result<(), String> {
9595
}
9696

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

109+
// 获取今天的日期字符串
110+
let today = chrono::Local::now().format("%Y-%m-%d").to_string();
111+
info!("获取日志 -> 查找今天({})的日志文件", today);
112+
109113
let mut log_files = Vec::new();
110114

111115
if let Ok(entries) = std::fs::read_dir(&log_dir) {
112116
for entry in entries.flatten() {
113117
if let Some(filename) = entry.file_name().to_str() {
114-
if filename.ends_with(".log") && filename.starts_with("codeforge-") {
118+
if filename.ends_with(".log")
119+
&& filename.starts_with("codeforge-")
120+
&& filename.contains(&today)
121+
{
115122
log_files.push(filename.to_string());
116-
info!("获取日志 -> 发现日志文件: {}", filename);
123+
info!("获取日志 -> 发现今天的日志文件: {}", filename);
117124
}
118125
}
119126
}
120127
}
121128

122-
info!("获取日志 -> 找到 {} 个日志文件", log_files.len());
123-
log_files.sort();
124-
log_files.reverse(); // 最新的在前面
129+
info!("获取日志 -> 找到 {} 个今天的日志文件", log_files.len());
130+
131+
// 按日志级别排序:error -> warn -> info -> debug -> 普通日志
132+
log_files.sort_by(|a, b| {
133+
let get_priority = |filename: &str| -> u8 {
134+
if filename.contains("-info-") {
135+
1
136+
} else if filename.contains("-warn-") {
137+
2
138+
} else if filename.contains("-error-") {
139+
3
140+
} else if filename.contains("-debug-") {
141+
4
142+
} else {
143+
0
144+
}
145+
};
146+
147+
let priority_a = get_priority(a);
148+
let priority_b = get_priority(b);
149+
150+
priority_a.cmp(&priority_b).then_with(|| a.cmp(b))
151+
});
125152

126153
Ok(log_files)
127154
}

src-tauri/tauri.conf.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
"minHeight": 600,
1818
"width": 1800,
1919
"height": 1200,
20+
"center": true,
21+
"devtools": true,
2022
"additionalBrowserArgs": "--disable-context-menu"
2123
}
2224
],

0 commit comments

Comments
 (0)