DalUploadFloor.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /* ==============================================================================
  2. * 功能描述:上传或下载楼层文件
  3. * 创 建 者:Garrett
  4. * 创建日期:2018/3/30 18:16:55
  5. * ==============================================================================*/
  6. using Autodesk.Revit.DB;
  7. using Autodesk.Revit.DB.Mechanical;
  8. using SAGA.DotNetUtils;
  9. using SAGA.DotNetUtils.Extend;
  10. using SAGA.DotNetUtils.Logger;
  11. using SAGA.MBI.Calc;
  12. using SAGA.MBI.Common;
  13. using SAGA.MBI.Extend;
  14. using SAGA.MBI.Model;
  15. using SAGA.MBI.RequestData;
  16. using SAGA.MBI.Tools;
  17. using SAGA.MBI.WinView.Upload;
  18. using SAGA.RevitUtils;
  19. using SAGA.RevitUtils.Extends;
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Collections.ObjectModel;
  23. using System.IO;
  24. using System.Linq;
  25. using System.Reflection;
  26. using SAGA.RevitUtils.MEP;
  27. namespace SAGA.MBI.DataArrange
  28. {
  29. /// <summary>
  30. /// DalUploadFloor
  31. /// </summary>
  32. public class DalUploadFloor
  33. {
  34. /// <summary>
  35. /// 检测是否需要下载模型,如果需要下载
  36. /// 下载前关闭打开的模型;
  37. /// 开始下载
  38. /// </summary>
  39. public static void CheckAndBeginDownLoadFile()
  40. {
  41. Log4Net.Debug("开始:检测是否需要下载模型,如果需要下载");
  42. if (!IsAllFloorClosed()) return;
  43. Log4Net.Debug("中间:检测下载模型,如果需要下载");
  44. BeginDownLoadFile();
  45. Log4Net.Debug("结束:检测是否需要下载模型,如果需要下载");
  46. }
  47. /// <summary>
  48. /// 对比文件,开始下载
  49. /// </summary>
  50. public static bool BeginDownLoadFile()
  51. {
  52. List<Tuple<string, int, string>> tuples = DalVisionOperate.GetNeedDownLoadFiles();
  53. int i = 0, j = 0;
  54. int count = tuples.Count;
  55. foreach (var tuple in tuples)
  56. {
  57. i++;
  58. if (UpLoadFileRequest.DownLoadFileAsync(tuple, count, i))
  59. {
  60. //下载成功-更新LocalFileVision文件
  61. string floorid = tuple.Item1.GetFileName();
  62. DalVisionOperate.SaveLocalVision(floorid, DalVisionOperate.GetCloudFileVision(floorid));
  63. //下载成功清除本机本层的日志数据,其它用户的日志上传成功的时候才清除日志
  64. ProjectLogManager.ClearFile(tuple.Item1);
  65. j++;
  66. }
  67. else
  68. {
  69. break;
  70. }
  71. }
  72. if (count >= 1)
  73. //下载完成提示窗体;文件服务器缺少文件,会出现进度条无法关闭的情况;
  74. UpLoadFileRequest.CloseDownloadWin(count == j, hasTip: true);
  75. return i == j;
  76. }
  77. /// <summary>
  78. /// 重新下载模型文件
  79. /// </summary>
  80. /// <param name="floor"></param>
  81. /// <returns></returns>
  82. public static bool? ReDownLoadFile(MFloor floor, ref string msg)
  83. {
  84. string fullPath = floor.FullPath;
  85. bool? downloadstate;
  86. if (DalVisionOperate.IsFileChanged(fullPath, floor.ToString()))
  87. {
  88. Tuple<string, int, string> tuple = new Tuple<string, int, string>(fullPath, 2, floor.ToString());
  89. //模型文件有改动,备份并下载
  90. downloadstate = UpLoadFileRequest.DownLoadFileAsync(tuple, 1, 1);
  91. msg = downloadstate == true ? "模型文件更新成功" : "模型文件更新失败";
  92. string floorid = floor.Id;
  93. DalVisionOperate.SaveLocalVision(floorid, DalVisionOperate.GetCloudFileVision(floorid));
  94. //下载成功清除本机本层的日志数据,其它用户的日志上传成功的时候才清除日志
  95. ProjectLogManager.ClearFile(tuple.Item1);
  96. }
  97. else
  98. {
  99. //模型文件没有改动
  100. msg = "本地已是最新模型文件,无需更新;";
  101. downloadstate = null;
  102. }
  103. return downloadstate;
  104. }
  105. /// <summary>
  106. /// 获取有模型文件的楼层
  107. /// </summary>
  108. /// <param name="type"></param>
  109. /// <returns></returns>
  110. public static ObservableCollection<UploadFloor> GetHasFileFloors()
  111. {
  112. ObservableCollection<UploadFloor> ufloors = new ObservableCollection<UploadFloor>();
  113. List<MFloor> mfloors = DalProjectTree.GetAllFloors();
  114. foreach (var mFloor in mfloors)
  115. {
  116. UploadFloor ufloor = new UploadFloor();
  117. ufloor.BuildingName = mFloor.BuildingId;
  118. ufloor.FloorName = mFloor.ToString();
  119. ufloor.FloorPath = Path.Combine(mFloor.RelativePath, mFloor.RevitName + ".rvt");
  120. if (!mFloor.IsMissFile)
  121. {
  122. ufloor.MFloor = mFloor;
  123. ufloors.Add(ufloor);
  124. }
  125. }
  126. return ufloors;
  127. }
  128. /// <summary>
  129. /// 检查是否可以上传楼层
  130. /// 上传模型之前需要关闭所有模型文件
  131. /// </summary>
  132. public static bool IsAllFloorClosed()
  133. {
  134. //打开空文件并激活
  135. var placeholderFile = MBIConst.EmptyFilePath;
  136. var uiApp = ExternalDataWrapper.Current.UiApp;
  137. var docs = uiApp.Application.Documents;
  138. if (docs.IsEmpty) return true;
  139. var allFloors = GetHasFileFloors();
  140. //首先判断ActiveUIDocument是否为当前项目下的楼层
  141. if (uiApp.ActiveUIDocument == null) return true;
  142. Action replaceActiveDoc = () =>
  143. {
  144. string activeName = uiApp.ActiveUIDocument.Document.PathName;
  145. var floor = allFloors.FirstOrDefault(t => t.MFloor.FullPath == activeName);
  146. if (floor == null)
  147. {
  148. //不用打开空模型
  149. }
  150. else
  151. {
  152. //打开空模型
  153. uiApp.OpenAndActivateDocument(placeholderFile);
  154. }
  155. };
  156. List<Document> modifyFloors = new List<Document>();
  157. List<Document> nomodifyFloors = new List<Document>();
  158. //获取没有更改的楼层,同时获取更改的楼层
  159. foreach (Document doc in docs)
  160. {
  161. string activeName = doc.PathName;
  162. var floor = allFloors.FirstOrDefault(t => t.MFloor.FullPath == activeName);
  163. if (floor != null)
  164. {
  165. if (doc.IsModified)
  166. modifyFloors.Add(doc);
  167. else
  168. {
  169. nomodifyFloors.Add(doc);
  170. }
  171. }
  172. }
  173. //如果有更改的楼层,弹出确认框,待用户确认后,保存
  174. if (modifyFloors.Count > 0)
  175. {
  176. //弹出保存提示框
  177. WinUploadSaveFileConfirm win = new WinUploadSaveFileConfirm();
  178. if (win.ShowDialog() != true) return false;
  179. replaceActiveDoc();
  180. foreach (Document doc in modifyFloors)
  181. {
  182. doc.Close(true);
  183. }
  184. }
  185. {
  186. replaceActiveDoc();
  187. //关闭没有更改的楼层,
  188. foreach (Document doc in nomodifyFloors)
  189. {
  190. doc.Close(false);
  191. }
  192. }
  193. return true;
  194. }
  195. /// <summary>
  196. /// 是否需要更新模型文件
  197. /// </summary>
  198. /// <returns></returns>
  199. public static bool IsNeedUpdataFile()
  200. {
  201. bool result = true;
  202. var allFloors = GetHasFileFloors();
  203. //获取MD5改变的文件
  204. var modifyFloors = new ObservableCollection<UploadFloor>(allFloors
  205. .Where(t => DalVisionOperate.IsModifyFileOverdue(t.MFloor.FullPath, t.MFloor.ToString())).ToList());
  206. if (modifyFloors.Count > 0)
  207. {
  208. WinUploadTipFileOverdue win = new WinUploadTipFileOverdue();
  209. win.UploadFloors = modifyFloors;
  210. win.ShowDialog();
  211. }
  212. return modifyFloors.Count > 0;
  213. }
  214. /// <summary>
  215. /// 准备需要上传的楼层及拓扑关系
  216. /// </summary>
  217. public static VMUploadModeManage PrepareUploadFloors()
  218. {
  219. Log4Net.Info("PrepareUpload Start");
  220. string currentFloor = string.Empty;
  221. VMUploadModeManage vm = new VMUploadModeManage();
  222. try
  223. {
  224. //获取有模型文件的楼层
  225. var allFloors = GetHasFileFloors();
  226. //获取MD5改变的文件
  227. var modifyFloors = new ObservableCollection<UploadFloor>(allFloors
  228. .Where(t => DalVisionOperate.IsFileChanged(t.MFloor.FullPath, t.MFloor.ToString())).ToList());
  229. //获取所有的拓扑图类型
  230. var topologyGriphs = GetAllTopologyGriphs();
  231. foreach (UploadFloor uploadFloor in modifyFloors)
  232. {
  233. if (uploadFloor == null) continue;
  234. currentFloor = uploadFloor.MFloor.ToString();
  235. try
  236. {
  237. #region 日志影响拓扑图
  238. foreach (var topologyGriph in topologyGriphs)
  239. {
  240. uploadFloor.ReferGriphs.Add(topologyGriph);
  241. }
  242. #endregion
  243. uploadFloor.IsUpload = true;
  244. }
  245. catch (Exception e)
  246. {
  247. throw;
  248. }
  249. finally
  250. {
  251. }
  252. }
  253. vm.UploadFloors = modifyFloors;
  254. vm.MTopologyGriphs = PrepareMTopologyGriphs(modifyFloors);
  255. }
  256. catch (Exception e)
  257. {
  258. MessageShow.Show(e, strMessage: $"楼层 { currentFloor ?? string.Empty} 打开异常或网络异常,请检查后再进行操作!\r\n");
  259. vm = null;
  260. }
  261. Log4Net.Info("PrepareUpload Start");
  262. return vm;
  263. }
  264. /// <summary>
  265. /// 对 删除并保留岗位日志 进行的操作
  266. /// </summary>
  267. /// <param name="mode"></param>
  268. private static void OperateDelSaveDutyLog(MRevitEquipBase mode)
  269. {
  270. if (mode != null)
  271. {
  272. mode.Operator = DocumentChangedOperator.DeleteSaveDuty;
  273. }
  274. }
  275. /// <summary>
  276. /// 处理增加日志
  277. /// </summary>
  278. private static void OperateModifyLog(MRevitEquipBase mode, Element elem, CalcContext context)
  279. {
  280. //如果为空间并且周长为零,删除云平台的空间数据
  281. if (JudgeDeleteOperate(mode, elem)) return;
  282. var revitmode = DalCommon.GetEquipmentBase(elem);
  283. //不知什么原因,日志就显示add,但物理世界存在这条信息
  284. if (mode != null)
  285. {
  286. IsEquipClassCodeChanged(mode, elem, revitmode, context);
  287. }
  288. else
  289. {
  290. if (revitmode.IsNullOrDefaultEquip())
  291. {//不能识别的设备,部件,信标,空间
  292. }
  293. else
  294. {
  295. //请求Duty,Bim数据库中的id
  296. var dutyId = revitmode.GetDutyBIMRelationByBIM()?.DutyId;
  297. if (dutyId.IsNullOrEmpty())
  298. {//本地数据库不存在此岗位
  299. revitmode.Operator = DocumentChangedOperator.Add;
  300. context.Add(revitmode);
  301. }
  302. else
  303. {
  304. var cloudmode = CommonConvert.QueryObjectById(dutyId);
  305. if (cloudmode == null)
  306. {
  307. revitmode.Operator = DocumentChangedOperator.Add;
  308. context.Add(revitmode);
  309. }
  310. else
  311. {
  312. //待建模型清单新建的设备
  313. cloudmode.BimID = revitmode.BimID;
  314. IsEquipClassCodeChanged(cloudmode, elem, revitmode, context);
  315. context.Add(cloudmode);
  316. }
  317. }
  318. }
  319. }
  320. }
  321. /// <summary>
  322. /// 判断设备类编码是否更改
  323. /// 如果发生更改,把之前的删除。
  324. /// 重建岗位。
  325. /// </summary>
  326. /// <param name="mode"></param>
  327. /// <param name="tempmode"></param>
  328. /// <param name="context"></param>
  329. /// <returns></returns>
  330. private static bool IsEquipClassCodeChanged(MRevitEquipBase mode, Element elem, MRevitEquipBase tempmode, CalcContext context)
  331. {
  332. bool result = false;
  333. if (tempmode.IsNullOrDefaultEquip())
  334. {
  335. //本地编码不可识别,删除服务器数据
  336. //xls 新编码和旧编码一致,则不处理数据
  337. if (EquipmentCodeMap.GetOriginCode(mode.EquipClassCode) == EquipmentCodeMap.GetOriginCode(tempmode.EquipClassCode))
  338. {
  339. mode.Operator = DocumentChangedOperator.Modified;
  340. mode.ReadRevitParamter(elem);
  341. }
  342. else
  343. {
  344. mode.Operator = DocumentChangedOperator.Delete;
  345. }
  346. }
  347. else
  348. {
  349. //如果设备族四位或六位改了,需要将岗位删除,重建岗位
  350. //string code1 = EquipmentCodeMap.GetOriginCode(mode.EquipClassCode);
  351. //(tempmode.EquipClassCode 这个的取法上上一个不一样
  352. // string code2 = EquipmentCodeMap.GetOriginCode(tempmode.EquipClassCode);
  353. if (EquipmentCodeMap.GetOriginCode(mode.EquipClassCode) != EquipmentCodeMap.GetOriginCode(tempmode.EquipClassCode))
  354. {
  355. SetSavePropertyValue(tempmode, mode);
  356. mode.Operator = DocumentChangedOperator.Delete;
  357. tempmode.Operator = DocumentChangedOperator.Add;
  358. context.Add(tempmode);
  359. result = true;
  360. }
  361. else
  362. {
  363. mode.Operator = DocumentChangedOperator.Modified;
  364. mode.ReadRevitParamter(elem);
  365. }
  366. }
  367. return result;
  368. }
  369. /// <summary>
  370. /// 编码更改时保留的信息点
  371. /// </summary>
  372. /// <param name="mode"></param>
  373. /// <param name="oldmode"></param>
  374. public static void SetSavePropertyValue(MRevitEquipBase mode, MRevitEquipBase oldmode)
  375. {
  376. string[] saveProperties = new[] { "LocalId", "LocalName" };
  377. var oldProperties = oldmode.GetType().GetProperties();
  378. foreach (PropertyInfo property in oldProperties)
  379. {
  380. string name = property.Name;
  381. if (saveProperties.Contains(name))
  382. {
  383. object value = property.GetValue(oldmode);
  384. if (value != null)
  385. {
  386. property.SetValue(mode, value);
  387. }
  388. }
  389. }
  390. }
  391. /// <summary>
  392. /// 1,处理是无用的空间,周长为零
  393. /// 2,对象被删除
  394. /// </summary>
  395. /// <param name="elem"></param>
  396. /// <returns></returns>
  397. private static bool JudgeDeleteOperate(MRevitEquipBase mode, Element elem)
  398. {
  399. bool result = false;
  400. if (mode != null)
  401. {
  402. if (elem == null)
  403. {
  404. mode.Operator = DocumentChangedOperator.Delete;
  405. result = true;
  406. }
  407. else if (elem is Space space)
  408. {
  409. if (space.IsDeleteSpace())
  410. {
  411. //如果是无用空间,直接删除云平台对应数据
  412. mode.Operator = DocumentChangedOperator.Delete;
  413. result = true;
  414. }
  415. }
  416. }
  417. return result;
  418. }
  419. /// <summary>
  420. /// 准备需要显示的拓扑图(全集)
  421. /// </summary>
  422. /// <param name="uploadFloors"></param>
  423. /// <returns></returns>
  424. public static ObservableCollection<MTopologyGriph> PrepareMTopologyGriphs(ObservableCollection<UploadFloor> uploadFloors)
  425. {
  426. ObservableCollection<MTopologyGriph> list = new ObservableCollection<MTopologyGriph>();
  427. foreach (var uploadFloor in uploadFloors)
  428. {
  429. foreach (MTopologyGriph griph in uploadFloor.ReferGriphs)
  430. {
  431. var tempgriph = list.FirstOrDefault(t => t.Name == griph.Name);
  432. if (tempgriph == null)
  433. list.Add(griph);
  434. }
  435. }
  436. return list;
  437. }
  438. /// <summary>
  439. /// 上传
  440. /// </summary>
  441. public static void Upload()
  442. {
  443. //常规计算
  444. //常规上传
  445. //拓扑计算
  446. //拓扑上传
  447. }
  448. /// <summary>
  449. /// 获取所有的拓扑图类型
  450. /// </summary>
  451. /// <returns></returns>
  452. public static List<MTopologyGriph> GetAllTopologyGriphs()
  453. {
  454. List<MTopologyGriph> list = new List<MTopologyGriph>();
  455. list.Add(new MTopologyGriph() { Name = "空调冷冻水环路" });
  456. list.Add(new MTopologyGriph() { Name = "空调冷却水环路" });
  457. list.Add(new MTopologyGriph() { Name = "新风管网" });
  458. list.Add(new MTopologyGriph() { Name = "空调风管网" });
  459. list.Add(new MTopologyGriph() { Name = "光照辐射关系" });
  460. list.Add(new MTopologyGriph() { Name = "空间邻接关系" });
  461. list.Add(new MTopologyGriph() { Name = "建筑交通关系" });
  462. list.Add(new MTopologyGriph() { Name = "空间流通网络" });
  463. return list;
  464. }
  465. /// <summary>
  466. /// 新旧文件对比过后,需要添加的数据
  467. /// </summary>
  468. public static void WrapperContext(CalcContext cloudContext, CalcContext localContext)
  469. {
  470. CalcContext addContext = null;
  471. CalcContext delContext = null;
  472. CalcContext modifyContext = null;
  473. var cloudDutys = cloudContext.GetAllDutys();
  474. var localDutys = localContext.GetAllDutys();
  475. //设置初始状态
  476. cloudContext.SetState(DocumentChangedOperator.None);
  477. localContext.SetState(DocumentChangedOperator.None);
  478. #region Modify
  479. foreach (var lduty in localContext.GetAllDutys())
  480. {
  481. string bimId = lduty.BimID;
  482. var cdutys = cloudDutys.Where(t => t.BimID == bimId).ToList();
  483. MRevitEquipBase cduty = null;
  484. //如果对应多个岗位,仅保留信息点多的岗位,删除其它岗位
  485. if (cdutys.Any())
  486. {
  487. if (cdutys.Count() > 1)
  488. {//信息点的个数从大到小排序
  489. cdutys.Sort((x, y) => { return -x.CloundJObject.Count.CompareTo(y.CloundJObject.Count); });
  490. //删除多余的岗位
  491. for (int i = 1; i < cdutys.Count; i++)
  492. {
  493. cdutys[i].Operator = DocumentChangedOperator.Delete;
  494. }
  495. }
  496. cduty = cdutys.FirstOrDefault();
  497. }
  498. if (cduty == null)
  499. continue;
  500. //判断族编码是否更改
  501. if (EquipmentCodeMap.GetOriginCode(lduty.EquipClassCode) !=
  502. EquipmentCodeMap.GetOriginCode(cduty.EquipClassCode))
  503. {
  504. //族编码更改。删除旧岗位,创建新岗位
  505. cduty.Operator = DocumentChangedOperator.Delete;
  506. lduty.Operator = DocumentChangedOperator.Add;
  507. }
  508. else
  509. {
  510. lduty.Id = cduty.Id;
  511. lduty.Operator = DocumentChangedOperator.Modified;
  512. cduty.Operator = DocumentChangedOperator.Modified;
  513. }
  514. //处理设备所在空间的关系
  515. //??删除重建??没错
  516. var equipInSpace = localContext.RltEquipInSpaces.FirstOrDefault(t => t.MEquipment.BimID == bimId);
  517. if (equipInSpace == null) continue;
  518. equipInSpace.Operator = DocumentChangedOperator.Delete;
  519. localContext.RltEquipInSpaces.Add(new RltEquipInSpace(equipInSpace.MSpace, equipInSpace.MEquipment) { Operator = DocumentChangedOperator.Add });
  520. }
  521. #endregion
  522. #region Delete
  523. //CloudDuty,有两种操作,更新和删除。更新等价于None
  524. foreach (var duty in cloudDutys)
  525. {
  526. //物理世界修改,不做处理
  527. if (duty.Operator == DocumentChangedOperator.Modified)
  528. {
  529. duty.Operator = DocumentChangedOperator.None;
  530. continue;
  531. }
  532. duty.Operator = DocumentChangedOperator.Delete;
  533. //删除时,会删除所在空间和所在楼层的关系
  534. }
  535. #endregion
  536. #region Add
  537. //LocalDuty,有两种操作,更新和增加。除Modify以外的全部为添加
  538. foreach (var duty in localDutys)
  539. {
  540. if (duty.Operator == DocumentChangedOperator.Modified) continue;
  541. duty.Operator = DocumentChangedOperator.Add;
  542. //添加时,添加设备所在元空间关系
  543. localContext.RltEquipInSpaces.Where(t => t.MEquipment.BimID == duty.BimID).ToList()
  544. .ForEach(t => t.Operator = DocumentChangedOperator.Add);
  545. }
  546. #endregion
  547. }
  548. }
  549. }