Browse Source

总分包汇总,1.0

MaiXinRong 7 years ago
parent
commit
c3e82cbf72

+ 56 - 0
Forms/MainFrm.dfm

@@ -390,6 +390,7 @@ object MainForm: TMainForm
           Visible = True
         end
         item
+          BeginGroup = True
           Item = dxsiImportExcel
           Visible = True
         end
@@ -398,6 +399,7 @@ object MainForm: TMainForm
           Visible = True
         end
         item
+          BeginGroup = True
           Item = dxbtnExportCloudTenderFile
           Visible = True
         end
@@ -406,8 +408,14 @@ object MainForm: TMainForm
           Visible = True
         end
         item
+          BeginGroup = True
           Item = dxbtnImportDmf
           Visible = True
+        end
+        item
+          BeginGroup = True
+          Item = dxbtnExportSumBaseFile
+          Visible = True
         end>
     end
     object dxsiEdit: TdxBarSubItem
@@ -1000,6 +1008,14 @@ object MainForm: TMainForm
         item
           Item = dxbtnTenderPartition
           Visible = True
+        end
+        item
+          Item = dxbtnGatherSubTender
+          Visible = True
+        end
+        item
+          Item = dxbtnCheckBills
+          Visible = True
         end>
     end
     object dxbtnTenderPartition: TdxBarButton
@@ -1124,6 +1140,36 @@ object MainForm: TMainForm
       Hint = #23450#20301#33267#21488#36134#20998#35299
       Visible = ivAlways
     end
+    object dxbtnExportSumBaseFile: TdxBarButton
+      Action = actnExportSumBaseFile
+      Category = 0
+      Hint = #23548#20986#24635#21253#22522#20934#25991#20214
+    end
+    object dxbtnGatherSubTender: TdxBarButton
+      Caption = #20998#21253#26631#27573#27719#24635
+      Category = 0
+      Hint = #20998#21253#26631#27573#27719#24635
+      Visible = ivAlways
+      OnClick = dxbtnGatherSubTenderClick
+    end
+    object dxbtnCheckBills: TdxBarButton
+      Caption = #26816#26597'0'#21495#21488#36134#28165#21333#32467#26500
+      Category = 0
+      Hint = #26816#26597'0'#21495#21488#36134#28165#21333#32467#26500
+      Visible = ivAlways
+    end
+    object dxBarButton1: TdxBarButton
+      Caption = #23548#20986#21333#26631#27573#38169#35823#20449#24687
+      Category = 0
+      Hint = #23548#20986#21333#26631#27573#38169#35823#20449#24687
+      Visible = ivAlways
+    end
+    object dxBarButton2: TdxBarButton
+      Caption = #23548#20986#20840#37096#38169#35823#20449#24687
+      Category = 0
+      Hint = #23548#20986#20840#37096#38169#35823#20449#24687
+      Visible = ivAlways
+    end
   end
   object Images: TImageList
     DrawingStyle = dsTransparent
@@ -3297,6 +3343,16 @@ object MainForm: TMainForm
       OnExecute = actnImportDmfExecute
       OnUpdate = actnImportCloudTenderFileUpdate
     end
+    object actnExportSumBaseFile: TAction
+      Category = 'File'
+      Caption = #23548#20986#24635#21253#22522#20934#25991#20214
+      OnExecute = actnExportSumBaseFileExecute
+      OnUpdate = actnUnlockInfoUpdate
+    end
+    object actnCheckBills: TAction
+      Caption = #26816#26597'0'#21495#21488#36134#28165#21333#32467#26500
+      OnUpdate = actnCloseProjectUpdate
+    end
   end
   object dxpmTabSet: TdxBarPopupMenu
     BarManager = dxBarManager

+ 56 - 1
Forms/MainFrm.pas

@@ -168,6 +168,13 @@ type
     dxbtnLocateZJJL: TdxBarButton;
     dxbtnEpure: TdxBarButton;
     dxbtnLocateCompileBills: TdxBarButton;
