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

Merge branch 'master' of http://192.168.1.12:3000/MaiXinRong/Measure

CSL 9 роки тому
батько
коміт
8f41f46b01
46 змінених файлів з 1033 додано та 172 видалено
  1. 50 12
      DataModules/BillsCompileDm.pas
  2. 4 2
      DataModules/BillsMeasureDm.pas
  3. 1 1
      Dprs/Pro/Measure.cfg
  4. 13 12
      Dprs/Pro/Measure.dof
  5. 3 1
      Dprs/Pro/Measure.dpr
  6. BIN
      Dprs/Pro/Measure.res
  7. 1 1
      Dprs/Pro/Measure_Cloud.cfg
  8. 8 7
      Dprs/Pro/Measure_Cloud.dof
  9. 3 1
      Dprs/Pro/Measure_Cloud.dpr
  10. BIN
      Dprs/Pro/Measure_Cloud.res
  11. 1 1
      Dprs/Pro/Measure_GuangDong.cfg
  12. 7 6
      Dprs/Pro/Measure_GuangDong.dof
  13. 3 1
      Dprs/Pro/Measure_GuangDong.dpr
  14. BIN
      Dprs/Pro/Measure_GuangDong.res
  15. 1 1
      Dprs/Pro/Measure_GuangDong_Cloud.cfg
  16. 8 7
      Dprs/Pro/Measure_GuangDong_Cloud.dof
  17. 3 1
      Dprs/Pro/Measure_GuangDong_Cloud.dpr
  18. BIN
      Dprs/Pro/Measure_GuangDong_Cloud.res
  19. 1 1
      Dprs/Pro/Measure_GuangDong_TZ.cfg
  20. 10 9
      Dprs/Pro/Measure_GuangDong_TZ.dof
  21. 3 1
      Dprs/Pro/Measure_GuangDong_TZ.dpr
  22. BIN
      Dprs/Pro/Measure_GuangDong_TZ.res
  23. 1 1
      Dprs/Pro/Measure_TZ.cfg
  24. 11 10
      Dprs/Pro/Measure_TZ.dof
  25. 3 1
      Dprs/Pro/Measure_TZ.dpr
  26. BIN
      Dprs/Pro/Measure_TZ.res
  27. 1 1
      Dprs/Trail/Measure.cfg
  28. 14 13
      Dprs/Trail/Measure.dof
  29. 3 1
      Dprs/Trail/Measure.dpr
  30. BIN
      Dprs/Trail/Measure.res
  31. 1 1
      Dprs/Trail/Measure_GuangDong.cfg
  32. 13 12
      Dprs/Trail/Measure_GuangDong.dof
  33. 3 1
      Dprs/Trail/Measure_GuangDong.dpr
  34. BIN
      Dprs/Trail/Measure_GuangDong.res
  35. 22 16
      Forms/MainFrm.dfm
  36. 13 2
      Forms/MainFrm.pas
  37. 4 1
      Forms/WelcomeFrm.pas
  38. 9 0
      Frames/BillsCompileFme.dfm
  39. 22 1
      Frames/BillsCompileFme.pas
  40. 3 2
      Frames/ProjectManagerFme.pas
  41. 31 0
      Units/BillsTree.pas
  42. 581 0
      Units/DetailExcelImport.pas
  43. 46 0
      Units/MCacheTree.pas
  44. 101 31
      Units/ProjectCommands.pas
  45. 23 10
      Units/ProjectData.pas
  46. 8 3
      Units/UtilMethods.pas

+ 50 - 12
DataModules/BillsCompileDm.pas

@@ -27,7 +27,6 @@ type
     FBillsData: TBillsData;
     FBillsCompileTree: TBillsIDTree;
 
-    FBeforeChangeParentID: Integer;
     FOnRecChange: TRecChangeEvent;
 
     function GatherChildrenOrg(ANode: TsdIDTreeNode): Double;
@@ -84,6 +83,7 @@ type
 
     procedure ExpandNodeTo(ALevel: Integer);
     procedure ExpandXmjNode;
+    procedure ExpandPegXmjNode;
 
     procedure ReorderChildrenCode(ANode: TsdIDTreeNode);
 
@@ -121,6 +121,7 @@ begin
   FBillsCompileTree.DataView := sdvBillsCompile;
   FBillsCompileTree.SeedID := Max(FBillsCompileTree.SeedID, 100);
   FBillsCompileTree.DoOnAfterDeleteNode := DoOnAfterDeleteNode;
+  FBillsCompileTree.OnReCalcParent := Calculate;
 end;
 
 destructor TBillsCompileData.Destroy;
@@ -228,12 +229,6 @@ begin
       SameText(AValue.FieldName, 'DgnQuantity1') then
     CalculateTotal(AValue.Owner.ValueByName('ID').AsInteger);
 
-  if (AValue.FieldName = 'ParentID') then
-  begin
-    Calculate(FBeforeChangeParentID);
-    Calculate(AValue.AsInteger);
-  end;
-
   if (AValue.FieldName = 'LockedInfo') then
   begin
     stnNode := BillsCompileTree.FindNode(AValue.Owner.ValueByName('ID').AsInteger);
@@ -307,9 +302,7 @@ begin
       DataSetErrorMessage(Allow, '变更清单不可填写0号台账数量与金额');
   end;
   if not Allow then Exit;
-
-  if SameText(AValue.FieldName, 'ParentID') then
-    FBeforeChangeParentID := AValue.AsInteger;
+    
   if SameText(AValue.FieldName, 'OrgQuantity') or
       SameText(AValue.FieldName, 'MisQuantity') or
       SameText(AValue.FieldName, 'OthQuantity') or
@@ -643,7 +636,7 @@ procedure TBillsCompileData.sdvBillsCompileSetText(var Text: String;
     begin
       if Text = '' then
         Exit
-      else if (Pos('Quantity', AColumn.FieldName) > 0) or
+      else if ((Pos('Quantity', AColumn.FieldName) > 0) and (Pos('Dgn', AColumn.FieldName) <=0)) or
           (Pos('TotalPrice', AColumn.FieldName) > 0) then
         SetTextErrorHint('该清单有子计算项,不能直接修改!')
       else if (Pos('Price', AColumn.FieldName) > 0) then
@@ -684,7 +677,7 @@ procedure TBillsCompileData.sdvBillsCompileSetText(var Text: String;
 begin
   if not Assigned(AValue) then Exit;
   // 修改后数据与原数据相同则不提交
-  if AValue.AsString = Text then Exit;
+  if (AValue.AsString = Text) or ((AValue.AsFloat = 0) and (Text = '')) then Exit;
 
   CheckLockedData;
   if not Allow then Exit;
@@ -1075,4 +1068,49 @@ begin
     ANode.Rec.DgnPrice.Clear;
 end;
 
+procedure TBillsCompileData.ExpandPegXmjNode;
+
+  function HasPegChild(ANode: TBillsIDTreeNode): Boolean;
+  var
+    NextNode: TBillsIDTreeNode;
+  begin
+    Result := False;
+    NextNode := TBillsIDTreeNode(ANode.NextNode);
+    while ((NextNode.MajorIndex - ANode.MajorIndex) <= ANode.PosterityCount) do
+    begin
+      if CheckPeg(NextNode.Rec.Name.AsString) then
+      begin
+        Result := True;
+        Break;
+      end;
+      NextNode := TBillsIDTreeNode(NextNode.NextNode);
+    end;
+  end;
+
+  function HasGclChild(ANode: TBillsIDTreeNode): Boolean;
+  var
+    vChild: TBillsIDTreeNode;
+  begin
+    Result := True;
+    vChild := TBillsIDTreeNode(ANode.FirstChild);
+    while Assigned(vChild) and not Result do
+    begin
+      if vChild.Rec.B_Code.AsString <> '' then
+        Result := False;
+      vChild := TBillsIDTreeNode(vChild.NextSibling);
+    end;
+  end;
+
+var
+  iIndex: Integer;
+  vNode: TBillsIDTreeNode;
+begin
+  for iIndex := 0 to BillsCompileTree.Count - 1 do
+  begin
+    vNode := TBillsIDTreeNode(BillsCompileTree.Items[iIndex]);
+    if vNode.HasChildren then
+      vNode.Expanded := HasPegChild(vNode) or not HasGclChild(vNode);
+  end;
+end;
+
 end.

+ 4 - 2
DataModules/BillsMeasureDm.pas

@@ -371,12 +371,12 @@ procedure TBillsMeasureData.sdvBillsMeasureSetText(var Text: String;
     AValue.Owner.ValueByName(AField + 'Quantity').AsString := '';
     if CheckStringNull(Text) or CheckNumeric(Text) then
     begin
-      AValue.Owner.ValueByName('Formula').AsString := '';
+      AValue.Owner.ValueByName(AField + 'Formula').AsString := '';
       Text := FloatToStr(TotalPriceRoundTo(StrToFloatDef(Text, 0)));
     end
     else
     begin
-      AValue.Owner.ValueByName('Formula').AsString := Text;
+      AValue.Owner.ValueByName(AField + 'Formula').AsString := Text;
       Text := FloatToStr(TotalPriceRoundTo(EvaluateExprs(Text)));
     end;
   end;
@@ -405,6 +405,8 @@ procedure TBillsMeasureData.sdvBillsMeasureSetText(var Text: String;
 
 begin
   if not Assigned(AValue) then Exit;
+  // 修改后数据与原数据相同则不提交
+  if (AValue.AsString = Text) or ((AValue.AsFloat = 0) and (Text = '')) then Exit;
 
   CheckLockedData;
   if not Allow then Exit;

+ 1 - 1
Dprs/Pro/Measure.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\Measure"
+-E"D:\SmartCostExe\Measure"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 13 - 12
Dprs/Pro/Measure.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\Measure
+OutputDir=D:\SmartCostExe\Measure
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1053
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化专业版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1053
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -154,12 +154,13 @@ Count=2
 Item0=..\..\Dcus
 Item1=..\Dcus
 [HistoryLists\hlOutputDirectorry]
-Count=8
-Item0=E:\SmartCostExe\Measure
-Item1=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版4)
-Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
-Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版2)
-Item4=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
-Item5=D:\Program Files\纵横软件\Environment
-Item6=..\..\Environment
-Item7=..\Dcus
+Count=9
+Item0=D:\SmartCostExe\Measure
+Item1=E:\SmartCostExe\Measure
+Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版4)
+Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
+Item4=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版2)
+Item5=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
+Item6=D:\Program Files\纵横软件\Environment
+Item7=..\..\Environment
+Item8=..\Dcus

