/* ============================================================================== * 功能描述:上传或下载楼层文件 * 创 建 者:Garrett * 创建日期:2018/3/30 18:16:55 * ==============================================================================*/ using Autodesk.Revit.DB; using Autodesk.Revit.DB.Mechanical; using SAGA.DotNetUtils; using SAGA.DotNetUtils.Extend; using SAGA.DotNetUtils.Logger; using SAGA.MBI.Calc; using SAGA.MBI.Common; using SAGA.MBI.Extend; using SAGA.MBI.Model; using SAGA.MBI.RequestData; using SAGA.MBI.Tools; using SAGA.MBI.WinView.Upload; using SAGA.RevitUtils; using SAGA.RevitUtils.Extends; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reflection; using SAGA.MBI.FileStream; using SAGA.MBI.WinView.TraceView; using SAGA.RevitUtils.MEP; namespace SAGA.MBI.DataArrange { /// /// DalUploadFloor /// public class DalUploadFloor { /// /// 检测是否需要下载模型,如果需要下载 /// 下载前关闭打开的模型; /// 开始下载 /// public static void CheckAndBeginDownLoadFile() { Log4Net.Debug("开始:检测是否需要下载模型,如果需要下载"); if (!IsAllFloorClosed()) return; Log4Net.Debug("中间:检测下载模型,如果需要下载"); BeginDownLoadFile(); Log4Net.Debug("结束:检测是否需要下载模型,如果需要下载"); } /// /// 对比文件,开始下载 /// public static bool BeginDownLoadFile() { List> tuples = DalVisionOperate.GetNeedDownLoadFiles(); int i = 0, j = 0; int count = tuples.Count; foreach (var tuple in tuples) { i++; if (UpLoadFileRequest.DownLoadFileAsync(tuple, count, i)) { //下载成功-更新LocalFileVision文件 string floorid = tuple.Item1.GetFileName(); DalVisionOperate.SaveLocalVision(floorid, DalVisionOperate.GetCloudFileVision(floorid)); //下载成功清除本机本层的日志数据,其它用户的日志上传成功的时候才清除日志 ProjectLogManager.ClearFile(tuple.Item1); //更新拓扑计算结果版本 GplotWatch.RefreshAll(DateTime.Now); j++; } else { break; } } if (count >= 1) //下载完成提示窗体;文件服务器缺少文件,会出现进度条无法关闭的情况; UpLoadFileRequest.CloseDownloadWin(count == j, hasTip: true); return i == j; } /// /// 重新下载模型文件 /// /// /// public static bool? ReDownLoadFile(MFloor floor, ref string msg) { string fullPath = floor.FullPath; bool? downloadstate; if (DalVisionOperate.IsFileChanged(fullPath, floor.ToString())) { Tuple tuple = new Tuple(fullPath, 2, floor.ToString()); //模型文件有改动,备份并下载 downloadstate = UpLoadFileRequest.DownLoadFileAsync(tuple, 1, 1); msg = downloadstate == true ? "模型文件更新成功" : "模型文件更新失败"; string floorid = floor.Id; DalVisionOperate.SaveLocalVision(floorid, DalVisionOperate.GetCloudFileVision(floorid)); //下载成功清除本机本层的日志数据,其它用户的日志上传成功的时候才清除日志 ProjectLogManager.ClearFile(tuple.Item1); GplotWatch.RefreshAll(DateTime.Now); } else { //模型文件没有改动 msg = "本地已是最新模型文件,无需更新;"; downloadstate = null; } return downloadstate; } /// /// 获取有模型文件的楼层 /// /// /// public static ObservableCollection GetHasFileFloors() { ObservableCollection ufloors = new ObservableCollection(); List mfloors = DalProjectTree.GetAllFloors(); foreach (var mFloor in mfloors) { UploadFloor ufloor = new UploadFloor(); ufloor.BuildingName = mFloor.BuildingId; ufloor.FloorName = mFloor.ToString(); ufloor.FloorPath = Path.Combine(mFloor.RelativePath, mFloor.RevitName + ".rvt"); if (!mFloor.IsMissFile) { ufloor.MFloor = mFloor; ufloors.Add(ufloor); } } return ufloors; } /// /// 检查是否可以上传楼层 /// 上传模型之前需要关闭所有模型文件 /// public static bool IsAllFloorClosed() { //打开空文件并激活 var placeholderFile = MBIConst.EmptyFilePath; var uiApp = ExternalDataWrapper.Current.UiApp; var docs = uiApp.Application.Documents; if (docs.IsEmpty) return true; var allFloors = GetHasFileFloors(); //首先判断ActiveUIDocument是否为当前项目下的楼层 if (uiApp.ActiveUIDocument == null) return true; Action replaceActiveDoc = () => { string activeName = uiApp.ActiveUIDocument.Document.PathName; var floor = allFloors.FirstOrDefault(t => t.MFloor.FullPath == activeName); if (floor == null) { //不用打开空模型 } else { //打开空模型 uiApp.OpenAndActivateDocument(placeholderFile); } }; List modifyFloors = new List(); List nomodifyFloors = new List(); //获取没有更改的楼层,同时获取更改的楼层 foreach (Document doc in docs) { string activeName = doc.PathName; var floor = allFloors.FirstOrDefault(t => t.MFloor.FullPath == activeName); if (floor != null) { if (doc.IsModified) modifyFloors.Add(doc); else { nomodifyFloors.Add(doc); } } } //如果有更改的楼层,弹出确认框,待用户确认后,保存 if (modifyFloors.Count > 0) { //弹出保存提示框 WinUploadSaveFileConfirm win = new WinUploadSaveFileConfirm(); if (win.ShowDialog() != true) return false; replaceActiveDoc(); foreach (Document doc in modifyFloors) { doc.Close(true); } } { replaceActiveDoc(); //关闭没有更改的楼层, foreach (Document doc in nomodifyFloors) { doc.Close(false); } } return true; } /// /// 是否需要更新模型文件 /// /// public static bool IsNeedUpdataFile() { bool result = true; var allFloors = GetHasFileFloors(); //获取MD5改变的文件 var modifyFloors = new ObservableCollection(allFloors .Where(t => DalVisionOperate.IsModifyFileOverdue(t.MFloor.FullPath, t.MFloor.ToString())).ToList()); if (modifyFloors.Count > 0) { WinUploadTipFileOverdue win = new WinUploadTipFileOverdue(); win.UploadFloors = modifyFloors; win.ShowDialog(); } return modifyFloors.Count > 0; } /// /// 准备需要上传的楼层及拓扑关系 /// public static VMUploadModeManage PrepareUploadFloors() { Log4Net.Info("PrepareUpload Start"); string currentFloor = string.Empty; VMUploadModeManage vm = new VMUploadModeManage(); try { //获取有模型文件的楼层 var allFloors = GetHasFileFloors(); //获取MD5改变的文件 var modifyFloors = new ObservableCollection(allFloors .Where(t => DalVisionOperate.IsFileChanged(t.MFloor.FullPath, t.MFloor.ToString())).ToList()); //获取所有的拓扑图类型 var topologyGriphs = GetAllTopologyGriphs(); foreach (UploadFloor uploadFloor in modifyFloors) { if (uploadFloor == null) continue; currentFloor = uploadFloor.MFloor.ToString(); try { #region 日志影响拓扑图 foreach (var topologyGriph in topologyGriphs) { uploadFloor.ReferGriphs.Add(topologyGriph); } #endregion uploadFloor.IsUpload = true; } catch (Exception e) { throw; } finally { } } vm.UploadFloors = modifyFloors; vm.MTopologyGriphs = PrepareMTopologyGriphs(modifyFloors); } catch (Exception e) { MessageShow.Show(e, strMessage: $"楼层 { currentFloor ?? string.Empty} 打开异常或网络异常,请检查后再进行操作!\r\n"); vm = null; } Log4Net.Info("PrepareUpload Start"); return vm; } /// /// 对 删除并保留岗位日志 进行的操作 /// /// private static void OperateDelSaveDutyLog(MRevitEquipBase mode) { if (mode != null) { mode.Operator = DocumentChangedOperator.DeleteSaveDuty; } } /// /// 处理增加日志 /// private static void OperateModifyLog(MRevitEquipBase mode, Element elem, CalcContext context) { //如果为空间并且周长为零,删除云平台的空间数据 if (JudgeDeleteOperate(mode, elem)) return; var revitmode = DalCommon.GetEquipmentBase(elem); //不知什么原因,日志就显示add,但物理世界存在这条信息 if (mode != null) { IsEquipClassCodeChanged(mode, elem, revitmode, context); } else { if (revitmode.IsNullOrDefaultEquip()) {//不能识别的设备,部件,信标,空间 } else { //请求Duty,Bim数据库中的id var dutyId = revitmode.GetDutyBIMRelationByBIM()?.DutyId; if (dutyId.IsNullOrEmpty()) {//本地数据库不存在此岗位 revitmode.Operator = DocumentChangedOperator.Add; context.Add(revitmode); } else { var cloudmode = CommonConvert.QueryObjectById(dutyId); if (cloudmode == null) { revitmode.Operator = DocumentChangedOperator.Add; context.Add(revitmode); } else { //待建模型清单新建的设备 cloudmode.BimID = revitmode.BimID; IsEquipClassCodeChanged(cloudmode, elem, revitmode, context); context.Add(cloudmode); } } } } } /// /// 判断设备类编码是否更改 /// 如果发生更改,把之前的删除。 /// 重建岗位。 /// /// /// /// /// private static bool IsEquipClassCodeChanged(MRevitEquipBase mode, Element elem, MRevitEquipBase tempmode, CalcContext context) { bool result = false; if (tempmode.IsNullOrDefaultEquip()) { //本地编码不可识别,删除服务器数据 //xls 新编码和旧编码一致,则不处理数据 if (EquipmentCodeMap.GetOriginCode(mode.EquipClassCode) == EquipmentCodeMap.GetOriginCode(tempmode.EquipClassCode)) { mode.Operator = DocumentChangedOperator.Modified; mode.ReadRevitParamter(elem); } else { mode.Operator = DocumentChangedOperator.Delete; } } else { //如果设备族四位或六位改了,需要将岗位删除,重建岗位 //string code1 = EquipmentCodeMap.GetOriginCode(mode.EquipClassCode); //(tempmode.EquipClassCode 这个的取法上上一个不一样 // string code2 = EquipmentCodeMap.GetOriginCode(tempmode.EquipClassCode); if (EquipmentCodeMap.GetOriginCode(mode.EquipClassCode) != EquipmentCodeMap.GetOriginCode(tempmode.EquipClassCode)) { SetSavePropertyValue(tempmode, mode); mode.Operator = DocumentChangedOperator.Delete; tempmode.Operator = DocumentChangedOperator.Add; context.Add(tempmode); result = true; } else { mode.Operator = DocumentChangedOperator.Modified; mode.ReadRevitParamter(elem); } } return result; } /// /// 编码更改时保留的信息点 /// /// /// public static void SetSavePropertyValue(MRevitEquipBase mode, MRevitEquipBase oldmode) { string[] saveProperties = new[] { "LocalId", "LocalName" }; var oldProperties = oldmode.GetType().GetProperties(); foreach (PropertyInfo property in oldProperties) { string name = property.Name; if (saveProperties.Contains(name)) { object value = property.GetValue(oldmode); if (value != null) { property.SetValue(mode, value); } } } } /// /// 1,处理是无用的空间,周长为零 /// 2,对象被删除 /// /// /// private static bool JudgeDeleteOperate(MRevitEquipBase mode, Element elem) { bool result = false; if (mode != null) { if (elem == null) { mode.Operator = DocumentChangedOperator.Delete; result = true; } else if (elem is Space space) { if (space.IsDeleteSpace()) { //如果是无用空间,直接删除云平台对应数据 mode.Operator = DocumentChangedOperator.Delete; result = true; } } } return result; } /// /// 准备需要显示的拓扑图(全集) /// /// /// public static ObservableCollection PrepareMTopologyGriphs(ObservableCollection uploadFloors) { ObservableCollection list = new ObservableCollection(); foreach (var uploadFloor in uploadFloors) { foreach (MTopologyGriph griph in uploadFloor.ReferGriphs) { var tempgriph = list.FirstOrDefault(t => t.Name == griph.Name); if (tempgriph == null) list.Add(griph); } } return list; } /// /// 获取所有的拓扑图类型 /// /// public static List GetAllTopologyGriphs() { List list = new List(); list.Add(new MTopologyGriph() { Name = "空调冷冻水环路" }); list.Add(new MTopologyGriph() { Name = "空调冷却水环路" }); list.Add(new MTopologyGriph() { Name = "新风管网" }); list.Add(new MTopologyGriph() { Name = "空调风管网" }); list.Add(new MTopologyGriph() { Name = "光照辐射关系" }); list.Add(new MTopologyGriph() { Name = "空间邻接关系" }); list.Add(new MTopologyGriph() { Name = "建筑交通关系" }); list.Add(new MTopologyGriph() { Name = "空间流通网络" }); return list; } /// /// 判断物理世界岗位与本地岗位是否一致 /// 依据1:BimID /// --暂时不使用,依据2:CADID /// /// /// /// public static bool IsEqualCloudDuty2LocalDuty(MRevitEquipBase cduty,MRevitEquipBase lduty) { string lbimId = lduty.BimID; string cbimId = cduty.BimID; bool result = false; do { result = lbimId == cbimId; result = !cbimId.IsOnlyDutyNoModelBIMID() && result; break; //本地的bimid一定是完整的。 //有对应的bimId,或者bimId的格式正确。 if (result||!cbimId.IsOnlyDutyNoModelBIMID()) { break; } string lcadId, ccadId; //bimId格式不正确,判断CADID //设备 if (lduty is MEquipment lequip && cduty is MEquipment cequip) { lcadId = lequip.CADID; ccadId = cequip.CADID; result = lcadId.IsNotNullEmpty() && lcadId == ccadId; break; } //部件 if (lduty is MEquipmentPart lpart && cduty is MEquipmentPart cpart) { lcadId = lpart.CADID; ccadId = cpart.CADID; result = lcadId.IsNotNullEmpty() && lcadId == ccadId; break; } } while (false); return result; } /// /// 判断物理世界岗位与本地岗位是否一致 /// 依据1:BimID /// 依据2:CADID /// /// /// /// public static bool IsEqualDutyByCADID(MRevitEquipBase cduty, MRevitEquipBase lduty) { bool result = false; do { if (!cduty.BimID.IsOnlyDutyNoModelBIMID()) { result = false; break; } string lcadId, ccadId; //bimId格式不正确,判断CADID //设备 if (lduty is MEquipment lequip && cduty is MEquipment cequip) { lcadId = lequip.CADID; ccadId = cequip.CADID; result = lcadId.IsNotNullEmpty() && lcadId == ccadId; break; } //部件 if (lduty is MEquipmentPart lpart && cduty is MEquipmentPart cpart) { lcadId = lpart.CADID; ccadId = cpart.CADID; result = lcadId.IsNotNullEmpty() && lcadId == ccadId; break; } } while (false); return result; } /// /// 新旧文件对比过后,需要添加的数据 /// public static void WrapperContext(CalcContext cloudContext, CalcContext localContext) { var cloudDutys = cloudContext.GetAllDutys(); var localDutys = localContext.GetAllDutys(); //设置初始状态 cloudContext.SetState(DocumentChangedOperator.None); localContext.SetState(DocumentChangedOperator.None); #region Modify Add foreach (var lduty in localDutys) { var cdutys = cloudDutys.Where(t=> IsEqualCloudDuty2LocalDuty(t,lduty)).ToList(); var cdutysByCADID= cloudDutys.Where(t => IsEqualDutyByCADID(t, lduty)).ToList(); MRevitEquipBase cduty = null; //如果对应多个岗位,仅保留信息点多的岗位,删除其它岗位 if (cdutys.Any()||cdutysByCADID.Count==1) { //如果通过CADID只找到一个,当做对应岗位处理。 cdutys.AddRange(cdutysByCADID); if (cdutys.Count() > 1) {//信息点的个数从大到小排序 cdutys.Sort((x, y) => { return -x.CloundJObject.Count.CompareTo(y.CloundJObject.Count); }); //删除多余的岗位 for (int i = 1; i < cdutys.Count; i++) { cdutys[i].Operator = DocumentChangedOperator.Delete; } } } else { //通过CADID找到多个,也当做新增处理 190823 tjc //请求Duty,Bim数据库中的id,待建模型清单产生的 var dutyId = lduty.GetDutyBIMRelationByBIM()?.DutyId; if (dutyId.IsNotNullEmpty()) { cdutys = cloudDutys.Where(t => t.Id == dutyId).ToList(); if (!cdutys.Any()) { //去跟据id物理世界查找 var tempcduty = DalCommon.QueryObjectById(dutyId); if (tempcduty != null) { cdutys.Add(tempcduty); //添加设备所在楼层 localContext.UnGroupDatas.Add(new RltEquipinFloor(dutyId,cloudContext.FloorId){Operator = DocumentChangedOperator.Add}); } } } else { lduty.Id = dutyId; } } cduty = cdutys.FirstOrDefault(); if (cduty == null) { //找不到物理世界对应的岗位,即为添加 lduty.Operator = DocumentChangedOperator.Add; } else { //判断族编码是否更改 if (EquipmentCodeMap.GetOriginCode(lduty.EquipClassCode) != EquipmentCodeMap.GetOriginCode(cduty.EquipClassCode)) { //族编码更改。删除旧岗位,创建新岗位 cduty.Operator = DocumentChangedOperator.Delete; lduty.Operator = DocumentChangedOperator.Add; } else { lduty.Id = cduty.Id; lduty.Operator = DocumentChangedOperator.Modified; //后续物理世界Modified转化为None cduty.Operator = DocumentChangedOperator.Modified; } } //处理设备所在空间的关系 OperateBaseRelation(localContext, lduty); } #endregion #region Delete //CloudDuty,有两种操作,更新和删除。更新等价于None foreach (var duty in cloudDutys) { //物理世界修改,不做处理或台账转过来的岗位 if (duty.BimID.IsOnlyDutyNoModelBIMID() || duty.Operator == DocumentChangedOperator.Modified) { duty.Operator = DocumentChangedOperator.None; continue; } duty.Operator = DocumentChangedOperator.Delete; DelServiceRelation(cloudContext, duty); //删除时,会删除所在空间和所在楼层的关系 } #endregion } /// /// 删除服务器基本关系 /// private static void DelServiceRelation(CalcContext localContext, MRevitEquipBase mode) { if (mode.Operator != DocumentChangedOperator.Delete) return; #region EquipInSpace,Beacon var equiprelations = localContext.RltEquipInSpaces; var beaconrelations = localContext.RltBeaconinElementSps; if (mode is MBSpace) { var equipRelation = new RltEquipInSpace(null, mode.Id) { Operator = DocumentChangedOperator.Delete }; equiprelations.Add(equipRelation); var beaconRelation = new RltBeaconinElementSp(null, mode.Id) { Operator = DocumentChangedOperator.Delete }; beaconrelations.Add(beaconRelation); } else if (mode is MBeacon) { var beaconRelation = new RltBeaconinElementSp(mode.Id, null) { Operator = DocumentChangedOperator.Delete }; beaconrelations.Add(beaconRelation); } else { var equipRelation = new RltEquipInSpace(mode.Id, null) { Operator = DocumentChangedOperator.Delete }; equiprelations.Add(equipRelation); } #endregion } /// /// 处理基本关系 /// private static void OperateBaseRelation(CalcContext localContext, MRevitEquipBase mode) { string bimid = mode.BimID; #region EquipInSpace,Beacon var equiprelations = localContext.RltEquipInSpaces; var beaconrelations = localContext.RltBeaconinElementSps; List tempEquipRelations = new List(); List tempBeaconRelations = new List(); if (mode is MBSpace) { tempEquipRelations = equiprelations.Where(t => t.MSpace.BimID == bimid).ToList(); tempBeaconRelations = beaconrelations.Where(t => t.MSpace.BimID == bimid).ToList(); } else if (mode is MBeacon) { tempBeaconRelations = beaconrelations.Where(t => t.MBeacon.BimID == bimid).ToList(); } else { tempEquipRelations = equiprelations.Where(t => t.MEquipment.BimID == bimid).ToList(); } switch (mode.Operator) { case DocumentChangedOperator.Add: tempEquipRelations.ForEach(t => t.Operator = DocumentChangedOperator.Add); tempBeaconRelations.ForEach(t => t.Operator = DocumentChangedOperator.Add); break; case DocumentChangedOperator.Delete: tempEquipRelations.ForEach(t => t.Operator = DocumentChangedOperator.Delete); tempBeaconRelations.ForEach(t => t.Operator = DocumentChangedOperator.Delete); break; case DocumentChangedOperator.Modified: tempEquipRelations.ForEach(t => t.Operator = DocumentChangedOperator.Delete); tempEquipRelations.ForEach(t => equiprelations.Add(new RltEquipInSpace(t.MSpace, t.MEquipment) { Operator = DocumentChangedOperator.Add })); tempBeaconRelations.ForEach(t => t.Operator = DocumentChangedOperator.Delete); tempBeaconRelations.ForEach(t => beaconrelations.Add(new RltBeaconinElementSp(t.MSpace, t.MBeacon) { Operator = DocumentChangedOperator.Add })); break; default: break; } #endregion } /// /// 上传岗位和基本关系数据操作 /// /// public static void UploadDataOperate(MFloor floor) { LoadingOperation.Update(); CalcContext serviceContext = DalCommon.DownLoadFloorDataByBIMFloorInfo(floor); LoadingOperation.Update(); CalcContext localContext = ObjectCalc.Calc(floor); LoadingOperation.Update(); WrapperContext(serviceContext, localContext); LoadingOperation.Update(); serviceContext.Upload(); UploadReportUtil.SendReport(serviceContext,localContext); LoadingOperation.Update(); localContext.Upload(); } /// /// 上传或下载完成之后的操作 /// public static void AfterUploadOperate(MFloor floor, bool isunlock = true) { //请除Duty和BIMID的关系 MBIAssistHelper.DeleteFloorRelation(floor.Id); if (isunlock) //解锁 DalLock.UnLockFloor(floor.Id, false); //上传成功后清除日志数据 ProjectLogManager.ClearFiles(floor.Id); //删除备份文件 FloorFileOperate.Del000BakFile(floor.FullPath); } } }