Переглянути джерело

Merge branch 'sumUp'

Conflicts:
	Forms/MainFrm.dfm
	Forms/MainFrm.pas
	Frames/BillsCompileFme.dfm
	Units/ProjectData.pas
MaiXinRong 7 роки тому
батько
коміт
ecb9103edc

+ 3 - 3
DataModules/StageDm.pas

@@ -25,9 +25,6 @@ type
     FBeforeChangeQuantity: Double;
     FBeforeChangeTotalPrice: Double;
 
-    procedure BeforeBatchOperation;
-    procedure AfterBatchOperation;
-
     procedure UpdateParentRecord(ABillsID: Integer; ATotalPrice: Double; const AFieldName: string);
     procedure UpdateComplete(ABillsID: Integer; AQuantity, ATotalPrice: Double);
 
@@ -78,6 +75,9 @@ type
     procedure Open(AConnection: TADOConnection);
     procedure Save;
 
+    procedure BeforeBatchOperation;
+    procedure AfterBatchOperation;
+
     // 计算任一清单节点的价差金额,并增量汇总至父项
     procedure CalculatePriceMargin(ABillsID: Integer);
     // 计算材料调差节点

+ 7 - 4
DataModules/ZJJLDm.pas

@@ -530,9 +530,12 @@ procedure TZJJLData.CheckZjjlVerison;
     for i := 0 to sddZJJL.RecordCount - 1 do
     begin
       Rec := sddZJJL.Records[i];
-      SetHistory('CertificateCode', Rec.ValueByName('CertificateCode').AsString, Rec);
-      SetHistory('FormulaMemo', Rec.ValueByName('FormulaMemo').AsString, Rec);
-      SetHistory('RelaFile', Rec.ValueByName('RelaFile').AsString, Rec);
+      if Rec.ValueByName('CertificateCode').AsString <> '' then
+        SetHistory('CertificateCode', Rec.ValueByName('CertificateCode').AsString, Rec);
+      if Rec.ValueByName('FormulaMemo').AsString <> '' then
+        SetHistory('FormulaMemo', Rec.ValueByName('FormulaMemo').AsString, Rec);
+      if Rec.ValueByName('RelaFile').AsString <> '' then
+        SetHistory('RelaFile', Rec.ValueByName('RelaFile').AsString, Rec);
     end;
   end;
 
