ExcelImport_Bills.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. unit ExcelImport_Bills;
  2. // 导入0号台账/分项清单
  3. interface
  4. uses
  5. DetailExcelImport, Classes, MCacheTree, sdDB, ProjectData;
  6. type
  7. Tdei_CustomBills = class(TDetailExcelImport)
  8. private
  9. FCacheTree: TBillsCacheTree;
  10. FCurRow: Integer;
  11. FIsFirstPart: Boolean;
  12. FWithLevelCode: Boolean;
  13. FWithoutGclBills: Boolean;
  14. FBaseTree: TBillsCacheTree;
  15. FFixedIDNodes: TList;
  16. FCodeCol: Integer;
  17. FB_CodeCol: Integer;
  18. FNameCol: Integer;
  19. FUnitsCol: Integer;
  20. FPriceCol: Integer;
  21. FOrgQuantityCol: Integer;
  22. FMisQuantityCol: Integer;
  23. FOthQuantityCol: Integer;
  24. FDgnQuantity1Col: Integer;
  25. FDgnQuantity2Col: Integer;
  26. FDrawingCol: Integer;
  27. FMemoCol: Integer;
  28. FLevelCol: Integer;
  29. protected
  30. procedure BeginImport; override;
  31. procedure EndImport; override;
  32. function GetFixedIDNode(AID: Integer): TBillsCacheNode;
  33. function GetFixedID(ACode, AName: string): Integer;
  34. procedure CheckFixedIDNodes;
  35. procedure LoadColumnsFromHead;
  36. procedure LoadBaseTree(ATree: TBillsCacheTree);
  37. procedure LoadNode;
  38. procedure LoadNodes;
  39. procedure WriteNode(ADataSet: TsdDataSet; ANode: TBillsCacheNode);
  40. procedure WriteNodes(ADataSet: TsdDataSet);
  41. procedure Import; override;
  42. public
  43. procedure ImportFile(const AFileName: string; AWithLevelCode, AWithoutGclBills: Boolean); overload;
  44. end;
  45. implementation
  46. uses
  47. Forms, Controls, ProgressHintFrm, ConstUnit, UtilMethods, ExcelImport,
  48. SysUtils, mDataRecord, XLSAdapter;
  49. { Tdei_CustomBills }
  50. procedure Tdei_CustomBills.BeginImport;
  51. begin
  52. Screen.Cursor := crHourGlass;
  53. ShowProgressHint('导入Excel数据', 100, '读取Excel数据', 100);
  54. FCurRow := 1;
  55. FIsFirstPart := True;
  56. FCacheTree := TBillsCacheTree.Create;
  57. FCacheTree.NewNodeID := 101;
  58. // 以层次编号为依据,分隔用'.',以项目节、清单编号为依据,分隔用'-'
  59. if FWithLevelCode then
  60. FCacheTree.SeparateChar := '.'
  61. else
  62. FCacheTree.SeparateChar := '-';
  63. FCacheTree.AutoSort := True;
  64. ProjectData.DisConnectTree;
  65. ProjectData.BillsData.DisableEvents;
  66. FBaseTree := TBillsCacheTree.Create;
  67. FBaseTree.NewNodeID := 101;
  68. FBaseTree.SeparateChar := '.';
  69. FFixedIDNodes := TList.Create;
  70. end;
  71. procedure Tdei_CustomBills.CheckFixedIDNodes;
  72. function GetHintStr(ANode: TBillsCacheNode): string;
  73. begin
  74. Result := '';
  75. if ANode.Code <> '' then
  76. Result := Result + '编号:' + ANode.Code + ';';
  77. if ANode.Name <> '' then
  78. Result := Result + '名称:' + ANode.Name + ';';
  79. end;
  80. function GetInvalidModel(ANoPM: Boolean; ACount: Integer): string;
  81. begin
  82. if ANoPM then
  83. begin
  84. if ACount > 1 then
  85. Result := '价差功能,部分报表'
  86. else
  87. Result := '价差功能'
  88. end
  89. else
  90. Result := '部分报表';
  91. Result := Result + '将不可使用' + #13#10 + '如有疑问,请联系纵横客服,企业QQ:800003850 电话:(0756)3850888';
  92. end;
  93. var
  94. sgs: TStrings;
  95. iBase: Integer;
  96. vBase, vImport: TBillsCacheNode;
  97. sHint: string;
  98. bNoPM: Boolean;
  99. begin
  100. bNoPM := False;
  101. sgs := TStringList.Create;
  102. try
  103. sgs.Add('缺少如下固定清单节点:');
  104. for iBase := 0 to FBaseTree.FixedIDNodes.Count - 1 do
  105. begin
  106. vBase := TBillsCacheNode(FBaseTree.FixedIDNodes.Items[iBase]);
  107. vImport := FCacheTree.FindFixedIDNode(vBase.ID);
  108. if not Assigned(vImport) then
  109. begin
  110. sgs.Add(GetHintStr(vBase));
  111. if vBase.ID = iPriceMarginID then
  112. bNoPM := True;
  113. end;
  114. end;
  115. finally
  116. if sgs.Count > 1 then
  117. begin
  118. sgs.Add(GetInvalidModel(bNoPM, sgs.Count - 1));
  119. WarningMessage(sgs.Text);
  120. end;
  121. sgs.Free;
  122. end;
  123. end;
  124. procedure Tdei_CustomBills.EndImport;
  125. begin
  126. // For Test
  127. // FCacheTree.SaveTreeToFile('E:\Tree.txt');
  128. if FWithLevelCode then
  129. CheckFixedIDNodes;
  130. FFixedIDNodes.Free;
  131. FBaseTree.Free;
  132. ProjectData.BillsData.EnableEvents;
  133. ProjectData.ReConnectTree;
  134. FCacheTree.Free;
  135. ProjectData.BillsCompileData.CalculateAll;
  136. CloseProgressHint;
  137. Screen.Cursor := crDefault;
  138. end;
  139. function Tdei_CustomBills.GetFixedID(ACode, AName: string): Integer;
  140. var
  141. i: Integer;
  142. Node: TBillsCacheNode;
  143. begin
  144. Result := -1;
  145. for i := 0 to FBaseTree.CacheNodes.Count - 1 do
  146. begin
  147. Node := TBillsCacheNode(FBaseTree.CacheNodes.Items[i]);
  148. if (Node.Code = ACode) and (Node.Name = AName) then
  149. begin
  150. if Node.ID < 100 then
  151. Result := Node.ID;
  152. Break;
  153. end;
  154. end;
  155. end;
  156. function Tdei_CustomBills.GetFixedIDNode(AID: Integer): TBillsCacheNode;
  157. var
  158. i: Integer;
  159. Node: TBillsCacheNode;
  160. begin
  161. Result := nil;
  162. for i := 0 to FFixedIDNodes.Count - 1 do
  163. begin
  164. Node := TBillsCacheNode(FFixedIDNodes.Items[i]);
  165. if (AID = Node.ID) then
  166. begin
  167. Result := Node;
  168. Break;
  169. end;
  170. end;
  171. end;
  172. procedure Tdei_CustomBills.Import;
  173. begin
  174. if FWithLevelCode then
  175. LoadBaseTree(FBaseTree)
  176. else
  177. LoadBaseTree(FCacheTree);
  178. LoadColumnsFromHead;
  179. LoadNodes;
  180. WriteNodes(ProjectData.BillsData.sddBills);
  181. end;
  182. procedure Tdei_CustomBills.ImportFile(const AFileName: string;
  183. AWithLevelCode, AWithoutGclBills: Boolean);
  184. begin
  185. FWithLevelCode := AWithLevelCode;
  186. FWithoutGclBills := AWithoutGclBills;
  187. ImportFile(AFileName);
  188. end;
  189. procedure Tdei_CustomBills.LoadBaseTree(ATree: TBillsCacheTree);
  190. var
  191. BaseImportor: TBillsExcelImport;
  192. begin
  193. BaseImportor := TBillsExcelImport.Create(nil);
  194. try
  195. BaseImportor.ImportToTree(ATree, GetTemplateBillsFileName);
  196. finally
  197. BaseImportor.Free;
  198. end;
  199. end;
  200. procedure Tdei_CustomBills.LoadColumnsFromHead;
  201. var
  202. iCol: Integer;
  203. sColName: string;
  204. begin
  205. FCodeCol := -1;
  206. FB_CodeCol := -1;
  207. FNameCol := -1;
  208. FUnitsCol := -1;
  209. FPriceCol := -1;
  210. FOrgQuantityCol := -1;
  211. FMisQuantityCol := -1;
  212. FOthQuantityCol := -1;
  213. FDgnQuantity1Col := -1;
  214. FDgnQuantity2Col := -1;
  215. FDrawingCol := -1;
  216. FMemoCol := -1;
  217. FLevelCol := -1;
  218. for iCol := 1 to Excel.XlsFile.MaxCol do
  219. begin
  220. sColName := GetCellTrimStr(Excel.XlsFile, FCurRow, iCol);
  221. if Pos('项目节', sColName) > 0 then
  222. FCodeCol := iCol
  223. else if (sColName = '清单编号') or (Pos('子目号', sColName) > 0) then
  224. FB_CodeCol := iCol
  225. else if sColName = '名称' then
  226. FNameCol := iCol
  227. else if sColName = '单位' then
  228. FUnitsCol := iCol
  229. else if sColName = '单价' then
  230. FPriceCol := iCol
  231. else if (sColName = '清单数量') or (sColName = '工程量') or (sColName = '数量') or (sColName = '施工图数量') then
  232. FOrgQuantityCol := iCol
  233. else if (sColName = '设计错漏数量') then
  234. FMisQuantityCol := iCol
  235. else if (sColName = '其他错漏数量') then
  236. FOthQuantityCol := iCol
  237. else if (sColName = '设计数量1') or (sColName = '数量1') then
  238. FDgnQuantity1Col := iCol
  239. else if (sColName = '设计数量2') or (sColName = '数量2') then
  240. FDgnQuantity2Col := iCol
  241. else if sColName = '图号' then
  242. FDrawingCol := iCol
  243. else if sColName = '备注' then
  244. FMemoCol := iCol
  245. else if sColName = '层次编号' then
  246. FLevelCol := iCol;
  247. end;
  248. Inc(FCurRow);
  249. end;
  250. procedure Tdei_CustomBills.LoadNode;
  251. var
  252. sLevelCode, sCode, sB_Code, sName: string;
  253. Node: TBillsCacheNode;
  254. vValue: Variant;
  255. iFixedID: Integer;
  256. begin
  257. sLevelCode := GetCellTrimStr(Excel.XlsFile, FCurRow, FLevelCol);
  258. sCode := GetCellTrimStr(Excel.XlsFile, FCurRow, FCodeCol);
  259. sB_Code := GetCellTrimStr(Excel.XlsFile, FCurRow, FB_CodeCol);
  260. sName := GetCellTrimStr(Excel.XlsFile, FCurRow, FNameCol);
  261. // 含层次编号时,层次编号为空不导入
  262. // 不含层次编号时,仅导入第一部分,且项目节编号、清单编号均未空时不导入
  263. if FWithLevelCode then
  264. begin
  265. if sLevelCode = '' then Exit;
  266. end
  267. else
  268. begin
  269. if ((sCode = '') and (sB_Code = '')) or SameText(sCode, '2') or
  270. (Pos('第二部分', sName) > 0) then
  271. begin
  272. FIsFirstPart := False;
  273. Exit;
  274. end;
  275. end;
  276. if (sCode = '') and FWithoutGclBills then Exit;
  277. // 含层次编号时,以层次编号为依据新增节点;反之以项目节编号为依据新增节点
  278. if not FWithLevelCode then
  279. begin
  280. if (sCode <> '') then
  281. Node := FCacheTree.AddNodeByCode(sCode, -1)
  282. else
  283. Node := FCacheTree.AddLeafBillsNode(sB_Code);
  284. end
  285. else
  286. begin
  287. // 1. 从模板树中查询当前节点是否为固定ID,否则为-1
  288. iFixedID := GetFixedID(sCode, sName);
  289. // 2. 从导入树中查询是否添加过该固定ID,防止存在两个固定ID节点主键冲突
  290. // 如果已添加过固定ID节点,则其他节点未非固定ID节点
  291. Node := GetFixedIDNode(iFixedID);
  292. if Assigned(Node) then
  293. iFixedID := -1;
  294. // 3. 添加当前节点
  295. Node := FCacheTree.AddNodeByCode(sLevelCode, iFixedID);
  296. // 4. 如果当前添加的节点为固定ID节点,则添加到List中便于2快速查找
  297. if Node.ID < 100 then
  298. FFixedIDNodes.Add(Node);
  299. end;
  300. Node.Code := sCode;
  301. Node.B_Code := sB_Code;
  302. Node.Name := sName;
  303. Node.Units := GetCellTrimStr(Excel.XlsFile, FCurRow, FUnitsCol);
  304. Node.Price := GetCellFloat(Excel.XlsFile, FCurRow, FPriceCol);
  305. Node.OrgQuantity := GetCellFloat(Excel.XlsFile, FCurRow, FOrgQuantityCol);
  306. Node.MisQuantity := GetCellFloat(Excel.XlsFile, FCurRow, FMisQuantityCol);
  307. Node.OthQuantity := GetCellFloat(Excel.XlsFile, FCurRow, FOthQuantityCol);
  308. Node.DgnQuantity1 := GetCellFloat(Excel.XlsFile, FCurRow, FDgnQuantity1Col);
  309. Node.DgnQuantity2 := GetCellFloat(Excel.XlsFile, FCurRow, FDgnQuantity2Col);
  310. Node.DrawingCode := GetCellTrimStr(Excel.XlsFile, FCurRow, FDrawingCol);
  311. Node.MemoStr := GetCellTrimStr(Excel.XlsFile, FCurRow, FMemoCol);
  312. end;
  313. procedure Tdei_CustomBills.LoadNodes;
  314. var
  315. iPos, iSubPos: Integer;
  316. begin
  317. while (FCurRow <= Excel.XlsFile.MaxRow){ and FIsFirstPart }do
  318. begin
  319. LoadNode;
  320. Inc(FCurRow);
  321. iSubPos := FCurRow * 100 div Excel.XlsFile.MaxRow;
  322. iPos := iSubPos div 2;
  323. UpdateProgressPosition(iPos, iSubPos);
  324. end;
  325. end;
  326. procedure Tdei_CustomBills.WriteNode(ADataSet: TsdDataSet;
  327. ANode: TBillsCacheNode);
  328. var
  329. Rec: TBillsRecord;
  330. begin
  331. if ANode.Code <> '' then
  332. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Code)
  333. else if ANode.B_Code <> '' then
  334. UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
  335. else
  336. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
  337. Rec := TBillsRecord(ADataSet.Add);
  338. Rec.ID.AsInteger := ANode.ID;
  339. Rec.ParentID.AsInteger := ANode.ParentID;
  340. Rec.NextSiblingID.AsInteger := ANode.NextSiblingID;
  341. Rec.Code.AsString := ANode.Code;
  342. Rec.B_Code.AsString := ANode.B_Code;
  343. Rec.Name.AsString := ANode.Name;
  344. Rec.Units.AsString := ANode.Units;
  345. Rec.Price.AsFloat := PriceRoundTo(ANode.Price);
  346. Rec.OrgQuantity.AsFloat := QuantityRoundTo(ANode.OrgQuantity);
  347. Rec.MisQuantity.AsFloat := QuantityRoundTo(ANode.MisQuantity);
  348. Rec.OthQuantity.AsFloat := QuantityRoundTo(ANode.OthQuantity);
  349. Rec.DgnQuantity1.AsFloat := QuantityRoundTo(ANode.DgnQuantity1);
  350. Rec.DgnQuantity2.AsFloat := QuantityRoundTo(ANode.DgnQuantity2);
  351. Rec.DrawingCode.AsString := ANode.DrawingCode;
  352. Rec.MemoStr.AsString := ANode.MemoStr;
  353. end;
  354. procedure Tdei_CustomBills.WriteNodes(ADataSet: TsdDataSet);
  355. var
  356. i, iPos, iSubPos: Integer;
  357. begin
  358. UpdateProgressHint('写入读取的Excel数据', True);
  359. UpdateProgressPosition(50, 0);
  360. ADataSet.DeleteAll;
  361. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  362. begin
  363. WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
  364. iSubPos := i*100 div FCacheTree.CacheNodes.Count;
  365. iPos := 50 + iSubPos div 2;
  366. UpdateProgressPosition(iPos, iSubPos);
  367. end;
  368. UpdateProgressPosition(100, 100);
  369. end;
  370. end.