0
0

完成了3点的修改:1、添加了文件系统监控,监控文件的动态变化,并及时ui显示。 2、添加了打开刷新,完善点1. 3、git上传优化,子集存在git上传时先删除子集git

This commit is contained in:
xubing
2026-01-30 15:28:30 +08:00
parent 10f6f34127
commit 942dab0f96
6 changed files with 784 additions and 3 deletions

View File

@@ -673,6 +673,258 @@ class ProjectService {
return false;
}
}
registerConfigFromDisk(name, fileName, containerId) {
// 查重:只要同一个容器下有相同的 fileName就视为已存在
const existing = this.configs.find(c => c.containerId === containerId && c.fileName === fileName);
if (existing)
return false;
const newId = this.generateUniqueId('cfg', this.configs);
this.configs.push({
id: newId,
name: name,
fileName: fileName,
containerId: containerId
});
return true;
}
/**
* [新方法] 仅在内存中注册模块文件夹(用于监测到磁盘文件夹创建时)
*/
registerModuleFolderFromDisk(folderName, containerId, aircraftId, projectId, aircraftName, containerName, fullPath) {
const relativePath = `/${projectId}/${aircraftName}/${containerName}/${folderName}`;
// 查重:只要同一个容器下,有任何一个模块指向了相同的文件夹名,就视为已存在
// 这样即使旧数据的 localPath 路径字符串是过时的,也不会重复添加
const existing = this.moduleFolders.find(f => {
if (f.containerId !== containerId)
return false;
// 从 localPath 中提取最后一部分(文件夹名)进行比对
const existingFolderName = f.localPath.split('/').pop();
return existingFolderName === folderName;
});
if (existing)
return false;
// 智能检测:如果文件夹下有 .git则标记为 git 类型
let type = 'local';
if (fullPath) {
const gitDir = path.join(fullPath, '.git');
if (fs.existsSync(gitDir)) {
type = 'git';
}
}
const folderId = this.generateUniqueId(type === 'git' ? 'git-' : 'local-', this.moduleFolders);
this.moduleFolders.push({
id: folderId,
name: folderName,
type: type,
localPath: relativePath,
containerId: containerId,
uploaded: type === 'git'
});
return true;
}
/**
* [新方法] 处理磁盘删除事件:根据路径移除对应的 Config 或 ModuleFolder
*/
removeEntityByPath(filePath, projectId) {
// 这里的 filePath 是绝对路径,需要反解出是哪个 Config 或 Folder
// 这是一个比较繁琐的过程,简化逻辑如下:
let changed = false;
const projectPath = this.projectPaths.get(projectId);
if (!projectPath || !filePath.startsWith(projectPath))
return false;
// 尝试匹配 Config
const configToDelete = this.configs.find(c => {
const p = this.getConfigFilePath(c.id);
return p && path.normalize(p) === path.normalize(filePath);
});
if (configToDelete) {
this.deleteConfig(configToDelete.id);
return true;
}
// 尝试匹配 ModuleFolder
const folderToDelete = this.moduleFolders.find(f => {
const p = this.getModuleFolderFullPath(f);
return p && path.normalize(p) === path.normalize(filePath);
});
if (folderToDelete) {
this.deleteModuleFolder(folderToDelete.id);
return true;
}
return false;
}
/**
* 刷新项目内容:同步飞行器列表
*/
async refreshProjectContent(projectId) {
const projectPath = this.projectPaths.get(projectId);
if (!projectPath || !fs.existsSync(projectPath))
return false;
let changed = false;
// 1. 扫描磁盘,添加缺失的飞行器
try {
const entries = await fs.promises.readdir(projectPath, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory())
continue;
if (entry.name.startsWith('.') || entry.name === 'dcsp-data.json')
continue;
// 检查内存中是否存在
const exists = this.getAircraftsByProject(projectId).find(a => a.name === entry.name);
if (!exists) {
// 不存在则导入
await this.importAircraftFromExistingFolder(projectId, entry.name);
changed = true;
}
}
}
catch (e) {
console.error('扫描项目目录失败:', e);
}
// 2. 检查内存,移除磁盘不存在的飞行器 (清理无效数据)
const currentAircrafts = this.getAircraftsByProject(projectId);
for (const aircraft of currentAircrafts) {
const aircraftPath = path.join(projectPath, aircraft.name);
if (!fs.existsSync(aircraftPath)) {
this.deleteAircraft(aircraft.id);
changed = true;
}
}
return changed;
}
/**
* 刷新飞行器内容:同步容器列表
*/
async refreshAircraftContent(aircraftId) {
const dirPath = this.getAircraftDirectoryPath(aircraftId);
if (!dirPath || !fs.existsSync(dirPath))
return false;
let changed = false;
// 1. 扫描磁盘,添加缺失的容器
try {
const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory())
continue;
if (entry.name.startsWith('.'))
continue; // 忽略 .git 等
const exists = this.getContainersByAircraft(aircraftId).find(c => c.name === entry.name);
if (!exists) {
await this.importContainerFromExistingFolder(aircraftId, entry.name);
changed = true;
}
}
}
catch (e) {
console.error('扫描飞行器目录失败:', e);
}
// 2. 检查内存,移除磁盘不存在的容器
const currentContainers = this.getContainersByAircraft(aircraftId);
for (const container of currentContainers) {
const containerPath = path.join(dirPath, container.name);
if (!fs.existsSync(containerPath)) {
this.deleteContainer(container.id);
changed = true;
}
}
return changed;
}
/**
* 刷新容器内容:同步配置和模块列表
*/
async refreshContainerContent(containerId) {
const dirPath = this.getContainerDirectoryPath(containerId);
if (!dirPath || !fs.existsSync(dirPath))
return false;
const container = this.getContainer(containerId);
if (!container)
return false;
const aircraft = this.getAircraft(container.aircraftId);
if (!aircraft)
return false;
let changed = false;
// 1. 扫描磁盘,添加缺失的配置和模块
try {
const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith('.') || entry.name === 'dcsp-data.json')
continue;
if (entry.isFile()) {
// 尝试注册配置 (registerConfigFromDisk 内部会自动去重)
const isNew = this.registerConfigFromDisk(entry.name, entry.name, containerId);
if (isNew)
changed = true;
}
else if (entry.isDirectory()) {
// 尝试注册模块
const isNew = this.registerModuleFolderFromDisk(entry.name, containerId, aircraft.id, aircraft.projectId, aircraft.name, container.name);
if (isNew)
changed = true;
}
}
}
catch (e) {
console.error('扫描容器目录失败:', e);
}
// 2. 检查内存,移除磁盘不存在的 配置
const currentConfigs = this.getConfigsByContainer(containerId);
for (const config of currentConfigs) {
const configPath = path.join(dirPath, config.fileName);
if (!fs.existsSync(configPath)) {
this.deleteConfig(config.id);
changed = true;
}
}
// 3. 检查内存,移除磁盘不存在的 模块文件夹
const currentModules = this.getModuleFoldersByContainer(containerId);
for (const folder of currentModules) {
// 注意Git 类型的模块文件夹,其 localPath 也是指向这个目录的
// 这里我们简单拼接路径来检查
// folder.localPath 格式: /projectId/aircraft/container/folderName
const folderName = folder.localPath.split('/').pop();
if (folderName) {
const folderPath = path.join(dirPath, folderName);
if (!fs.existsSync(folderPath)) {
this.deleteModuleFolder(folder.id);
changed = true;
}
}
}
return changed;
}
/**
* [新增] 递归清理目录下所有的嵌套 .git 文件夹
* 作用:保留 rootDir 下的 .git但删除所有子目录中的 .git
* 解决父级上传时因包含子级仓库导致的冲突
*/
async cleanNestedGitFolders(rootDir) {
if (!fs.existsSync(rootDir))
return;
try {
const entries = await fs.promises.readdir(rootDir, { withFileTypes: true });
for (const entry of entries) {
// 1. 如果遍历到的是当前目录下的 .git直接跳过这是我们要保留的主仓库
if (entry.name === '.git')
continue;
// 2. 只处理目录
if (entry.isDirectory()) {
const subDir = path.join(rootDir, entry.name);
const nestedGit = path.join(subDir, '.git');
// 检查子目录下是否有 .git
if (fs.existsSync(nestedGit)) {
console.log(`🧹 发现嵌套 Git 仓库,正在移除以支持父级上传: ${nestedGit}`);
// 使用您之前实现的强力删除方法(带权限处理)
await this.deleteDirectoryFromDisk(nestedGit);
}
// 继续递归,防止有多层嵌套
await this.cleanNestedGitFolders(subDir);
}
}
}
catch (error) {
console.error(`清理嵌套 Git 失败: ${error}`);
// 不抛出错误,尽力而为,以免打断上传流程
}
}
}
exports.ProjectService = ProjectService;
//# sourceMappingURL=ProjectService.js.map

File diff suppressed because one or more lines are too long