+ 3 - 1
Dprs/Pro/Measure.dpr

@@ -135,7 +135,9 @@ uses
   BGLClipboard in '..\..\Units\BGLClipboard.pas',
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Pro/Measure.res


+ 1 - 1
Dprs/Pro/Measure_Cloud.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\Measure"
+-E"D:\SmartCostExe\Measure"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 8 - 7
Dprs/Pro/Measure_Cloud.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\Measure
+OutputDir=D:\SmartCostExe\Measure
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1053
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化云版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1053
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -150,10 +150,11 @@ Item0=..\..\Dcus
 Item1=E:\DelphiTemp
 Item2=D:\Dcu
 [HistoryLists\hlOutputDirectorry]
-Count=3
-Item0=E:\SmartCostExe\Measure
-Item1=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(云版)
-Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
+Count=4
+Item0=D:\SmartCostExe\Measure
+Item1=E:\SmartCostExe\Measure
+Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(云版)
+Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
 [HistoryLists\hlBPLOutput]
 Count=1
 Item0=..\Bin

+ 3 - 1
Dprs/Pro/Measure_Cloud.dpr

@@ -139,7 +139,9 @@ uses
   rmMentalCustomized1Dm in '..\..\DataModules\ReportMemoryDm\rmMentalCustomized1Dm.pas' {rmMentalCustomized1Data: TDataModule},
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Pro/Measure_Cloud.res


+ 1 - 1
Dprs/Pro/Measure_GuangDong.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\Measure"
+-E"D:\SmartCostExe\Measure"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 7 - 6
Dprs/Pro/Measure_GuangDong.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\Measure
+OutputDir=D:\SmartCostExe\Measure
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1053
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化广东专业版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1053
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -146,9 +146,10 @@ Item0=..\..\Dcus
 Item1=..\Dcus
 Item2=D:\Dcu
 [HistoryLists\hlOutputDirectorry]
-Count=2
-Item0=E:\SmartCostExe\Measure
-Item1=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(广东专业版)
+Count=3
+Item0=D:\SmartCostExe\Measure
+Item1=E:\SmartCostExe\Measure
+Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(广东专业版)
 [HistoryLists\hlBPLOutput]
 Count=1
 Item0=..\Bin

+ 3 - 1
Dprs/Pro/Measure_GuangDong.dpr

@@ -135,7 +135,9 @@ uses
   mDataRecord in '..\..\Units\mDataRecord.pas',
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Pro/Measure_GuangDong.res


+ 1 - 1
Dprs/Pro/Measure_GuangDong_Cloud.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\Measure"
+-E"D:\SmartCostExe\Measure"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 8 - 7
Dprs/Pro/Measure_GuangDong_Cloud.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\Measure
+OutputDir=D:\SmartCostExe\Measure
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1053
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化广东云版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1053
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -153,10 +153,11 @@ Item0=..\..\Dcus
 Item1=E:\DelphiTemp
 Item2=D:\Dcu
 [HistoryLists\hlOutputDirectorry]
-Count=3
-Item0=E:\SmartCostExe\Measure
-Item1=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(广东云版)15审核人
-Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
+Count=4
+Item0=D:\SmartCostExe\Measure
+Item1=E:\SmartCostExe\Measure
+Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(广东云版)15审核人
+Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
 [HistoryLists\hlBPLOutput]
 Count=1
 Item0=..\Bin

+ 3 - 1
Dprs/Pro/Measure_GuangDong_Cloud.dpr

@@ -139,7 +139,9 @@ uses
   rmMentalCustomized1Dm in '..\..\DataModules\ReportMemoryDm\rmMentalCustomized1Dm.pas' {rmMentalCustomized1Data: TDataModule},
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Pro/Measure_GuangDong_Cloud.res


+ 1 - 1
Dprs/Pro/Measure_GuangDong_TZ.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\Measure"
+-E"D:\SmartCostExe\Measure"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 10 - 9
Dprs/Pro/Measure_GuangDong_TZ.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\Measure
+OutputDir=D:\SmartCostExe\Measure
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -110,12 +110,12 @@ ActiveLang=
 ProjectLang=
 RootDir=D:\Program Files\Borland\Delphi7\Bin\
 [Version Info]
-IncludeVerInfo=0
+IncludeVerInfo=1
 AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
+MajorVer=3
+MinorVer=1
+Release=3
+Build=1050
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=
 FileDescription=
-FileVersion=1.0.0.0
+FileVersion=3.1.3.1050
 InternalName=
 LegalCopyright=
 LegalTrademarks=
@@ -142,5 +142,6 @@ Count=2
 Item0=..\..\Dcus
 Item1=..\...\Dcus
 [HistoryLists\hlOutputDirectorry]
-Count=1
-Item0=E:\SmartCostExe\Measure
+Count=2
+Item0=D:\SmartCostExe\Measure
+Item1=E:\SmartCostExe\Measure

+ 3 - 1
Dprs/Pro/Measure_GuangDong_TZ.dpr

@@ -135,7 +135,9 @@ uses
   mDataRecord in '..\..\Units\mDataRecord.pas',
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Pro/Measure_GuangDong_TZ.res


+ 1 - 1
Dprs/Pro/Measure_TZ.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\Measure"
+-E"D:\SmartCostExe\Measure"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 11 - 10
Dprs/Pro/Measure_TZ.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\Measure
+OutputDir=D:\SmartCostExe\Measure
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1051
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横0号台账专业版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1051
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -155,10 +155,11 @@ Count=2
 Item0=..\..\Dcus
 Item1=..\Dcus
 [HistoryLists\hlOutputDirectorry]
-Count=6
-Item0=E:\SmartCostExe\Measure
-Item1=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
-Item2=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
-Item3=D:\Program Files\纵横软件\Environment
-Item4=..\..\Environment
-Item5=..\Dcus
+Count=7
+Item0=D:\SmartCostExe\Measure
+Item1=E:\SmartCostExe\Measure
+Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
+Item3=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
+Item4=D:\Program Files\纵横软件\Environment
+Item5=..\..\Environment
+Item6=..\Dcus

+ 3 - 1
Dprs/Pro/Measure_TZ.dpr

@@ -135,7 +135,9 @@ uses
   rmMentalCustomized1Dm in '..\..\DataModules\ReportMemoryDm\rmMentalCustomized1Dm.pas' {rmMentalCustomized1Data: TDataModule},
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Pro/Measure_TZ.res