@@ -735,7 +738,7 @@ procedure TZJJLData.sdvZJJLBeforeValueChange(AValue: TsdValue;
 var
   sNewValue: string;
 begin
-  if CheckFieldNeedHistory(AValue.FieldName) then
+  if CheckFieldNeedHistory(AValue.FieldName) and not TPhaseData(FPhaseData).StageDataReadOnly then
   begin
     sNewValue := VarToStrDef(NewValue, '');
     if sNewValue <> AValue.AsString then

+ 72 - 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,18 @@ object MainForm: TMainForm
           Visible = True
         end
         item
+          BeginGroup = True
           Item = dxbtnImportDmf
           Visible = True
+        end
+        item
+          BeginGroup = True
+          Item = dxbtnExportSumBaseFile
+          Visible = True
+        end
+        item
+          Item = dxbtnImportSubTenderGather
+          Visible = True
         end>
     end
     object dxsiEdit: TdxBarSubItem
@@ -1000,6 +1012,10 @@ object MainForm: TMainForm
         item
           Item = dxbtnTenderPartition
           Visible = True
+        end
+        item
+          Item = dxbtnGatherSubTender
+          Visible = True
         end>
     end
     object dxbtnTenderPartition: TdxBarButton
@@ -1124,12 +1140,56 @@ object MainForm: TMainForm
       Hint = #23450#20301#33267#21488#36134#20998#35299
       Visible = ivAlways
     end
+<<<<<<< HEAD
     object dxbtnGclGatherZJJL: TdxBarButton
       Caption = #35745#37327#27719#24635#26684#24335
       Category = 0
       Hint = #35745#37327#27719#24635#26684#24335
       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 dxbtnExportTenderError: 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 dxbtnExportAllError: TdxBarButton
+      Caption = #23548#20986#20840#37096#38169#35823#20449#24687
+      Category = 0
+      Hint = #23548#20986#20840#37096#38169#35823#20449#24687
+      Visible = ivAlways
+    end
+    object dxbtnExportStgResultExcel: TdxBarButton
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      Category = 0
+      Hint = #23548#20986#20998#21253#27719#24635#32467#26524
+      Visible = ivAlways
+      ImageIndex = 13
+    end
+    object dxbtnExportStgResult: TdxBarButton
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      Category = 0
+      Hint = #23548#20986#20998#21253#27719#24635#32467#26524
+      Visible = ivAlways
+    end
+    object dxbtnImportSubTenderGather: TdxBarButton
+      Action = actnImportSubTenderGather
+      Category = 0
+    end
+>>>>>>> sumUp
   end
   object Images: TImageList
     DrawingStyle = dsTransparent
@@ -3303,6 +3363,18 @@ 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 actnImportSubTenderGather: TAction
+      Category = 'File'
+      Caption = #23548#20837#20998#21253#27719#24635#25968#25454
+      OnExecute = actnImportSubTenderGatherExecute
+      OnUpdate = actnImportSubTenderGatherUpdate
+    end
   end
   object dxpmTabSet: TdxBarPopupMenu
     BarManager = dxBarManager

+ 80 - 1
Forms/MainFrm.pas

@@ -168,7 +168,19 @@ type
     dxbtnLocateZJJL: TdxBarButton;
     dxbtnEpure: TdxBarButton;
     dxbtnLocateCompileBills: TdxBarButton;
+<<<<<<< HEAD
     dxbtnGclGatherZJJL: TdxBarButton;
+=======
+    dxbtnExportSumBaseFile: TdxBarButton;
+    actnExportSumBaseFile: TAction;
+    dxbtnGatherSubTender: TdxBarButton;
+    dxbtnExportTenderError: TdxBarButton;
+    dxbtnExportAllError: TdxBarButton;
+    dxbtnExportStgResultExcel: TdxBarButton;
+    dxbtnExportStgResult: TdxBarButton;
+    dxbtnImportSubTenderGather: TdxBarButton;
+    actnImportSubTenderGather: TAction;
+>>>>>>> sumUp
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure jtsProjectsChange(Sender: TObject; NewTab: Integer;
@@ -214,6 +226,10 @@ type
     procedure dxbtnTenderPartitionClick(Sender: TObject);
     procedure actnImportDmfExecute(Sender: TObject);
     procedure dxbtnHelpCenterClick(Sender: TObject);
+    procedure actnExportSumBaseFileExecute(Sender: TObject);
+    procedure dxbtnGatherSubTenderClick(Sender: TObject);
+    procedure actnImportSubTenderGatherExecute(Sender: TObject);
+    procedure actnImportSubTenderGatherUpdate(Sender: TObject);
   private
     FProjectManagerFrame: TProjectManagerFrame;
     FProjectFrames: TList;
@@ -251,7 +267,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}
@@ -875,4 +892,66 @@ 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;
+
+procedure TMainForm.actnImportSubTenderGatherExecute(Sender: TObject);
+var
+  sFileName: string;
+begin
+  if CurProjectFrame.ProjectData.ProjProperties.PhaseCount = 0 then
+    WarningMessage('未开始计量,请在开始计量后再导入分包汇总数据。')
+  else if CurProjectFrame.ProjectData.StageDataReadOnly then
+    WarningMessage('当前正在查看往期数据,请切换至最新一起再导入分包汇总数据。')
+  else if SelectFile(sFileName, '.sgf') then
+    CurProjectFrame.ProjectData.ImportSubTenderGather(sFileName);
+end;
+
+procedure TMainForm.actnImportSubTenderGatherUpdate(Sender: TObject);
+begin
+  TAction(Sender).Enabled := (jtsProjects.Tabs.Count > 1) and Assigned(CurProjectFrame);
+end;
+
 end.

+ 14 - 13
Frames/BillsCompileFme.dfm

@@ -53,7 +53,11 @@ object BillsCompileFrame: TBillsCompileFrame
       Height = 376
       Options = [goRangeSelect, goRowSizing, goColSizing, goCellNotMaintainData, goFixedRowShowNo, goFixedColShowNo, goAlwaysShowSelection, goShowTreeLine]
       OptionsEx = []
+<<<<<<< HEAD
       ColCount = 25
+=======
+      ColCount = 26
+>>>>>>> sumUp
       RowCount = 7
       FixedRowCount = 3
       ShowGridLine = False
@@ -678,7 +682,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
@@ -692,13 +696,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
@@ -712,13 +716,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
@@ -732,13 +735,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
@@ -752,10 +754,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

+ 276 - 0
SubTenderGather/stgExcelExport.pas

@@ -0,0 +1,276 @@
+unit stgExcelExport;
+
+interface
+
+uses
+  Classes, OExport, OExport_Vcl, OExport_VclForms, stgGatherDm, sdDB,
+  stgGatherCacheData, stgGatherUtils, sdIDTree, Graphics;
+
+type
+  TstgExcelExport = class
+  private
+    FTempFile: string;
+    FGatherData: TstgGatherData;
+    FOExport: TOExport;
+    FOExportor: TOCustomExporter;
+  protected
+    function AddHeadCell(ARow: TExportRow; const AHead: string; AWidth: Integer): TExportCellString;
+
+    function GetExportor(const AFileType: string): TOCustomExporter;
+
+    procedure SaveFile(const AFileName: string);
+
+    procedure BeforeExport;
+    procedure AfterExport;
+  public
+    constructor Create(AGatherData: TstgGatherData);
+
+    property GatherData: TstgGatherData read FGatherData;
+    property OExport: TOExport read FOExport;
+  end;
+
+  TstgErrorExcelExport = class(TstgExcelExport)
+  private
+    procedure InitSheet(ASheet: TExportWorkSheet);
+    procedure ExportSubTenderToSheet(ATenderID: Integer; ASheet: TExportWorkSheet);
+  public
+    procedure ExportSubTender(ARec: TsdDataRecord; const AFileName: string);
+    procedure ExportAll(const AFileName: string);
+  end;
+
+  TstgGatherExcelExport = class(TstgExcelExport)
+  private
+    procedure InitSheet(ASheet: TExportWorkSheet);
+    procedure ExportTreeNodeToSheet(ANode: TsdIDTreeNode; ASheet: TExportWorkSheet);
+    procedure ExportGatherToSheet(ASheet: TExportWorkSheet);
+  public
+    procedure ExportGather(const AFileName: string);
+  end;
+
+implementation
+
+uses SysUtils, UtilMethods, ZhAPI;
+
+{ TstgErrorExcelExport }
+
+procedure TstgErrorExcelExport.ExportAll(const AFileName: string);
+var
+  i: Integer;
+  vRec: TsdDataRecord;
+begin
+  BeforeExport;
+  try
+    GetExportor(ExtractFileExt(AFileName));
+    for i := 0 to FGatherData.sddSubTenders.RecordCount - 1 do
+    begin
+      vRec := FGatherData.sddSubTenders.Records[i];
+      ExportSubTenderToSheet(vRec.ValueByName('ID').AsInteger, FOExport.AddWorkSheet(vRec.ValueByName('Name').AsString));
+    end;
+    SaveFile(AFileName);
+  finally
+    AfterExport;
+  end;
+end;
+
+procedure TstgErrorExcelExport.ExportSubTender(ARec: TsdDataRecord;
+  const AFileName: string);
+begin
+  BeforeExport;
+  try
+    GetExportor(ExtractFileExt(AFileName));
+    ExportSubTenderToSheet(ARec.ValueByName('ID').AsInteger, FOExport.AddWorkSheet(ARec.ValueByName('Name').AsString));
+    SaveFile(AFileName);
+  finally
+    AfterExport;
+  end;
+end;
+
+procedure TstgErrorExcelExport.ExportSubTenderToSheet(ATenderID: Integer;
+  ASheet: TExportWorkSheet);
+
+  procedure ExportErrorRecord(ARec: TsdDataRecord);
+  var
+    vRow: TExportRow;
+    vCell: TExportCell;
+  begin
+    vRow := ASheet.AddRow;
+    vCell := vRow.AddCellString(ARec.ValueByName('RelaCode').AsString);
+    vCell := vRow.AddCellString(ARec.ValueByName('RelaSerialNo').AsString);
+    vCell.SetAlignment(cahCenter);
+    vCell := vRow.AddCellString(ARec.ValueByName('DetailCode').AsString);
+    vCell := vRow.AddCellString(ARec.ValueByName('DetailSerialNo').AsString);
+    vCell.SetAlignment(cahCenter);
+    vCell := vRow.AddCellString(GetErrorTypeText(ARec.ValueByName('ErrorType').AsInteger));
+  end;
+
+var
+  vIdx: TsdIndex;
+  i, iBegin, iEnd: Integer;
+  vRec: TsdDataRecord;
+begin
+  InitSheet(ASheet);
+  vIdx := GatherData.sddErrorDetail.FindIndex('idxTenderID');
+  iBegin := vIdx.FindKeyIndex(ATenderID);
+  iEnd := vIdx.FindKeyLastIndex(ATenderID);
+  if iBegin = -1 then Exit;
+  for i := iBegin to iEnd do
+    ExportErrorRecord(vIdx.Records[i]);
+end;
+
+procedure TstgErrorExcelExport.InitSheet(ASheet: TExportWorkSheet);
+var
+  vRow: TExportRow;
+  vCell: TExportCellString;
+begin
+  vRow := ASheet.AddRow;
+  vCell := AddHeadCell(vRow, '出错源', 120);
+  vCell.ColSpan := 2;
+  vCell := AddHeadCell(vRow, '可计量清单', 80);
+  vCell.ColSpan := 2;
+  vCell := AddHeadCell(vRow, '错误原因', 200);
+  vCell.RowSpan := 2;
+
+  vRow := ASheet.Rows.Items[vRow.RowIndex + 1];
+  vCell := AddHeadCell(vRow, '编号', 120);
+  vCell := AddHeadCell(vRow, '行号', 50);
+  vCell := AddHeadCell(vRow, '编号', 80);
+  vCell := AddHeadCell(vRow, '行号', 50);
+end;
+
+{ TstgExcelExport }
+
+function TstgExcelExport.AddHeadCell(ARow: TExportRow; const AHead: string;
+  AWidth: Integer): TExportCellString;
+begin
+  Result := ARow.AddCellString(AHead);
+  Result.SetAlignment(cahCenter);
+  Result.SetVAlignment(cavCenter);
+  Result.Font.Name := '黑体';
+  Result.Font.Size := 10;
+  Result.Width := AWidth;
+end;
+
+procedure TstgExcelExport.AfterExport;
+begin
+  FOExport.Free;
+  if Assigned(FOExportor) then
+    FOExportor.Free;
+  if FileExists(FTempFile) then
+    DeleteFile(FTempFile);
+end;
+
+procedure TstgExcelExport.BeforeExport;
+begin
+  FOExport := TOExport.Create;
+  FOExport.UseProgress := False;
+  FTempFile := GetTempFileName;
+end;
+
+constructor TstgExcelExport.Create(AGatherData: TstgGatherData);
+begin
+  FGatherData := AGatherData;
+end;
+
+function TstgExcelExport.GetExportor(
+  const AFileType: string): TOCustomExporter;
+begin
+  if SameText(AFileType, '.xls') then
+    FOExportor := TOCustomExporterXLS.Create
+  else //if SameText(AFileType, '.xlsx') then
+    FOExportor := TOCustomExporterXLSX.Create;
+end;
+
+procedure TstgExcelExport.SaveFile(const AFileName: string);
+begin
+  FOExport.SaveToFile(FTempFile, FOExportor);
+  if not FileExists(AFileName) or QuestMessage('存在同名文件,是否替换?') then
+    CopyFileOrFolder(FTempFile, AFileName);
+end;
+
+{ TstgGatherExcelExport }
+
+procedure TstgGatherExcelExport.ExportGather(const AFileName: string);
+begin
+  BeforeExport;
+  try
+    GetExportor(ExtractFileExt(AFileName));
+    ExportGatherToSheet(OExport.AddWorkSheet('分包数据汇总'));
+    SaveFile(AFileName);
+  finally
+    AfterExport;
+  end;
+end;
+
+procedure TstgGatherExcelExport.ExportGatherToSheet(
+  ASheet: TExportWorkSheet);
+var
+  vTree: TsdIDTree;
+begin
+  InitSheet(ASheet);
+  vTree := TsdIDTree.Create;
+  try
+    vTree.KeyFieldName := 'ID';
+    vTree.ParentFieldName := 'ParentID';
+    vTree.NextSiblingFieldName := 'NextSiblingID';
+    vTree.DataView := GatherData.sdvGatherTree;
+    ExportTreeNodeToSheet(vTree.FirstNode, ASheet);
+  finally
+    vTree.Free;
+  end;
+end;
+
+procedure TstgGatherExcelExport.ExportTreeNodeToSheet(ANode: TsdIDTreeNode;
+  ASheet: TExportWorkSheet);
+
+  procedure AddCellString(ARow: TExportRow; const AStr: string; AColor: TColor);
+  var
+    vCell: TExportCellString;
+  begin
+    vCell := ARow.AddCellString(AStr);
+    vCell.Font.Color := AColor;
+  end;
+
+  procedure AddCellNumber(ARow: TExportRow; const ANum: Double; AColor: TColor);
+  var
+    vCell: TExportCellNumber;
+  begin
+    vCell := ARow.AddCellNumber(ANum);
+    vCell.Font.Color := AColor;
+    vCell.EmptyIfZero := True;
+  end;
+
+var
+  vColor: TColor;
+  vRow: TExportRow;
+  vCell: TExportCellNumber;
+begin
+  if not Assigned(ANode) then Exit;
+  if ANode.Rec.ValueByName('IsSubTender').AsBoolean then
+    vColor := $00D5D5D5
+  else
+    vColor := clWindowText;
+  vRow := ASheet.AddRow;
+  AddCellString(vRow, ANode.Rec.ValueByName('Code').AsString, vColor);
+  AddCellString(vRow, ANode.Rec.ValueByName('B_Code').AsString, vColor);
+  AddCellString(vRow, ANode.Rec.ValueByName('Name').AsString, vColor);
+  AddCellString(vRow, ANode.Rec.ValueByName('Units').AsString, vColor);
+  AddCellNumber(vRow, ANode.Rec.ValueByName('DealQuantity').AsFloat, vColor);
+  AddCellNumber(vRow, ANode.Rec.ValueByName('QcQuantity').AsFloat, vColor);
+  ExportTreeNodeToSheet(ANode.FirstChild, ASheet);
+  ExportTreeNodeToSheet(ANode.NextSibling, ASheet);
+end;
+
+procedure TstgGatherExcelExport.InitSheet(ASheet: TExportWorkSheet);
+var
+  vRow: TExportRow;
+begin
+  vRow := ASheet.AddRow;
+  AddHeadCell(vRow, '项目节编号', 180);
+  AddHeadCell(vRow, '清单编号', 80);
+  AddHeadCell(vRow, '名称', 240);
+  AddHeadCell(vRow, '单位', 50);
+  AddHeadCell(vRow, '合同计量', 100);
+  AddHeadCell(vRow, '数量变更计量', 100);
+end;
+
+end.

+ 429 - 0
SubTenderGather/stgGather.pas

@@ -0,0 +1,429 @@
+unit stgGather;
+
+interface
+
+uses
+  Classes, stgGatherCacheData, ProjectData, BillsTree, sdIDTree;
+
+type
+  TProgramHintEvent = procedure (const ATenderName: string) of Object;
+
+  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;
+    FLoadHint: TProgramHintEvent;
+    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);
+
+    property LoadHint: TProgramHintEvent read FLoadHint write FLoadHint;
+  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;
+  Result.IsLeaf := not ANode.HasChildren;
+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
+  if (AGatherNode.IsSubTender) or (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;
+    FLoadHint(vNode.Rec.ValueByName('Name').AsString);
+    FProjectData := OpenProjectManager.FindProjectData(ASubTenderID);
+    try
+      if not Assigned(FProjectData) then
+      begin
+        FProjectData := TProjectData.Create;
+        FProjectData.OpenForSumUpGather(GetMyProjectsFilePath + vNode.Rec.ValueByName('FileName').AsString);
+      end;
+      FCacheData.AddSubTender(vNode.Rec);
+      GatherSubTenderTreeNode(FProjectData.BillsMeasureData.BillsMeasureTree.FirstNode, nil);
+    finally
+      if not Assigned(OpenProjectManager.FindProjectData(ASubTenderID)) then
+        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
+    vNext := FCacheData.GatherTree.FindNextSibling(AParent, vNode.Rec.Code.AsString, vNode.Rec.B_Code.AsString);
+    if not Assigned(AParent) or (not (AParent.IsSumBase and AParent.IsLeafXmj)) or (vNode.Rec.B_Code.AsString <> '') {or (not ANode.HasChildren)} then
+    begin
+      if ANode.ID < 100 then
+        Result := FCacheData.GatherTree.AddSubTenderNode(AParent, vNext, ANode.ID)
+      else
+        Result := FCacheData.GatherTree.AddSubTenderNode(AParent, vNext);
+      Result.Code := Trim(vNode.Rec.Code.AsString);
+      Result.B_Code := Trim(vNode.Rec.B_Code.AsString);
+      Result.Name := Trim(vNode.Rec.Name.AsString);
+      Result.Units := Trim(vNode.Rec.Units.AsString);
+      Result.IsLeaf := not vNode.HasChildren;
+    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, iErrorGclMore)
+  else if HasShortRelaCodeChild(ANode) then
+    NewError(ANode, iErrorGclLess)
+  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) and (vChild.IsSumBase) 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) and (vChild.IsSumBase) 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 and vChild.IsSumBase 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.