+    dxbtnExportSumBaseFile: TdxBarButton;
+    actnExportSumBaseFile: TAction;
+    dxbtnGatherSubTender: TdxBarButton;
+    dxbtnCheckBills: TdxBarButton;
+    actnCheckBills: TAction;
+    dxBarButton1: TdxBarButton;
+    dxBarButton2: TdxBarButton;
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure jtsProjectsChange(Sender: TObject; NewTab: Integer;
@@ -213,6 +220,8 @@ type
     procedure dxbtnTenderPartitionClick(Sender: TObject);
     procedure actnImportDmfExecute(Sender: TObject);
     procedure dxbtnHelpCenterClick(Sender: TObject);
+    procedure actnExportSumBaseFileExecute(Sender: TObject);
+    procedure dxbtnGatherSubTenderClick(Sender: TObject);
   private
     FProjectManagerFrame: TProjectManagerFrame;
     FProjectFrames: TList;
@@ -250,7 +259,8 @@ uses
   ProjectProperty, ConstUnit, PHPWebDm, Math, ShellAPI,
   FindUserFrm, ImportExcelHintFrm, ConfigDoc, ExportExcel,
   ProjectCommands, BillsCompileDm, tpMainFrm,
-  DealBillsExcelImport, ExcelImport_Bills, DetailExcelImport;
+  DealBillsExcelImport, ExcelImport_Bills, DetailExcelImport,
+  stgGatherControl, stgSelectFileFrm;
 
 {$R *.dfm}
 {$R MeasureIcons.RES}
@@ -874,4 +884,49 @@ begin
   MeasureLog.AppendLogTo(AE.Message);
 end;
 
+procedure TMainForm.actnExportSumBaseFileExecute(Sender: TObject);
+var
+  sFileName: string;
+  Exportor: TTenderExport;
+  Rec: TsdDataRecord;
+begin
+  // 导出前先保存
+  CurProjectFrame.ProjectData.SaveAndCheck;
+  // 导出云版专用
+  sFileName := SupportManager.ConfigInfo.OutputPath + CurProjectFrame.ProjectData.ProjectName + '.sbf';
+  if SaveFile(sFileName, '.sbf') then
+  begin
+    if FileExists(sFileName) and not QuestMessage(Format('存在同名文件“%s”,是否替换?', [ExtractFileName(sFileName)])) then
+      Exit;
+
+    Screen.Cursor := crHourGlass;
+    try
+      Rec := ProjectManagerFrame.Rec(CurProjectFrame.ProjectData.ProjectID);
+      Exportor := TTenderExport.Create(Rec, sFileName);
+      try
+        Exportor.Execute;
+      finally
+        Exportor.Free;
+      end;
+    finally
+      Screen.Cursor := crDefault;
+    end;
+  end;
+end;
+
+procedure TMainForm.dxbtnGatherSubTenderClick(Sender: TObject);
+var
+  gc: TstgGatherControl;
+begin
+  gc := TstgGatherControl.Create;
+  Screen.Cursor := crHourGlass;
+  try
+    if SelectFileForSubTenderGather(gc) then
+      gc.Gather;
+  finally
+    gc.Free;
+    Screen.Cursor := crDefault;
+  end;
+end;
+
 end.

+ 11 - 14
Frames/BillsCompileFme.dfm

@@ -53,7 +53,7 @@ object BillsCompileFrame: TBillsCompileFrame
       Height = 376
       Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
       OptionsEx = []
-      ColCount = 23
+      ColCount = 26
       RowCount = 7
       FixedRowCount = 3
       ShowGridLine = False
@@ -640,7 +640,7 @@ object BillsCompileFrame: TBillsCompileFrame
         ReadOnly = False
       end
       item
-        Title.Caption = 'ID'
+        Title.Caption = 'ChapterParentID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
@@ -654,13 +654,13 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Style = []
-        FieldName = 'ID'
+        FieldName = 'ChapterParentID'
         Width = 50
         Visible = False
-        ReadOnly = True
+        ReadOnly = False
       end
       item
-        Title.Caption = 'ParentID'
+        Title.Caption = 'ID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
@@ -674,13 +674,12 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Style = []
-        FieldName = 'ParentID'
+        FieldName = 'ID'
         Width = 50
-        Visible = False
         ReadOnly = True
       end
       item
-        Title.Caption = 'NextSiblingID'
+        Title.Caption = 'ParentID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
@@ -694,13 +693,12 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Style = []
-        FieldName = 'NextSiblingID'
+        FieldName = 'ParentID'
         Width = 50
-        Visible = False
         ReadOnly = True
       end
       item
-        Title.Caption = 'ChapterParentID'
+        Title.Caption = 'NextSiblingID'
         Title.CaptionAcrossCols = '1'
         Title.CaptionAcrossRows = 3
         Title.Font.Charset = GB2312_CHARSET
@@ -714,10 +712,9 @@ object BillsCompileFrame: TBillsCompileFrame
         Font.Height = -12
         Font.Name = #23435#20307
         Font.Style = []
-        FieldName = 'ChapterParentID'
+        FieldName = 'NextSiblingID'
         Width = 50
-        Visible = False
-        ReadOnly = False
+        ReadOnly = True
       end>
     Grid = zgBillsCompile
     ExtendRowCount = 3

+ 414 - 0
SubTenderGather/stgGather.pas

@@ -0,0 +1,414 @@
+unit stgGather;
+
+interface
+
+uses
+  Classes, stgGatherCacheData, ProjectData, BillsTree, sdIDTree;
+
+type
+  TstgSumBaseFileLoader = class
+  private
+    FTree: TstgGatherTree;
+    FSumBaseFile: string;
+    FTempFolder: string;
+    FFileName: string;
+    FProjectData: TProjectData;
+
+    procedure LoadFileName;
+    function LoadTreeNodeData(ANode: TBillsIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+    procedure LoadSumBaseTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+  public
+    constructor Create(ATree: TstgGatherTree; const ASumBaseFile: string);
+    destructor Destroy; override;
+
+    procedure LoadData;
+  end;
+
+  TstgSubTenderFileGather = class
+  private
+    FCacheData: TstgGatherCacheData;
+    FProjectData: TProjectData;
+    FCurSubTenderID: Integer;
+    procedure GatherDetailData(AGatherNode: TstgGatherTreeNode; ASourceNode: TMeasureBillsIDTreeNode);
+    function GatherSubTenderTreeNodeData(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+    procedure GatherSubTenderTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+    procedure GatherSubTender(ASubTenderID: Integer);
+  public
+    procedure GatherTo(AGatherCacheData: TstgGatherCacheData; ASubTenders: TList);
+  end;
+
+  TstgErrorChecker = class
+  private
+    FCacheData: TstgGatherCacheData;
+
+    procedure NewError(ANode: TstgGatherTreeNode; AType: Integer);
+
+    function SafeCheckParent(ANode, ACheckParent: TstgGatherTreeNode): TstgGatherTreeNode;
+
+    // ACheckParent的子项(总包中存在),存在与ANode同编号节点
+    function HasSameCodeLevelChild(ANode: TstgGatherTreeNode;
+      ACheckParent: tstgGatherTreeNode = nil): Boolean;
+    // ACheckParent的子项(总包中存在),存在与ANode同编号、名称、单位,但不同层次节点
+    function HasSameChildWithDiffLevel(ANode: TstgGatherTreeNode;
+      ACheckParent: TstgGatherTreeNode = nil): Boolean;
+    // ACheckParent的子项(总包中存在)(含子项的子项),存在与ANode同编号节点
+    // 子项(含子项的子项),存在与CheckParent的子项(总包中存在)同编号节点
+
+    function HasShortRelaCodeChild(ANode: TstgGatherTreeNode): Boolean;
+    function HasLongRelaCodeChild(ANode:TstgGatherTreeNode): Boolean;
+    function HasXmjChildWithSameCodeChild(ANode: TstgGatherTreeNode): Boolean;
+
+    procedure AddXmjError(ANode: TstgGatherTreeNode);
+    procedure AddGclError(ANode: TstgGatherTreeNode);
+
+    procedure AddError(ANode: TstgGatherTreeNode);
+  public
+    procedure Check(AGatherCacheData: TstgGatherCacheData);
+  end;
+
+implementation
+
+uses Math, Globals, mDataRecord, UtilMethods, SysUtils, XMLDoc, XMLIntf,
+  CacheTree;
+
+{ TstgSumBaseFileLoader }
+
+constructor TstgSumBaseFileLoader.Create(ATree: TstgGatherTree;
+  const ASumBaseFile: string);
+begin
+  FTree := ATree;
+  FSumBaseFile := ASumBaseFile;
+  FTempFolder := GenerateTempFolder(GetTempFilePath);
+  FProjectData := TProjectData.Create;
+end;
+
+destructor TstgSumBaseFileLoader.Destroy;
+begin
+  if FileExists(FTempFolder) then
+    DeleteFolder(FTempFolder);
+  if Assigned(FProjectData) then
+    FProjectData.Free;
+  inherited;
+end;
+
+procedure TstgSumBaseFileLoader.LoadData;
+begin
+  UnZipFile(FSumBaseFile, FTempFolder);
+  LoadFileName;
+  FProjectData.OpenForSumUpBase(FTempFolder + '\' + FFileName);
+  LoadSumBaseTreeNode(FProjectData.BillsCompileData.BillsCompileTree.FirstNode, nil);
+  FTree.MarkLeafXmj;
+end;
+
+procedure TstgSumBaseFileLoader.LoadFileName;
+var
+  FXmlDocument: IXMLDocument;
+  RootXmlNode, InfoXmlNode: IXMLNode;
+  ChildNodes: IXMLNodeList;
+begin
+  FXmlDocument := TXMLDocument.Create(nil) as IXMLDocument;
+  try
+    FXmlDocument.LoadFromFile(FTempFolder + '\Info.xml');
+    FXmlDocument.Options := [doNodeAutoCreate,doNodeAutoIndent,doAutoPrefix,doNamespaceDecl];
+    RootXmlNode := FXmlDocument.DocumentElement;
+
+    ChildNodes := RootXmlNode.ChildNodes;
+    InfoXmlNode := ChildNodes.FindNode('ProjectInfo');
+
+    FFileName := InfoXmlNode.Attributes['FileName'];
+  finally
+    FXmlDocument := nil;
+  end;
+end;
+
+procedure TstgSumBaseFileLoader.LoadSumBaseTreeNode(ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+var
+  vCurGatherNode: TstgGatherTreeNode;
+begin
+  if not Assigned(ANode) then Exit;
+  vCurGatherNode := LoadTreeNodeData(TBillsIDTreeNode(ANode), AParent);
+  LoadSumBaseTreeNode(ANode.FirstChild, vCurGatherNode);
+  LoadSumBaseTreeNode(ANode.NextSibling, AParent);
+end;
+
+function TstgSumBaseFileLoader.LoadTreeNodeData(ANode: TBillsIDTreeNode;
+  AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+begin
+  Result := FTree.AddSumBaseNode(AParent, ANode.ID);
+  Result.Code := ANode.Rec.Code.AsString;
+  Result.B_Code := ANode.Rec.B_Code.AsString;
+  Result.Name := ANode.Rec.Name.AsString;
+  Result.Units := ANode.Rec.Units.AsString;
+end;
+
+{ TstgSubTenderFileGather }
+
+procedure TstgSubTenderFileGather.GatherDetailData(
+  AGatherNode: TstgGatherTreeNode; ASourceNode: TMeasureBillsIDTreeNode);
+var
+  vSubTender: TstgSubTenderStageData;
+begin
+  //if Assigned(ASourceNode.StageRec) and
+  //   ((ASourceNode.StageRec.GatherQuantity.AsFloat <> 0) or (ASourceNode.StageRec.GatherTotalPrice.AsFloat <> 0)) then
+  
+  if not ASourceNode.HasChildren then
+  begin
+    vSubTender := AGatherNode.SafeSubTender(FCurSubTenderID);
+    vSubTender.AddDetail(ASourceNode);
+  end;
+end;
+
+procedure TstgSubTenderFileGather.GatherSubTender(ASubTenderID: Integer);
+var
+  vNode: TsdIDTreeNode;
+begin
+  FCurSubTenderID := ASubTenderID;
+  vNode := ProjectManager.ProjectsTree.FindNode(ASubTenderID);
+  if vNode.Rec.ValueByName('Type').AsInteger = 1 then
+  begin
+    FProjectData := TProjectData.Create;
+    try
+      FProjectData.OpenForSumUpGather(GetMyProjectsFilePath + vNode.Rec.ValueByName('FileName').AsString);
+      FCacheData.AddSubTender(vNode.Rec);
+      GatherSubTenderTreeNode(FProjectData.BillsMeasureData.BillsMeasureTree.FirstNode, nil);
+    finally
+      FProjectData.Free;
+    end;
+  end;
+end;
+
+procedure TstgSubTenderFileGather.GatherSubTenderTreeNode(
+  ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode);
+var
+  vCur: TstgGatherTreeNode;
+begin
+  if not Assigned(ANode) then Exit;
+  vCur := GatherSubTenderTreeNodeData(ANode, AParent);
+  GatherSubTenderTreeNode(ANode.FirstChild, vCur);
+  GatherSubTenderTreeNode(ANode.NextSibling, AParent);
+end;
+
+function TstgSubTenderFileGather.GatherSubTenderTreeNodeData(
+  ANode: TsdIDTreeNode; AParent: TstgGatherTreeNode): TstgGatherTreeNode;
+var
+  vNode: TMeasureBillsIDTreeNode;
+  vNext: TstgGatherTreeNode;
+begin
+  vNode := TMeasureBillsIDTreeNode(ANode);
+  if ANode.ID <= 100 then
+    Result := FCacheData.GatherTree.FindNode(ANode.ID)
+  else
+    Result := FCacheData.GatherTree.FindNode(AParent, vNode);
+
+  if not Assigned(Result) then
+  begin
+    if not Assigned(AParent) or (not (AParent.IsSumBase and AParent.IsLeafXmj)) or (not ANode.HasChildren) then
+    begin
+      if ANode.ID < 100 then
+        Result := FCacheData.GatherTree.AddSubTenderNode(AParent, nil, ANode.ID)
+      else
+        Result := FCacheData.GatherTree.AddSubTenderNode(AParent, nil);
+      Result.Code := vNode.Rec.Code.AsString;
+      Result.B_Code := vNode.Rec.B_Code.AsString;
+      Result.Name := vNode.Rec.Name.AsString;
+      Result.Units := vNode.Rec.Units.AsString
+    end
+    else
+      Result := AParent;
+  end;
+
+  if Assigned(Result) then
+    GatherDetailData(Result, vNode)
+  else
+    Result := AParent;
+end;
+
+procedure TstgSubTenderFileGather.GatherTo(AGatherCacheData: TstgGatherCacheData;
+  ASubTenders: TList);
+var
+  i, iSubTenderID: Integer;
+begin
+  FCacheData := AGatherCacheData;
+  for i := 0 to ASubTenders.Count - 1 do
+    GatherSubTender(Integer(ASubTenders.Items[i]));
+  FCacheData.GatherTree.CalculateAll;
+end;
+
+{ TstgErrorChecker }
+
+procedure TstgErrorChecker.AddError(ANode: TstgGatherTreeNode);
+begin
+  if ANode.IsGclBills then
+    AddGclError(ANode)
+  else
+    AddXmjError(ANode);
+end;
+
+procedure TstgErrorChecker.AddGclError(ANode: TstgGatherTreeNode);
+begin
+  if HasXmjChildWithSameCodeChild(ANode) then
+    NewError(ANode, iErrorXmjLess)
+  else if HasLongRelaCodeChild(ANode) then
+    NewError(ANode, iErrorGclLess)
+  else if HasShortRelaCodeChild(ANode) then
+    NewError(ANode, iErrorGclMore)
+  else if HasSameChildWithDiffLevel(ANode) then
+    NewError(ANode, iErrorGclMore)
+  else if HasSameCodeLevelChild(ANode) then
+    NewError(ANode, iErrorGclDiff)
+  else
+    NewError(ANode, iErrorGclAdd);
+end;
+
+procedure TstgErrorChecker.AddXmjError(ANode: TstgGatherTreeNode);
+begin
+  if HasSameCodeLevelChild(ANode) then
+    NewError(ANode, iErrorXmjDiff)
+  else
+    NewError(ANode, iErrorXmjAdd);
+end;
+
+procedure TstgErrorChecker.Check(AGatherCacheData: TstgGatherCacheData);
+var
+  i: Integer;
+  vNode, vParent: TstgGatherTreeNode;
+begin
+  FCacheData := AGatherCacheData;
+  for i := 0 to FCacheData.GatherTree.CacheNodes.Count - 1 do
+  begin
+    vNode := TstgGatherTreeNode(FCacheData.GatherTree.CacheNodes[i]);
+    vParent := TstgGatherTreeNode(vNode.Parent);
+    if vNode.IsSubTender and (not Assigned(vParent) or not vParent.IsSubTender) then
+      AddError(vNode);
+  end;
+end;
+
+function TstgErrorChecker.HasLongRelaCodeChild(
+  ANode: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, nil);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if Pos(ANode.B_Code + '-', vChild.B_Code) = 1 then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasSameChildWithDiffLevel(ANode,
+  ACheckParent: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, ACheckParent);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if vChild.IsSumBase and (vChild.Code = ANode.Code) and
+       (vChild.B_Code = ANode.B_Code) and (vChild.Name = ANode.Name) and
+       (vChild.Units = ANode.Units) and (vChild.IsLeaf = vChild.IsLeaf) then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasSameCodeLevelChild(ANode,
+  ACheckParent: tstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, ACheckParent);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if vChild.IsSumBase and (vChild.Code = ANode.Code) and (vChild.B_Code = ANode.B_Code) and (vChild.IsLeaf = vChild.IsLeaf) then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasShortRelaCodeChild(
+  ANode: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, nil);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if Pos(vChild.B_Code + '-', ANode.B_Code) = 1 then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function TstgErrorChecker.HasXmjChildWithSameCodeChild(
+  ANode: TstgGatherTreeNode): Boolean;
+var
+  vParent, vChild: TstgGatherTreeNode;
+  i: Integer;
+begin
+  Result := False;
+  vParent := SafeCheckParent(ANode, nil);
+  for i := 0 to vParent.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(vParent.Children.Items[i]);
+    if not vChild.IsGclBills and ANode.IsGclBills then
+    begin
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+procedure TstgErrorChecker.NewError(ANode: TstgGatherTreeNode;
+  AType: Integer);
+
+  procedure RecursiveNewError(AParent: TstgGatherTreeNode);
+  var
+    i: Integer;
+  begin
+    if AParent.Children.Count > 0 then
+    begin
+      for i := 0 to AParent.Children.Count - 1 do
+        RecursiveNewError(TstgGatherTreeNode(AParent.Children.Items[i]));
+    end
+    else
+      FCacheData.AddError(ANode, AParent, AType);
+  end;
+
+begin
+  RecursiveNewError(ANode);
+end;
+
+function TstgErrorChecker.SafeCheckParent(ANode,
+  ACheckParent: TstgGatherTreeNode): TstgGatherTreeNode;
+begin
+  if Assigned(ACheckParent) then
+    Result := ACheckParent
+  else if Assigned(ANode.Parent) then
+    Result := TstgGatherTreeNode(ANode.Parent)
+  else
+    Result := TstgGatherTreeNode(FCacheData.GatherTree.Root);
+end;
+
+end.

+ 718 - 0
SubTenderGather/stgGatherCacheData.pas

@@ -0,0 +1,718 @@
+unit stgGatherCacheData;
+
+interface
+
+uses
+  CacheTree, SysUtils, BillsTree, Classes, sdDB, mDataRecord;
+
+const
+  // 新增项目节
+  iErrorXmjAdd = 1;
+  // 存在同号项目节,但名称、单价不同
+  iErrorXmjDiff = 2;
+  // 项目节层次少于总包
+  iErrorXmjLess = 3;
+
+  // 新增工程量清单
+  iErrorGclAdd = 11;
+  // 存在同名工程量清单,但名称、单价不同
+  iErrorGclDiff = 12;
+  // 工程量清单层次多于总包
+  iErrorGclMore = 13;
+  // 工程量清单层次少于总包
+  iErrorGclLess = 14;
+
+type
+  TstgStageData = class
+  private
+    FDealQuantity: Double;
+    FDealTotalPrice: Double;
+    FQcQuantity: Double;
+    FQcTotalPrice: Double;
+    FQcBGLCode: string;
+    FQcBGLNum: string;
+
+    procedure AddBGLCodeAndNum(ACode, ANum: string);
+  public
+    procedure ClearData;
+    procedure AddStageData(AStageData: TstgStageData);
+    procedure AssignedData(AStageRecord: TStageRecord);
+
+    property DealQuantity: Double read FDealQuantity;
+    property DealTotalPrice: Double read FDealTotalPrice;
+    property QcQuantity: Double read FQcQuantity;
+    property QcTotalPrice: Double read FQcTotalPrice;
+    property QcBGLCode: string read FQcBGLCode;
+    property QcBGLNum: string read FQcBGLNum;
+  end;
+
+  TstgSubTenderDetailData = class
+  private
+    FSerialNo: Integer;
+    FLeafXmjCode: string;
+    FDetailStage: TstgStageData;
+  public
+    constructor Create(ANode: TMeasureBillsIDTreeNode);
+    destructor Destroy; override;
+
+    property SerialNo: Integer read FSerialNo;
+    property LeafXmjCode: string read FLeafXmjCode;
+    property DetailStage: TstgStageData read FDetailStage;
+  end;
+
+  TstgSubTenderStageData = class
+  private
+    FSubTenderID: Integer;
+    FGather: TstgStageData;
+    FDetails: TList;
+    function GetDetail(AIndex: Integer): TstgSubTenderDetailData;
+    function GetDetailCount: Integer;
+  public
+    constructor Create(ASubTenderID: Integer);
+    destructor Destroy; override;
+
+    function AddDetail(ANode: TMeasureBillsIDTreeNode): TstgSubTenderDetailData;
+
+    procedure CalculateGather;
+
+    property SubTenderID: Integer read FSubTenderID;
+    property Gather: TstgStageData read FGather;
+    property DetailCount: Integer read GetDetailCount;
+    property Detail[AIndex: Integer]: TstgSubTenderDetailData read GetDetail;
+  end;
+
+  TstgGatherTreeNode = class(TCacheNode)
+  private
+    FCode: string;
+    FB_Code: string;
+    FName: string;
+    FUnits: string;
+
+    FIsSumBase: Boolean;
+    FIsLeafXmj: Boolean;
+    FIsLeaf: Boolean;
+    FIsSubTender: Boolean;
+
+    FGather: TstgStageData;
+    FSubTenders: TList;
+    function GetIsGclBills: Boolean;
+    function GetSubTender(AIndex: Integer): TstgSubTenderStageData;
+    function GetSubTenderCount: Integer;
+  public
+    constructor Create(ATree: TCacheTree; AID: Integer); override;
+    destructor Destroy; override;
+
+    function FindSubTender(ASubTenderID: Integer): TstgSubTenderStageData;
+    function SafeSubTender(ASubTenderID: Integer): TstgSubTenderStageData;
+
+    procedure CalculateGather;
+
+    property Code: string read FCode write FCode;
+    property B_Code: string read FB_Code write FB_Code;
+    property Name: string read FName write FName;
+    property Units: string read FUnits write FUnits;
+
+    property IsSumBase: Boolean read FIsSumBase write FIsSumBase;
+    property IsLeafXmj: Boolean read FIsLeafXmj write FIsLeafXmj;
+    property IsLeaf: Boolean read FIsLeaf write FIsLeaf;
+    property IsSubTender: Boolean read FIsSubTender write FIsSubTender;
+
+    property IsGclBills: Boolean read GetIsGclBills;
+
+    property SubTenderCount: Integer read GetSubTenderCount;
+    property SubTender[AIndex: Integer]: TstgSubTenderStageData read GetSubTender;
+
+    property Gather: TstgStageData read FGather;
+  end;
+
+  TstgGatherTree = class(TCacheTree)
+  private
+    FFixedNodes: TCacheNodeList;
+    // -1的情况下默认自动赋值一个新的ID
+    function GetNewNode(AID: Integer = -1): TstgGatherTreeNode; overload;
+
+    function CheckLeafXmj(ANode: TstgGatherTreeNode): Boolean;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+
+    function FindNextSibling(AParent: TCacheNode; ACode: string): TstgGatherTreeNode;
+    function FindNode(AParent: TCacheNode; AInfo: TBillsIDTreeNode): TstgGatherTreeNode; overload;
+    function FindNode(AID: Integer): TstgGatherTreeNode; overload;
+
+    function AddFixedNode(AParent: TCacheNode; ANextSibling:
+      TCacheNode = nil; AFixedID: Integer = -1): TstgGatherTreeNode;
+    function AddNode(AParent: TCacheNode; ANextSibling:
+      TCacheNode = nil; ASumBaseID: Integer = -1): TstgGatherTreeNode;
+
+    function AddSumBaseNode(AParent: TCacheNode; ASumBaseID: Integer): TstgGatherTreeNode;
+    function AddSubTenderNode(AParent: TCacheNode; ANextSibling: TCacheNode; AFixedID: Integer = -1): TstgGatherTreeNode;
+
+    // Only for Debugging lot of Data
+    procedure SaveTreeToFile(const AFileName: string);
+
+    procedure MarkLeafXmj;
+    procedure CalculateAll;
+  end;
+
+  TstgGatherSubTender = class
+  private
+    FID: Integer;
+    FRec: TsdDataRecord;
+  public
+    constructor Create(ARec: TsdDataRecord);
+
+    property ID: Integer read FID;
+    property Rec: TsdDataRecord read FRec;
+  end;
+
+  TstgErrorInfo = class
+  private
+    FRelaNode: TstgGatherTreeNode;
+    FErrorType: Integer;
+
+    FDetails: TList;
+    function GetDetail(AIndex: Integer): TstgGatherTreeNode;
+    function GetDetailCount: Integer;
+  public
+    constructor Create(ARelaNode: TstgGatherTreeNode);
+    destructor Destroy; override;
+
+    procedure AddErrorDetail(ARelaDetailNode: TstgGatherTreeNode);
+
+    property RelaNode: TstgGatherTreeNode read FRelaNode;
+    property ErrorType: Integer read FErrorType write FErrorType;
+
+    property DetailCount: Integer read GetDetailCount;
+    property Detail[AIndex: Integer]: TstgGatherTreeNode read GetDetail;
+  end;
+
+  TstgGatherCacheData = class
+  private
+    FGatherTree: TstgGatherTree;
+    FSubTenders: TList;
+    FErrors: TList;
+
+    function FindError(ANode: TstgGatherTreeNode): TstgErrorInfo;
+    function NewError(ANode: TstgGatherTreeNode; AErrorType: Integer): TstgErrorInfo;
+
+    function GetSubTenderCount: Integer;
+    function GetSubTender(AIndex: Integer): TstgGatherSubTender;
+    function GetErrorCount: Integer;
+    function GetError(AIndex: Integer): TstgErrorInfo;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    function FindSubTender(AID: Integer): TstgGatherSubTender;
+    function AddSubTender(ARec: TsdDataRecord): TstgGatherSubTender;
+
+    procedure AddError(ANode, ALeafErrorNode: TstgGatherTreeNode; AErrorType: Integer);
+
+    property SubTenderCount: Integer read GetSubTenderCount;
+    property SubTender[AIndex: Integer]: TstgGatherSubTender read GetSubTender;
+
+    property ErrorCount: Integer read GetErrorCount;
+    property Error[AIndex: Integer]: TstgErrorInfo read GetError;
+
+    property GatherTree: TstgGatherTree read FGatherTree;
+  end;
+
+implementation
+
+uses
+  ZhAPI, UtilMethods, Math;
+
+{ TstgGatherTreeNode }
+
+procedure TstgGatherTreeNode.CalculateGather;
+var
+  i: Integer;
+  vSubTender: TstgSubTenderDetailData;
+begin
+  FGather.ClearData;
+  for i := 0 to FSubTenders.Count - 1 do
+  begin
+    SubTender[i].CalculateGather;
+    FGather.AddStageData(SubTender[i].Gather);
+  end;
+end;
+
+constructor TstgGatherTreeNode.Create(ATree: TCacheTree; AID: Integer);
+begin
+  inherited Create(ATree, AID);
+  FSubTenders := TList.Create;
+  FGather := TstgStageData.Create;
+end;
+
+destructor TstgGatherTreeNode.Destroy;
+begin
+  FGather.Free;
+  ClearObjects(FSubTenders);
+  FSubTenders.Free;
+  inherited;
+end;
+
+function TstgGatherTreeNode.FindSubTender(
+  ASubTenderID: Integer): TstgSubTenderStageData;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to FSubTenders.Count - 1 do
+  begin
+    if ASubTenderID = SubTender[i].SubTenderID then
+    begin
+      Result := SubTender[i];
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherTreeNode.GetIsGclBills: Boolean;
+begin
+  Result := FB_Code <> '';
+end;
+
+function TstgGatherTreeNode.GetSubTender(
+  AIndex: Integer): TstgSubTenderStageData;
+begin
+  Result := TstgSubTenderStageData(FSubTenders.Items[AIndex]);
+end;
+
+function TstgGatherTreeNode.GetSubTenderCount: Integer;
+begin
+  Result := FSubTenders.Count;
+end;
+
+function TstgGatherTreeNode.SafeSubTender(
+  ASubTenderID: Integer): TstgSubTenderStageData;
+begin
+  Result := FindSubTender(ASubTenderID);
+  if not Assigned(Result) then
+  begin
+    Result := TstgSubTenderStageData.Create(ASubTenderID);
+    FSubTenders.Add(Result);
+  end;
+end;
+
+{ TstgGatherTree }
+
+function TstgGatherTree.AddFixedNode(AParent, ANextSibling: TCacheNode;
+  AFixedID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(AFixedID);
+  if Assigned(ANextSibling) then
+    ANextSibling.InsertPreSibling(Result)
+  else if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+  FFixedNodes.Add(Result);
+end;
+
+function TstgGatherTree.AddNode(AParent, ANextSibling: TCacheNode;
+  ASumBaseID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(ASumBaseID);
+  if Assigned(ANextSibling) then
+    ANextSibling.InsertPreSibling(Result)
+  else if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+end;
+
+function TstgGatherTree.AddSubTenderNode(AParent, ANextSibling: TCacheNode;
+  AFixedID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(AFixedID);
+  Result.IsSubTender := True;
+
+  if Assigned(ANextSibling) then
+    ANextSibling.InsertPreSibling(Result)
+  else if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+end;
+
+function TstgGatherTree.AddSumBaseNode(AParent: TCacheNode;
+  ASumBaseID: Integer): TstgGatherTreeNode;
+begin
+  Result := GetNewNode(ASumBaseID);
+  Result.IsSumBase := True;
+
+  if Assigned(AParent) then
+    AParent.InsertChild(Result)
+  else
+    Root.InsertChild(Result);
+end;
+
+procedure TstgGatherTree.CalculateAll;
+var
+  i: Integer;
+begin
+  for i := 0 to CacheNodes.Count - 1 do
+    TstgGatherTreeNode(CacheNodes[i]).CalculateGather;
+end;
+
+function TstgGatherTree.CheckLeafXmj(ANode: TstgGatherTreeNode): Boolean;
+var
+  iChild: Integer;
+  vChild: TstgGatherTreeNode;
+begin
+  Result := True;
+  for iChild := 0 to ANode.Children.Count - 1 do
+  begin
+    vChild := TstgGatherTreeNode(ANode.Children.Items[iChild]);
+    if vChild.FB_Code = '' then
+    begin
+      Result := False;
+      Break;
+    end;
+  end;
+end;
+
+constructor TstgGatherTree.Create;
+begin
+  inherited;
+  FFixedNodes := TCacheNodeList.Create;
+  NewNodeID := 100;
+end;
+
+destructor TstgGatherTree.Destroy;
+begin
+  FFixedNodes.Free;
+  inherited;
+end;
+
+function TstgGatherTree.FindNextSibling(AParent: TCacheNode;
+  ACode: string): TstgGatherTreeNode;
+begin
+
+end;
+
+function TstgGatherTree.FindNode(AID: Integer): TstgGatherTreeNode;
+var
+  i: Integer;
+  Node: TCacheNode;
+begin
+  Result := nil;
+  for i := 0 to FFixedNodes.Count - 1 do
+  begin
+    Node := FFixedNodes.Items[i];
+    if Node.ID = AID then
+    begin
+      Result := TstgGatherTreeNode(Node);
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherTree.FindNode(AParent: TCacheNode;
+  AInfo: TBillsIDTreeNode): TstgGatherTreeNode;
+var
+  vNode: TstgGatherTreeNode;
+begin
+  Result := nil;
+  if Assigned(AParent) then
+    vNode := TstgGatherTreeNode(AParent.FirstChild)
+  else
+    vNode := TstgGatherTreeNode(Root.FirstChild);
+
+  while Assigned(vNode) and not Assigned(Result) do
+  begin
+    if SameText(vNode.Code, AInfo.Rec.Code.AsString) and SameText(vNode.B_Code, AInfo.Rec.B_Code.AsString)
+        and SameText(vNode.Name, AInfo.Rec.Name.AsString) and SameText(vNode.Units, AInfo.Rec.Units.AsString) then
+      Result := vNode;
+    vNode := TstgGatherTreeNode(vNode.NextSibling);
+  end;
+end;
+
+function TstgGatherTree.GetNewNode(AID: Integer): TstgGatherTreeNode;
+begin
+  if AID = -1 then
+    Result := TstgGatherTreeNode.Create(Self, GetNewNodeID)
+  else
+    Result := TstgGatherTreeNode.Create(Self, AID);
+  NewNodeID := Max(NewNodeID, AID + 1);
+  CacheNodes.Add(Result);
+  if AID < 100 then
+    FFixedNodes.Add(Result);
+end;
+
+procedure TstgGatherTree.MarkLeafXmj;
+var
+  i: Integer;
+  vNode: TstgGatherTreeNode;
+begin
+  for i := 0 to CacheNodes.Count - 1 do
+  begin
+    vNode := TstgGatherTreeNode(CacheNodes.Items[i]);
+    vNode.IsLeafXmj := CheckLeafXmj(vNode);
+  end;
+end;
+
+procedure TstgGatherTree.SaveTreeToFile(const AFileName: string);
+var
+  sgs: TStringList;
+  I: Integer;
+  Node: TstgGatherTreeNode;
+begin
+  sgs := TStringList.Create;
+  try
+    for I := 0 to CacheNodes.Count - 1 do
+    begin
+      Node := TstgGatherTreeNode(CacheNodes.Items[I]);
+      sgs.Add(Format('ID: %3d; ParentID: %3d; NextID: %3d; Code: %s; B_Code: %s; Name: %s;',
+        [Node.ID, Node.ParentID, Node.NextSiblingID, Node.Code, Node.B_Code, Node.Name]));
+    end;
+    sgs.SaveToFile(AFileName);
+  finally
+    sgs.Free;
+  end;
+end;
+
+{ TstgGatherCacheData }
+
+procedure TstgGatherCacheData.AddError(ANode,
+  ALeafErrorNode: TstgGatherTreeNode; AErrorType: Integer);
+var
+  vError: TstgErrorInfo;
+begin
+  vError := FindError(ANode);
+  if not Assigned(vError) then
+    vError := NewError(ANode, AErrorType);
+  vError.AddErrorDetail(ALeafErrorNode);
+end;
+
+function TstgGatherCacheData.AddSubTender(
+  ARec: TsdDataRecord): TstgGatherSubTender;
+begin
+  Result := FindSubTender(ARec.ValueByName('ID').AsInteger);
+  if not Assigned(Result) then
+  begin
+    Result := TstgGatherSubTender.Create(ARec);
+    FSubTenders.Add(Result);
+  end;
+end;
+
+constructor TstgGatherCacheData.Create;
+begin
+  FGatherTree := TstgGatherTree.Create;
+  FSubTenders := TList.Create;
+  FErrors := TList.Create;
+end;
+
+destructor TstgGatherCacheData.Destroy;
+begin
+  ClearObjects(FErrors);
+  FErrors.Free;
+  ClearObjects(FSubTenders);
+  FSubTenders.Free;
+  FGatherTree.Free;
+  inherited;
+end;
+
+function TstgGatherCacheData.FindError(
+  ANode: TstgGatherTreeNode): TstgErrorInfo;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to ErrorCount - 1 do
+  begin
+    if Error[i].RelaNode = ANode then
+    begin
+      Result := Error[i];
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherCacheData.FindSubTender(
+  AID: Integer): TstgGatherSubTender;
+var
+  i: Integer;
+begin
+  Result := nil;
+  for i := 0 to SubTenderCount - 1 do
+  begin
+    if SubTender[i].ID = AID then
+    begin
+      Result := SubTender[i];
+      Break;
+    end;
+  end;
+end;
+
+function TstgGatherCacheData.GetError(AIndex: Integer): TstgErrorInfo;
+begin
+  Result := TstgErrorInfo(FErrors.Items[AIndex]);
+end;
+
+function TstgGatherCacheData.GetErrorCount: Integer;
+begin
+  Result := FErrors.Count;
+end;
+
+function TstgGatherCacheData.GetSubTender(AIndex: Integer): TstgGatherSubTender;
+begin
+  Result := TstgGatherSubTender(FSubTenders.Items[AIndex]);
+end;
+
+function TstgGatherCacheData.GetSubTenderCount: Integer;
+begin
+  Result := FSubTenders.Count;
+end;
+
+function TstgGatherCacheData.NewError(
+  ANode: TstgGatherTreeNode; AErrorType: Integer): TstgErrorInfo;
+begin
+  Result := TstgErrorInfo.Create(ANode);
+  Result.ErrorType := AErrorType;
+  FErrors.Add(Result);
+end;
+
+{ TstgGatherSubTender }
+
+constructor TstgGatherSubTender.Create(ARec: TsdDataRecord);
+begin
+  FID := ARec.ValueByName('ID').AsInteger;
+  FRec := ARec;
+end;
+
+{ TstgStageData }
+
+procedure TstgStageData.AddBGLCodeAndNum(ACode, ANum: string);
+var
+  sCode, sNum: string;
+begin
+  sCode := FQcBGLCode;
+  sNum := FQcBGLNum;
+  MergeRelaBGLAndNum(sCode, sNum, ACode, ANum);
+  FQcBGLCode := sCode;
+  FQcBGLNum := sNum;
+end;
+
+procedure TstgStageData.AddStageData(AStageData: TstgStageData);
+begin
+  FDealQuantity := FDealQuantity + AStageData.DealQuantity;
+  FDealTotalPrice := FDealTotalPrice + AStageData.DealTotalPrice;
+  FQcQuantity := FQcQuantity + AStageData.QcQuantity;
+  FQcTotalPrice := FQcTotalPrice + AStageData.QcTotalPrice;
+  AddBGLCodeAndNum(AStageData.QcBGLCode, AStageData.QcBGLNum);
+end;
+
+procedure TstgStageData.AssignedData(AStageRecord: TStageRecord);
+begin
+  FDealQuantity := AStageRecord.DealQuantity.AsFloat;
+  FDealTotalPrice := AStageRecord.DealTotalPrice.AsFloat;
+  FQcQuantity := AStageRecord.QcQuantity.AsFloat;
+  FQcTotalPrice := AStageRecord.QcTotalPrice.AsFloat;
+  FQcBGLCode := AStageRecord.QcBGLCode.AsString;
+  FQcBGLNum := AStageRecord.QcBGLNum.AsString;
+end;
+
+procedure TstgStageData.ClearData;
+begin
+  FDealQuantity := 0;
+  FDealTotalPrice := 0;
+  FQcQuantity := 0;
+  FQcTotalPrice := 0;
+  FQcBGLCode := '';
+  FQcBGLNum := '';
+end;
+
+{ TstgSubTenderStageData }
+
+function TstgSubTenderStageData.AddDetail(
+  ANode: TMeasureBillsIDTreeNode): TstgSubTenderDetailData;
+begin
+  Result := TstgSubTenderDetailData.Create(ANode);
+  FDetails.Add(Result);
+end;
+
+procedure TstgSubTenderStageData.CalculateGather;
+var
+  i: Integer;
+begin
+  FGather.ClearData;
+  for i := 0 to DetailCount - 1 do
+    FGather.AddStageData(Detail[i].DetailStage);
+end;
+
+constructor TstgSubTenderStageData.Create(ASubTenderID: Integer);
+begin
+  FSubTenderID := ASubTenderID;
+  FGather := TstgStageData.Create;
+  FDetails := TList.Create;
+end;
+
+destructor TstgSubTenderStageData.Destroy;
+begin
+  ClearObjects(FDetails);
+  FDetails.Free;
+  FGather.Free;
+  inherited;
+end;
+
+function TstgSubTenderStageData.GetDetail(
+  AIndex: Integer): TstgSubTenderDetailData;
+begin
+  Result := TstgSubTenderDetailData(FDetails.Items[AIndex]);
+end;
+
+function TstgSubTenderStageData.GetDetailCount: Integer;
+begin
+  Result := FDetails.Count;
+end;
+
+{ TstgSubTenderDetailData }
+
+constructor TstgSubTenderDetailData.Create(ANode: TMeasureBillsIDTreeNode);
+begin
+  FSerialNo := ANode.MajorIndex;
+  FDetailStage := TstgStageData.Create;
+  if Assigned(ANode.StageRec) then
+    FDetailStage.AssignedData(ANode.StageRec);
+end;
+
+destructor TstgSubTenderDetailData.Destroy;
+begin
+  FDetailStage.Free;
+  inherited;
+end;
+
+{ TstgErrorInfo }
+
+procedure TstgErrorInfo.AddErrorDetail(
+  ARelaDetailNode: TstgGatherTreeNode);
+begin
+  FDetails.Add(ARelaDetailNode);
+end;
+
+constructor TstgErrorInfo.Create(ARelaNode: TstgGatherTreeNode);
+begin
+  FRelaNode := ARelaNode;
+  FDetails := TList.Create;
+end;
+
+destructor TstgErrorInfo.Destroy;
+begin
+  FDetails.Free;
+  inherited;
+end;
+
+function TstgErrorInfo.GetDetail(AIndex: Integer): TstgGatherTreeNode;
+begin
+  Result :=  TstgGatherTreeNode(FDetails.Items[AIndex]);
+end;
+
+function TstgErrorInfo.GetDetailCount: Integer;
+begin
+  Result := FDetails.Count;
+end;
+
+end.

+ 110 - 0
SubTenderGather/stgGatherControl.pas

@@ -0,0 +1,110 @@
+unit stgGatherControl;
+
+interface
+
+uses
+  Classes, stgGatherCacheData, stgGatherDm, stgResultFrm,
+  stgGather;
+
+type
+  TstgGatherControl = class
+  private
+    FProjects: TList;
+    FSumBaseFile: string;
+
+    FGatherCacheData: tstgGatherCacheData;
+    FGatherData: TstgGatherData;
+    FResultForm: TstgResultForm;
+
+    procedure LoadSumBaseFile;
+    procedure GatherSubTenderFiles;
+    procedure CheckErrorData;
+    procedure SaveGatherResult;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    procedure Gather;
+
+    property Projects: TList read FProjects;
+    property SumBaseFile: string read FSumBaseFile write FSumBaseFile;
+  end;
+
+implementation
+
+{ TstgGatherControl }
+
+procedure TstgGatherControl.CheckErrorData;
+var
+  vChecker: TstgErrorChecker;
+begin
+  vChecker := TstgErrorChecker.Create;
+  try
+    vChecker.Check(FGatherCacheData);
+  finally
+    vChecker.Free;
+  end;
+end;
+
+constructor TstgGatherControl.Create;
+begin
+  FProjects := TList.Create;
+  FGatherCacheData := TstgGatherCacheData.Create;
+  FGatherData := TstgGatherData.Create(nil);
+end;
+
+destructor TstgGatherControl.Destroy;
+begin
+  FGatherData.Free;
+  FGatherCacheData.Free;
+  FProjects.Free;
+  inherited;
+end;
+
+procedure TstgGatherControl.Gather;
+begin
+  LoadSumBaseFile;
+  GatherSubTenderFiles;
+  CheckErrorData;
+  SaveGatherResult;
+end;
+
+procedure TstgGatherControl.GatherSubTenderFiles;
+var
+  vGather: TstgSubTenderFileGather;
+begin
+  vGather := TstgSubTenderFileGather.Create;
+  try
+    vGather.GatherTo(FGatherCacheData, FProjects);
+  finally
+    vGather.Free;
+  end;
+end;
+
+procedure TstgGatherControl.LoadSumBaseFile;
+var
+  vLoader: TstgSumBaseFileLoader;
+begin
+  vLoader := TstgSumBaseFileLoader.Create(FGatherCacheData.GatherTree, FSumBaseFile);
+  try
+    vLoader.LoadData;
+  finally
+    vLoader.Free;
+  end;
+end;
+
+procedure TstgGatherControl.SaveGatherResult;
+var
+  Form: TstgResultForm;
+begin
+  FGatherData.LoadGatherData(FGatherCacheData);
+  Form := TstgResultForm.Create(nil);
+  try
+    Form.SetGatherData(FGatherData);
+    Form.ShowModal;
+  finally
+    Form.Free;
+  end;
+end;
+
+end.

+ 295 - 0
SubTenderGather/stgGatherDm.dfm

@@ -0,0 +1,295 @@
+object stgGatherData: TstgGatherData
+  OldCreateOrder = False
+  Left = 192
+  Top = 123
+  Height = 253
+  Width = 482
+  object smpGatherTree: TsdMemoryProvider
+    Left = 40
+    Top = 24
+  end
+  object sddGatherTree: TsdDataSet
+    Active = True
+    Provider = smpGatherTree
+    Left = 40
+    Top = 87
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650809507265636973696F6E02000453697A6502000001044E616D
+      650608506172656E744944094669656C644E616D650608506172656E74494408
+      44617461547970650203084461746153697A6502040549734B6579080F4E6565
+      6450726F636573734E616D650809507265636973696F6E02000453697A650200
+      0001044E616D65060D4E6578745369626C696E674944094669656C644E616D65
+      060D4E6578745369626C696E6749440844617461547970650203084461746153
+      697A6502040549734B6579080F4E65656450726F636573734E616D6508095072
+      65636973696F6E02000453697A6502000001044E616D650604436F6465094669
+      656C644E616D650604436F64650844617461547970650218084461746153697A
+      6502320549734B6579080F4E65656450726F636573734E616D65080950726563
+      6973696F6E02000453697A6502000001044E616D650606425F436F6465094669
+      656C644E616D650606425F436F64650844617461547970650218084461746153
+      697A6502320549734B6579080F4E65656450726F636573734E616D6508095072
+      65636973696F6E02000453697A6502000001044E616D6506044E616D65094669
+      656C644E616D6506044E616D650844617461547970650218084461746153697A
+      6503FF000549734B6579080F4E65656450726F636573734E616D650809507265
+      636973696F6E02000453697A6502000001044E616D650605556E697473094669
+      656C644E616D650605556E697473084461746154797065021808446174615369
+      7A6502140549734B6579080F4E65656450726F636573734E616D650809507265
+      636973696F6E02000453697A6502000001044E616D65060C4465616C5175616E
+      74697479094669656C644E616D65060C4465616C5175616E7469747908446174
+      61547970650206084461746153697A6502080549734B6579080F4E6565645072
+      6F636573734E616D650809507265636973696F6E02000453697A650200000104
+      4E616D65060A51635175616E74697479094669656C644E616D65060A51635175
+      616E746974790844617461547970650206084461746153697A6502080549734B
+      6579080F4E65656450726F636573734E616D650809507265636973696F6E0200
+      0453697A6502000001044E616D65060B497353756254656E646572094669656C
+      644E616D65060B497353756254656E6465720844617461547970650205084461
+      746153697A6502010549734B6579080F4E65656450726F636573734E616D6508
+      09507265636973696F6E02000453697A6502000001044E616D65060E4465616C
+      546F74616C5072696365094669656C644E616D65060E4465616C546F74616C50
+      726963650844617461547970650206084461746153697A6502080549734B6579
+      080F4E65656450726F636573734E616D650809507265636973696F6E02000453
+      697A6502000001044E616D65060C5163546F74616C5072696365094669656C64
+      4E616D65060C5163546F74616C50726963650844617461547970650206084461
+      746153697A6502080549734B6579080F4E65656450726F636573734E616D6508
+      09507265636973696F6E02000453697A6502000001044E616D65060951634247
+      4C436F6465094669656C644E616D650609516342474C436F6465084461746154
+      7970650218084461746153697A6503FF000549734B6579080F4E65656450726F
+      636573734E616D650809507265636973696F6E02000453697A6502000001044E
+      616D650608516342474C4E756D094669656C644E616D650608516342474C4E75
+      6D0844617461547970650218084461746153697A6503FF000549734B6579080F
+      4E65656450726F636573734E616D650809507265636973696F6E02000453697A
+      6502000000}
+  end
+  object sdvGatherTree: TsdDataView
+    Active = False
+    DataSet = sddGatherTree
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'ID'
+      end
+      item
+        FieldName = 'ParentID'
+      end
+      item
+        FieldName = 'NextSiblingID'
+      end
+      item
+        FieldName = 'Code'
+      end
+      item
+        FieldName = 'B_Code'
+      end
+      item
+        FieldName = 'Name'
+      end
+      item
+        FieldName = 'Units'
+      end
+      item
+        FieldName = 'DealQuantity'
+      end
+      item
+        FieldName = 'QcQuantity'
+      end>
+    OnCurrentChanged = sdvGatherTreeCurrentChanged
+    OnGetText = sdvGatherTreeGetText
+    Left = 40
+    Top = 152
+  end
+  object smpSubTenders: TsdMemoryProvider
+    Left = 136
+    Top = 24
+  end
+  object sddSubTenders: TsdDataSet
+    Active = True
+    Provider = smpSubTenders
+    Left = 136
+    Top = 88
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650809507265636973696F6E02000453697A6502000001044E616D
+      6506044E616D65094669656C644E616D6506044E616D65084461746154797065
+      0218084461746153697A6503FF000549734B6579080F4E65656450726F636573
+      734E616D650809507265636973696F6E02000453697A6502000000}
+  end
+  object sdvSubTenders: TsdDataView
+    Active = True
+    DataSet = sddSubTenders
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'ID'
+      end
+      item
+        FieldName = 'Name'
+      end
+      item
+        FieldName = 'ErrorCount'
+      end>
+    OnCurrentChanged = sdvSubTendersCurrentChanged
+    Left = 136
+    Top = 152
+  end
+  object smpBillsDetail: TsdMemoryProvider
+    Left = 248
+    Top = 24
+  end
+  object sddBillsDetail: TsdDataSet
+    Active = True
+    Provider = smpBillsDetail
+    Left = 248
+    Top = 88
+    FieldListData = {
+      0101044E616D65060742696C6C734944094669656C644E616D65060742696C6C
+      7349440844617461547970650203084461746153697A6502040549734B657908
+      0F4E65656450726F636573734E616D650809507265636973696F6E0200045369
+      7A6502000001044E616D65060854656E6465724944094669656C644E616D6506
+      0854656E64657249440844617461547970650203084461746153697A65020405
+      49734B6579080F4E65656450726F636573734E616D650809507265636973696F
+      6E02000453697A6502000001044E616D65060A54656E6465724E616D65094669
+      656C644E616D65060A54656E6465724E616D6508446174615479706502180844
+      61746153697A6503FF000549734B6579080F4E65656450726F636573734E616D
+      650809507265636973696F6E02000453697A6502000001044E616D6506085365
+      7269616C4E6F094669656C644E616D65060853657269616C4E6F084461746154
+      7970650203084461746153697A6502040549734B6579080F4E65656450726F63
+      6573734E616D650809507265636973696F6E02000453697A6502000001044E61
+      6D65060C4465616C5175616E74697479094669656C644E616D65060C4465616C
+      5175616E746974790844617461547970650206084461746153697A6502080549
+      734B6579080F4E65656450726F636573734E616D650809507265636973696F6E
+      02000453697A6502000001044E616D65060E4465616C546F74616C5072696365
+      094669656C644E616D65060E4465616C546F74616C5072696365084461746154
+      7970650206084461746153697A6502080549734B6579080F4E65656450726F63
+      6573734E616D650809507265636973696F6E02000453697A6502000001044E61
+      6D65060A51635175616E74697479094669656C644E616D65060A51635175616E
+      746974790844617461547970650206084461746153697A6502080549734B6579
+      080F4E65656450726F636573734E616D650809507265636973696F6E02000453
+      697A6502000001044E616D65060C5163546F74616C5072696365094669656C64
+      4E616D65060C5163546F74616C50726963650844617461547970650206084461
+      746153697A6502080549734B6579080F4E65656450726F636573734E616D6508
+      09507265636973696F6E02000453697A6502000001044E616D65060951634247
+      4C436F6465094669656C644E616D650609516342474C436F6465084461746154
+      7970650218084461746153697A6503FF000549734B6579080F4E65656450726F
+      636573734E616D650809507265636973696F6E02000453697A6502000001044E
+      616D650608516342474C4E756D094669656C644E616D650608516342474C4E75
+      6D0844617461547970650218084461746153697A6503FF000549734B6579080F
+      4E65656450726F636573734E616D650809507265636973696F6E02000453697A
+      6502000000}
+  end
+  object sdvBillsDetail: TsdDataView
+    Active = False
+    DataSet = sddBillsDetail
+    Filtered = True
+    Columns = <
+      item
+        FieldName = 'BillsID'
+      end
+      item
+        FieldName = 'TenderID'
+      end
+      item
+        FieldName = 'TenderName'
+      end
+      item
+        FieldName = 'SerialNo'
+      end
+      item
+        FieldName = 'DealQuantity'
+      end
+      item
+        FieldName = 'DealTotalPrice'
+      end
+      item
+        FieldName = 'QcQuantity'
+      end
+      item
+        FieldName = 'QcTotalPrice'
+      end
+      item
+        FieldName = 'QcBGLCode'
+      end
+      item
+        FieldName = 'QcBGLNum'
+      end
+      item
+      end>
+    OnFilterRecord = sdvBillsDetailFilterRecord
+    OnGetText = sdvBillsDetailGetText
+    Left = 248
+    Top = 152
+  end
+  object sdmErrorDetail: TsdMemoryProvider
+    Left = 352
+    Top = 24
+  end
+  object sddErrorDetail: TsdDataSet
+    Active = True
+    Provider = sdmErrorDetail
+    Left = 352
+    Top = 88
+    FieldListData = {
+      0101044E616D65060854656E6465724944094669656C644E616D65060854656E
+      64657249440844617461547970650203084461746153697A6502040549734B65
+      79080F4E65656450726F636573734E616D650809507265636973696F6E020004
+      53697A6502000001044E616D65060A54656E6465724E616D65094669656C644E
+      616D65060A54656E6465724E616D650844617461547970650218084461746153
+      697A6503FF000549734B6579080F4E65656450726F636573734E616D65080950
+      7265636973696F6E02000453697A6502000001044E616D65060852656C61436F
+      6465094669656C644E616D65060852656C61436F646508446174615479706502
+      18084461746153697A6502320549734B6579080F4E65656450726F636573734E
+      616D650809507265636973696F6E02000453697A6502000001044E616D65060C
+      52656C6153657269616C4E6F094669656C644E616D65060C52656C6153657269
+      616C4E6F0844617461547970650203084461746153697A6502040549734B6579
+      080F4E65656450726F636573734E616D650809507265636973696F6E02000453
+      697A6502000001044E616D65060A44657461696C436F6465094669656C644E61
+      6D65060A44657461696C436F6465084461746154797065021808446174615369
+      7A6502320549734B6579080F4E65656450726F636573734E616D650809507265
+      636973696F6E02000453697A6502000001044E616D65060E44657461696C5365
+      7269616C4E6F094669656C644E616D65060E44657461696C53657269616C4E6F
+      0844617461547970650203084461746153697A6502040549734B6579080F4E65
+      656450726F636573734E616D650809507265636973696F6E02000453697A6502
+      000001044E616D6506094572726F7254797065094669656C644E616D65060945
+      72726F72547970650844617461547970650203084461746153697A6502040549
+      734B6579080F4E65656450726F636573734E616D650809507265636973696F6E
+      02000453697A6502000000}
+  end
+  object sdvErrorDetail: TsdDataView
+    Active = False
+    DataSet = sddErrorDetail
+    Filtered = False
+    Columns = <
+      item
+        FieldName = 'TenderID'
+      end
+      item
+        FieldName = 'TenderName'
+      end
+      item
+        FieldName = 'RelaID'
+      end
+      item
+        FieldName = 'RelaCode'
+      end
+      item
+        FieldName = 'RelaSerialNo'
+      end
+      item
+        FieldName = 'DetailID'
+      end
+      item
+        FieldName = 'DetailCode'
+      end
+      item
+        FieldName = 'DetailSerialNo'
+      end
+      item
+        FieldName = 'ErrorType'
+      end>
+    OnFilterRecord = sdvErrorDetailFilterRecord
+    OnGetText = sdvErrorDetailGetText
+    Left = 352
+    Top = 152
+  end
+end

+ 277 - 0
SubTenderGather/stgGatherDm.pas

@@ -0,0 +1,277 @@
+unit stgGatherDm;
+
+interface
+
+uses
+  SysUtils, Classes, stgGatherCacheData, sdDB, sdProvider;
+
+type
+  TstgGatherData = class(TDataModule)
+    smpGatherTree: TsdMemoryProvider;
+    sddGatherTree: TsdDataSet;
+    sdvGatherTree: TsdDataView;
+    smpSubTenders: TsdMemoryProvider;
+    sddSubTenders: TsdDataSet;
+    sdvSubTenders: TsdDataView;
+    smpBillsDetail: TsdMemoryProvider;
+    sddBillsDetail: TsdDataSet;
+    sdvBillsDetail: TsdDataView;
+    sdmErrorDetail: TsdMemoryProvider;
+    sddErrorDetail: TsdDataSet;
+    sdvErrorDetail: TsdDataView;
+    procedure sdvBillsDetailGetText(var Text: String;
+      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+      DisplayText: Boolean);
+    procedure sdvBillsDetailFilterRecord(ARecord: TsdDataRecord;
+      var Allow: Boolean);
+    procedure sdvGatherTreeCurrentChanged(ARecord: TsdDataRecord);
+    procedure sdvGatherTreeGetText(var Text: String;
+      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+      DisplayText: Boolean);
+    procedure sdvErrorDetailFilterRecord(ARecord: TsdDataRecord;
+      var Allow: Boolean);
+    procedure sdvSubTendersCurrentChanged(ARecord: TsdDataRecord);
+    procedure sdvErrorDetailGetText(var Text: String;
+      ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+      DisplayText: Boolean);
+  private
+    procedure LoadSubTenders(ACacheData: TstgGatherCacheData);
+
+    procedure LoadGatherTreeNodeDetail(ANode: TstgGatherTreeNode);
+    procedure LoadGatherTreeNode(ANode: TstgGatherTreeNode);
+    procedure LoadGatherTree(ACacheData: TstgGatherCacheData);
+
+    procedure LoadError(AError: TstgErrorInfo);
+    procedure LoadErrors(ACacheData: TstgGatherCacheData);
+  public
+    procedure LoadGatherData(ACacheData: TstgGatherCacheData);
+  end;
+
+implementation
+
+uses
+  Variants, DB, ConditionalDefines;
+
+{$R *.dfm}
+
+{ TstgGatherData }
+
+procedure TstgGatherData.LoadGatherData(ACacheData: TstgGatherCacheData);
+begin
+  LoadSubTenders(ACacheData);
+  LoadGatherTree(ACacheData);
+  LoadErrors(ACacheData);
+
+  sdvGatherTree.Active := True;
+  sdvBillsDetail.Active := True;
+  sdvBillsDetail.RefreshFilter;
+
+  sdvSubTenders.Active := True;
+  sdvErrorDetail.Active := True;
+  sdvErrorDetail.RefreshFilter;
+end;
+
+procedure TstgGatherData.LoadGatherTree(ACacheData: TstgGatherCacheData);
+var
+  i: Integer;
+  vNode:TstgGatherTreeNode;
+begin
+  if _IsDebugView then
+    ACacheData.GatherTree.SaveTreeToFile('E:\stgGatherTree.txt');
+  for i := 0 to ACacheData.GatherTree.CacheNodes.Count - 1 do
+  begin
+    vNode := TstgGatherTreeNode(ACacheData.GatherTree.CacheNodes.Items[i]);
+    LoadGatherTreeNode(vNode);
+  end;
+end;
+
+procedure TstgGatherData.LoadGatherTreeNode(ANode: TstgGatherTreeNode);
+var
+  Rec: TsdDataRecord;
+begin
+  Rec := sddGatherTree.Add;
+  Rec.ValueByName('ID').AsInteger := ANode.ID;
+  Rec.ValueByName('ParentID').AsInteger := ANode.ParentID;
+  Rec.ValueByName('NextSiblingID').AsInteger := ANode.NextSiblingID;
+  Rec.ValueByName('Code').AsString := ANode.Code;
+  Rec.ValueByName('B_Code').AsString := ANode.B_Code;
+  Rec.ValueByName('Name').AsString := ANode.Name;
+  Rec.ValueByName('Units').AsString := ANode.Units;
+  Rec.ValueByName('IsSubTender').AsBoolean := ANode.IsSubTender;
+
+  Rec.ValueByName('DealQuantity').AsFloat := ANode.Gather.DealQuantity;
+  Rec.ValueByName('DealTotalPrice').AsFloat := ANode.Gather.DealTotalPrice;
+  Rec.ValueByName('QcQuantity').AsFloat := ANode.Gather.QcQuantity;
+  Rec.ValueByName('QcTotalPrice').AsFloat := ANode.Gather.QcTotalPrice;
+  Rec.ValueByName('QcBGLCode').AsString := ANode.Gather.QcBGLCode;
+  Rec.ValueByName('QcBGLNum').AsString := ANode.Gather.QcBGLNum;
+  if ANode.Children.Count = 0 then
+    LoadGatherTreeNodeDetail(ANode);
+end;
+
+procedure TstgGatherData.LoadGatherTreeNodeDetail(
+  ANode: TstgGatherTreeNode);
+var
+  iSub, iDetail: Integer;
+  vSub: TstgSubTenderStageData;
+  vDetail: TstgSubTenderDetailData;
+  Rec: TsdDataRecord;
+  sSubTenderName: string;
+begin
+  for iSub := 0 to ANode.SubTenderCount - 1 do
+  begin
+    vSub := ANode.SubTender[iSub];
+    for iDetail := 0 to vSub.DetailCount - 1 do
+    begin
+      vDetail := vSub.Detail[iDetail];
+      Rec := sddBillsDetail.Add;
+      Rec.ValueByName('BillsID').AsInteger := ANode.ID;
+      Rec.ValueByName('TenderID').AsInteger := vSub.SubTenderID;
+      Rec.ValueByName('TenderName').AsString := '';
+      Rec.ValueByName('SerialNo').AsInteger := vDetail.SerialNo;
+      Rec.ValueByName('DealQuantity').AsFloat := vDetail.DetailStage.DealQuantity;
+      Rec.ValueByName('DealTotalPrice').AsFloat := vDetail.DetailStage.DealTotalPrice;
+      Rec.ValueByName('QcQuantity').AsFloat := vDetail.DetailStage.QcQuantity;
+      Rec.ValueByName('QcTotalPrice').AsFloat := vDetail.DetailStage.QcTotalPrice;
+      Rec.ValueByName('QcBGLCode').AsString := vDetail.DetailStage.QcBGLCode;
+      Rec.ValueByName('QcBGLNum').AsString := vDetail.DetailStage.QcBGLNum;
+    end;
+  end;
+end;
+
+procedure TstgGatherData.LoadSubTenders(ACacheData: TstgGatherCacheData);
+var
+  i: Integer;
+  vSubTender: TstgGatherSubTender;
+  Rec: TsdDataRecord;
+begin
+  for i := 0 to ACacheData.SubTenderCount - 1 do
+  begin
+    vSubTender := ACacheData.SubTender[i];
+    Rec := sddSubTenders.Add;
+    Rec.ValueByName('ID').AsInteger := vSubTender.ID;
+    Rec.ValueByName('Name').AsString := vSubTender.Rec.ValueByName('Name').AsString;
+  end;
+end;
+
+procedure TstgGatherData.sdvBillsDetailGetText(var Text: String;
+  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+  DisplayText: Boolean);
+
+  function GetTenderName(ATenderID: Integer): string;
+  begin
+    Result := VarToStrDef(sddSubTenders.Lookup('ID', ATenderID, 'Name'), '');
+  end;
+
+begin
+  if DisplayText and (AColumn.FieldName = 'TenderName') then
+    Text := GetTenderName(ARecord.ValueByName('TenderID').asInteger);
+end;
+
+procedure TstgGatherData.sdvBillsDetailFilterRecord(ARecord: TsdDataRecord;
+  var Allow: Boolean);
+begin
+  if Assigned(sdvGatherTree.Current) then
+    Allow := ARecord.ValueByName('BillsID').AsInteger = sdvGatherTree.Current.ValueByName('ID').AsInteger
+  else
+    Allow := False;
+end;
+
+procedure TstgGatherData.sdvGatherTreeCurrentChanged(
+  ARecord: TsdDataRecord);
+begin
+  sdvBillsDetail.RefreshFilter;
+end;
+
+procedure TstgGatherData.sdvGatherTreeGetText(var Text: String;
+  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+  DisplayText: Boolean);
+begin
+  if (AValue.DataType = ftFloat) and (AValue.AsFloat = 0) then
+  begin
+    Text := '';
+  end;
+end;
+
+procedure TstgGatherData.LoadErrors(ACacheData: TstgGatherCacheData);
+var
+  i: Integer;
+begin
+  for i := 0 to ACacheData.ErrorCount - 1 do
+    LoadError(ACacheData.Error[i]);
+end;
+
+procedure TstgGatherData.sdvErrorDetailFilterRecord(ARecord: TsdDataRecord;
+  var Allow: Boolean);
+begin
+  if Assigned(sdvSubTenders.Current) then
+    Allow := ARecord.ValueByName('TenderID').AsInteger = sdvSubTenders.Current.ValueByName('ID').AsInteger
+  else
+    Allow := False;
+end;
+
+procedure TstgGatherData.LoadError(AError: TstgErrorInfo);
+var
+  i, j, k: Integer;
+  vRelaDetail: TstgGatherTreeNode;
+  vRelaDetailStage: TstgSubTenderStageData;
+  Rec: TsdDataRecord;
+begin
+  for i := 0 to AError.DetailCount - 1 do
+  begin
+    vRelaDetail := AError.Detail[i];
+    for j := 0 to vRelaDetail.SubTenderCount - 1 do
+    begin
+      vRelaDetailStage := vRelaDetail.SubTender[j];
+      for k := 0 to vRelaDetailStage.DetailCount - 1 do
+      begin
+        Rec := sddErrorDetail.Add;
+        Rec.ValueByName('TenderID').AsInteger := vRelaDetail.SubTender[j].SubTenderID;
+        Rec.ValueByName('RelaCode').AsString := AError.RelaNode.Code + AError.RelaNode.B_Code;
+        Rec.ValueByName('DetailCode').AsString := vRelaDetail.Code + vRelaDetail.B_Code;
+        Rec.ValueByName('DetailSerialNo').AsInteger := vRelaDetailStage.Detail[k].SerialNo;
+        Rec.ValueByName('ErrorType').AsInteger := AError.ErrorType;
+      end;
+    end;
+  end;
+end;
+
+procedure TstgGatherData.sdvSubTendersCurrentChanged(
+  ARecord: TsdDataRecord);
+begin
+  sdvErrorDetail.RefreshFilter;
+end;
+
+procedure TstgGatherData.sdvErrorDetailGetText(var Text: String;
+  ARecord: TsdDataRecord; AValue: TsdValue; AColumn: TsdViewColumn;
+  DisplayText: Boolean);
+
+  function GetTenderName(ATenderID: Integer): string;
+  begin
+    Result := VarToStrDef(sddSubTenders.Lookup('ID', ATenderID, 'Name'), '');
+  end;
+
+  function GetErrorTypeText(AErrorType: Integer): string;
+  begin
+    case AErrorType of
+      iErrorXmjAdd: Result := '劤藤';
+      iErrorXmjDiff: Result := '닸瞳谿뵀꼇谿츰(데貫)';
+      iErrorXmjLess: Result := '만淃淃커쌘,꿔늴�黨悧관';
+      iErrorGclAdd: Result := '劤藤';
+      iErrorGclDiff: Result := '닸瞳谿뵀꼇谿츰(데貫)';
+      iErrorGclMore: Result := '묏넋좆헌데,꿔늴뜩黨悧관';
+      iErrorGclLess: Result := '묏넋좆헌데,꿔늴�黨悧관';
+    end;
+  end;
+
+begin
+  if DisplayText then
+  begin
+    if (AColumn.FieldName = 'TenderName') then
+      Text := GetTenderName(ARecord.ValueByName('TenderID').asInteger)
+    else if (AColumn.FieldName = 'ErrorType') then
+      Text := GetErrorTypeText(AValue.AsInteger);
+  end;
+end;
+
+end.

+ 625 - 0
SubTenderGather/stgResultFrm.dfm

@@ -0,0 +1,625 @@
+object stgResultForm: TstgResultForm
+  Left = 192
+  Top = 123
+  Width = 1305
+  Height = 675
+  ActiveControl = zgGatherTree
+  Caption = #20998#21253#27719#24635
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+  object jpsResult: TJimPages
+    Left = 0
+    Top = 22
+    Width = 1297
+    Height = 594
+    ActivePage = jpsResultBillsDetail
+    ActivePageIndex = 0
+    Align = alClient
+    Caption = 'jpsResult'
+    object jpsResultBillsDetail: TJimPage
+      Left = 0
+      Top = 0
+      Width = 1297
+      Height = 594
+      TabName = 'BillsDetail'
+      Caption = 'Tree'
+      object Splitter1: TSplitter
+        Left = 924
+        Top = 0
+        Height = 594
+        Align = alRight
+      end
+      object pnlGatherTree: TPanel
+        Left = 0
+        Top = 0
+        Width = 924
+        Height = 594
+        Align = alClient
+        BevelOuter = bvNone
+        TabOrder = 0
+        object zgGatherTree: TZJGrid
+          Left = 0
+          Top = 0
+          Width = 924
+          Height = 594
+          Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
+          OptionsEx = []
+          ColCount = 7
+          ShowGridLine = False
+          DefaultColWidth = 73
+          DefaultFixedColWidth = 25
+          Selection.AlphaBlend = False
+          Selection.TransparentColor = False
+          FrozenCol = 0
+          FrozenRow = 0
+          OnCellGetColor = zgGatherTreeCellGetColor
+          Align = alClient
+        end
+      end
+      object pnlDetail: TPanel
+        Left = 927
+        Top = 0
+        Width = 370
+        Height = 594
+        Align = alRight
+        BevelOuter = bvNone
+        TabOrder = 1
+        object zgBillsDetail: TZJGrid
+          Left = 0
+          Top = 0
+          Width = 370
+          Height = 594
+          Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection]
+          OptionsEx = []
+          ShowGridLine = False
+          DefaultColWidth = 73
+          DefaultFixedColWidth = 25
+          Selection.AlphaBlend = False
+          Selection.TransparentColor = False
+          FrozenCol = 0
+          FrozenRow = 0
+          Align = alClient
+        end
+      end
+    end
+    object jpsResultErrorDetail: TJimPage
+      Left = 0
+      Top = 0
+      Width = 1297
+      Height = 594
+      TabName = 'ErrorDetail'
+      Caption = 'Main'
+      object pnlError: TPanel
+        Left = 0
+        Top = 0
+        Width = 1297
+        Height = 594
+        Align = alClient
+        BevelOuter = bvNone
+        TabOrder = 0
+        object Splitter2: TSplitter
+          Left = 440
+          Top = 0
+          Height = 594
+        end
+        object pnlErrorInfo: TPanel
+          Left = 0
+          Top = 0
+          Width = 440
+          Height = 594
+          Align = alLeft
+          BevelOuter = bvNone
+          TabOrder = 0
+          object zgErrorInfo: TZJGrid
+            Left = 0
+            Top = 0
+            Width = 440
+            Height = 594
+            Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection]
+            OptionsEx = []
+            ColCount = 3
+            ShowGridLine = False
+            DefaultColWidth = 73
+            DefaultFixedColWidth = 25
+            Selection.AlphaBlend = False
+            Selection.TransparentColor = False
+            FrozenCol = 0
+            FrozenRow = 0
+            Align = alClient
+          end
+        end
+        object pnlErrorDetail: TPanel
+          Left = 443
+          Top = 0
+          Width = 854
+          Height = 594
+          Align = alClient
+          BevelOuter = bvNone
+          TabOrder = 1
+          object zgErrorDetail: TZJGrid
+            Left = 0
+            Top = 0
+            Width = 854
+            Height = 594
+            Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection]
+            OptionsEx = []
+            ColCount = 6
+            RowCount = 6
+            FixedRowCount = 2
+            ShowGridLine = False
+            DefaultColWidth = 73
+            DefaultFixedColWidth = 25
+            Selection.AlphaBlend = False
+            Selection.TransparentColor = False
+            FrozenCol = 0
+            FrozenRow = 0
+            Align = alClient
+          end
+        end
+      end
+    end
+  end
+  object jtsGatherData: TJimTabSet
+    Left = 0
+    Top = 0
+    Width = 1297
+    Height = 22
+    Align = alTop
+    BackgroundColor = clGradientInactiveCaption
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -12
+    Font.Name = 'smartSimSun'
+    Font.Style = []
+    SelectedColor = clWhite
+    XPSelectedColor = clWhite
+    XPUnSelectedColor = 15200496
+    Tabs.Strings = (
+      #27719#24635#32467#26524
+      #38169#35823#21015#34920)
+    TabIndex = 0
+    TabPosition = jtpTop
+    TabStyle = tdsNew
+    UnselectedColor = 15200496
+    OnChange = jtsGatherDataChange
+  end
+  object pnlResult: TPanel
+    Left = 0
+    Top = 616
+    Width = 1297
+    Height = 28
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 2
+    object lblResult: TLabel
+      Left = 4
+      Top = 8
+      Width = 692
+      Height = 13
+      Caption = #20849#27719#24635'3'#20010#26631#27573#25968#25454#65292#20849#27719#24635#24037#31243#37327#28165#21333'X'#26465#65292#20854#20013'Y'#26465#27491#30830#27719#24635#65292#35813#37096#20998#21487#27491#30830#23548#20837#24635#21253#65292#26410#27491#30830#27719#24635#28165#21333#21487#35265#28165#21333#26126#32454#20013#28784#33394#37096#20998
+    end
+  end
+  object saGatherTree: TsdGridTreeDBA
+    Columns = <
+      item
+        Title.Caption = #39033#30446#33410#32534#21495
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Code'
+        Width = 180
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #28165#21333#32534#21495
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'B_Code'
+        Width = 80
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21517#31216
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Name'
+        Width = 240
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21333#20301
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Units'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = 'ID'
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ID'
+        Visible = False
+        ReadOnly = False
+      end
+      item
+        Title.Caption = 'ParentID'
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ParentID'
+        Visible = False
+        ReadOnly = False
+      end
+      item
+        Title.Caption = 'NextSiblingID'
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'NextSiblingID'
+        Visible = False
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21512#21516#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DealQuantity'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #25968#37327#21464#26356#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'QcQuantity'
+        ReadOnly = False
+      end>
+    Grid = zgGatherTree
+    ExtendRowCount = 0
+    Options = []
+    AutoExpand = True
+    KeyFieldName = 'ID'
+    ParentFieldName = 'ParentID'
+    NextSiblingFieldName = 'NextSiblingID'
+    TreeOptions = []
+    TopLevelBold = True
+    Left = 104
+    Top = 110
+  end
+  object sdBillsDetail: TsdGridDBA
+    Columns = <
+      item
+        Title.Caption = #26631#27573
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'TenderName'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #20301#32622
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'SerialNo'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21512#21516#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DealQuantity'
+        Width = 85
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #25968#37327#21464#26356#35745#37327
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taRightJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'QcQuantity'
+        Width = 85
+        ReadOnly = False
+      end>
+    Grid = zgBillsDetail
+    ExtendRowCount = 0
+    Options = []
+    Left = 157
+    Top = 110
+  end
+  object sdErrorInfo: TsdGridDBA
+    Columns = <
+      item
+        Title.Caption = #21517#31216
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Name'
+        Width = 300
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #26410#27491#30830#27719#24635
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ErrorCount'
+        Width = 80
+        ReadOnly = False
+      end>
+    Grid = zgErrorInfo
+    ExtendRowCount = 0
+    Options = []
+    Left = 104
+    Top = 196
+  end
+  object sdErrorDetail: TsdGridDBA
+    Columns = <
+      item
+        Title.Caption = #20986#38169#28304'|'#32534#21495
+        Title.CaptionAcrossCols = '2'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'RelaCode'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = '|'#20301#32622
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'RelaSerialNo'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21487#35745#37327#28165#21333'|'#32534#21495
+        Title.CaptionAcrossCols = '2'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DetailCode'
+        ReadOnly = False
+      end
+      item
+        Title.Caption = '|'#20301#32622
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'DetailSerialNo'
+        Width = 50
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #38169#35823#31867#22411
+        Title.CaptionAcrossCols = '1'
+        Title.CaptionAcrossRows = 2
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'ErrorType'
+        Width = 200
+        ReadOnly = False
+      end>
+    Grid = zgErrorDetail
+    ExtendRowCount = 0
+    Options = []
+    Left = 156
+    Top = 195
+  end
+  object dxpmError: TdxBarPopupMenu
+    BarManager = MainForm.dxBarManager
+    ItemLinks = <
+      item
+        Item = MainForm.dxBarButton1
+        Visible = True
+      end
+      item
+        Item = MainForm.dxBarButton2
+        Visible = True
+      end>
+    UseOwnFont = False
+    Left = 104
+    Top = 235
+  end
+  object dxBarPopupMenu2: TdxBarPopupMenu
+    BarManager = MainForm.dxBarManager
+    ItemLinks = <>
+    UseOwnFont = False
+    Left = 104
+    Top = 148
+  end
+end

+ 73 - 0
SubTenderGather/stgResultFrm.pas

@@ -0,0 +1,73 @@
+unit stgResultFrm;
+
+interface
+
+uses
+  stgGatherDm, sdIDTree,
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, JimTabs, JimPages, sdGridDBA, sdGridTreeDBA, ZJGrid, ExtCtrls,
+  StdCtrls, dxBar;
+
+type
+  TstgResultForm = class(TForm)
+    jpsResult: TJimPages;
+    jpsResultErrorDetail: TJimPage;
+    jpsResultBillsDetail: TJimPage;
+    jtsGatherData: TJimTabSet;
+    pnlGatherTree: TPanel;
+    zgGatherTree: TZJGrid;
+    saGatherTree: TsdGridTreeDBA;
+    pnlDetail: TPanel;
+    zgBillsDetail: TZJGrid;
+    Splitter1: TSplitter;
+    sdBillsDetail: TsdGridDBA;
+    pnlError: TPanel;
+    pnlErrorInfo: TPanel;
+    zgErrorInfo: TZJGrid;
+    sdErrorInfo: TsdGridDBA;
+    pnlResult: TPanel;
+    lblResult: TLabel;
+    Splitter2: TSplitter;
+    pnlErrorDetail: TPanel;
+    zgErrorDetail: TZJGrid;
+    sdErrorDetail: TsdGridDBA;
+    dxpmError: TdxBarPopupMenu;
+    dxBarPopupMenu2: TdxBarPopupMenu;
+    procedure jtsGatherDataChange(Sender: TObject; NewTab: Integer;
+      var AllowChange: Boolean);
+    procedure zgGatherTreeCellGetColor(Sender: TObject; ACoord: TPoint;
+      var AColor: TColor);
+  private
+  public
+    procedure SetGatherData(AGatherData: TstgGatherData);
+  end;
+
+implementation
+
+{$R *.dfm}
+
+procedure TstgResultForm.jtsGatherDataChange(Sender: TObject;
+  NewTab: Integer; var AllowChange: Boolean);
+begin
+  jpsResult.ActivePageIndex := NewTab;
+end;
+
+procedure TstgResultForm.SetGatherData(AGatherData: TstgGatherData);
+begin
+  saGatherTree.DataView := AGatherData.sdvGatherTree;
+  sdBillsDetail.DataView := AGatherData.sdvBillsDetail;
+  sdErrorInfo.DataView := AGatherData.sdvSubTenders;
+  sdErrorDetail.DataView := AGatherData.sdvErrorDetail;
+end;
+
+procedure TstgResultForm.zgGatherTreeCellGetColor(Sender: TObject;
+  ACoord: TPoint; var AColor: TColor);
+var
+  vNode: TsdIDTreeNode;
+begin
+  vNode := saGatherTree.IDTree.Items[ACoord.Y - zgGatherTree.FixedRowCount];
+  if Assigned(vNode) and vNode.Rec.ValueByName('IsSubTender').AsBoolean then
+    AColor := $00D5D5D5;
+end;
+
+end.

+ 257 - 0
SubTenderGather/stgSelectFileFrm.dfm

@@ -0,0 +1,257 @@
+object stgSelectFileForm: TstgSelectFileForm
+  Left = 443
+  Top = 206
+  Width = 910
+  Height = 533
+  Caption = #20998#21253#26631#27573#27719#24635
+  Color = clBtnFace
+  Font.Charset = ANSI_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -12
+  Font.Name = #23435#20307
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poDesktopCenter
+  PixelsPerInch = 96
+  TextHeight = 12
+  object pnlTop: TPanel
+    Left = 0
+    Top = 0
+    Width = 902
+    Height = 33
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 0
+    DesignSize = (
+      902
+      33)
+    object leSumBaseFile: TLabeledEdit
+      Left = 117
+      Top = 7
+      Width = 727
+      Height = 18
+      Anchors = [akLeft, akTop, akRight]
+      Ctl3D = False
+      EditLabel.Width = 108
+      EditLabel.Height = 12
+      EditLabel.Caption = #36873#25321#24635#21253#22522#20934#25991#20214#65306
+      LabelPosition = lpLeft
+      ParentCtl3D = False
+      TabOrder = 0
+    end
+    object btnSelectSbf: TButton
+      Left = 851
+      Top = 5
+      Width = 44
+      Height = 21
+      Anchors = [akTop, akRight]
+      Caption = '...'
+      TabOrder = 1
+      OnClick = btnSelectSbfClick
+    end
+  end
+  object pnlGatherFiles: TPanel
+    Left = 0
+    Top = 33
+    Width = 902
+    Height = 428
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 1
+    object pnlSelect: TPanel
+      Left = 0
+      Top = 0
+      Width = 450
+      Height = 428
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object zgTenderSelect: TZJGrid
+        Left = 0
+        Top = 19
+        Width = 450
+        Height = 409
+        Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
+        OptionsEx = []
+        ColCount = 3
+        RowCount = 1
+        ShowGridLine = False
+        DefaultColWidth = 35
+        DefaultFixedColWidth = 25
+        DefaultFixedRowHeight = 22
+        Selection.AlphaBlend = False
+        Selection.TransparentColor = False
+        FrozenCol = 0
+        FrozenRow = 0
+        OnGetCellText = zgTenderSelectGetCellText
+        OnSetCellText = zgTenderSelectSetCellText
+        OnCellTextChanged = zgTenderSelectCellTextChanged
+        OnDrawCellText = zgTenderSelectDrawCellText
+        OnShowHint = zgTenderSelectShowHint
+        Align = alClient
+      end
+      object pnlSelectTitle: TPanel
+        Left = 0
+        Top = 0
+        Width = 450
+        Height = 19
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 1
+        object lblTenderList: TLabel
+          Left = 6
+          Top = 2
+          Width = 72
+          Height = 12
+          Caption = #21487#36873#39033#30446#21015#34920
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clBlue
+          Font.Height = -12
+          Font.Name = #23435#20307
+          Font.Style = []
+          ParentFont = False
+        end
+      end
+    end
+    object pnlDivision: TPanel
+      Left = 450
+      Top = 0
+      Width = 3
+      Height = 428
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 1
+    end
+    object pnlResult: TPanel
+      Left = 453
+      Top = 0
+      Width = 449
+      Height = 428
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 2
+      object zgResult: TZJGrid
+        Left = 0
+        Top = 19
+        Width = 449
+        Height = 409
+        OptionsEx = []
+        ColCount = 2
+        RowCount = 2
+        ShowGridLine = False
+        DefaultColWidth = 365
+        DefaultFixedColWidth = 25
+        DefaultFixedRowHeight = 22
+        Selection.AlphaBlend = False
+        Selection.TransparentColor = False
+        FrozenCol = 0
+        FrozenRow = 0
+        Align = alClient
+      end
+      object pnlResultTitle: TPanel
+        Left = 0
+        Top = 0
+        Width = 449
+        Height = 19
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 1
+        object lblResultList: TLabel
+          Left = 3
+          Top = 2
+          Width = 72
+          Height = 12
+          Caption = #25152#36873#39033#30446#21015#34920
+          Font.Charset = ANSI_CHARSET
+          Font.Color = clBlue
+          Font.Height = -12
+          Font.Name = #23435#20307
+          Font.Style = []
+          ParentFont = False
+        end
+      end
+    end
+  end
+  object pnlBottom: TPanel
+    Left = 0
+    Top = 461
+    Width = 902
+    Height = 41
+    Align = alBottom
+    BevelOuter = bvNone
+    TabOrder = 2
+    DesignSize = (
+      902
+      41)
+    object btnOk: TButton
+      Left = 731
+      Top = 8
+      Width = 75
+      Height = 25
+      Anchors = [akTop, akRight]
+      Caption = #30830#23450
+      TabOrder = 0
+      OnClick = btnOkClick
+    end
+    object btnCancel: TButton
+      Left = 817
+      Top = 8
+      Width = 75
+      Height = 25
+      Anchors = [akTop, akRight]
+      Caption = #21462#28040
+      TabOrder = 1
+    end
+  end
+  object stdTenderSelect: TsdGridTreeDBA
+    Columns = <
+      item
+        Title.Caption = #36873#25321
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taCenter
+        EditType = sgeCheckBox
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        Width = 30
+        ReadOnly = False
+      end
+      item
+        Title.Caption = #21517#31216
+        Title.CaptionAcrossCols = '1'
+        Title.Font.Charset = GB2312_CHARSET
+        Title.Font.Color = clWindowText
+        Title.Font.Height = -12
+        Title.Font.Name = #23435#20307
+        Title.Font.Style = []
+        Alignment = taLeftJustify
+        Font.Charset = GB2312_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -12
+        Font.Name = #23435#20307
+        Font.Style = []
+        FieldName = 'Name'
+        Width = 365
+        ReadOnly = True
+      end>
+    Grid = zgTenderSelect
+    ExtendRowCount = 0
+    Options = [aoAllowEdit]
+    AutoExpand = True
+    TreeCellCol = 2
+    KeyFieldName = 'ID'
+    ParentFieldName = 'ParentID'
+    NextSiblingFieldName = 'NextSiblingID'
+    TreeOptions = []
+    TopLevelBold = True
+    Left = 124
+    Top = 177
+  end
+end

+ 320 - 0
SubTenderGather/stgSelectFileFrm.pas

@@ -0,0 +1,320 @@
+unit stgSelectFileFrm;
+
+interface
+
+uses
+  stgGatherControl,
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, ExtCtrls, sdGridDBA, sdGridTreeDBA, ZJGrid, sdIDTree;
+
+type
+  TstgSelectFileForm = class(TForm)
+    pnlTop: TPanel;
+    leSumBaseFile: TLabeledEdit;
+    btnSelectSbf: TButton;
+    pnlGatherFiles: TPanel;
+    pnlSelect: TPanel;
+    zgTenderSelect: TZJGrid;
+    pnlSelectTitle: TPanel;
+    lblTenderList: TLabel;
+    stdTenderSelect: TsdGridTreeDBA;
+    pnlDivision: TPanel;
+    pnlResult: TPanel;
+    zgResult: TZJGrid;
+    pnlResultTitle: TPanel;
+    lblResultList: TLabel;
+    pnlBottom: TPanel;
+    btnOk: TButton;
+    btnCancel: TButton;
+    procedure zgTenderSelectDrawCellText(ACanvas: TCanvas;
+      const ARect: TRect; const ACoord: TPoint; AGrid: TZJGrid;
+      const Text: String; var ADefaultDraw: Boolean);
+    procedure zgTenderSelectShowHint(var HintStr: String;
+      var CanShow: Boolean; var HintInfo: THintInfo; const ACoord: TPoint);
+    procedure zgTenderSelectSetCellText(Sender: TObject;
+      const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+    procedure zgTenderSelectGetCellText(Sender: TObject;
+      const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+    procedure zgTenderSelectCellTextChanged(Sender: TObject; Col,
+      Row: Integer);
+    procedure btnOkClick(Sender: TObject);
+    procedure btnSelectSbfClick(Sender: TObject);
+  private
+    FSelects: TList;
+
+    procedure AddRows(ANode: TsdIDTreeNode);
+    procedure RemoveRows(ANode: TsdIDTreeNode);
+
+    procedure InitResultGrid;
+    procedure AssignResultGrid;
+    procedure AssignResult;
+    function GetSelectCount: Integer;
+  public
+    constructor Create(AGatherControl: TstgGatherControl);
+    destructor Destroy; override;
+
+    procedure AssignSelect(AGatherControl: TstgGatherControl);
+    property SelectCount: Integer read GetSelectCount;
+  end;
+
+function SelectFileForSubTenderGather(AGatherControl: TstgGatherControl): Boolean;
+
+implementation
+
+uses MainFrm, Globals, UtilMethods;
+
+{$R *.dfm}
+
+function SelectFileForSubTenderGather(AGatherControl: TstgGatherControl): Boolean;
+var
+  vSelectFrm: TstgSelectFileForm;
+begin
+  vSelectFrm := TstgSelectFileForm.Create(AGatherControl);
+  try
+    Result := vSelectFrm.ShowModal = mrOk;
+    if Result then
+      vSelectFrm.AssignSelect(AGatherControl);
+  finally
+    vSelectFrm.Free;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectDrawCellText(ACanvas: TCanvas;
+  const ARect: TRect; const ACoord: TPoint; AGrid: TZJGrid;
+  const Text: String; var ADefaultDraw: Boolean);
+
+  procedure GetBitmap(AImage: TBitmap);
+  begin
+    with stdTenderSelect.IDTree.Items[ACoord.Y - 1] do
+      if Rec.ValueByName('Type').AsInteger = 0 then
+        if Expanded and HasChildren then
+          MainForm.Images.GetBitmap(34, AImage)
+        else
+          MainForm.Images.GetBitmap(34, AImage)
+      else
+        MainForm.Images.GetBitmap(11, AImage);
+  end;
+
+const
+  rIconWidth = 16;
+  rIconHeight = 16;
+var
+  Img: TBitmap;
+  Cell: TZjCell;
+  rImg: TRect;
+begin
+ if (ACoord.X = 2) and (ACoord.Y > zgTenderSelect.FixedRowCount - 1) then
+  begin
+    Cell := zgTenderSelect.Cells[ACoord.X, ACoord.Y];
+    Img := TBitmap.Create;
+    try
+      GetBitmap(Img);
+      case Cell.Align of
+        gaTopLeft, gaTopCenter, gaTopRight:
+          rImg := Rect(ARect.Left + 2, ARect.Top, ARect.Left + rIconWidth, ARect.Top + rIconHeight);
+        gaCenterLeft, gaCenterCenter, gaCenterRight:
+          rImg := Rect(ARect.Left + 2, ARect.Top + (ARect.Bottom - ARect.Top - rIconHeight) div 2, ARect.Left + rIconWidth, ARect.Bottom - (ARect.Bottom - ARect.Top - rIconHeight) div 2);
+        gaBottomLeft, gaBottomCenter, gaBottomRight:
+          rImg := Rect(ARect.Left + 2, ARect.Bottom - rIconHeight, ARect.Left + rIconWidth, ARect.Bottom);
+      end;
+      ACanvas.StretchDraw(rImg, Img);
+      WriteText(ACanvas, Rect(ARect.Left + rIconWidth, ARect.Top, ARect.Right, ARect.Bottom)
+        , 2, 2, Text, Cell.Align, False);
+      ADefaultDraw := False;
+    finally
+      Img.Free;
+    end;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectShowHint(var HintStr: String;
+  var CanShow: Boolean; var HintInfo: THintInfo; const ACoord: TPoint);
+var
+  vCell: TZjCell;
+  vNode: TsdIDTreeNode;
+  iLevelWidth: Integer;
+  rText: TRect;
+
+  procedure CalcTextRect(var R: TRect);
+  var
+    DC: HDC;
+    iTextHeight: Integer;
+  begin
+    DC := CreateCompatibleDC(0);
+    try
+      SelectObject(DC, vCell.Font.Handle);
+      iTextHeight := DrawText(DC, PChar(vCell.Text), Length(vCell.Text), R, DT_SINGLELINE or DT_VCenter
+        or DT_NOCLIP or DT_CALCRECT);
+    finally
+      DeleteDC(DC);
+    end;
+  end;
+
+begin
+  if ACoord.Y < 1 then Exit;
+
+  vCell := zgTenderSelect.Cells[ACoord.X, ACoord.Y];
+  with HintInfo do
+  begin
+    vNode := stdTenderSelect.IDTree.Items[ACoord.Y - 1];
+    if not Assigned(vNode) then Exit;
+    iLevelWidth := (vNode.Level + 1) * 20 + 16;
+
+    rText := CursorRect;
+    CalcTextRect(rText);
+    if (rText.Right - rText.Left + iLevelWidth > CursorRect.Right - CursorRect.Left) or
+      (rText.Right > ClientWidth) then
+    begin
+      CanShow := True;
+      HintStr := vCell.Text;
+      GetCursorPos(HintPos);
+    end;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectSetCellText(Sender: TObject;
+  const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+var
+  stnNode: TsdIDTreeNode;
+begin
+  if ACoord.X = 1 then
+  begin
+    stnNode := stdTenderSelect.IDTree.Items[ACoord.Y - 1];
+    if Value = 'True' then
+      AddRows(stnNode)
+    else
+      RemoveRows(stnNode);
+    AssignResult;
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectGetCellText(Sender: TObject;
+  const ACoord: TPoint; var Value: String; DisplayText: Boolean);
+var
+  stnNode: TsdIDTreeNode;
+begin
+  if ACoord.X = 1 then
+  begin
+    stnNode := stdTenderSelect.IDTree.Items[ACoord.Y - 1];
+    if Assigned(stnNode) and (FSelects.IndexOf(Pointer(stnNode.ID)) > -1) then
+      Value := 'True';
+  end;
+end;
+
+procedure TstgSelectFileForm.zgTenderSelectCellTextChanged(Sender: TObject;
+  Col, Row: Integer);
+begin
+  if (Col = 1) then
+    zgTenderSelect.InvalidateCol(1);
+end;
+
+procedure TstgSelectFileForm.AddRows(ANode: TsdIDTreeNode);
+var
+  iChild: Integer;
+begin
+  if not Assigned(ANode) then Exit;
+
+  if FSelects.IndexOf(Pointer(ANode.ID)) = -1 then
+    FSelects.Add(Pointer(ANode.ID));
+
+  if ANode.HasChildren then
+    for iChild := 0 to ANode.ChildCount - 1 do
+      AddRows(ANode.ChildNodes[iChild]);
+end;
+
+procedure TstgSelectFileForm.RemoveRows(ANode: TsdIDTreeNode);
+var
+  iChild: Integer;
+begin
+  if not Assigned(ANode) then Exit;
+
+  if FSelects.IndexOf(Pointer(ANode.ID)) > -1 then
+    FSelects.Remove(Pointer(ANode.ID));
+
+  if ANode.HasChildren then
+    for iChild := 0 to ANode.ChildCount - 1 do
+      RemoveRows(ANode.ChildNodes[iChild]);
+end;
+
+procedure TstgSelectFileForm.InitResultGrid;
+begin
+  zgResult.ColCount := 2;
+  zgResult.RowCount := 1;
+  zgResult.Cells[1, 0].Text := '所选项目';
+  zgResult.ColWidths[1] := 365;
+end;
+
+procedure TstgSelectFileForm.AssignResultGrid;
+var
+  i, iID: Integer;
+  vNode: TsdIDTreeNode;
+begin
+  for i := 0 to FSelects.Count - 1 do
+  begin
+    iID := Integer(FSelects.Items[i]);
+    vNode := stdTenderSelect.IDTree.FindNode(iID);
+    if vNode.Rec.ValueByName('Type').AsInteger = 1 then
+    begin
+      zgResult.RowCount := zgResult.RowCount + 1;
+      zgResult.Cells[1, zgResult.RowCount - 1].Text := vNode.Rec.ValueByName('Name').AsString;
+      zgResult.Cells[1, zgResult.RowCount - 1].Align := gaCenterLeft;
+      zgResult.Rows[zgResult.RowCount - 1].Data := vNode;
+    end;
+  end;
+end;
+
+procedure TstgSelectFileForm.AssignSelect(AGatherControl: TstgGatherControl);
+begin
+  AGatherControl.SumBaseFile := leSumBaseFile.Text;
+  AGatherControl.Projects.Assign(FSelects);
+end;
+
+constructor TstgSelectFileForm.Create(AGatherControl: TstgGatherControl);
+begin
+  inherited Create(nil);
+  stdTenderSelect.DataView := ProjectManager.sdvProjectsSpare;
+  FSelects := TList.Create;
+  FSelects.Assign(AGatherControl.Projects);
+  InitResultGrid;
+  leSumBaseFile.Text := AGatherControl.SumBaseFile;
+end;
+
+destructor TstgSelectFileForm.Destroy;
+begin
+  FSelects.Free;
+  inherited;
+end;
+
+procedure TstgSelectFileForm.AssignResult;
+begin
+  InitResultGrid;
+  AssignResultGrid;
+end;
+
+procedure TstgSelectFileForm.btnOkClick(Sender: TObject);
+begin
+  if (leSumBaseFile.Text = '') then
+    WarningMessage('请选择总包基准文件。', Handle)
+  else if not FileExists(leSumBaseFile.Text) then
+    WarningMessage('当前选择的总包基准文件不存在,请重新选择。', Handle)
+  else if SelectCount = 0 then
+    WarningMessage('请选择需要汇总的分包标段。', Handle)
+  else
+    ModalResult := mrOk;
+end;
+
+function TstgSelectFileForm.GetSelectCount: Integer;
+begin
+  Result := zgResult.RowCount - zgResult.FixedRowCount;
+end;
+
+procedure TstgSelectFileForm.btnSelectSbfClick(Sender: TObject);
+var
+  sFileName: string;
+begin
+  sFileName := leSumBaseFile.Text;
+  if SelectFile(sFileName, '.sbf') then
+    leSumBaseFile.Text := sFileName;
+end;
+
+end.

+ 2 - 2
Units/CacheTree.pas

@@ -55,7 +55,7 @@ type
 
     function GetNodeID(ANode: TCacheNode): Integer;
   public
-    constructor Create(ACacheTree: TCacheTree; AID: Integer);
+    constructor Create(ACacheTree: TCacheTree; AID: Integer); virtual;
     destructor Destroy; override;
 
     procedure InsertChild(AChildNode: TCacheNode);
@@ -87,7 +87,7 @@ type
     function GetFirstNode: TCacheNode;
     procedure SetNewNodeID(const Value: Integer);
   protected
-    function GetNewNodeID: Integer;   
+    function GetNewNodeID: Integer;
     function GetNewNode: TCacheNode; virtual;
   public
     constructor Create; virtual;

+ 1 - 1
Units/GclBillsGatherModel.pas

@@ -1069,7 +1069,7 @@ constructor TLeafXmjNode.Create(ALeafXmj, APeg: TBillsIDTreeNode);
   begin
     // 如果计量单元节点的名称为桩号(转化为判断计量单元节点与桩号节点为同一个)
     if not Assigned(APegNode) or (ANode.ID = APegNode.ID) then
-      // 取分工程
+      // 取分工程
       Result := GetNameFenXiang(ANode, APegNode)
     // 反之,取分项工程+计量单元
     else

+ 23 - 1
Units/ProjectData.pas

@@ -142,6 +142,10 @@ type
     procedure OpenForGather(const AFileName: string; APhaseIndex: Integer = -1);
     {OpenForSignOnline: BillsData, BillsMeasureTree, PhaseData(根据PhaseIndex指定打开)}
     procedure OpenForSignOnline(const AFileName: string; APhaseIndex: Integer = -1);
+    {OpenForSumUpBase: BillsData, BillsComplieTree}
+    procedure OpenForSumUpBase(const AFileName: string);
+    {OpenForSumUpGather: BillsData, BillsMeasureTree, PhaseData(根据PhaseIndex指定打开),直接调用OpenForSignOnline}
+    procedure OpenForSumUpGather(const AFileName: string; APhaseIndex: Integer = -1);
     //-----------------------  End ---后台打开 ------------------------
 
     procedure SaveDebugFile(const AFileName: string);
@@ -1441,7 +1445,7 @@ begin
   FBillsData.Open(FConnection.Connection);
   FBillsCompileData.Open;
   FDealPaymentData.Open(FConnection.Connection);
-  FBGLData.Open(FConnection.Connection);  
+  FBGLData.Open(FConnection.Connection);
 end;
 
 procedure TProjectData.OpenForReply(const AFileName: string);
@@ -2178,4 +2182,22 @@ begin
   FIsGuest := Value;
 end;
 
+procedure TProjectData.OpenForSumUpBase(const AFileName: string);
+begin
+  FProjectID := -1;
+  UnZipFile(AFileName, TempPath);
+  FConnection.Open(MainFileName);
+  UpdateProjectDataBase;
+  FProjProperties.Open(FConnection.Connection);
+  UpdateOldData;
+  FBillsData.Open(FConnection.Connection);
+  FBillsCompileData.Open;
+end;
+
+procedure TProjectData.OpenForSumUpGather(const AFileName: string;
+  APhaseIndex: Integer);
+begin
+  OpenForSignOnline(AFileName, APhaseIndex);
+end;
+
 end.