ExcelImport_Bills.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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. {if FWithLevelCode then
  127. CheckFixedIDNodes;}
  128. FFixedIDNodes.Free;
  129. FBaseTree.Free;
  130. ProjectData.BillsData.EnableEvents;
  131. ProjectData.ReConnectTree;
  132. FCacheTree.Free;
  133. ProjectData.BillsCompileData.CalculateAll;
  134. CloseProgressHint;
  135. Screen.Cursor := crDefault;
  136. end;
  137. function Tdei_CustomBills.GetFixedID(ACode, AName: string): Integer;
  138. var
  139. i: Integer;
  140. Node: TBillsCacheNode;
  141. begin
  142. Result := -1;
  143. for i := 0 to FBaseTree.CacheNodes.Count - 1 do
  144. begin
  145. Node := TBillsCacheNode(FBaseTree.CacheNodes.Items[i]);
  146. if (Node.Code = ACode) and (Node.Name = AName) then
  147. begin
  148. if Node.ID < 100 then
  149. Result := Node.ID;
  150. Break;
  151. end;
  152. end;
  153. end;
  154. function Tdei_CustomBills.GetFixedIDNode(AID: Integer): TBillsCacheNode;
  155. var
  156. i: Integer;
  157. Node: TBillsCacheNode;
  158. begin
  159. Result := nil;
  160. for i := 0 to FFixedIDNodes.Count - 1 do
  161. begin
  162. Node := TBillsCacheNode(FFixedIDNodes.Items[i]);
  163. if (AID = Node.ID) then
  164. begin
  165. Result := Node;
  166. Break;
  167. end;
  168. end;
  169. end;
  170. procedure Tdei_CustomBills.Import;
  171. begin
  172. if FWithLevelCode then
  173. LoadBaseTree(FBaseTree)
  174. else
  175. LoadBaseTree(FCacheTree);
  176. LoadColumnsFromHead;
  177. LoadNodes;
  178. WriteNodes(ProjectData.BillsData.sddBills);
  179. end;
  180. procedure Tdei_CustomBills.ImportFile(const AFileName: string;
  181. AWithLevelCode, AWithoutGclBills: Boolean);
  182. begin
  183. FWithLevelCode := AWithLevelCode;
  184. FWithoutGclBills := AWithoutGclBills;
  185. ImportFile(AFileName);
  186. end;
  187. procedure Tdei_CustomBills.LoadBaseTree(ATree: TBillsCacheTree);
  188. var
  189. BaseImportor: TBillsExcelImport;
  190. begin
  191. BaseImportor := TBillsExcelImport.Create(nil);
  192. try
  193. BaseImportor.ImportToTree(ATree, GetTemplateBillsFileName);
  194. finally
  195. BaseImportor.Free;
  196. end;
  197. end;
  198. procedure Tdei_CustomBills.LoadColumnsFromHead;
  199. var
  200. iCol: Integer;
  201. sColName: string;
  202. begin
  203. FCodeCol := -1;
  204. FB_CodeCol := -1;
  205. FNameCol := -1;
  206. FUnitsCol := -1;
  207. FPriceCol := -1;
  208. FOrgQuantityCol := -1;
  209. FMisQuantityCol := -1;
  210. FOthQuantityCol := -1;
  211. FDgnQuantity1Col := -1;
  212. FDgnQuantity2Col := -1;
  213. FDrawingCol := -1;
  214. FMemoCol := -1;
  215. FLevelCol := -1;
  216. for iCol := 1 to Excel.XlsFile.MaxCol do
  217. begin
  218. sColName := GetCellTrimStr(Excel.XlsFile, FCurRow, iCol);
  219. if Pos('项目节', sColName) > 0 then
  220. FCodeCol := iCol
  221. else if (sColName = '清单编号') or (Pos('子目号', sColName) > 0) then
  222. FB_CodeCol := iCol
  223. else if sColName = '名称' then
  224. FNameCol := iCol
  225. else if sColName = '单位' then
  226. FUnitsCol := iCol
  227. else if sColName = '单价' then
  228. FPriceCol := iCol
  229. else if (sColName = '清单数量') or (sColName = '工程量') or (sColName = '数量') or (sColName = '施工图数量') then
  230. FOrgQuantityCol := iCol
  231. else if (sColName = '设计错漏数量') then
  232. FMisQuantityCol := iCol
  233. else if (sColName = '其他错漏数量') then
  234. FOthQuantityCol := iCol
  235. else if (sColName = '设计数量1') or (sColName = '数量1') then
  236. FDgnQuantity1Col := iCol
  237. else if (sColName = '设计数量2') or (sColName = '数量2') then
  238. FDgnQuantity2Col := iCol
  239. else if sColName = '图号' then
  240. FDrawingCol := iCol
  241. else if sColName = '备注' then
  242. FMemoCol := iCol
  243. else if sColName = '层次编号' then
  244. FLevelCol := iCol;
  245. end;
  246. Inc(FCurRow);
  247. end;
  248. procedure Tdei_CustomBills.LoadNode;
  249. var
  250. sLevelCode, sCode, sB_Code, sName: string;
  251. Node: TBillsCacheNode;
  252. vValue: Variant;
  253. iFixedID: Integer;
  254. begin
  255. sLevelCode := GetCellTrimStr(Excel.XlsFile, FCurRow, FLevelCol);
  256. sCode := GetCellTrimStr(Excel.XlsFile, FCurRow, FCodeCol);
  257. sB_Code := GetCellTrimStr(Excel.XlsFile, FCurRow, FB_CodeCol);
  258. sName := GetCellTrimStr(Excel.XlsFile, FCurRow, FNameCol);
  259. // 含层次编号时,层次编号为空不导入
  260. // 不含层次编号时,仅导入第一部分,且项目节编号、清单编号均未空时不导入
  261. if FWithLevelCode then
  262. begin
  263. if sLevelCode = '' then Exit;
  264. end
  265. else
  266. begin
  267. if ((sCode = '') and (sB_Code = '')) or SameText(sCode, '2') or
  268. (Pos('第二部分', sName) > 0) then
  269. begin
  270. FIsFirstPart := False;
  271. Exit;
  272. end;
  273. end;
  274. if (sCode = '') and FWithoutGclBills then Exit;
  275. // 含层次编号时,以层次编号为依据新增节点;反之以项目节编号为依据新增节点
  276. if not FWithLevelCode then
  277. begin
  278. if (sCode <> '') then
  279. Node := FCacheTree.AddNodeByCode(sCode, -1)
  280. else
  281. Node := FCacheTree.AddLeafBillsNode(sB_Code);
  282. end
  283. else
  284. begin
  285. // 1. 从模板树中查询当前节点是否为固定ID,否则为-1
  286. iFixedID := GetFixedID(sCode, sName);
  287. // 2. 从导入树中查询是否添加过该固定ID,防止存在两个固定ID节点主键冲突
  288. // 如果已添加过固定ID节点,则其他节点未非固定ID节点
  289. Node := GetFixedIDNode(iFixedID);
  290. if Assigned(Node) then
  291. iFixedID := -1;
  292. // 3. 添加当前节点
  293. Node := FCacheTree.AddNodeByCode(sLevelCode, iFixedID);
  294. // 4. 如果当前添加的节点为固定ID节点,则添加到List中便于2快速查找
  295. if Node.ID < 100 then
  296. FFixedIDNodes.Add(Node);
  297. end;
  298. Node.Code := sCode;
  299. Node.B_Code := sB_Code;
  300. Node.Name := sName;
  301. Node.Units := GetCellTrimStr(Excel.XlsFile, FCurRow, FUnitsCol);
  302. Node.Price := GetCellFloat(Excel.XlsFile, FCurRow, FPriceCol);
  303. Node.OrgQuantity := GetCellFloat(Excel.XlsFile, FCurRow, FOrgQuantityCol);
  304. Node.MisQuantity := GetCellFloat(Excel.XlsFile, FCurRow, FMisQuantityCol);
  305. Node.OthQuantity := GetCellFloat(Excel.XlsFile, FCurRow, FOthQuantityCol);
  306. Node.DgnQuantity1 := GetCellFloat(Excel.XlsFile, FCurRow, FDgnQuantity1Col);
  307. Node.DgnQuantity2 := GetCellFloat(Excel.XlsFile, FCurRow, FDgnQuantity2Col);
  308. Node.DrawingCode := GetCellTrimStr(Excel.XlsFile, FCurRow, FDrawingCol);
  309. Node.MemoStr := GetCellTrimStr(Excel.XlsFile, FCurRow, FMemoCol);
  310. end;
  311. procedure Tdei_CustomBills.LoadNodes;
  312. var
  313. iPos, iSubPos: Integer;
  314. begin
  315. while (FCurRow <= Excel.XlsFile.MaxRow){ and FIsFirstPart }do
  316. begin
  317. LoadNode;
  318. Inc(FCurRow);
  319. iSubPos := FCurRow * 100 div Excel.XlsFile.MaxRow;
  320. iPos := iSubPos div 2;
  321. UpdateProgressPosition(iPos, iSubPos);
  322. end;
  323. end;
  324. procedure Tdei_CustomBills.WriteNode(ADataSet: TsdDataSet;
  325. ANode: TBillsCacheNode);
  326. var
  327. Rec: TBillsRecord;
  328. begin
  329. if ANode.Code <> '' then
  330. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Code)
  331. else if ANode.B_Code <> '' then
  332. UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
  333. else
  334. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
  335. Rec := TBillsRecord(ADataSet.Add);
  336. Rec.ID.AsInteger := ANode.ID;
  337. Rec.ParentID.AsInteger := ANode.ParentID;
  338. Rec.NextSiblingID.AsInteger := ANode.NextSiblingID;
  339. Rec.Code.AsString := ANode.Code;
  340. Rec.B_Code.AsString := ANode.B_Code;
  341. Rec.Name.AsString := ANode.Name;
  342. Rec.Units.AsString := ANode.Units;
  343. Rec.Price.AsFloat := PriceRoundTo(ANode.Price);
  344. Rec.OrgQuantity.AsFloat := QuantityRoundTo(ANode.OrgQuantity);
  345. Rec.MisQuantity.AsFloat := QuantityRoundTo(ANode.MisQuantity);
  346. Rec.OthQuantity.AsFloat := QuantityRoundTo(ANode.OthQuantity);
  347. Rec.DgnQuantity1.AsFloat := QuantityRoundTo(ANode.DgnQuantity1);
  348. Rec.DgnQuantity2.AsFloat := QuantityRoundTo(ANode.DgnQuantity2);
  349. Rec.DrawingCode.AsString := ANode.DrawingCode;
  350. Rec.MemoStr.AsString := ANode.MemoStr;
  351. end;
  352. procedure Tdei_CustomBills.WriteNodes(ADataSet: TsdDataSet);
  353. var
  354. i, iPos, iSubPos: Integer;
  355. begin
  356. UpdateProgressHint('写入读取的Excel数据', True);
  357. UpdateProgressPosition(50, 0);
  358. ADataSet.DeleteAll;
  359. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  360. begin
  361. WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
  362. iSubPos := i*100 div FCacheTree.CacheNodes.Count;
  363. iPos := 50 + iSubPos div 2;
  364. UpdateProgressPosition(iPos, iSubPos);
  365. end;
  366. UpdateProgressPosition(100, 100);
  367. end;
  368. end.