+ 738 - 0
SubTenderGather/stgGatherCacheData.pas

@@ -0,0 +1,738 @@
+unit stgGatherCacheData;
+
+interface
+
+uses
+  CacheTree, SysUtils, BillsTree, Classes, sdDB, mDataRecord;
+
+const
+  // 新增项目节
+  iErrorXmjAdd = 1;
+  sErrorXmjAdd = '新增';
+  // 存在同号项目节,但名称、单价不同
+  iErrorXmjDiff = 2;    
+  sErrorXmjDiff = '存在同号不同名(单位)';
+  // 项目节层次少于总包
+  iErrorXmjLess = 3;
+  sErrorXmjLess = '父项项目节,层次少于总包';
+
+  // 新增工程量清单
+  iErrorGclAdd = 11;
+  sErrorGclAdd = '新增';
+  // 存在同名工程量清单,但名称、单价不同
+  iErrorGclDiff = 12;   
+  sErrorGclDiff = '存在同号不同名(单位)';
+  // 工程量清单层次多于总包
+  iErrorGclMore = 13;
+  sErrorGclMore = '工程量清单,层次多于总包';
+  // 工程量清单层次少于总包
+  iErrorGclLess = 14;
+  sErrorGclLess = '工程量清单,层次少于总包';
+
+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, AB_Code: 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, AB_Code: string): TstgGatherTreeNode;
+var
+  vChild: TstgGatherTreeNode;
+begin
+  Result := nil;
+  if Assigned(AParent) then
+    vChild := TstgGatherTreeNode(AParent.FirstChild)
+  else
+    vChild := TstgGatherTreeNode(Root.FirstChild);
+  while not Assigned(Result) and Assigned(vChild) do
+  begin
+    if (CompareCode(ACode, vChild.Code) < 0) or (CompareCode(AB_Code, vChild.B_Code) < 0) then
+      Result := vChild;
+    vChild := TstgGatherTreeNode(vChild.NextSibling);
+  end;
+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, Trim(AInfo.Rec.Code.AsString)) and SameText(vNode.B_Code, Trim(AInfo.Rec.B_Code.AsString))
+        and SameText(vNode.Name, Trim(AInfo.Rec.Name.AsString)) and SameText(vNode.Units, Trim(AInfo.Rec.Units.AsString))
+        and ((vNode.B_Code = '') or (vNode.IsLeaf = not AInfo.HasChildren)) 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 + 1;
+  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.

