tpGatherTree.pas 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. unit tpGatherTree;
  2. // 实际上可以使用mCacheTree中的ReportCacheTree
  3. // 但此处的树节点更多,使用的清单数据不多,为了便于理解,故重写
  4. interface
  5. uses
  6. Classes, CacheTree, mDataRecord, ZhAPI, sdDB, sdIDTree;
  7. type
  8. TtpGatherTreeNode = class(TCacheNode)
  9. private
  10. FCode: string;
  11. FB_Code: string;
  12. FName: string;
  13. FUnits: string;
  14. FPrice: Double;
  15. FQuantity: Double;
  16. FTotalPrice: Double;
  17. FDgnQuantity1: Double;
  18. FDgnQuantity2: Double;
  19. FRelaPeg: Boolean;
  20. FParted: Boolean;
  21. public
  22. property Code: string read FCode write FCode;
  23. property B_Code: string read FB_Code write FB_Code;
  24. property Name: string read FName write FName;
  25. property Units: string read FUnits write FUnits;
  26. property Price: Double read FPrice write FPrice;
  27. property Quantity: Double read FQuantity write FQuantity;
  28. property TotalPrice: Double read FTotalPrice write FTotalPrice;
  29. property DgnQuantity1: Double read FDgnQuantity1 write FDgnQuantity1;
  30. property DgnQuantity2: Double read FDgnQuantity2 write FDgnQuantity2;
  31. // 节点为桩号/节点的父项为桩号/节点的子项全为桩号
  32. property RelaPeg: Boolean read FRelaPeg write FRelaPeg;
  33. property Parted: Boolean read FParted write FParted;
  34. end;
  35. TtpGatherTree = class(TCacheTree)
  36. private
  37. function SamePrice(APrice1, APrice2: Double): Boolean;
  38. function GetParentParted(ANode: TtpGatherTreeNode): Boolean;
  39. procedure CheckNodeParted(ANode: TtpGatherTreeNode);
  40. function GetParentRelaPeg(ANode: TtpGatherTreeNode): Boolean;
  41. procedure CheckNodeRelaPeg(ANode: TtpGatherTreeNode);
  42. protected
  43. function GetNewNode: TCacheNode; override;
  44. public
  45. function FindNode(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode;
  46. function FindNextSibling(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode;
  47. function AddNode(AParent: TCacheNode; ANextSibling: TCacheNode = nil): TtpGatherTreeNode;
  48. procedure CalculateAllParent;
  49. procedure WriteData(ADataSet: TsdDataSet);
  50. procedure CheckRelaPeg;
  51. procedure CheckParted;
  52. end;
  53. implementation
  54. uses SysUtils;
  55. { TtpGatherTree }
  56. function TtpGatherTree.AddNode(AParent,
  57. ANextSibling: TCacheNode): TtpGatherTreeNode;
  58. begin
  59. Result := TtpGatherTreeNode(GetNewNode);
  60. if Assigned(ANextSibling) then
  61. ANextSibling.InsertPreSibling(Result)
  62. else if Assigned(AParent) then
  63. AParent.InsertChild(Result)
  64. else
  65. Root.InsertChild(Result);
  66. end;
  67. procedure TtpGatherTree.CalculateAllParent;
  68. function GatherChildren(ANode: TtpGatherTreeNode): Double;
  69. var
  70. vChild: TtpGatherTreeNode;
  71. begin
  72. Result := 0;
  73. if not Assigned(ANode) then Exit;
  74. vChild := TtpGatherTreeNode(ANode.FirstChild);
  75. while Assigned(vChild) do
  76. begin
  77. Result := Result + vChild.TotalPrice;
  78. vChild := TtpGatherTreeNode(vChild.NextSibling);
  79. end;
  80. end;
  81. procedure CalculateParent(ANode: TtpGatherTreeNode);
  82. begin
  83. if not Assigned(ANode) or not Assigned(ANode.FirstChild) then Exit;
  84. CalculateParent(TtpGatherTreeNode(ANode.FirstChild));
  85. ANode.TotalPrice := GatherChildren(ANode);
  86. CalculateParent(TtpGatherTreeNode(ANode.NextSibling));
  87. end;
  88. begin
  89. CalculateParent(TtpGatherTreeNode(Root.FirstChild));
  90. end;
  91. procedure TtpGatherTree.CheckNodeParted(ANode: TtpGatherTreeNode);
  92. begin
  93. if not Assigned(ANode) then Exit;
  94. if Assigned(ANode.FirstChild) then
  95. begin
  96. CheckNodeParted(TtpGatherTreeNode(ANode.FirstChild));
  97. ANode.Parted := GetParentParted(ANode);
  98. end;
  99. CheckNodeParted(TtpGatherTreeNode(ANode.NextSibling));
  100. end;
  101. procedure TtpGatherTree.CheckNodeRelaPeg(ANode: TtpGatherTreeNode);
  102. begin
  103. if not Assigned(ANode) then Exit;
  104. if Assigned(ANode.FirstChild) then
  105. begin
  106. CheckNodeRelaPeg(TtpGatherTreeNode(ANode.FirstChild));
  107. ANode.RelaPeg := GetParentRelaPeg(ANode);
  108. end;
  109. CheckNodeRelaPeg(TtpGatherTreeNode(ANode.NextSibling));
  110. end;
  111. procedure TtpGatherTree.CheckParted;
  112. begin
  113. CheckNodeParted(TtpGatherTreeNode(Root.FirstChild));
  114. end;
  115. procedure TtpGatherTree.CheckRelaPeg;
  116. begin
  117. CheckNodeRelaPeg(TtpGatherTreeNode(Root.FirstChild));
  118. end;
  119. function TtpGatherTree.FindNextSibling(AParent: TtpGatherTreeNode;
  120. ARec: TBillsRecord): TtpGatherTreeNode;
  121. var
  122. vNode: TtpGatherTreeNode;
  123. sCodeID, sCodeID2, sB_CodeID, sB_CodeID2: string;
  124. begin
  125. if Assigned(AParent) then
  126. vNode := TtpGatherTreeNode(AParent.FirstChild)
  127. else
  128. vNode := TtpGatherTreeNode(Root.FirstChild);
  129. Result := nil;
  130. if (ARec.Code.AsString = '') and (ARec.B_Code.AsString = '') then Exit;
  131. sCodeID := ConvertDigitCode(ARec.Code.AsString, 3, '-');
  132. sB_CodeID := ConvertDigitCode(ARec.B_Code.AsString, 4, '-');
  133. while Assigned(vNode) do
  134. begin
  135. sCodeID2 := ConvertDigitCode(vNode.Code, 3, '-');
  136. sB_CodeID2 := ConvertDigitCode(vNode.B_Code, 4, '-');
  137. if sCodeID < sCodeID2 then
  138. begin
  139. Result := vNode;
  140. Break;
  141. end
  142. else if sB_CodeID < sB_CodeID2 then
  143. begin
  144. Result := vNode;
  145. Break;
  146. end;
  147. vNode := TtpGatherTreeNode(vNode.NextSibling);
  148. end;
  149. end;
  150. function TtpGatherTree.FindNode(AParent: TtpGatherTreeNode; ARec: TBillsRecord): TtpGatherTreeNode;
  151. var
  152. vNode: TtpGatherTreeNode;
  153. begin
  154. if Assigned(AParent) then
  155. vNode := TtpGatherTreeNode(AParent.FirstChild)
  156. else
  157. vNode := TtpGatherTreeNode(Root.FirstChild);
  158. while Assigned(vNode) do
  159. begin
  160. if SameText(vNode.Code, ARec.Code.AsString) and
  161. SameText(vNode.B_Code, ARec.B_Code.AsString) and
  162. SameText(vNode.Name, ARec.Name.AsString) and
  163. SameText(vNode.Units, ARec.Units.AsString) and
  164. SamePrice(vNode.Price, ARec.Price.AsFloat) then
  165. begin
  166. Result := vNode;
  167. Break;
  168. end;
  169. vNode := TtpGatherTreeNode(vNode.NextSibling);
  170. end;
  171. end;
  172. function TtpGatherTree.GetNewNode: TCacheNode;
  173. begin
  174. Result := TtpGatherTreeNode.Create(Self, GetNewNodeID);
  175. CacheNodes.Add(Result);
  176. end;
  177. function TtpGatherTree.GetParentParted(ANode: TtpGatherTreeNode): Boolean;
  178. var
  179. i: Integer;
  180. vChild: TtpGatherTreeNode;
  181. begin
  182. if Assigned(ANode.FirstChild) then
  183. begin
  184. Result := True;
  185. vChild := TtpGatherTreeNode(ANode.FirstChild);
  186. while Assigned(vChild) and Result do
  187. begin
  188. Result := Result and vChild.Parted;
  189. vChild := TtpGatherTreeNode(vChild.NextSibling);
  190. end;
  191. end
  192. else
  193. Result := ANode.Parted;
  194. end;
  195. function TtpGatherTree.GetParentRelaPeg(ANode: TtpGatherTreeNode): Boolean;
  196. var
  197. i: Integer;
  198. vChild: TtpGatherTreeNode;
  199. begin
  200. if Assigned(ANode.FirstChild) then
  201. begin
  202. Result := True;
  203. vChild := TtpGatherTreeNode(ANode.FirstChild);
  204. while Assigned(vChild) and Result do
  205. begin
  206. Result := Result and vChild.RelaPeg;
  207. vChild := TtpGatherTreeNode(vChild.NextSibling);
  208. end;
  209. end
  210. else
  211. Result := ANode.RelaPeg;
  212. end;
  213. function TtpGatherTree.SamePrice(APrice1, APrice2: Double): Boolean;
  214. begin
  215. Result := (APrice1 - APrice2) < 0.001;
  216. end;
  217. procedure TtpGatherTree.WriteData(ADataSet: TsdDataSet);
  218. procedure BeforeWrite;
  219. begin
  220. ADataSet.DisableControls;
  221. ADataSet.BeginUpdate;
  222. ADataSet.DeleteAll;
  223. end;
  224. procedure AfterWrite;
  225. begin
  226. ADataSet.EndUpdate;
  227. ADataSet.EnableControls;
  228. end;
  229. var
  230. i: Integer;
  231. vNode: TtpGatherTreeNode;
  232. Rec: TsdDataRecord;
  233. begin
  234. BeforeWrite;
  235. try
  236. for i := 0 to CacheNodes.Count - 1 do
  237. begin
  238. vNode := TtpGatherTreeNode(CacheNodes.Items[i]);
  239. Rec := ADataSet.Add;
  240. Rec.ValueByName('ID').AsInteger := vNode.ID;
  241. Rec.ValueByName('ParentID').AsInteger := vNode.ParentID;
  242. Rec.ValueByName('NextSiblingID').AsInteger := vNode.NextSiblingID;
  243. Rec.ValueByName('Code').AsString := vNode.Code;
  244. Rec.ValueByName('B_Code').AsString := vNode.B_Code;
  245. Rec.ValueByName('Name').AsString := vNode.Name;
  246. Rec.ValueByName('Units').AsString := vNode.Units;
  247. Rec.ValueByName('Price').AsFloat := vNode.Price;
  248. Rec.ValueByName('Quantity').AsFloat := vNode.Quantity;
  249. Rec.ValueByName('TotalPrice').AsFloat := vNode.TotalPrice;
  250. Rec.ValueByName('DgnQuantity1').AsFloat := vNode.DgnQuantity1;
  251. Rec.ValueByName('DgnQuantity2').AsFloat := vNode.DgnQuantity2;
  252. end;
  253. finally
  254. AfterWrite;
  255. end;
  256. end;
  257. end.