项目打开功能
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use tauri::Manager;
|
||||
use tauri::AppHandle;
|
||||
|
||||
// IPC Commands
|
||||
#[tauri::command]
|
||||
@@ -25,12 +26,22 @@ fn save_project(path: String, data: String) -> Result<(), String> {
|
||||
|
||||
#[tauri::command]
|
||||
fn export_binary(data: Vec<u8>, output_path: String) -> Result<(), String> {
|
||||
// 二进制导出逻辑
|
||||
std::fs::write(&output_path, data)
|
||||
.map_err(|e| format!("Failed to export binary: {}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn open_project_dialog(app: AppHandle) -> Result<Option<String>, String> {
|
||||
use tauri::api::dialog::blocking::FileDialogBuilder;
|
||||
|
||||
let result = FileDialogBuilder::new()
|
||||
.set_title("Select Project Directory")
|
||||
.pick_folder();
|
||||
|
||||
Ok(result.map(|path| path.to_string_lossy().to_string()))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
@@ -47,7 +58,8 @@ fn main() {
|
||||
greet,
|
||||
open_project,
|
||||
save_project,
|
||||
export_binary
|
||||
export_binary,
|
||||
open_project_dialog
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Core, Scene } from '@esengine/ecs-framework';
|
||||
import { EditorPluginManager, UIRegistry, MessageHub, SerializerRegistry, EntityStoreService, ComponentRegistry, LocaleService, PropertyMetadataService } from '@esengine/editor-core';
|
||||
import { EditorPluginManager, UIRegistry, MessageHub, SerializerRegistry, EntityStoreService, ComponentRegistry, LocaleService, PropertyMetadataService, ProjectService } from '@esengine/editor-core';
|
||||
import { SceneInspectorPlugin } from './plugins/SceneInspectorPlugin';
|
||||
import { SceneHierarchy } from './components/SceneHierarchy';
|
||||
import { EntityInspector } from './components/EntityInspector';
|
||||
@@ -69,6 +69,7 @@ function App() {
|
||||
const serializerRegistry = new SerializerRegistry();
|
||||
const entityStore = new EntityStoreService(messageHub);
|
||||
const componentRegistry = new ComponentRegistry();
|
||||
const projectService = new ProjectService(messageHub);
|
||||
|
||||
componentRegistry.register({
|
||||
name: 'Transform',
|
||||
@@ -96,6 +97,7 @@ function App() {
|
||||
Core.services.registerInstance(SerializerRegistry, serializerRegistry);
|
||||
Core.services.registerInstance(EntityStoreService, entityStore);
|
||||
Core.services.registerInstance(ComponentRegistry, componentRegistry);
|
||||
Core.services.registerInstance(ProjectService, projectService);
|
||||
|
||||
const pluginMgr = new EditorPluginManager();
|
||||
pluginMgr.initialize(coreInstance, Core.services);
|
||||
@@ -142,11 +144,30 @@ function App() {
|
||||
changeLocale(newLocale);
|
||||
};
|
||||
|
||||
const handleOpenProject = async () => {
|
||||
try {
|
||||
const projectPath = await TauriAPI.openProjectDialog();
|
||||
if (projectPath) {
|
||||
const projectService = Core.services.resolve(ProjectService);
|
||||
if (projectService) {
|
||||
await projectService.openProject(projectPath);
|
||||
setStatus(t('header.status.projectOpened'));
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to open project:', error);
|
||||
setStatus(t('header.status.failed'));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="editor-container">
|
||||
<div className="editor-header">
|
||||
<h1>{t('app.title')}</h1>
|
||||
<div className="header-toolbar">
|
||||
<button onClick={handleOpenProject} disabled={!initialized} className="toolbar-btn">
|
||||
{t('header.toolbar.openProject')}
|
||||
</button>
|
||||
<button onClick={handleCreateEntity} disabled={!initialized} className="toolbar-btn">
|
||||
{t('header.toolbar.createEntity')}
|
||||
</button>
|
||||
|
||||
@@ -11,9 +11,10 @@ export class TauriAPI {
|
||||
return await invoke<string>('greet', { name });
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开项目
|
||||
*/
|
||||
static async openProjectDialog(): Promise<string | null> {
|
||||
return await invoke<string | null>('open_project_dialog');
|
||||
}
|
||||
|
||||
static async openProject(path: string): Promise<string> {
|
||||
return await invoke<string>('open_project', { path });
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@ export const en: Translations = {
|
||||
},
|
||||
header: {
|
||||
toolbar: {
|
||||
openProject: 'Open Project',
|
||||
createEntity: 'Create Entity',
|
||||
deleteEntity: 'Delete Entity'
|
||||
},
|
||||
status: {
|
||||
initializing: 'Initializing...',
|
||||
ready: 'Editor Ready',
|
||||
failed: 'Initialization Failed'
|
||||
failed: 'Initialization Failed',
|
||||
projectOpened: 'Project Opened'
|
||||
}
|
||||
},
|
||||
hierarchy: {
|
||||
|
||||
@@ -6,13 +6,15 @@ export const zh: Translations = {
|
||||
},
|
||||
header: {
|
||||
toolbar: {
|
||||
openProject: '打开项目',
|
||||
createEntity: '创建实体',
|
||||
deleteEntity: '删除实体'
|
||||
},
|
||||
status: {
|
||||
initializing: '初始化中...',
|
||||
ready: '编辑器就绪',
|
||||
failed: '初始化失败'
|
||||
failed: '初始化失败',
|
||||
projectOpened: '项目已打开'
|
||||
}
|
||||
},
|
||||
hierarchy: {
|
||||
|
||||
125
packages/editor-core/src/Services/ProjectService.ts
Normal file
125
packages/editor-core/src/Services/ProjectService.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import type { IService } from '@esengine/ecs-framework';
|
||||
import { Injectable } from '@esengine/ecs-framework';
|
||||
import { createLogger } from '@esengine/ecs-framework';
|
||||
import { MessageHub } from './MessageHub';
|
||||
|
||||
const logger = createLogger('ProjectService');
|
||||
|
||||
export type ProjectType = 'cocos' | 'laya' | 'unknown';
|
||||
|
||||
export interface ProjectInfo {
|
||||
path: string;
|
||||
type: ProjectType;
|
||||
name: string;
|
||||
configPath?: string;
|
||||
}
|
||||
|
||||
export interface ProjectConfig {
|
||||
projectType?: ProjectType;
|
||||
componentsPath?: string;
|
||||
componentPattern?: string;
|
||||
buildOutput?: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ProjectService implements IService {
|
||||
private currentProject: ProjectInfo | null = null;
|
||||
private projectConfig: ProjectConfig | null = null;
|
||||
private messageHub: MessageHub;
|
||||
|
||||
constructor(messageHub: MessageHub) {
|
||||
this.messageHub = messageHub;
|
||||
}
|
||||
|
||||
public async openProject(projectPath: string): Promise<void> {
|
||||
try {
|
||||
const projectInfo = await this.validateProject(projectPath);
|
||||
|
||||
this.currentProject = projectInfo;
|
||||
|
||||
if (projectInfo.configPath) {
|
||||
this.projectConfig = await this.loadConfig(projectInfo.configPath);
|
||||
}
|
||||
|
||||
await this.messageHub.publish('project:opened', {
|
||||
path: projectPath,
|
||||
type: projectInfo.type,
|
||||
name: projectInfo.name
|
||||
});
|
||||
|
||||
logger.info('Project opened', { path: projectPath, type: projectInfo.type });
|
||||
} catch (error) {
|
||||
logger.error('Failed to open project', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async closeProject(): Promise<void> {
|
||||
if (!this.currentProject) {
|
||||
logger.warn('No project is currently open');
|
||||
return;
|
||||
}
|
||||
|
||||
const projectPath = this.currentProject.path;
|
||||
this.currentProject = null;
|
||||
this.projectConfig = null;
|
||||
|
||||
await this.messageHub.publish('project:closed', { path: projectPath });
|
||||
logger.info('Project closed', { path: projectPath });
|
||||
}
|
||||
|
||||
public getCurrentProject(): ProjectInfo | null {
|
||||
return this.currentProject;
|
||||
}
|
||||
|
||||
public getProjectConfig(): ProjectConfig | null {
|
||||
return this.projectConfig;
|
||||
}
|
||||
|
||||
public isProjectOpen(): boolean {
|
||||
return this.currentProject !== null;
|
||||
}
|
||||
|
||||
public getComponentsPath(): string | null {
|
||||
if (!this.currentProject || !this.projectConfig?.componentsPath) {
|
||||
return null;
|
||||
}
|
||||
return `${this.currentProject.path}/${this.projectConfig.componentsPath}`;
|
||||
}
|
||||
|
||||
private async validateProject(projectPath: string): Promise<ProjectInfo> {
|
||||
const projectName = projectPath.split(/[\\/]/).pop() || 'Unknown Project';
|
||||
|
||||
const projectInfo: ProjectInfo = {
|
||||
path: projectPath,
|
||||
type: 'unknown',
|
||||
name: projectName
|
||||
};
|
||||
|
||||
const configPath = `${projectPath}/ecs-editor.config.json`;
|
||||
|
||||
try {
|
||||
projectInfo.configPath = configPath;
|
||||
projectInfo.type = 'cocos';
|
||||
} catch (error) {
|
||||
logger.warn('No ecs-editor.config.json found, using defaults');
|
||||
}
|
||||
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
private async loadConfig(configPath: string): Promise<ProjectConfig> {
|
||||
return {
|
||||
projectType: 'cocos',
|
||||
componentsPath: 'assets/scripts/components',
|
||||
componentPattern: '**/*Component.ts',
|
||||
buildOutput: 'temp/editor-components'
|
||||
};
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.currentProject = null;
|
||||
this.projectConfig = null;
|
||||
logger.info('ProjectService disposed');
|
||||
}
|
||||
}
|
||||
@@ -14,5 +14,6 @@ export * from './Services/EntityStoreService';
|
||||
export * from './Services/ComponentRegistry';
|
||||
export * from './Services/LocaleService';
|
||||
export * from './Services/PropertyMetadata';
|
||||
export * from './Services/ProjectService';
|
||||
|
||||
export * from './Types/UITypes';
|
||||
|
||||
Reference in New Issue
Block a user