+ 137 - 0
SubTenderGather/stgGatherControl.pas

@@ -0,0 +1,137 @@
+unit stgGatherControl;
+
+interface
+
+uses
+  Classes, stgGatherCacheData, stgGatherDm, stgResultFrm,
+  stgGather;
+
+type
+  TstgGatherControl = class
+  private
+    FProjects: TList;
+    FSumBaseFile: string;
+
+    FGatherCacheData: tstgGatherCacheData;
+    FGatherData: TstgGatherData;
+    FResultForm: TstgResultForm;
+
+    FHintPosition: Integer;
+
+    procedure LoadHint(const ATenderName: string);
+
+    procedure LoadSumBaseFile;
+    procedure GatherSubTenderFiles;
+    procedure CheckErrorData;
+    procedure SaveGatherResult;
+    procedure ShowGatherResult;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    procedure Gather;
+
+    property Projects: TList read FProjects;
+    property SumBaseFile: string read FSumBaseFile write FSumBaseFile;
+  end;
+
+implementation
+
+uses
+  ProgressHintFrm, SysUtils;
+
+{ 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
+  FHintPosition := 0;
+  ShowProgressHint('正在导入总包基准文件数据...', FProjects.Count + 2);
+  LoadSumBaseFile;
+  GatherSubTenderFiles;
+  UpdateProgressHint('正在检查汇总结果...');
+  UpdateProgressPosition(FProjects.Count + 1);
+  CheckErrorData;
+  UpdateProgressPosition(FProjects.Count + 2);
+  SaveGatherResult;
+  CloseProgressHint;
+  ShowGatherResult;
+end;
+
+procedure TstgGatherControl.GatherSubTenderFiles;
+var
+  vGather: TstgSubTenderFileGather;
+begin
+  vGather := TstgSubTenderFileGather.Create;
+  try
+    vGather.LoadHint := LoadHint;
+    vGather.GatherTo(FGatherCacheData, FProjects);
+  finally
+    vGather.Free;
+  end;
+end;
+
+procedure TstgGatherControl.LoadHint(const ATenderName: string);
+begin
+  Inc(FHintPosition);
+  UpdateProgressHint(Format('正在汇总分包标段"%s"...', [ATenderName]));
+  UpdateProgressPosition(FHintPosition);
+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;
+begin
+  FGatherData.LoadGatherData(FGatherCacheData);
+end;
+
+procedure TstgGatherControl.ShowGatherResult; 
+var
+  Form: TstgResultForm;
+begin
+  Form := TstgResultForm.Create(nil);
+  try
+    Form.SetGatherData(FGatherData);
+    Form.ShowModal;
+  finally
+    Form.Free;
+  end;
+end;
+
+end.

+ 304 - 0
SubTenderGather/stgGatherDm.dfm

@@ -0,0 +1,304 @@
+object stgGatherData: TstgGatherData
+  OldCreateOrder = False
+  Left = 37
+  Top = 195
+  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
+      6502000001044E616D650609497353756D42617365094669656C644E616D6506
+      09497353756D426173650844617461547970650205084461746153697A650201
+      0549734B6579080F4E65656450726F636573734E616D65080950726563697369
+      6F6E02000453697A6502000001044E616D65060649734C656166094669656C64
+      4E616D65060649734C6561660844617461547970650205084461746153697A65
+      02010549734B6579080F4E65656450726F636573734E616D6508095072656369
+      73696F6E02000453697A6502000000}
+  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}
+    IndexListData = {
+      01044E616D65060B69647854656E64657249440A4669656C644E616D65730608
+      54656E64657249440000}
+  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

