123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664 |
- /* ==============================================================================
- * 功能描述:上传或下载楼层文件
- * 创 建 者:Garrett
- * 创建日期:2018/3/30 18:16:55
- * ==============================================================================*/
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using Autodesk.Revit.DB;
- using Autodesk.Revit.DB.Mechanical;
- using SAGA.DotNetUtils;
- using SAGA.DotNetUtils.Extend;
- using SAGA.DotNetUtils.Logger;
- using SAGA.DotNetUtils.Others;
- using SAGA.MBI.Calc;
- using SAGA.MBI.Common;
- using SAGA.MBI.Extend;
- using SAGA.MBI.FileStream;
- using SAGA.MBI.Interaction;
- using SAGA.MBI.JsonConvert;
- using SAGA.MBI.Model;
- using SAGA.MBI.RequestData;
- using SAGA.MBI.Tools;
- using SAGA.MBI.WinView.Upload;
- using SAGA.RevitUtils;
- using SAGA.RevitUtils.Extends;
- namespace SAGA.MBI.DataArrange
- {
- /// <summary>
- /// DalUploadFloor
- /// </summary>
- public class DalUploadFloor
- {
- /// <summary>
- /// 检测是否需要下载模型,如果需要下载
- /// 下载前关闭打开的模型;
- /// 开始下载
- /// </summary>
- public static void CheckAndBeginDownLoadFile()
- {
- Log4Net.Debug("开始:检测是否需要下载模型,如果需要下载");
- if (!IsAllFloorClosed()) return;
- Log4Net.Debug("中间:检测下载模型,如果需要下载");
- BeginDownLoadFile();
- Log4Net.Debug("结束:检测是否需要下载模型,如果需要下载");
- }
- /// <summary>
- /// 对比文件,开始下载
- /// </summary>
- public static bool BeginDownLoadFile()
- {
- List<Tuple<string, int, string>> 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);
- j++;
- }
- else
- {
- break;
- }
- }
- if (count >= 1)
- //下载完成提示窗体;文件服务器缺少文件,会出现进度条无法关闭的情况;
- UpLoadFileRequest.CloseDownloadWin(count == j, hasTip: true);
- return i == j;
- }
- /// <summary>
- /// 重新下载模型文件
- /// </summary>
- /// <param name="floor"></param>
- /// <returns></returns>
- public static bool? ReDownLoadFile(MFloor floor, ref string msg)
- {
- string fullPath = floor.FullPath;
- bool? downloadstate;
- if (DalVisionOperate.IsFileChanged(fullPath, floor.ToString()))
- {
- Tuple<string, int, string> tuple = new Tuple<string, int, string>(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);
- }
- else
- {
- //模型文件没有改动
- msg = "本地已是最新模型文件,无需更新;";
- downloadstate = null;
- }
- return downloadstate;
- }
- /// <summary>
- /// 获取有模型文件的楼层
- /// </summary>
- /// <param name="type"></param>
- /// <returns></returns>
- public static ObservableCollection<UploadFloor> GetHasFileFloors()
- {
- ObservableCollection<UploadFloor> ufloors = new ObservableCollection<UploadFloor>();
- List<MFloor> 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;
- }
- /// <summary>
- /// 检查是否可以上传楼层
- /// 上传模型之前需要关闭所有模型文件
- /// </summary>
- 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<Document> modifyFloors = new List<Document>();
- List<Document> nomodifyFloors = new List<Document>();
- //获取没有更改的楼层,同时获取更改的楼层
- 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;
- }
- /// <summary>
- /// 是否需要更新模型文件
- /// </summary>
- /// <returns></returns>
- public static bool IsNeedUpdataFile()
- {
- bool result = true;
- var allFloors = GetHasFileFloors();
- //获取MD5改变的文件
- var modifyFloors = new ObservableCollection<UploadFloor>(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;
- }
- /// <summary>
- /// 准备需要上传的楼层及拓扑关系
- /// </summary>
- public static VMUploadModeManage PrepareUploadFloors()
- {
- string currentFloor = string.Empty;
- try
- {
- VMUploadModeManage vm = new VMUploadModeManage();
- //获取有模型文件的楼层
- var allFloors = GetHasFileFloors();
- //获取MD5改变的文件
- var modifyFloors = new ObservableCollection<UploadFloor>(allFloors
- .Where(t => DalVisionOperate.IsFileChanged(t.MFloor.FullPath, t.MFloor.ToString())).ToList());
- //获取所有的拓扑图类型
- var topologyGriphs = GetAllTopologyGriphs();
- foreach (UploadFloor uploadFloor in modifyFloors)
- {
- if (uploadFloor == null) continue;
- //检测到自己加锁 才读取日志
- if (uploadFloor.MFloor.FloorLock.LockState != MFloorLockState.LockBySelf)
- continue;
- currentFloor = uploadFloor.MFloor.ToString();
- Document document = null;
- try
- {
- #region 同步空间名称
- document = ExternalDataWrapper.Current.App.OpenDocumentFile(uploadFloor.MFloor.FullPath);
- MBIModelInfoManager.SyncPlatformToRevit(document);
- #endregion
- #region 跟据日志整理跟要上传的数据
- //检测有日志文件,才上传
- var logs = DalLogOperate.GetLogs(uploadFloor.MFloor.Id);
- if (!logs.Any()) continue;
- uploadFloor.CalcContext = DalCommon.DownLoadCouldData(uploadFloor.MFloor);
- CalcContext context = uploadFloor.CalcContext;
- //按id分组后的日志
- var floorLogsGroupByBimId = logs.GroupBy(t => t.Id);
- //所有的拓扑图类型
- var tempGriphs = new List<MTopologyGriph>(topologyGriphs);
- foreach (IGrouping<string, DocumentChangedLogMode> logGroup in floorLogsGroupByBimId)
- {
- DocumentChangedLogMode log = logGroup.LastOrDefault();
- if (log == null) continue;
- var bimId = CommonTool.GetCloudBIMId(log.DocName, log.Id);
- var elem = document.GetElement(log.Id.ToInt());
- //日志影响构件
- var operate =
- (DocumentChangedOperator)Enum.Parse(typeof(DocumentChangedOperator), log.Operator);
- var mode = context.FindItem(bimId);
- //模型和物理世界都找不到这条数据,Next
- if (mode == null && elem == null) continue;
- switch (operate)
- {
- case DocumentChangedOperator.Add:
- case DocumentChangedOperator.Modified:
- case DocumentChangedOperator.Delete:
- OperateModifyLog(mode, elem, context);
- break;
- case DocumentChangedOperator.DeleteSaveDuty:
- OperateDelSaveDutyLog(mode);
- break;
- }
- #region 日志影响拓扑图
- //日志影响拓扑图,影响则标记,从所有中移除
- var useGriphs = new List<MTopologyGriph>(topologyGriphs);
- foreach (var topologyGriph in tempGriphs)
- {
- if (topologyGriph.IsAffectGriph(log))
- {
- useGriphs.Add(topologyGriph);
- uploadFloor.ReferGriphs.Add(topologyGriph);
- }
- }
- tempGriphs.RemoveAll(t => useGriphs.Contains(t));
- #endregion
- }
- #endregion
- //处理设备所在空间
- CheckEquipSpaceRlt(context);
- uploadFloor.IsUpload = true;
- }
- catch (Exception e)
- {
- throw;
- }
- finally
- {
- document?.CloseDoc();
- }
- }
- vm.UploadFloors = modifyFloors;
- vm.MTopologyGriphs = PrepareMTopologyGriphs(modifyFloors);
- return vm;
- }
- catch (Exception e)
- {
- MessageShow.Show(e, strMessage: $"楼层 { currentFloor ?? string.Empty} 打开异常或网络异常,请检查后再进行操作!\r\n");
- return null;
- }
- }
- /// <summary>
- /// 对 删除并保留岗位日志 进行的操作
- /// </summary>
- /// <param name="mode"></param>
- private static void OperateDelSaveDutyLog(MRevitEquipBase mode)
- {
- if (mode != null)
- {
- mode.Operator = DocumentChangedOperator.DeleteSaveDuty;
- }
- }
- /// <summary>
- /// 处理增加日志
- /// </summary>
- 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);
- }
- }
- }
- }
- }
- /// <summary>
- /// 判断设备类编码是否更改
- /// 如果发生更改,把之前的删除。
- /// 重建岗位。
- /// </summary>
- /// <param name="mode"></param>
- /// <param name="tempmode"></param>
- /// <param name="context"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 编码更改时保留的信息点
- /// </summary>
- /// <param name="mode"></param>
- /// <param name="oldmode"></param>
- 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);
- }
- }
- }
- }
- /// <summary>
- /// 1,处理是无用的空间,周长为零
- /// 2,对象被删除
- /// </summary>
- /// <param name="elem"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 准备需要显示的拓扑图(全集)
- /// </summary>
- /// <param name="uploadFloors"></param>
- /// <returns></returns>
- public static ObservableCollection<MTopologyGriph> PrepareMTopologyGriphs(ObservableCollection<UploadFloor> uploadFloors)
- {
- ObservableCollection<MTopologyGriph> list = new ObservableCollection<MTopologyGriph>();
- 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;
- }
- /// <summary>
- /// 关闭revit文件
- /// </summary>
- /// <param name="uploadFloors"></param>
- /// <returns></returns>
- public static ObservableCollection<MTopologyGriph> CloseFloorDoc(ObservableCollection<UploadFloor> uploadFloors)
- {
- ObservableCollection<MTopologyGriph> list = new ObservableCollection<MTopologyGriph>();
- foreach (var uploadFloor in uploadFloors)
- {
- uploadFloor.CalcContext?.RevitDoc.CloseDoc();
- }
- return list;
- }
- /// <summary>
- /// 处理设备所在空间
- /// </summary>
- /// <param name="context"></param>
- private static void CheckEquipSpaceRlt(CalcContext context)
- {
- //设备
- foreach (MEquipment equip in context.MEquipments)
- {
- OperateEquipInSpace(equip, context);
- }
- //部件
- foreach (MEquipmentPart equip in context.MEquipmentParts)
- {
- OperateEquipInSpace(equip, context);
- }
- //信标
- foreach (MBeacon mode in context.MBeacons)
- {
- OperateRltBeaconinElementSp(mode, context);
- }
- }
- /// <summary>
- /// 处理设备所在空间
- /// </summary>
- /// <param name="mode"></param>
- /// <param name="context"></param>
- private static void OperateEquipInSpace(MRevitEquipBase mode, CalcContext context)
- {
- //if (mode.Operator == DocumentChangedOperator.None) return;
- var revitId = mode.BimID.GetBIMID();
- if (revitId == 0) return;
- var fi = context.RevitDoc.GetElement(revitId) as FamilyInstance;
- Autodesk.Revit.DB.Mechanical.Space space = fi?.GetReferenceSpace();
- if (space == null) return;
- //查询有没有Space对象
- string spaceId = space.GetCloudBIMId();
- var mspace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
- if (mspace == null) return;
- switch (mode.Operator)
- {
- case DocumentChangedOperator.Add:
- context.RltEquipInSpaces.Add(new RltEquipInSpace(mspace, mode) { Operator = DocumentChangedOperator.Add });
- break;
- case DocumentChangedOperator.Delete:
- context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
- break;
- case DocumentChangedOperator.Modified:
- //修改为,先删除,再新建
- context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
- context.RltEquipInSpaces.Add(new RltEquipInSpace(mspace, mode) { Operator = DocumentChangedOperator.Add });
- break;
- case DocumentChangedOperator.None:
- //空间更改可能不引起设备修改,所以设备所在元空间关系跟据元空间状态重新计算。
- if (mspace.Operator == DocumentChangedOperator.Add ||
- mspace.Operator == DocumentChangedOperator.Modified)
- {
- context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
- context.RltEquipInSpaces.Add(new RltEquipInSpace(mspace, mode) { Operator = DocumentChangedOperator.Add });
- }
- else if (mspace.Operator == DocumentChangedOperator.Delete)
- {
- context.RltEquipInSpaces.Add(new RltEquipInSpace(null, mode) { Operator = DocumentChangedOperator.Delete });
- }
- break;
- }
- }
- /// <summary>
- /// 信标所在元空间
- /// </summary>
- /// <param name="mode"></param>
- /// <param name="context"></param>
- private static void OperateRltBeaconinElementSp(MRevitEquipBase mode, CalcContext context)
- {
- if (mode.Operator == DocumentChangedOperator.None) return;
- var revitId = mode.BimID.GetBIMID();
- var fi = context.RevitDoc.GetElement(revitId) as FamilyInstance;
- Autodesk.Revit.DB.Mechanical.Space space = fi?.Space;
- if (space == null) return;
- //查询有没有Space对象
- string spaceId = space.GetCloudBIMId();
- var mspace = context.MSpaces.FirstOrDefault(t => t.BimID == spaceId);
- if (mspace == null) return;
- switch (mode.Operator)
- {
- case DocumentChangedOperator.Add:
- context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(mspace, mode) { Operator = DocumentChangedOperator.Add });
- break;
- case DocumentChangedOperator.Modified:
- //修改为,先删除,再新建
- context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(null, mode) { Operator = DocumentChangedOperator.Delete });
- context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(mspace, mode) { Operator = DocumentChangedOperator.Add });
- break;
- case DocumentChangedOperator.Delete:
- context.RltBeaconinElementSps.Add(new RltBeaconinElementSp(null, mode) { Operator = DocumentChangedOperator.Delete });
- break;
- }
- }
- /// <summary>
- /// 上传
- /// </summary>
- public static void Upload()
- {
- //常规计算
- //常规上传
- //拓扑计算
- //拓扑上传
- }
- /// <summary>
- /// 获取所有的拓扑图类型
- /// </summary>
- /// <returns></returns>
- public static List<MTopologyGriph> GetAllTopologyGriphs()
- {
- List<MTopologyGriph> list = new List<MTopologyGriph>();
- 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;
- }
- }
- public enum UploadType
- {
- //文件模型修正
- ModeModify,
- //更新模型文件
- FileReplace
- }
- }
|