+ 1 - 1
Dprs/Trail/Measure.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\MeasureTrail"
+-E"D:\SmartCostExe\MeasureTrail"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 14 - 13
Dprs/Trail/Measure.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\MeasureTrail
+OutputDir=D:\SmartCostExe\MeasureTrail
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1051
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化专业版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1051
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -153,13 +153,14 @@ Count=2
 Item0=..\..\Dcus
 Item1=..\Dcus
 [HistoryLists\hlOutputDirectorry]
-Count=9
-Item0=E:\SmartCostExe\MeasureTrail
-Item1=E:\SmartCostExe\Measure
-Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(广东专业版)
-Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
-Item4=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版2)
-Item5=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
-Item6=D:\Program Files\纵横软件\Environment
-Item7=..\..\Environment
-Item8=..\Dcus
+Count=10
+Item0=D:\SmartCostExe\MeasureTrail
+Item1=E:\SmartCostExe\MeasureTrail
+Item2=E:\SmartCostExe\Measure
+Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(广东专业版)
+Item4=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
+Item5=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版2)
+Item6=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
+Item7=D:\Program Files\纵横软件\Environment
+Item8=..\..\Environment
+Item9=..\Dcus

+ 3 - 1
Dprs/Trail/Measure.dpr

@@ -135,7 +135,9 @@ uses
   rmMentalCustomized1Dm in '..\..\DataModules\ReportMemoryDm\rmMentalCustomized1Dm.pas' {rmMentalCustomized1Data: TDataModule},
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Trail/Measure.res


+ 1 - 1
Dprs/Trail/Measure_GuangDong.cfg

@@ -31,7 +31,7 @@
 -M
 -$M16384,1048576
 -K$00400000
--E"E:\SmartCostExe\MeasureTrail"
+-E"D:\SmartCostExe\MeasureTrail"
 -N"..\..\Dcus"
 -LE"d:\program files (x86)\borland\delphi7\Projects\Bpl"
 -LN"d:\program files (x86)\borland\delphi7\Projects\Bpl"

+ 13 - 12
Dprs/Trail/Measure_GuangDong.dof

@@ -90,7 +90,7 @@ MaxStackSize=1048576
 ImageBase=4194304
 ExeDescription=
 [Directories]
-OutputDir=E:\SmartCostExe\MeasureTrail
+OutputDir=D:\SmartCostExe\MeasureTrail
 UnitOutputDir=..\..\Dcus
 PackageDLLOutputDir=
 PackageDCPOutputDir=
@@ -115,7 +115,7 @@ AutoIncBuild=1
 MajorVer=3
 MinorVer=1
 Release=3
-Build=1031
+Build=1051
 Debug=0
 PreRelease=0
 Special=0
@@ -126,7 +126,7 @@ CodePage=936
 [Version Info Keys]
 CompanyName=珠海纵横创新软件有限公司
 FileDescription=纵横结算决算计量一体化广东学习版
-FileVersion=3.1.3.1031
+FileVersion=3.1.3.1051
 InternalName=Measure
 LegalCopyright=版权所有(C) 珠海纵横创新软件有限公司 2003-2014。保留所有权利。
 LegalTrademarks=Measure
@@ -156,12 +156,13 @@ Count=2
 Item0=..\..\Dcus
 Item1=..\Dcus
 [HistoryLists\hlOutputDirectorry]
-Count=8
-Item0=E:\SmartCostExe\MeasureTrail
-Item1=E:\SmartCostExe\Measure
-Item2=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
-Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版2)
-Item4=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
-Item5=D:\Program Files\纵横软件\Environment
-Item6=..\..\Environment
-Item7=..\Dcus
+Count=9
+Item0=D:\SmartCostExe\MeasureTrail
+Item1=E:\SmartCostExe\MeasureTrail
+Item2=E:\SmartCostExe\Measure
+Item3=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版)
+Item4=D:\Program Files (x86)\纵横软件\纵横计量决算一体化软件(专业版2)
+Item5=D:\Program Files (x86)\纵横软件\纵横公路工程计量支付(专业版)
+Item6=D:\Program Files\纵横软件\Environment
+Item7=..\..\Environment
+Item8=..\Dcus

+ 3 - 1
Dprs/Trail/Measure_GuangDong.dpr

@@ -135,7 +135,9 @@ uses
   mDataRecord in '..\..\Units\mDataRecord.pas',
   rmGcl_XmjBillsDm in '..\..\DataModules\ReportMemoryDm\rmGcl_XmjBillsDm.pas' {rmGcl_XmjBillsData: TDataModule},
   rmCustomized2Dm in '..\..\DataModules\ReportMemoryDm\rmCustomized2Dm.pas' {rmCustomized2Data: TDataModule},
-  CalcDecimal in '..\..\Units\CalcDecimal.pas';
+  CalcDecimal in '..\..\Units\CalcDecimal.pas',
+  BillsPasteSelectFrm in '..\..\Forms\BillsPasteSelectFrm.pas' {BillsPasteSelectForm},
+  DetailExcelImport in '..\..\Units\DetailExcelImport.pas';
 
 {$R *.res}
 

BIN
Dprs/Trail/Measure_GuangDong.res


+ 22 - 16
Forms/MainFrm.dfm

@@ -20,8 +20,8 @@ object MainForm: TMainForm
   TextHeight = 12
   object jtsProjects: TJimTabSet
     Left = 0
-    Top = 49
-    Width = 734
+    Top = 48
+    Width = 742
     Height = 21
     Align = alTop
     BackgroundColor = clGradientInactiveCaption
@@ -45,8 +45,8 @@ object MainForm: TMainForm
   end
   object dxStatusBar: TdxStatusBar
     Left = 0
-    Top = 480
-    Width = 734
+    Top = 484
+    Width = 742
     Height = 20
     Panels = <
       item
@@ -78,12 +78,12 @@ object MainForm: TMainForm
     object dxStatusBarContainer2: TdxStatusBarContainerControl
       Left = 604
       Top = 2
-      Width = 128
+      Width = 136
       Height = 16
       object ProgressBar: TProgressBar
         Left = 0
         Top = 0
-        Width = 128
+        Width = 136
         Height = 16
         Align = alClient
         Max = 200
@@ -93,9 +93,9 @@ object MainForm: TMainForm
   end
   object jpsMain: TJimPages
     Left = 0
-    Top = 70
-    Width = 734
-    Height = 410
+    Top = 69
+    Width = 742
+    Height = 415
     ActivePage = jpsMainProjectsManager
     ActivePageIndex = 0
     Align = alClient
@@ -103,8 +103,8 @@ object MainForm: TMainForm
     object jpsMainProjectsManager: TJimPage
       Left = 0
       Top = 0
-      Width = 734
-      Height = 410
+      Width = 742
+      Height = 415
       TabName = 'ProjectsManager'
       Caption = 'ProjsMgr'
       object pnlUser: TPanel
@@ -201,8 +201,8 @@ object MainForm: TMainForm
     object jpsMainProjects: TJimPage
       Left = 0
       Top = 0
-      Width = 734
-      Height = 410
+      Width = 742
+      Height = 415
       TabName = 'Projects'
       Caption = 'Projects'
       object jpsProjects: TJimPages
@@ -220,7 +220,7 @@ object MainForm: TMainForm
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -12
-    Font.Name = #24494#36719#38597#40657
+    Font.Name = #23435#20307
     Font.Style = []
     Bars = <
       item
@@ -266,7 +266,7 @@ object MainForm: TMainForm
         Caption = #24037#20855#26639
         DockedDockingStyle = dsTop
         DockedLeft = 0
-        DockedTop = 27
+        DockedTop = 26
         DockingStyle = dsTop
         FloatLeft = 484
         FloatTop = 279
@@ -375,7 +375,7 @@ object MainForm: TMainForm
     DockControlHeights = (
       0
       0
-      49
+      48
       0)
     object dxsiFile: TdxBarSubItem
       Caption = #25991#20214'(&F)'
@@ -956,6 +956,12 @@ object MainForm: TMainForm
       Hint = #23450#20301
       Visible = ivAlways
     end
+    object dxbtnImportPlaneFxBillsToXmj: TdxBarButton
+      Caption = #23548#20837#21488#36134'('#24179#38754#32467#26500')'#33267#39033#30446#33410
+      Category = 0
+      Hint = #23548#20837#21488#36134'('#24179#38754#32467#26500')'#33267#39033#30446#33410
+      Visible = ivAlways
+    end
   end
   object Images: TImageList
     DrawingStyle = dsTransparent