+ 281 - 0
SubTenderGather/stgGatherDm.pas

@@ -0,0 +1,281 @@
+unit stgGatherDm;
+// ½á¹ûչʾ£¬ÄÚ´æ±í
+
+interface
+
+uses
+  SysUtils, Classes, stgGatherCacheData, sdDB, sdProvider, stgGatherUtils;
+
+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('IsSumBase').AsBoolean := ANode.IsSumBase;
+  Rec.ValueByName('IsLeaf').AsBoolean := ANode.IsLeaf;
+
+  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);
+
+  function GetSubTenderSerialNo(ANode: TstgGatherTreeNode; ATenderID: Integer): Integer;
+  var
+    vSource: TstgSubTenderStageData;
+  begin
+    vSource := ANode.FindSubTender(ATenderID);
+    if Assigned(vSource) then
+      Result := vSource.Detail[0].SerialNo;
+  end;
+
+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;
+        if AError.RelaNode.IsLeaf then
+          Rec.ValueByName('RelaSerialNo').AsInteger := vRelaDetailStage.Detail[k].SerialNo
+        else
+          Rec.ValueByName('RelaSerialNo').AsInteger := GetSubTenderSerialNo(AError.RelaNode, vRelaDetailStage.SubTenderID);
+        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;
+
+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.

+ 25 - 0
SubTenderGather/stgGatherUtils.pas

@@ -0,0 +1,25 @@
+unit stgGatherUtils;
+
+interface
+
+uses
+  stgGatherCacheData;
+
+  function GetErrorTypeText(AErrorType: Integer): string;
+
+implementation
+
+function GetErrorTypeText(AErrorType: Integer): string;
+begin
+  case AErrorType of
+    iErrorXmjAdd: Result := sErrorXmjAdd;
+    iErrorXmjDiff: Result := sErrorXmjDiff;
+    iErrorXmjLess: Result := sErrorXmjLess;
+    iErrorGclAdd: Result := sErrorGclAdd;
+    iErrorGclDiff: Result := sErrorGclDiff;
+    iErrorGclMore: Result := sErrorGclMore;
+    iErrorGclLess: Result := sErrorGclLess;
+  end;
+end;
+
+end.

+ 664 - 0
SubTenderGather/stgResultFrm.dfm

@@ -0,0 +1,664 @@
+object stgResultForm: TstgResultForm
+  Left = 192
+  Top = 123
+  Width = 1305
+  Height = 675
+  ActiveControl = zgGatherTree
+  BorderIcons = [biSystemMenu, biMaximize]
+  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
+  Position = poMainFormCenter
+  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
+          OnMouseDown = zgGatherTreeMouseDown
+          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
+            OnMouseDown = zgErrorInfoMouseDown
+            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
+    Visible = False
+    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 = 160
+    Top = 195
+  end
+  object dxpmError: TdxBarPopupMenu
+    BarManager = MainForm.dxBarManager
+    ItemLinks = <
+      item
+        Item = MainForm.dxbtnExportTenderError
+        Visible = True
+      end
+      item
+        Item = MainForm.dxbtnExportAllError
+        Visible = True
+      end>
+    UseOwnFont = False
+    OnPopup = dxpmErrorPopup
+    Left = 104
+    Top = 235
+  end
+  object dxpmGatherTree: TdxBarPopupMenu
+    BarManager = MainForm.dxBarManager
+    ItemLinks = <
+      item
+        Item = MainForm.dxbtnExportStgResult
+        Visible = True
+      end
+      item
+        Item = MainForm.dxbtnExportStgResultExcel
+        Visible = True
+      end>
+    UseOwnFont = False
+    OnPopup = dxpmGatherTreePopup
+    Left = 104
+    Top = 148
+  end
+  object alStgResult: TActionList
+    Images = MainForm.Images
+    Left = 256
+    Top = 110
+    object actnExportAllError: TAction
+      Caption = #23548#20986#20840#37096#38169#35823#20449#24687
+      ImageIndex = 13
+      OnExecute = actnExportAllErrorExecute
+    end
+    object actnExportTenderError: TAction
+      Caption = #23548#20986#21333#26631#27573#38169#35823#20449#24687
+      ImageIndex = 13
+      OnExecute = actnExportTenderErrorExecute
+    end
+    object actnExportStgResultExcel: TAction
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      ImageIndex = 13
+      OnExecute = actnExportStgResultExcelExecute
+    end
+    object actnExportStgResult: TAction
+      Caption = #23548#20986#20998#21253#27719#24635#32467#26524
+      OnExecute = actnExportStgResultExecute
+    end
+  end
+end

+ 190 - 0
SubTenderGather/stgResultFrm.pas

