diff --git a/Controllers/ShellController.cs b/Controllers/ShellController.cs index dfb267d..a5f00e1 100644 --- a/Controllers/ShellController.cs +++ b/Controllers/ShellController.cs @@ -288,8 +288,26 @@ namespace RevitHttpControl.Controllers } catch (InvalidOperationException ex) { + if (ex.Message.Contains(ErrorMessages.NO_DOCUMENT_OPEN_MSG)) + { + return this.CreateErrorResponse( + ErrorCodes.NO_DOCUMENT_OPEN, + ex.Message, + HttpStatusCode.BadRequest + ); + } + + if (ex.Message.Contains("创建备份失败")) + { + return this.CreateErrorResponse( + ErrorCodes.FILE_WRITE_PERMISSION_DENIED, + ex.Message, + HttpStatusCode.Forbidden + ); + } + return this.CreateErrorResponse( - ErrorCodes.NO_DOCUMENT_OPEN, + ErrorCodes.REVIT_COMMAND_FAILED, ex.Message, HttpStatusCode.BadRequest ); diff --git a/Services/ShellOptimizer.cs b/Services/ShellOptimizer.cs index 2fa12f6..f8cc17b 100644 --- a/Services/ShellOptimizer.cs +++ b/Services/ShellOptimizer.cs @@ -274,10 +274,22 @@ namespace RevitHttpControl.Services if (worksetId != WorksetId.InvalidWorksetId) { var doc = element.Document; - var worksetTable = doc.GetWorksetTable(); - var workset = worksetTable.GetWorkset(worksetId); - if (workset.IsOpen && workset.Owner != doc.Application.Username) - return false; + // 仅对工作共享文档执行“他人占用”校验,避免本地/样例文件误判。 + if (doc.IsWorkshared) + { + var worksetTable = doc.GetWorksetTable(); + var workset = worksetTable.GetWorkset(worksetId); + var owner = workset?.Owner; + var currentUser = doc.Application?.Username; + + if (workset != null && + workset.IsOpen && + !string.IsNullOrWhiteSpace(owner) && + !string.Equals(owner, currentUser, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + } } // 检查是否有依赖关系(如主体构件) @@ -341,18 +353,38 @@ namespace RevitHttpControl.Services throw new InvalidOperationException("文档必须先保存才能创建备份"); } - var directory = Path.GetDirectoryName(originalPath); var fileName = Path.GetFileNameWithoutExtension(originalPath); var extension = Path.GetExtension(originalPath); var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - var backupFileName = $"{fileName}_backup_{timestamp}{extension}"; - var backupPath = Path.Combine(directory, backupFileName); - // 复制文件 - File.Copy(originalPath, backupPath, false); - - return backupPath; + // 先尝试写入原目录;若无权限则回退到用户本地目录。 + var sourceDirectory = Path.GetDirectoryName(originalPath); + if (!string.IsNullOrWhiteSpace(sourceDirectory)) + { + var backupPathInSource = Path.Combine(sourceDirectory, backupFileName); + try + { + File.Copy(originalPath, backupPathInSource, false); + return backupPathInSource; + } + catch (UnauthorizedAccessException) + { + // Ignore and fallback. + } + catch (IOException ex) when (File.Exists(backupPathInSource)) + { + throw new InvalidOperationException($"备份文件已存在: {backupPathInSource}", ex); + } + } + + var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var fallbackDirectory = Path.Combine(localAppData, "RevitHttpControl", "Backups"); + Directory.CreateDirectory(fallbackDirectory); + + var backupPathInFallback = Path.Combine(fallbackDirectory, backupFileName); + File.Copy(originalPath, backupPathInFallback, false); + return backupPathInFallback; } catch (Exception ex) { @@ -367,9 +399,20 @@ namespace RevitHttpControl.Services { try { - if (doc.IsModified) + if (!doc.IsModified) + { + return; + } + + try { doc.Save(); + return; + } + catch (Exception ex) when (IsReadOnlySaveError(ex)) + { + SaveDocumentAsWritableCopy(doc); + return; } } catch (Exception ex) @@ -378,6 +421,38 @@ namespace RevitHttpControl.Services } } + private bool IsReadOnlySaveError(Exception ex) + { + if (ex == null) return false; + var message = ex.Message ?? string.Empty; + return message.IndexOf("read-only", StringComparison.OrdinalIgnoreCase) >= 0 || + message.IndexOf("只读", StringComparison.OrdinalIgnoreCase) >= 0; + } + + private void SaveDocumentAsWritableCopy(Document doc) + { + var originalPath = doc.PathName; + if (string.IsNullOrWhiteSpace(originalPath)) + throw new InvalidOperationException("文档为只读且无法获取原始路径,不能自动另存为"); + + var fileName = Path.GetFileNameWithoutExtension(originalPath); + var extension = Path.GetExtension(originalPath); + var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); + + var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var outputDirectory = Path.Combine(localAppData, "RevitHttpControl", "Optimized"); + Directory.CreateDirectory(outputDirectory); + + var outputPath = Path.Combine(outputDirectory, $"{fileName}_optimized_{timestamp}{extension}"); + var saveAsOptions = new SaveAsOptions + { + OverwriteExistingFile = false, + Compact = true + }; + + doc.SaveAs(outputPath, saveAsOptions); + } + /// /// 获取文档文件大小 ///