unit tpGatherTree; // 实际上可以使用mCacheTree中的ReportCacheTree // 但此处的树节点更多,使用的清单数据不多,为了便于理解,故重写 interface uses Classes, CacheTree, mDataRecord, ZhAPI, sdDB, sdIDTree; type TtpGatherTreeNode = class(TCacheNode) private FCode: string; FB_Code: string; FName: string; FUnits: string; FPrice: Double; FQuantity: Double; FTotalPrice: Double; FDgnQuantity1: Double; FDgnQuantity2: Double; FRelaPeg: Boolean; FParted: Boolean; FDrawingCode: string; public 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 Price: Double read FPrice write FPrice; property Quantity: Double read FQuantity write FQuantity; property TotalPrice: Double read FTotalPrice write FTotalPrice; property DgnQuantity1: Double read FDgnQuantity1 write FDgnQuantity1; property DgnQuantity2: Double read FDgnQuantity2 write FDgnQuantity2; // 节点为桩号/节点的父项为桩号/节点的子项全为桩号 property RelaPeg: Boolean read FRelaPeg write FRelaPeg; property Parted: Boolean read FParted write FParted; property DrawingCode: string read FDrawingCode write FDrawingCode; end; TtpGatherTree = class(TCacheTree) private function SamePrice(APrice1, APrice2: Double): Boolean; function GetParentParted(ANode: TtpGatherTreeNode): Boolean; procedure CheckNodeParted(ANode: TtpGatherTreeNode); function GetParentRelaPeg(ANode: TtpGatherTreeNode): Boolean; procedure CheckNodeRelaPeg(ANode: TtpGatherTreeNode); protected function GetNewNode: TCacheNode; override; public function FindNode(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode; function FindNextSibling(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode; function AddNode(AParent: TCacheNode; ANextSibling: TCacheNode = nil): TtpGatherTreeNode; procedure CalculateAllParent; procedure WriteData(ADataSet: TsdDataSet); procedure CheckRelaPeg; procedure CheckParted; end; implementation uses SysUtils; { TtpGatherTree } function TtpGatherTree.AddNode(AParent, ANextSibling: TCacheNode): TtpGatherTreeNode; begin Result := TtpGatherTreeNode(GetNewNode); if Assigned(ANextSibling) then ANextSibling.InsertPreSibling(Result) else if Assigned(AParent) then AParent.InsertChild(Result) else Root.InsertChild(Result); end; procedure TtpGatherTree.CalculateAllParent; function GatherChildren(ANode: TtpGatherTreeNode): Double; var vChild: TtpGatherTreeNode; begin Result := 0; if not Assigned(ANode) then Exit; vChild := TtpGatherTreeNode(ANode.FirstChild); while Assigned(vChild) do begin Result := Result + vChild.TotalPrice; vChild := TtpGatherTreeNode(vChild.NextSibling); end; end; procedure CalculateParent(ANode: TtpGatherTreeNode); begin if not Assigned(ANode) or not Assigned(ANode.FirstChild) then Exit; CalculateParent(TtpGatherTreeNode(ANode.FirstChild)); ANode.TotalPrice := GatherChildren(ANode); CalculateParent(TtpGatherTreeNode(ANode.NextSibling)); end; begin CalculateParent(TtpGatherTreeNode(Root.FirstChild)); end; procedure TtpGatherTree.CheckNodeParted(ANode: TtpGatherTreeNode); begin if not Assigned(ANode) then Exit; if Assigned(ANode.FirstChild) then begin CheckNodeParted(TtpGatherTreeNode(ANode.FirstChild)); ANode.Parted := GetParentParted(ANode); end; CheckNodeParted(TtpGatherTreeNode(ANode.NextSibling)); end; procedure TtpGatherTree.CheckNodeRelaPeg(ANode: TtpGatherTreeNode); begin if not Assigned(ANode) then Exit; if Assigned(ANode.FirstChild) then begin CheckNodeRelaPeg(TtpGatherTreeNode(ANode.FirstChild)); ANode.RelaPeg := GetParentRelaPeg(ANode); end; CheckNodeRelaPeg(TtpGatherTreeNode(ANode.NextSibling)); end; procedure TtpGatherTree.CheckParted; begin CheckNodeParted(TtpGatherTreeNode(Root.FirstChild)); end; procedure TtpGatherTree.CheckRelaPeg; begin CheckNodeRelaPeg(TtpGatherTreeNode(Root.FirstChild)); end; function TtpGatherTree.FindNextSibling(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode; var vNode: TtpGatherTreeNode; sCodeID, sCodeID2, sB_CodeID, sB_CodeID2: string; begin if Assigned(AParent) then vNode := TtpGatherTreeNode(AParent.FirstChild) else vNode := TtpGatherTreeNode(Root.FirstChild); Result := nil; if (ARec.Code.AsString = '') and (ARec.B_Code.AsString = '') then Exit; sCodeID := ConvertDigitCode(ARec.Code.AsString, 3, '-'); sB_CodeID := ConvertDigitCode(ARec.B_Code.AsString, 4, '-'); while Assigned(vNode) do begin sCodeID2 := ConvertDigitCode(vNode.Code, 3, '-'); sB_CodeID2 := ConvertDigitCode(vNode.B_Code, 4, '-'); if sCodeID < sCodeID2 then begin Result := vNode; Break; end else if sB_CodeID < sB_CodeID2 then begin Result := vNode; Break; end; vNode := TtpGatherTreeNode(vNode.NextSibling); end; end; function TtpGatherTree.FindNode(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode; var vNode: TtpGatherTreeNode; begin if Assigned(AParent) then vNode := TtpGatherTreeNode(AParent.FirstChild) else vNode := TtpGatherTreeNode(Root.FirstChild); while Assigned(vNode) do begin if SameText(vNode.Code, ARec.Code.AsString) and SameText(vNode.B_Code, ARec.B_Code.AsString) and SameText(vNode.Name, ARec.Name.AsString) and SameText(vNode.Units, ARec.Units.AsString) and SamePrice(vNode.Price, ARec.Price.AsFloat) then begin Result := vNode; Break; end; vNode := TtpGatherTreeNode(vNode.NextSibling); end; end; function TtpGatherTree.GetNewNode: TCacheNode; begin Result := TtpGatherTreeNode.Create(Self, GetNewNodeID); CacheNodes.Add(Result); end; function TtpGatherTree.GetParentParted(ANode: TtpGatherTreeNode): Boolean; var i: Integer; vChild: TtpGatherTreeNode; begin if Assigned(ANode.FirstChild) then begin Result := True; vChild := TtpGatherTreeNode(ANode.FirstChild); while Assigned(vChild) and Result do begin Result := Result and vChild.Parted; vChild := TtpGatherTreeNode(vChild.NextSibling); end; end else Result := ANode.Parted; end; function TtpGatherTree.GetParentRelaPeg(ANode: TtpGatherTreeNode): Boolean; var i: Integer; vChild: TtpGatherTreeNode; begin if Assigned(ANode.FirstChild) then begin Result := True; vChild := TtpGatherTreeNode(ANode.FirstChild); while Assigned(vChild) and Result do begin Result := Result and vChild.RelaPeg; vChild := TtpGatherTreeNode(vChild.NextSibling); end; end else Result := ANode.RelaPeg; end; function TtpGatherTree.SamePrice(APrice1, APrice2: Double): Boolean; begin Result := (APrice1 - APrice2) < 0.001; end; procedure TtpGatherTree.WriteData(ADataSet: TsdDataSet); procedure BeforeWrite; begin ADataSet.DisableControls; ADataSet.BeginUpdate; ADataSet.DeleteAll; end; procedure AfterWrite; begin ADataSet.EndUpdate; ADataSet.EnableControls; end; var i: Integer; vNode: TtpGatherTreeNode; Rec: TsdDataRecord; begin BeforeWrite; try for i := 0 to CacheNodes.Count - 1 do begin vNode := TtpGatherTreeNode(CacheNodes.Items[i]); Rec := ADataSet.Add; Rec.ValueByName('ID').AsInteger := vNode.ID; Rec.ValueByName('ParentID').AsInteger := vNode.ParentID; Rec.ValueByName('NextSiblingID').AsInteger := vNode.NextSiblingID; Rec.ValueByName('Code').AsString := vNode.Code; Rec.ValueByName('B_Code').AsString := vNode.B_Code; Rec.ValueByName('Name').AsString := vNode.Name; Rec.ValueByName('Units').AsString := vNode.Units; Rec.ValueByName('Price').AsFloat := vNode.Price; Rec.ValueByName('Quantity').AsFloat := vNode.Quantity; Rec.ValueByName('TotalPrice').AsFloat := vNode.TotalPrice; Rec.ValueByName('DgnQuantity1').AsFloat := vNode.DgnQuantity1; Rec.ValueByName('DgnQuantity2').AsFloat := vNode.DgnQuantity2; Rec.ValueByName('DrawingCode').AsString := vNode.DrawingCode; end; finally AfterWrite; end; end; end.