@@ -0,0 +1,190 @@
+unit stgResultFrm;
+
+interface
+
+uses
+  stgGatherDm, sdIDTree, UtilMethods, stgExcelExport, stgSubGatherFile,
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, JimTabs, JimPages, sdGridDBA, sdGridTreeDBA, ZJGrid, ExtCtrls,
+  StdCtrls, dxBar, ActnList;
+
+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;
+    dxpmGatherTree: TdxBarPopupMenu;
+    alStgResult: TActionList;
+    actnExportAllError: TAction;
+    actnExportTenderError: TAction;
+    actnExportStgResultExcel: TAction;
+    actnExportStgResult: TAction;
+    procedure jtsGatherDataChange(Sender: TObject; NewTab: Integer;
+      var AllowChange: Boolean);
+    procedure zgGatherTreeCellGetColor(Sender: TObject; ACoord: TPoint;
+      var AColor: TColor);
+    procedure zgErrorInfoMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure zgGatherTreeMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure dxpmErrorPopup(Sender: TObject);
+    procedure actnExportAllErrorExecute(Sender: TObject);
+    procedure actnExportTenderErrorExecute(Sender: TObject);
+    procedure dxpmGatherTreePopup(Sender: TObject);
+    procedure actnExportStgResultExcelExecute(Sender: TObject);
+    procedure actnExportStgResultExecute(Sender: TObject);
+  private
+    FGatherData: TstgGatherData;
+    FExcelExportor: TstgErrorExcelExport;
+    function GetExcelExportor: TstgErrorExcelExport;
+  public
+    destructor Destroy; override;
+
+    procedure SetGatherData(AGatherData: TstgGatherData);
+
+    property ExcelExportor: TstgErrorExcelExport read GetExcelExportor; 
+  end;
+
+implementation
+
+uses
+  MainFrm;
+
+{$R *.dfm}
+
+procedure TstgResultForm.jtsGatherDataChange(Sender: TObject;
+  NewTab: Integer; var AllowChange: Boolean);
+begin
+  jpsResult.ActivePageIndex := NewTab;
+end;
+
+procedure TstgResultForm.SetGatherData(AGatherData: TstgGatherData);
+begin
+  FGatherData := AGatherData;
+  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;
+
+procedure TstgResultForm.zgErrorInfoMouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+  if Button = mbRight then
+    dxpmError.PopupFromCursorPos;
+end;
+
+procedure TstgResultForm.zgGatherTreeMouseDown(Sender: TObject;
+  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+  if Button = mbRight then
+    dxpmGatherTree.PopupFromCursorPos;
+end;
+
+procedure TstgResultForm.dxpmErrorPopup(Sender: TObject);
+begin
+  SetDxBtnAction(actnExportAllError, MainForm.dxbtnExportAllError);
+  SetDxBtnAction(actnExportTenderError, MainForm.dxbtnExportTenderError);
+end;
+
+procedure TstgResultForm.actnExportAllErrorExecute(Sender: TObject);
+var
+  sFileName: string;
+begin
+  if SaveExcelFile(sFileName) then
+    ExcelExportor.ExportAll(sFileName);
+end;
+
+procedure TstgResultForm.actnExportTenderErrorExecute(Sender: TObject);
+var
+  sFileName: string;
+begin
+  if SaveExcelFile(sFileName) then
+    ExcelExportor.ExportSubTender(sdErrorInfo.DataView.Current, sFileName);
+end;
+
+function TstgResultForm.GetExcelExportor: TstgErrorExcelExport;
+begin
+  if Assigned(FGatherData) then
+  begin
+    if not Assigned(FExcelExportor) then
+      FExcelExportor := TstgErrorExcelExport.Create(FGatherData);
+    Result := FExcelExportor;
+  end
+  else
+    ErrorMessage('当前无汇总数据,无法导出');
+end;
+
+destructor TstgResultForm.Destroy;
+begin
+  if Assigned(FExcelExportor) then
+    FExcelExportor.Free;
+  inherited;
+end;
+
+procedure TstgResultForm.dxpmGatherTreePopup(Sender: TObject);
+begin
+  SetDxBtnAction(actnExportStgResult, MainForm.dxbtnExportStgResult);
+  SetDxBtnAction(actnExportStgResultExcel, MainForm.dxbtnExportStgResultExcel);
+end;
+
+procedure TstgResultForm.actnExportStgResultExcelExecute(Sender: TObject);
+var
+  vExportor: TstgGatherExcelExport;
+  sFileName: string;
+begin
+  vExportor := TstgGatherExcelExport.Create(FGatherData);
+  try
+    if SaveExcelFile(sFileName) then
+      vExportor.ExportGather(sFileName);
+  finally
+    vExportor.Free;
+  end;
+end;
+
+procedure TstgResultForm.actnExportStgResultExecute(Sender: TObject);
+var
+  sFileName: string;
+  vExportor: TstgSubGatherFileExportor;
+begin
+  if SaveFile(sFileName, '.sgf') then
+  begin
+    vExportor := TstgSubGatherFileExportor.Create;
+    try
+      vExportor.ExportGatherDataTo(FGatherData, sFileName);
+    finally
+      vExportor.Free;
+    end;
+  end;
+end;
+
+end.

+ 258 - 0
SubTenderGather/stgSelectFileFrm.dfm

@@ -0,0 +1,258 @@
+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
+      ModalResult = 2
+      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.

+ 214 - 0
SubTenderGather/stgSubGatherFile.pas

@@ -0,0 +1,214 @@
+unit stgSubGatherFile;
+// µ¼Èëµ¼³ö»ã×ܽá¹û
+
+interface
+
+uses
+  stgSubGatherFileDm, ADODB, sdDB, stgGatherDm, SysUtils, StageDm, mDataRecord;
+
+type
+  TstgSubGatherFileHelper = class
+  private
+    FTempFile: string;
+    FConnection: TADOConnection;
+    FGatherData: TstgSubGatherData;
+  public
+    constructor Create;
+    destructor Destroy; override;
+
+    procedure Open(const AFileName: string);
+    procedure Close;
+    procedure SaveTo(const AFileName: string);
+
+    property Connection: TADOConnection read FConnection;
+    property GatherData: TstgSubGatherData read FGatherData;
+  end;
+
+  TstgSubGatherFileExportor = class(TstgSubGatherFileHelper)
+  private
+    procedure LoadMemoryRecord(ARec: TsdDataRecord);
+    procedure LoadMemoryGatherData(AGatherData: TstgGatherData);
+  public
+    procedure ExportGatherDataTo(AGatherData:TstgGatherData; const AFileName: string);
+  end;
+
+  TstgSubGatherFileImportor = class(TstgSubGatherFileHelper)
+  private
+    procedure ClearOldData(AStageData: TStageData);
+    procedure ImportGatherData(AStageData: TStageData);
+  public
+    procedure ImportGatherDataTo(AStageData: TStageData; const AFileName: string);
+  end;
+
+implementation
+
+
+uses
+  UtilMethods, ZhAPI, Connections, stgTables, ScAutoUpdateUnit, Math;
+
+{ TstgSubGatherFileExportor }
+
+procedure TstgSubGatherFileExportor.ExportGatherDataTo(
+  AGatherData: TstgGatherData; const AFileName: string);
+begin
+  Open(GetEmptyDataBaseFileName);
+  try
+    LoadMemoryGatherData(AGatherData);
+  finally                             
+    SaveTo(AFileName);
+  end;
+end;
+
+procedure TstgSubGatherFileExportor.LoadMemoryRecord(ARec: TsdDataRecord);
+var
+  vRec: TsdDataRecord;
+begin
+  vRec := GatherData.sddBills.Add;
+  vRec.ValueByName('ID').AsInteger := ARec.ValueByName('ID').AsInteger;
+  vRec.ValueByName('ParentID').AsInteger := ARec.ValueByName('ParentID').AsInteger;
+  vRec.ValueByName('NextSiblingID').AsInteger := ARec.ValueByName('NextSiblingID').AsInteger;
+  vRec.ValueByName('Code').AsString := ARec.ValueByName('Code').AsString;
+  vRec.ValueByName('B_Code').AsString := ARec.ValueByName('B_Code').AsString;
+  vRec.ValueByName('Name').AsString := ARec.ValueByName('Name').AsString;
+  vRec.ValueByName('Units').AsString := ARec.ValueByName('Units').AsString;
+  vRec.ValueByName('IsSumBase').AsBoolean := ARec.ValueByName('IsSumBase').AsBoolean;
+  vRec.ValueByName('IsLeaf').AsBoolean := ARec.ValueByName('IsLeaf').AsBoolean;
+  vRec.ValueByName('DealQuantity').AsFloat := ARec.ValueByName('DealQuantity').AsFloat;
+  vRec.ValueByName('DealTotalPrice').AsFloat := ARec.ValueByName('DealTotalPrice').AsFloat;
+  vRec.ValueByName('QcQuantity').AsFloat := ARec.ValueByName('QcQuantity').AsFloat;
+  vRec.ValueByName('QcTotalPrice').AsFloat := ARec.ValueByName('QcTotalPrice').AsFloat;
+  vRec.ValueByName('QcBGLCode').AsString := ARec.ValueByName('QcBGLCode').AsString;
+  vRec.ValueByName('QcBGLNum').AsString := ARec.ValueByName('QcBGLNum').AsString;
+end;
+
+procedure TstgSubGatherFileExportor.LoadMemoryGatherData(
+  AGatherData: TstgGatherData);
+var
+  i: Integer;
+  vRec: TsdDataRecord;
+begin
+  GatherData.sddBills.BeginUpdate;
+  try
+    for i := 0 to AGatherData.sddGatherTree.RecordCount - 1 do
+    begin
+      vRec := AGatherData.sddGatherTree.Records[i];
+      LoadMemoryRecord(vRec);
+    end;
+  finally
+    GatherData.sddBills.EndUpdate;
+  end;
+end;
+
+{ TstgSubGatherFileHelper }
+
+procedure TstgSubGatherFileHelper.Close;
+begin
+  FConnection.Close;
+  if FileExists(FTempFile) then
+    DeleteFile(FTempFile);
+end;
+
+constructor TstgSubGatherFileHelper.Create;
+begin
+  FConnection := TADOConnection.Create(nil);
+  FConnection.LoginPrompt := False;
+  FGatherData := TstgSubGatherData.Create(nil);
+end;
+
+destructor TstgSubGatherFileHelper.Destroy;
+begin
+  Close;
+  FGatherData.Free;
+  FConnection.Free;
+  inherited;
+end;
+
+procedure TstgSubGatherFileHelper.Open(const AFileName: string);
+
+  procedure UpdateDataTables;
+  var
+    Updater: TScUpdater;
+  begin
+    Updater := TScUpdater.Create;
+    try
+      Updater.ForceUpdate := True;
+      Updater.Open('', FConnection, '', '');
+      Updater.AddTableDef(sStgBills, @tdStgBills, Length(tdStgBills), False, False);
+      Updater.ExcuteUpdate;
+    finally
+      Updater.Free;
+    end;
+  end;
+
+begin
+  FTempFile := GetTempFileName;
+  CopyFileOrFolder(AFileName, FTempFile);
+  FConnection.ConnectionString := Format(SAdoConnectStr, [FTempFile]);
+  FConnection.Open;
+  UpdateDataTables;
+  GatherData.Open(FConnection);
+end;
+
+procedure TstgSubGatherFileHelper.SaveTo(const AFileName: string);
+begin
+  FGatherData.Save;
+  CopyFileOrFolder(FTempFile, AFileName);
+end;
+
+{ TstgSubGatherFileImportor }
+
+procedure TstgSubGatherFileImportor.ClearOldData(AStageData: TStageData);
+var
+  i: Integer;
+  vRec: TStageRecord;
+begin
+  for i := 0 to AStageData.sddStage.RecordCount - 1 do
+  begin
+    vRec := TStageRecord(AStageData.sddStage.Records[i]);
+    vRec.DealQuantity.AsFloat := 0;
+    vRec.DealTotalPrice.AsFloat := 0;
+    vRec.DealFlag.AsInteger := 0;
+    vRec.DealFormula.AsString := '';
+    vRec.QcQuantity.AsFloat := 0;
+    vRec.QcTotalPrice.AsFloat := 0;
+    vRec.QcFlag.AsInteger := 0;
+    vRec.QcFormula.AsString := '';
+    vRec.QcBGLCode.AsString := '';
+    vRec.QcBGLNum.AsString := '';
+  end;
+end;
+
+procedure TstgSubGatherFileImportor.ImportGatherData(
+  AStageData: TStageData);
+var
+  i: Integer;
+  vOrgRec: TsdDataRecord;
+  vStageRec: TStageRecord;
+begin
+  for i := 0 to GatherData.sddBills.RecordCount - 1 do
+  begin
+    vOrgRec := GatherData.sddBills.Records[i];
+    if vOrgRec.ValueByName('IsSumBase').AsBoolean and vOrgRec.ValueByName('IsLeaf').AsBoolean then
+    begin
+      vStageRec := AStageData.StageRecordWithAdd(vOrgRec.ValueByName('ID').AsInteger);
+      vStageRec.DealQuantity.AsFloat := vOrgRec.ValueByName('DealQuantity').AsFloat;
+    end;
+  end;
+end;
+
+procedure TstgSubGatherFileImportor.ImportGatherDataTo(
+  AStageData: TStageData; const AFileName: string);
+begin
+  Open(AFileName);
+  AStageData.sddStage.BeginUpdate;
+  AStageData.BeforeBatchOperation;
+  try
+    ClearOldData(AStageData);
+    ImportGatherData(AStageData);
+  finally
+    AStageData.AfterBatchOperation;
+    AStageData.sddStage.EndUpdate;
+  end;
+end;
+
+end.

+ 68 - 0
SubTenderGather/stgSubGatherFileDm.dfm

@@ -0,0 +1,68 @@
+object stgSubGatherData: TstgSubGatherData
+  OldCreateOrder = False
+  Left = 27
+  Top = 244
+  Height = 202
+  Width = 186
+  object sdpBills: TsdADOProvider
+    TableName = 'Bills'
+    Left = 35
+    Top = 32
+  end
+  object sddBills: TsdDataSet
+    Active = False
+    Provider = sdpBills
+    Left = 35
+    Top = 96
+    FieldListData = {
+      0101044E616D6506024944094669656C644E616D650602494408446174615479
+      70650203084461746153697A6502040549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650608506172656E744944094669656C644E616D650608506172656E74494408
+      44617461547970650203084461746153697A6502040549734B6579080F4E6565
+      6450726F636573734E616D650909507265636973696F6E02000453697A650200
+      0001044E616D65060D4E6578745369626C696E674944094669656C644E616D65
+      060D4E6578745369626C696E6749440844617461547970650203084461746153
+      697A6502040549734B6579080F4E65656450726F636573734E616D6509095072
+      65636973696F6E02000453697A6502000001044E616D650604436F6465094669
+      656C644E616D650604436F64650844617461547970650218084461746153697A
+      6502320549734B6579080F4E65656450726F636573734E616D65090950726563
+      6973696F6E02000453697A6502000001044E616D650606425F436F6465094669
+      656C644E616D650606425F436F64650844617461547970650218084461746153
+      697A6502320549734B6579080F4E65656450726F636573734E616D6509095072
+      65636973696F6E02000453697A6502000001044E616D6506044E616D65094669
+      656C644E616D6506044E616D650844617461547970650218084461746153697A
+      6503C8000549734B6579080F4E65656450726F636573734E616D650909507265
+      636973696F6E02000453697A6502000001044E616D650605556E697473094669
+      656C644E616D650605556E697473084461746154797065021808446174615369
+      7A6502140549734B6579080F4E65656450726F636573734E616D650909507265
+      636973696F6E02000453697A6502000001044E616D650609497353756D426173
+      65094669656C644E616D650609497353756D4261736508446174615479706502
+      05084461746153697A6502010549734B6579080F4E65656450726F636573734E
+      616D650909507265636973696F6E02000453697A6502000001044E616D650606
+      49734C656166094669656C644E616D65060649734C6561660844617461547970
+      650205084461746153697A6502010549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      060C4465616C5175616E74697479094669656C644E616D65060C4465616C5175
+      616E746974790844617461547970650206084461746153697A6502080549734B
+      6579080F4E65656450726F636573734E616D650909507265636973696F6E0200
+      0453697A6502000001044E616D65060E4465616C546F74616C50726963650946
+      69656C644E616D65060E4465616C546F74616C50726963650844617461547970
+      650206084461746153697A6502080549734B6579080F4E65656450726F636573
+      734E616D650909507265636973696F6E02000453697A6502000001044E616D65
+      060A51635175616E74697479094669656C644E616D65060A51635175616E7469
+      74790844617461547970650206084461746153697A6502080549734B6579080F
+      4E65656450726F636573734E616D650909507265636973696F6E02000453697A
+      6502000001044E616D65060C5163546F74616C5072696365094669656C644E61
+      6D65060C5163546F74616C507269636508446174615479706502060844617461
+      53697A6502080549734B6579080F4E65656450726F636573734E616D65090950
+      7265636973696F6E02000453697A6502000001044E616D650609516342474C43
+      6F6465094669656C644E616D650609516342474C436F64650844617461547970
+      650218084461746153697A6503FF000549734B6579080F4E65656450726F6365
+      73734E616D650909507265636973696F6E02000453697A6502000001044E616D
+      650608516342474C4E756D094669656C644E616D650608516342474C4E756D08
+      44617461547970650218084461746153697A6503FF000549734B6579080F4E65
+      656450726F636573734E616D650909507265636973696F6E02000453697A6502
+      000000}
+  end
+end

+ 36 - 0
SubTenderGather/stgSubGatherFileDm.pas

@@ -0,0 +1,36 @@
+unit stgSubGatherFileDm;
+// 导入导出汇总结果,连接数据表
+
+interface
+
+uses
+  SysUtils, Classes, sdDB, sdProvider, ADODB, DB;
+
+type
+  TstgSubGatherData = class(TDataModule)
+    sdpBills: TsdADOProvider;
+    sddBills: TsdDataSet;
+  private
+  public
+    procedure Open(AConnection: TADOConnection);
+    procedure Save;
+  end;
+
+implementation
+
+{$R *.dfm}
+
+{ TstgSubGatherData }
+
+procedure TstgSubGatherData.Open(AConnection: TADOConnection);
+begin
+  sdpBills.Connection := AConnection;
+  sddBills.Open;
+end;
+
+procedure TstgSubGatherData.Save;
+begin
+  sddBills.Save;
+end;
+
+end.

+ 30 - 0
SubTenderGather/stgTables.pas

@@ -0,0 +1,30 @@
+unit stgTables;
+
+interface
+
+uses
+  DataBaseTables;
+
+const
+  sStgBills = 'Bills';
+  tdStgBills : array [0..14] of TScFieldDef = (
+    (FieldName: 'ID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: True; ForceUpdate: False),
+    (FieldName: 'ParentID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'NextSiblingID'; FieldType: ftInteger; Size: 0; Precision: 0; NotNull: True; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Code'; FieldType: ftString; Size: 50; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'B_Code'; FieldType: ftString; Size: 50; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Name'; FieldType: ftString; Size: 200; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'Units'; FieldType: ftString; Size: 50; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'IsSumBase'; FieldType: ftBoolean; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'IsLeaf'; FieldType: ftBoolean; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'DealQuantity'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'DealTotalPrice'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcQuantity'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcTotalPrice'; FieldType: ftDouble; Size: 0; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcBGLCode'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False),
+    (FieldName: 'QcBGLNum'; FieldType: ftString; Size: 255; Precision: 0; NotNull: False; PrimaryKey: False; ForceUpdate: False)
+  );
+
+implementation
+
+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

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

+ 48 - 1
Units/ProjectData.pas

@@ -143,7 +143,15 @@ type
     {OpenForGather: BillsData, BillsMeasureTree, DealPaymentData, BGLData, PhaseData(根据PhaseIndex指定打开)}
     procedure OpenForGather(const AFileName: string; APhaseIndex: Integer = -1);
     {OpenForSignOnline: BillsData, BillsMeasureTree, PhaseData(根据PhaseIndex指定打开)}
+<<<<<<< HEAD
     procedure OpenForSignOnline(AProjRec: TsdDataRecord; APhaseIndex: Integer = -1);
+=======
+    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);
+>>>>>>> sumUp
     //-----------------------  End ---后台打开 ------------------------
 
     procedure SaveDebugFile(const AFileName: string);
@@ -196,6 +204,7 @@ type
 
     procedure ImportCloudTenderFile(const AFileName: string);
     procedure ImportDmfFile(const AFileName: string);
+    procedure ImportSubTenderGather(const AFileName: string);
 
     function CheckPassword: Boolean;
 
@@ -268,7 +277,11 @@ implementation
 uses UtilMethods, Globals, ProjectCommands, sdIDTree, StageDm,
   ZJJLDm, PHPWebDm, XMLDoc, XMLIntf, ConstUnit, PasswordInputFrm,
   mProgressProFrm, mDataRecord, ConditionalDefines, DbTreeImport,
+<<<<<<< HEAD
   StrUtils, sdProvider, CalcDecimal, Math, CslJson, OrderCheckerFme;
+=======
+  StrUtils, sdProvider, CalcDecimal, Math, stgSubGatherFile;
+>>>>>>> sumUp
 
 { TProjectData }
 
@@ -1462,7 +1475,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);
@@ -2189,6 +2202,7 @@ begin
   FIsGuest := Value;
 end;
 
+<<<<<<< HEAD
 procedure TProjectData.LoadCheckersData;
 var
   sURL: string;
@@ -2208,6 +2222,39 @@ begin
         Checkers.LastChecker := Checkers.Item[iIndex];
     end;
   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;
+
+procedure TProjectData.ImportSubTenderGather(const AFileName: string);
+var
+  vImportor: TstgSubGatherFileImportor;
+begin
+  if PhaseData.StageDataReadOnly then Exit;
+
+  vImportor := TstgSubGatherFileImportor.Create;
+  try
+    vImportor.ImportGatherDataTo(PhaseData.StageData, AFileName);
+  finally
+    CalculateAll;
+    vImportor.Free;
+  end;
+>>>>>>> sumUp
 end;
 
 end.