+ 13 - 2
Forms/MainFrm.pas

@@ -142,6 +142,7 @@ type
     dxbtnChangeDealBillsMode: TdxBarButton;
     dxsiExpandTo: TdxBarSubItem;
     dxbtnLocateBookmark: TdxBarButton;
+    dxbtnImportPlaneFxBillsToXmj: TdxBarButton;
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure jtsProjectsChange(Sender: TObject; NewTab: Integer;
@@ -548,7 +549,12 @@ begin
   try
     CurProjectFrame.ProjectData.Save;
     {$O-}
-      CurProjectFrame.ProjectData.ReplyProject;
+      // 失败后重复一次
+      if not CurProjectFrame.ProjectData.ReplyProject then
+      begin
+        if not CurProjectFrame.ProjectData.ReplyProject then
+          ErrorMessage('批复项目失败!');
+      end;
     {$O+}
   finally
     Screen.Cursor := crDefault;
@@ -563,7 +569,12 @@ begin
   try
     CurProjectFrame.ProjectData.Save;
     {$O-}
-      CurProjectFrame.ProjectData.SubmitProject;
+      // 失败后重复一次
+      if not CurProjectFrame.ProjectData.SubmitProject then
+      begin
+        if not CurProjectFrame.ProjectData.SubmitProject then
+          ErrorMessage('上报项目失败!');
+      end;
     {$O+}
   finally
     Screen.Cursor := crDefault;

+ 4 - 1
Forms/WelcomeFrm.pas

@@ -4,7 +4,7 @@ interface
 
 uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
-  Dialogs, ExtCtrls, jpeg;
+  Dialogs, ExtCtrls, jpeg, UtilMethods;
 
 type
   TWelcomeForm = class(TForm)
@@ -37,6 +37,8 @@ var
   iFirstTime: Cardinal;
 begin
   WelcomeForm := TWelcomeForm.Create(nil);
+  if FileExists(GetAppFilePath + 'Welcome.jpg') then
+    WelcomeForm.imgWelcome.Picture.LoadFromFile(GetAppFilePath + 'Welcome.jpg');
   Result := WelcomeForm.Handle;
   WelcomeForm.Show;
   iFirstTime := GetTickCount;
@@ -52,6 +54,7 @@ begin
   end;
 
   WelcomeForm.AlphaBlendValue := 255;
+  Sleep(2000);
   SetForegroundWindow(WelcomeForm.Handle);
 end;
 

+ 9 - 0
Frames/BillsCompileFme.dfm

@@ -126,6 +126,10 @@ object BillsCompileFrame: TBillsCompileFrame
         Visible = True
       end
       item
+        Item = MainForm.dxbtnImportPlaneFxBillsToXmj
+        Visible = True
+      end
+      item
         BeginGroup = True
         Item = MainForm.dxbtnCheckAndClear
         Visible = True
@@ -757,5 +761,10 @@ object BillsCompileFrame: TBillsCompileFrame
       OnExecute = actnImportGclBillsToXmjExecute
       OnUpdate = actnImportGclBillsToXmjUpdate
     end
+    object actnImportPlaneFxBillsToXmj: TAction
+      Caption = #23548#20837#21488#36134'('#24179#38754#32467#26500')'#33267#39033#30446#33410
+      OnExecute = actnImportPlaneFxBillsToXmjExecute
+      OnUpdate = actnImportGclBillsToXmjUpdate
+    end
   end
 end

+ 22 - 1
Frames/BillsCompileFme.pas

@@ -30,6 +30,7 @@ type
     actnModifiedDealBills: TAction;
     actnSetBillsBookmark: TAction;
     actnImportGclBillsToXmj: TAction;
+    actnImportPlaneFxBillsToXmj: TAction;
     procedure zgBillsCompileCopy(Sender: TObject; const ABounds: TRect;
       var Allow: Boolean);
     procedure zgBillsCompilePaste(Sender: TObject; const ABounds: TRect;
@@ -65,6 +66,7 @@ type
     procedure actnSetBillsBookmarkExecute(Sender: TObject);
     procedure actnImportGclBillsToXmjUpdate(Sender: TObject);
     procedure actnImportGclBillsToXmjExecute(Sender: TObject);
+    procedure actnImportPlaneFxBillsToXmjExecute(Sender: TObject);
   private
     FBillsCompileData: TBillsCompileData;
     FShowIDField: Boolean;
@@ -107,7 +109,7 @@ implementation
 
 uses
   MainFrm, BatchInsertBillsFrm, ExportExcel, ProjectData, mEncryptEditions,
-  ExcelImport;
+  ExcelImport, DetailExcelImport;
 
 {$R *.dfm}
 
@@ -198,6 +200,7 @@ begin
   SetDxBtnAction(actnModifiedDealBills, MainForm.dxbtnModifyDealBills);
   SetDxBtnAction(actnSetBillsBookmark, MainForm.dxbtnSetBookmark);
   SetDxBtnAction(actnImportGclBillsToXmj, MainForm.dxbtnImportGclBillsToXmj);
+  SetDxBtnAction(actnImportPlaneFxBillsToXmj, MainForm.dxbtnImportPlaneFxBillsToXmj);
 end;
 
 constructor TBillsCompileFrame.Create(AParent: TFrame;
@@ -578,4 +581,22 @@ begin
   stdBillsCompile.Column('DrawingCode').ReadOnly := AReadOnly;
 end;
 
+procedure TBillsCompileFrame.actnImportPlaneFxBillsToXmjExecute(
+  Sender: TObject);
+var
+  sFileName: string;
+  Importor: TPlaneFxBillsExcelImport;
+begin
+  if SelectFile(sFileName, '.xls') then
+  begin
+    Importor := TPlaneFxBillsExcelImport.Create(TProjectData(FBillsCompileData.ProjectData));
+    try
+      Importor.ParentID := stdBillsCompile.IDTree.Selected.ID;
+      Importor.ImportFile(sFileName);
+    finally
+      Importor.Free;
+    end;
+  end;
+end;
+
 end.

+ 3 - 2
Frames/ProjectManagerFme.pas

@@ -328,10 +328,11 @@ var
               // 导入更新-------------------------------------------------------
 
               // 导入前须检测无锁文件中仅含有原报数据
-              vFileCheck := TTenderFileChecker.Create(sLocalFile);
+              vFileCheck := TTenderFileChecker.Create;
               try
                 // 有一期以上数据,且最新期数据审核状态为原报
-                bCanImp := (vFileCheck.PhaseCount > 0) and (vFileCheck.AuditStatus = 0);
+                bCanImp := vFileCheck.CheckFileValid(sLocalFile)
+                    and (vFileCheck.PhaseCount > 0) and (vFileCheck.AuditStatus = 0);
                 if not bCanImp then
                 begin
                   Application.MessageBox(PChar('已从云端下载原报上传的无锁文件到本地,但文件有错误,禁止导入!请致电纵横服务人员以获取帮助。'), '警告', MB_OK + MB_ICONWARNING);

+ 31 - 0
Units/BillsTree.pas

@@ -6,6 +6,8 @@ uses
   sdIDTree, sdDB, mDataRecord;
 
 type
+  TReCalculateTreeNode = procedure(AID: Integer) of Object;
+
   TBillsIDTreeNode = class(TsdIDTreeNode)
   private
     FDealQuantity: Double;
@@ -57,6 +59,7 @@ type
   TBillsIDTree = class(TsdIDTree)
   private
     FDoOnAfterDeleteNode: TbitAfterDeleteNode;
+    FOnReCalcParent: TReCalculateTreeNode;
   protected
     function CreateItem: TsdIDTreeNode; override;
   public
@@ -64,8 +67,10 @@ type
     function DeleteNode(ANode: TsdIDTreeNode): Boolean; override;
 
     function Add(AParentID, ANextSiblingID: TsdTreeNodeID): TsdIDTreeNode; override;
+    procedure DoOnReCalcParent(AID: Integer);
 
     property DoOnAfterDeleteNode: TbitAfterDeleteNode read FDoOnAfterDeleteNode write FDoOnAfterDeleteNode;
+    property OnReCalcParent: TReCalculateTreeNode read FOnReCalcParent write FOnReCalcParent;
   end;
 
   TEstimateIDTreeNode = class(TsdIDTreeNode)
@@ -120,6 +125,12 @@ begin
     FDoOnAfterDeleteNode(vParent);
 end;
 
+procedure TBillsIDTree.DoOnReCalcParent(AID: Integer);
+begin
+  if Assigned(FOnReCalcParent) then
+    FOnReCalcParent(AID);
+end;
+
 { TBillsIDTreeNode }
 
 function TBillsIDTreeNode.CanDownLevel: Boolean;
@@ -172,15 +183,25 @@ begin
 end;
 
 function TBillsIDTreeNode.DownLevel: Boolean;
+var
+  iOrgParentID: Integer;
 begin
+  iOrgParentID := ParentID;
   Result := inherited DownLevel;
 
+  if not Result then Exit;
   // 如升级后变为父项,则清空数量、单价
   if Assigned(Parent) then
   begin
+    Parent.Rec.ValueByName('OrgQuantity').AsFloat := 0;
+    Parent.Rec.ValueByName('MisQuantity').AsFloat := 0;
+    Parent.Rec.ValueByName('OthQuantity').AsFloat := 0;
     Parent.Rec.ValueByName('Quantity').AsFloat := 0;
     Parent.Rec.ValueByName('Price').AsFloat := 0;
   end;
+                                                   
+  TBillsIDTree(Owner).OnReCalcParent(ParentID);
+  TBillsIDTree(Owner).OnReCalcParent(iOrgParentID);
 end;
 
 function TBillsIDTreeNode.GetRec: TBillsRecord;
@@ -239,15 +260,25 @@ begin
 end;
 
 function TBillsIDTreeNode.UpLevel: Boolean;
+var
+  iOrgParentID: Integer;
 begin
+  iOrgParentID := ParentID;
   Result := inherited UpLevel;
 
+  if not Result then Exit;
   // 如升级后变为父项,则清空数量、单价
   if HasChildren then
   begin
+    Rec.ValueByName('OrgQuantity').AsFloat := 0;
+    Rec.ValueByName('MisQuantity').AsFloat := 0;
+    Rec.ValueByName('OthQuantity').AsFloat := 0;
     Rec.ValueByName('Quantity').AsFloat := 0;
     Rec.ValueByName('Price').AsFloat := 0;
   end;
+
+  TBillsIDTree(Owner).OnReCalcParent(iOrgParentID);
+  TBillsIDTree(Owner).OnReCalcParent(ParentID);
 end;
 
 { TEstimateIDTreeNode }

+ 581 - 0
Units/DetailExcelImport.pas

@@ -0,0 +1,581 @@
+unit DetailExcelImport;
+
+interface
+
+uses
+  Classes, ProjectData, ScXlsOutput, MCacheTree, XLSAdapter, sdDB,
+  Variants, Forms, Controls;
+
+type
+  TDetailExcelImport = class
+  private
+    FProjectData: TProjectData;
+    FTempFile: string;
+    FExcel: TXlsOutPut;
+
+    function GetCellValue(AXlsFile: TXLSFile; ARow, ACol: Integer): string;
+    function GetCellValueFormat(AXlsFile: TXLSFile; ARow, ACol: Integer): string;
+
+    procedure BeginImport; virtual; abstract;
+    procedure EndImport; virtual; abstract;
+
+    procedure Import; virtual; abstract;
+  public
+    constructor Create(AProjectData: TProjectData);
+    destructor Destroy; override;
+
+    procedure ImportFile(const AFileName: string);
+  end;
+
+  // 平面分项清单格式导入,导入至某项目节节点之下
+  TPlaneFxBillsExcelImport = class(TDetailExcelImport)
+  private
+    FParentID: Integer;
+    FCacheTree: TBillsCacheTree;
+    FCurRow: Integer;
+
+    FXmjLevel1Col: Integer;
+    FXmjLevel2Col: Integer;
+    FXmjLevel3Col: Integer;
+    FXmjLevel4Col: Integer;
+    FXmjLevel5Col: Integer;
+    FXmjLevel6Col: Integer;
+    FXmjLevel7Col: Integer;
+
+    FB_CodeCol: Integer;
+    FNameCol: Integer;
+    FUnitCol: Integer;
+    FQuantityCol: Integer;
+    FPriceCol: Integer;
+
+    FDrawingCol: Integer;
+    FMemoCol: Integer;
+
+    procedure LoadXmjLevel1(AXlsFile: TXLSFile);
+    procedure LoadXmjLevel2(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
+    procedure LoadXmjLevel3(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
+    procedure LoadXmjLevel4(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
+    procedure LoadXmjLevel5(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
+    procedure LoadXmjLevel6(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
+    procedure LoadXmjLevel7(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
+
+    procedure LoadBillsNode(AXlsFile: TXLSFile; AXmj: TBillsCacheNode);
+
+    function LoadColumnsFromHead(AXlsFile: TXlsFile): Boolean;
+    procedure LoadFxBills(AXlsFile: TXLSFile);
+
+    procedure WriteNode(ADataSet: TsdDataSet; ANode: TBillsCacheNode);
+    procedure WriteNodes(ADataSet: TsdDataSet);
+
+    procedure BeginImport; override;
+    procedure EndImport; override;
+
+    procedure Import; override;
+  public
+    property ParentID: Integer read FParentID write FParentID;
+  end;
+
+implementation
+
+uses
+  UtilMethods, SysUtils, ZhAPI, SheetSelectFrm, UExcelAdapter, UFlxMessages,
+  UFlxFormats, ProgressHintFrm;
+
+{ TDetailExcelImport }
+
+constructor TDetailExcelImport.Create(AProjectData: TProjectData);
+begin
+  FProjectData := AProjectData;
+  FTempFile := GetTempFileName;
+end;
+
+destructor TDetailExcelImport.Destroy;
+begin
+  if FileExists(FTempFile) then
+    DeleteFile(FTempFile);
+  inherited;
+end;
+
+function TDetailExcelImport.GetCellValue(AXlsFile: TXLSFile; ARow,
+  ACol: Integer): string;
+var
+  xlsCell: TXlsCellValue;
+begin
+  Result := '';
+  if not Assigned(AXlsFile) or (ARow = -1) or (ACol = -1) then Exit;
+  xlsCell := AXlsFile.CellValueX[ARow, ACol];
+  Result := xlsCell.Value;
+end;
+
+function TDetailExcelImport.GetCellValueFormat(AXlsFile: TXLSFile; ARow,
+  ACol: Integer): string;
+
+  function GetDigit(AFormat: WideString): Integer;
+  var
+    I: Integer;
+    bDigit: Boolean;
+  begin
+    Result := 0;
+    bDigit := False;
+    for I := 1 to Length(AFormat) do
+    begin
+      if AFormat[I] = '.' then
+      begin
+        if bDigit then Break
+        else bDigit := True;
+      end
+      else if AFormat[I] = ';' then Break
+      else if bDigit and (AFormat[I] = '0') then
+        Dec(Result);
+    end;
+  end;
+
+  function FormatNum(AValue: Variant; AFormat: WideString): string;
+  begin
+    Result := AValue;
+    if not VarIsNull(AValue) then
+    begin
+      if CheckNumeric(Result) then
+      begin
+        if Pos('%', AFormat) <> 0 then AValue := AValue * 100;
+        if AFormat <> '' then
+          Result := FloatToStr(AdvRoundTo(AValue, GetDigit(AFormat)))
+        else
+          Result := FloatToStr(AdvRoundTo(AValue, -2));
+        if Pos('%', AFormat) <> 0 then Result := Result + '%';
+        if AValue = '0' then Result := '';
+      end;
+    end;
+  end;
+
+var
+  xlsCell: TXlsCellValue;
+  FlxFormat: TFlxFormat;
+begin
+  Result := '';
+  if not Assigned(AXlsFile) or (ARow = -1) or (ACol = -1) then Exit;
+  xlsCell := AXlsFile.GetCellDataX(ARow, ACol);
+  Result := xlsCell.Value;
+  if xlsCell.XF <> -1 then
+  begin
+    FlxFormat := AXlsFile.FormatList[xlsCell.XF];
+    Result := FormatNum(xlsCell.Value, FlxFormat.Format);
+  end;
+end;
+
+procedure TDetailExcelImport.ImportFile(const AFileName: string);
+begin
+  CopyFileOrFolder(AFileName, FTempFile);
+  FExcel := TXlsOutPut.Create(FTempFile);
+  BeginImport;
+  try
+    Import;
+  finally
+    EndImport;
+    FExcel.Free;
+  end;
+end;
+
+{ TPlaneFxBillsExcelImport }
+
+procedure TPlaneFxBillsExcelImport.Import;
+begin
+  FCurRow := 1;
+  if LoadColumnsFromHead(FExcel.XlsFile) then
+  begin
+    LoadFxBills(FExcel.XlsFile);
+    WriteNodes(FProjectData.BillsData.sddBills);
+  end
+  else
+    ErrorMessage('导入的Excel格式有误!');
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadBillsNode(AXlsFile: TXLSFile;
+  AXmj: TBillsCacheNode);
+var
+  sB_Code, sName, sUnits: string;
+  vGclNode: TBillsCacheNode;
+  fPrice: Double;
+begin
+  sB_Code := Trim(GetCellValue(AXlsFile, FCurRow, FB_CodeCol));
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FNameCol));
+  sUnits := Trim(GetCellValue(AXlsFile, FCurRow, FUnitCol));
+  fPrice := StrToFloatDef(GetCellValue(AXlsFile, FCurRow, FPriceCol), 0);
+  if sB_Code <> '' then
+  begin
+    vGclNode := FCacheTree.FindGclChild(AXmj, sB_Code, sName, sUnits, fPrice);
+    if not Assigned(vGclNode) then
+    begin
+      vGclNode := FCacheTree.AddNode(AXmj, nil);
+      vGclNode.B_Code := sB_Code;
+      vGclNode.Name := sName;
+      vGclNode.Units := sUnits;
+      vGclNode.Quantity := StrToFloatDef(GetCellValue(AXlsFile, FCurRow, FQuantityCol), 0);
+      vGclNode.Price := fPrice;
+      vGclNode.DrawingCode := GetCellValue(AXlsFile, FCurRow, FDrawingCol);
+      vGclNode.MemoStr := GetCellValue(AXlsFile, FCurRow, FMemoCol);
+    end
+    else
+      vGclNode.Quantity := vGclNode.Quantity + StrToFloatDef(GetCellValue(AXlsFile, FCurRow, FQuantityCol), 0);
+  end;
+  Inc(FCurRow);
+end;
+
+function TPlaneFxBillsExcelImport.LoadColumnsFromHead(AXlsFile: TXlsFile): Boolean;
+var
+  iCol: Integer;
+  sColName: string;
+begin
+  Result := False;
+  FXmjLevel1Col := -1;
+  FXmjLevel2Col := -1;
+  FXmjLevel3Col := -1;
+  FXmjLevel4Col := -1;
+  FXmjLevel5Col := -1;
+  FXmjLevel6Col := -1;
+  FXmjLevel7Col := -1;
+  FB_CodeCol := -1;
+  FNameCol := -1;
+  FUnitCol := -1;
+  FQuantityCol := -1;
+  FPriceCol := -1;
+  FDrawingCol := -1;
+  FMemoCol := -1;
+  UpdateProgressHint('正在识别Excel数据格式');
+  UpdateProgressPosition(0);
+
+  while not Result and (FCurRow <= AXlsFile.MaxRow) do
+  begin
+    for iCol := 1 to AXlsFile.MaxCol do
+    begin
+      sColName := GetCellValue(AXlsFile, FCurRow, iCol);
+      if sColName = '第1层' then
+        FXmjLevel1Col := iCol
+      else if sColName = '第2层' then
+        FXmjLevel2Col := iCol
+      else if sColName = '第3层' then
+        FXmjLevel3Col := iCol
+      else if sColName = '第4层' then
+        FXmjLevel4Col := iCol
+      else if sColName = '第5层' then
+        FXmjLevel5Col := iCol
+      else if sColName = '第6层' then
+        FXmjLevel6Col := iCol
+      else if sColName = '第7层' then
+        FXmjLevel7Col := iCol
+      else if sColName = '清单号' then
+        FB_CodeCol := iCol
+      else if sColName = '清单名称' then
+        FNameCol := iCol
+      else if sColName = '单位' then
+        FUnitCol := iCol
+      else if sColName = '数量' then
+        FQuantityCol := iCol
+      else if sColName = '单价' then
+        FPriceCol := iCol
+      else if sColName = '图号' then
+        FDrawingCol := iCol
+      else if sColName = '备注' then
+        FMemoCol := iCol
+    end;
+
+    Result := FXmjLevel1Col <> -1;
+    Inc(FCurRow);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadFxBills(AXlsFile: TXLSFile);
+var
+  iPos: Integer;
+begin
+  UpdateProgressHint('正在解析平面台账数据');
+  while FCurRow <= AXlsFile.MaxRow do
+  begin
+    iPos := FCurRow*100 div AXlsFile.MaxRow;
+    UpdateProgressPosition(iPos);
+    LoadXmjLevel1(AXlsFile);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel1(AXlsFile: TXLSFile);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel1Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(nil, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(nil);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel1Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  if FXmjLevel2Col <> -1 then
+  begin
+    while FCurRow <= iEndRow do
+      LoadXmjLevel2(AXlsFile, vXmj);
+  end
+  else
+  begin
+    while FCurRow <= iEndRow do
+      LoadBillsNode(AXlsFile, vXmj);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel2(AXlsFile: TXLSFile;
+  AParent: TBillsCacheNode);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel2Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(AParent);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel2Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  if FXmjLevel3Col <> -1 then
+  begin
+    while FCurRow <= iEndRow do
+      LoadXmjLevel3(AXlsFile, vXmj);
+  end
+  else
+  begin
+    while FCurRow <= iEndRow do
+      LoadBillsNode(AXlsFile, vXmj);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel3(AXlsFile: TXLSFile;
+  AParent: TBillsCacheNode);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel3Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(AParent);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel3Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  if FXmjLevel4Col <> -1 then
+  begin
+    while FCurRow <= iEndRow do
+      LoadXmjLevel4(AXlsFile, vXmj);
+  end
+  else
+  begin
+    while FCurRow <= iEndRow do
+      LoadBillsNode(AXlsFile, vXmj);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel4(AXlsFile: TXLSFile;
+  AParent: TBillsCacheNode);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel4Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(AParent);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel4Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  if FXmjLevel5Col <> -1 then
+  begin
+    while FCurRow <= iEndRow do
+      LoadXmjLevel5(AXlsFile, vXmj);
+  end
+  else
+  begin
+    while FCurRow <= iEndRow do
+      LoadBillsNode(AXlsFile, vXmj);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel5(AXlsFile: TXLSFile;
+  AParent: TBillsCacheNode);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel5Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(AParent);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel5Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  if FXmjLevel6Col <> -1 then
+  begin
+    while FCurRow <= iEndRow do
+      LoadXmjLevel6(AXlsFile, vXmj);
+  end
+  else
+  begin
+    while FCurRow <= iEndRow do
+      LoadBillsNode(AXlsFile, vXmj);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel6(AXlsFile: TXLSFile;
+  AParent: TBillsCacheNode);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel6Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(AParent);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel6Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  if FXmjLevel7Col <> -1 then
+  begin
+    while FCurRow <= iEndRow do
+      LoadXmjLevel7(AXlsFile, vXmj);
+  end
+  else
+  begin
+    while FCurRow <= iEndRow do
+      LoadBillsNode(AXlsFile, vXmj);
+  end;
+end;
+
+procedure TPlaneFxBillsExcelImport.LoadXmjLevel7(AXlsFile: TXLSFile;
+  AParent: TBillsCacheNode);
+var
+  sName: string;
+  vXmj: TBillsCacheNode;
+  iEndRow: Integer;
+begin
+  sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel7Col));
+  if sName = '' then Exit;
+
+  vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
+  if not Assigned(vXmj) then
+  begin
+    vXmj := FCacheTree.AddNode(AParent);
+    vXmj.Name := sName;
+  end;
+
+  with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel7Col] do
+    iEndRow := FCurRow + Bottom - Top;
+
+  while FCurRow <= iEndRow do
+    LoadBillsNode(AXlsFile, vXmj);
+end;
+
+procedure TPlaneFxBillsExcelImport.WriteNodes(ADataSet: TsdDataSet);
+var
+  i, iPos: Integer;
+begin
+  UpdateProgressHint('写入读取的Excel数据');
+  UpdateProgressPosition(0);
+  for i := 0 to FCacheTree.CacheNodes.Count - 1 do
+  begin
+    WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
+    iPos := i*100 div FCacheTree.CacheNodes.Count;
+    UpdateProgressPosition(iPos);
+  end;
+  UpdateProgressPosition(100);
+end;
+
+procedure TPlaneFxBillsExcelImport.WriteNode(ADataSet: TsdDataSet;
+  ANode: TBillsCacheNode);
+var
+  Rec: TsdDataRecord;
+begin
+  if ANode.B_Code <> '' then
+    UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
+  else
+    UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
+
+  Rec := ADataSet.Add;
+  Rec.ValueByName('ID').AsInteger := ANode.ID;
+  if ANode.ParentID = -1 then
+    Rec.ValueByName('ParentID').AsInteger := ParentID
+  else
+    Rec.ValueByName('ParentID').AsInteger := ANode.ParentID;
+  Rec.ValueByName('NextSiblingID').AsInteger := ANode.NextSiblingID;
+  Rec.ValueByName('B_Code').AsString := ANode.B_Code;
+  Rec.ValueByName('Name').AsString := ANode.Name;
+  Rec.ValueByName('Units').AsString := ANode.Units;
+  Rec.ValueByName('Price').AsFloat := PriceRoundTo(ANode.Price);
+  Rec.ValueByName('OrgQuantity').AsFloat := QuantityRoundTo(ANode.Quantity);
+  Rec.ValueByName('DrawingCode').AsString := ANode.DrawingCode;
+  Rec.ValueByName('MemoStr').AsString := ANode.MemoStr;
+end;
+
+procedure TPlaneFxBillsExcelImport.BeginImport;
+begin
+  Screen.Cursor := crHourGlass;
+  ShowProgressHint('导入Excel数据', 100);
+
+  FCacheTree := TBillsCacheTree.Create;
+  FCacheTree.NewNodeID := FProjectData.BillsData.GetMaxBillsID + 1;
+
+  FProjectData.DisConnectTree;
+  FProjectData.BillsData.DisableEvents;
+end;
+
+procedure TPlaneFxBillsExcelImport.EndImport;
+begin
+  FCacheTree.Free;
+
+  FProjectData.BillsData.EnableEvents;
+  FProjectData.ReConnectTree;
+
+  FProjectData.BillsCompileData.CalculateAll;
+
+  CloseProgressHint;
+  Screen.Cursor := crDefault;
+end;
+
+end.

+ 46 - 0
Units/MCacheTree.pas

@@ -55,6 +55,9 @@ type
     function AddNodeByCode(const ACode: string; AFixedID: Integer = -1): TBillsCacheNode;
     function AddLeafBillsNode(const AB_Code: string): TBillsCacheNode;
 
+    function FindXmjChild(AParent: TBillsCacheNode; const ACode, AName: string): TBillsCacheNode;
+    function FindGclChild(AParent: TBillsCacheNode; const AB_Code, AName, AUnits: string; APrice: Double): TBillsCacheNode;
+
     // Only for Debugging lot of Data
     procedure SaveTreeToFile(const AFileName: string);
 
@@ -462,6 +465,49 @@ begin
   end;
 end;
 
+function TBillsCacheTree.FindGclChild(AParent: TBillsCacheNode;
+  const AB_Code, AName, AUnits: string; APrice: Double): TBillsCacheNode;
+var
+  vChild: TBillsCacheNode;
+begin
+  Result := nil;
+
+  if Assigned(AParent) then
+    vChild := TBillsCacheNode(AParent.FirstChild)
+  else
+    vChild := TBillsCacheNode(Root.FirstChild);
+
+  while Assigned(vChild) and not Assigned(Result) do
+  begin
+    if SameText(AB_Code, vChild.B_Code) and
+        SameText(AName, vChild.Name) and
+        SameText(AUnits, vChild.Units) and
+        (APrice = vChild.Price) then
+      Result := vChild;
+    vChild := TBillsCacheNode(vChild.NextSibling);
+  end;
+end;
+
+function TBillsCacheTree.FindXmjChild(AParent: TBillsCacheNode;
+  const ACode, AName: string): TBillsCacheNode;
+var
+  vChild: TBillsCacheNode;
+begin
+  Result := nil;
+
+  if Assigned(AParent) then
+    vChild := TBillsCacheNode(AParent.FirstChild)
+  else
+    vChild := TBillsCacheNode(Root.FirstChild);
+
+  while Assigned(vChild) and not Assigned(Result) do
+  begin
+    if SameText(ACode, vChild.Code) and SameText(AName, vChild.Name) then
+      Result := vChild;
+    vChild := TBillsCacheNode(vChild.NextSibling);
+  end;
+end;
+
 { TReportCacheNode }
 
 constructor TReportCacheNode.Create(ACacheTree: TCacheTree; AID,

+ 101 - 31
Units/ProjectCommands.pas

@@ -36,6 +36,8 @@ type
     procedure SaveInfoToXmlDocument(AXmlNode: IXMLNode);
     procedure ExportXmlInfo;
     function GetNewOutputFileName: string;
+
+    function CheckFile(const AFileName: string): Boolean;
   protected
     procedure OpenProject; virtual;
     procedure SaveProject; virtual;
@@ -43,8 +45,8 @@ type
     constructor Create(const AProjectName, AFileName: string; AProjectID: Integer);
     destructor Destroy; override;
 
-    procedure Execute; virtual;
-    procedure ExportTo(AFileName: string); virtual;
+    function Execute: Boolean; virtual;
+    function ExportTo(AFileName: string): Boolean; virtual;
   end;
 
   TSubmitProject = class(TReportBase)
@@ -52,8 +54,8 @@ type
     procedure OpenProject; override;
     procedure SaveProject; override;
   public
-    procedure Execute; override;
-    procedure ExportTo(AFileName: string); override;
+    function Execute: Boolean; override;
+    function ExportTo(AFileName: string): Boolean; override;
   end;
 
   TReplyProject = class(TReportBase)
@@ -61,8 +63,8 @@ type
     procedure OpenProject; override;
     procedure SaveProject; override;
   public
-    procedure Execute; override;
-    procedure ExportTo(AFileName: string); override;
+    function Execute: Boolean; override;
+    function ExportTo(AFileName: string): Boolean; override;
   end;
 
   {1. 生成临时文件夹
@@ -224,10 +226,27 @@ type
     procedure Execute;
   end;
 
+  // 文件检验
+  {
+    检验分为两部分:
+    1. 一致性检验:检验文件中的xml记录数据,与数据库中数据是否一致,以检验文件是否可用
+    2. 主动检验:  提供xml记录的部分数据,用户主动检验是否为所需文件
+
+    流程:
+    1. 解压文件,得到xml文件,项目文件
+    2. 读取xml文件,得到主要数据,与项目文件名
+    3. 读取项目文件,并检验基本数据是否与xml文件中描述一致
+    PS:用于主动检验的数据,在第2步中同步进行。要求,如果进行主动检验,必须先通过一致性检验。
+  }
   TTenderFileChecker = class
   private
-    FTempFolder: string;
     FFileName: string;
+    FTempFolder: string;
+    FTenderFileName: string;
+    FTenderTempFolder: string;
+
+    FValid: Boolean;
+
     FPhaseCount: Integer;
     FAuditStatus: Integer;
     FProjectName: string;
@@ -236,11 +255,14 @@ type
     procedure LoadInfoFromXmlDocument(AXmlNode: IXMLNode);
     procedure LoadInfoFromXml;
     procedure LoadInfo;
+
+    function DecryptFile(const AFileName: string): Boolean;
+    function CheckFileMatchXml: Boolean;
   public
-    constructor Create(AFileName: string);
-    destructor Destroy; override;
+    // 检验项目数据库数据与xml文件中主要数据是否吻合
+    function CheckFileValid(const AFileName: string): Boolean;
 
-    property ProjectName: string read FProjectName;
+    // xml文件中记录的信息,用于主动检验
     property PhaseCount: Integer read FPhaseCount;
     property AuditStatus: Integer read FAuditStatus;
   end;
@@ -253,19 +275,19 @@ uses
 
 { TSubmitProject }
 
-procedure TSubmitProject.Execute;
+function TSubmitProject.Execute: Boolean;
 begin
   FFileType := '.rmf';
   FNeedUpdate := True;
   FProjectData.LockedDataForSubmit;
-  inherited;
+  Result := inherited Execute;
 end;
 
-procedure TSubmitProject.ExportTo(AFileName: string);
+function TSubmitProject.ExportTo(AFileName: string): Boolean;
 begin
   FNeedUpdate := True;
   FProjectData.LockedDataForSubmit;
-  inherited;
+  Result := inherited ExportTo(AFileName);
 end;
 
 procedure TSubmitProject.OpenProject;
@@ -303,24 +325,35 @@ begin
   inherited;
 end;
 
-procedure TReportBase.Execute;
+function TReportBase.Execute: Boolean;
 var
   sFileName: string;
 begin
+  Result := False;
   ExportXmlInfo;
   SaveProject;
   ZipFolder(FTempFolder, FResultFile);
-  sFileName := GetNewOutputFileName;
-  if SaveFile(sFileName, FFileType) then
-    CopyFileOrFolder(FResultFile, sFileName);
+  // 检验导出文件
+  if CheckFile(FResultFile) then
+  begin
+    Result := True;
+    sFileName := GetNewOutputFileName;
+    if SaveFile(sFileName, FFileType) then
+      CopyFileOrFolder(FResultFile, sFileName);
+  end;
 end;
 
-procedure TReportBase.ExportTo(AFileName: string);
+function TReportBase.ExportTo(AFileName: string): Boolean;
 begin
+  Result := False;
   ExportXmlInfo;
   FProjectData.SimpleSaveAs(FTempFolder + '\' + ExtractSimpleFileName(FFileName));
   ZipFolder(FTempFolder, FResultFile);
-  CopyFileOrFolder(FResultFile, AFileName);
+  if CheckFile(FResultFile) then
+  begin
+    Result := True;
+    CopyFileOrFolder(FResultFile, AFileName);
+  end;
 end;
 
 procedure TReportBase.ExportXmlInfo;
@@ -402,19 +435,32 @@ begin
   vProp := AXmlNode.AddChild('TenderProperty');
 end;
 
+function TReportBase.CheckFile(const AFileName: string): Boolean;
+var
+  vChecker: TTenderFileChecker;
+begin
+  Result := False;
+  vChecker := TTenderFileChecker.Create;
+  try
+    Result := vChecker.CheckFileValid(AFileName);
+  finally
+    vChecker.Free;
+  end;
+end;
+
 { TReplyProject }
 
-procedure TReplyProject.Execute;
+function TReplyProject.Execute: Boolean;
 begin
   FFileType := '.arf';
   FProjectData.LockedDataForReply;
-  inherited;
+  Result := inherited Execute;
 end;
 
-procedure TReplyProject.ExportTo(AFileName: string);
+function TReplyProject.ExportTo(AFileName: string): Boolean;
 begin
   FProjectData.LockedDataForReply;
-  inherited;
+  Result := inherited ExportTo(AFileName);
 end;
 
 procedure TReplyProject.OpenProject;
@@ -986,18 +1032,41 @@ end;
 
 { TTenderFileChecker }
 
-constructor TTenderFileChecker.Create(AFileName: string);
+function TTenderFileChecker.CheckFileMatchXml: Boolean;
+var
+  FProjectData: TProjectData;
+begin
+  FProjectData := TProjectData.Create;
+  try
+    try
+      FProjectData.SimpleOpen(FTenderFileName);
+      Result := FProjectData.CheckDataBaseInfo(FPhaseCount, FAuditStatus);
+    except
+      Result := False;
+    end;
+  finally
+    FProjectData.Free;
+  end;
+end;
+
+function TTenderFileChecker.CheckFileValid(const AFileName: string): Boolean;
 begin
-  FFileName := AFileName;
   FTempFolder := GenerateTempFolder(GetTempFilePath);
-  UnZipFile(FFileName, FTempFolder);
-  LoadInfo;
+  FTenderTempFolder := FTempFolder + '\Tender';
+  CreateDirectoryInDeep(FTenderTempFolder);
+  try
+    Result := DecryptFile(AFileName) and CheckFileMatchXml;
+  finally
+    DeleteFileOrFolder(FTempFolder);
+  end;
 end;
 
-destructor TTenderFileChecker.Destroy;
+function TTenderFileChecker.DecryptFile(const AFileName: string): Boolean;
 begin
-  DeleteFileOrFolder(FTempFolder);
-  inherited;
+  Result := UnZipFile(AFileName, FTempFolder);
+  if not Result then Exit;
+  LoadInfo;
+  Result := UnZipFile(FTenderFileName, FTenderTempFolder);
 end;
 
 procedure TTenderFileChecker.LoadInfo;
@@ -1036,6 +1105,7 @@ begin
   FProjectName := AXmlNode.Attributes['ProjectName'];
   FPhaseCount := AXmlNode.Attributes['PhaseCount'];
   FAuditStatus := AXmlNode.Attributes['AuditStatus'];
+  FTenderFileName := FTempFolder + '\' + AXmlNode.Attributes['FileName'];
 end;
 
 end.

+ 23 - 10
Units/ProjectData.pas

@@ -132,10 +132,13 @@ type
     {创建审核数据}
     procedure UpdateDataForReceive;
 
-    // 上报文件
-    procedure SubmitProject(const AFileName: string = '');
-    // 批复文件
-    procedure ReplyProject(const AFileName: string = '');
+    // 上报文件:
+    { 返回值:
+      1. True 文件检验结果正确,生成文件
+      2. False 文件检验结果错误,不生成文件}
+    function SubmitProject(const AFileName: string = ''): Boolean;
+    // 批复文件: 返回值含义同上报
+    function ReplyProject(const AFileName: string = ''): Boolean;
     // json文件:清单
     procedure ExportJson_Bills(const AFileName: string);
     procedure ExportJson_Common(const AFileName: string);
@@ -150,6 +153,8 @@ type
 
     procedure CalculateAll;
 
+    function CheckDataBaseInfo(APhaseCount, AAuditStatus: Integer): Boolean;
+
     procedure ImportCloudTenderFile(const AFileName: string);
 
     function CheckPassword: Boolean;
@@ -540,31 +545,31 @@ begin
   end;
 end;
 
-procedure TProjectData.ReplyProject(const AFileName: string = '');
+function TProjectData.ReplyProject(const AFileName: string = ''): Boolean;
 var
   Replyor: TReplyProject;
 begin
   Replyor := TReplyProject.Create(FProjectName, FFileName, FProjectID);
   try
     if AFileName = '' then
-      Replyor.Execute
+      Result := Replyor.Execute
     else
-      Replyor.ExportTo(AFileName);
+      Result := Replyor.ExportTo(AFileName);
   finally
     Replyor.Free;
   end;
 end;
 
-procedure TProjectData.SubmitProject(const AFileName: string = '');
+function TProjectData.SubmitProject(const AFileName: string = ''): Boolean;
 var
   Submitor :TSubmitProject;
 begin
   Submitor := TSubmitProject.Create(FProjectName, FFileName, FProjectID);
   try
     if AFileName = '' then
-      Submitor.Execute
+      Result := Submitor.Execute
     else
-      Submitor.ExportTo(AFileName);
+      Result := Submitor.ExportTo(AFileName);
   finally
     Submitor.Free;
   end;
@@ -1487,4 +1492,12 @@ begin
   end;
 end;
 
+function TProjectData.CheckDataBaseInfo(APhaseCount, AAuditStatus: Integer): Boolean;
+begin
+  Result := (FProjProperties.PhaseCount = APhaseCount)
+         and (FProjProperties.AuditStatus = AAuditStatus);
+  if Result and (APhaseCount > 0) and (AAuditStatus <> -1) then
+    Result := PhaseData.AuditCount = AAuditStatus;
+end;
+
 end.

+ 8 - 3
Units/UtilMethods.pas

@@ -87,7 +87,7 @@ type
 
   {Zip}
   procedure ZipFolder(AFileFolder, AFileName: string);
-  procedure UnZipFile(AFileName, AFileFolder: string);
+  function UnZipFile(AFileName, AFileFolder: string): Boolean;
 
   {Copy By Stream}
   procedure CopyFileByStream(const ASourceFile, ADestFile: string);
@@ -771,10 +771,11 @@ begin
   end;
 end;
 
-procedure UnZipFile(AFileName, AFileFolder: string);
+function UnZipFile(AFileName, AFileFolder: string): Boolean;
 var
   vUnZip: TVCLZip;
 begin
+  Result := True;
   vUnZip := TVCLZip.Create(nil);
   try
     vUnZip.FilesList.Clear;
@@ -786,7 +787,11 @@ begin
     vUnZip.RelativePaths := True;
     vUnZip.DoAll := True;
     vUnZip.FilesList.Add('*.*');
-    vUnZip.UnZip;
+    try
+      vUnZip.UnZip;
+    except
+      Result := False;
+    end;
   finally
     vUnZip.Free;
   end;