ExcelImport_Bills.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. unit ExcelImport_Bills;
  2. // 导入0号台账/分项清单
  3. interface
  4. uses
  5. DetailExcelImport, Classes, MCacheTree, sdDB, ProjectData, OExport;
  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(ASheet: TExportWorkSheet);
  36. procedure LoadBaseTree(ATree: TBillsCacheTree);
  37. procedure LoadNode(ARow: TExportRow);
  38. procedure LoadNodes(ASheet: TExportWorkSheet);
  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 := 0;
  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(OExport.OpenWorkSheet);
  177. LoadNodes(OExport.OpenWorkSheet);
  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(ASheet: TExportWorkSheet);
  199. var
  200. vRow: TExportRow;
  201. iCol: Integer;
  202. sColName: string;
  203. begin
  204. FCodeCol := -1;
  205. FB_CodeCol := -1;
  206. FNameCol := -1;
  207. FUnitsCol := -1;
  208. FPriceCol := -1;
  209. FOrgQuantityCol := -1;
  210. FMisQuantityCol := -1;
  211. FOthQuantityCol := -1;
  212. FDgnQuantity1Col := -1;
  213. FDgnQuantity2Col := -1;
  214. FDrawingCol := -1;
  215. FMemoCol := -1;
  216. FLevelCol := -1;
  217. vRow := ASheet.Rows[FCurRow];
  218. for iCol := 0 to vRow.Cells.Count - 1 do
  219. begin
  220. sColName := GetCellTrimStr(vRow, 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(ARow: TExportRow);
  251. var
  252. sLevelCode, sCode, sB_Code, sName: string;
  253. Node: TBillsCacheNode;
  254. vValue: Variant;
  255. iFixedID: Integer;
  256. begin
  257. sLevelCode := GetCellTrimStr(ARow, FLevelCol);
  258. sCode := GetCellTrimStr(ARow, FCodeCol);
  259. sB_Code := GetCellTrimStr(ARow, FB_CodeCol);
  260. sName := GetCellTrimStr(ARow, FNameCol);
  261. // 含层次编号时,层次编号为空不导入
  262. // 不含层次编号时,仅导入第一部分,且项目节编号、清单编号均未空时不导入
  263. if FWithLevelCode then
  264. begin
  265. if sLevelCode = '' then Exit;
  266. end;
  267. (*
  268. else
  269. begin
  270. if ((sCode = '') and (sB_Code = '')) or SameText(sCode, '2') or
  271. (Pos('第二部分', sName) > 0) then
  272. begin
  273. FIsFirstPart := False;
  274. Exit;
  275. end;
  276. end;
  277. *)
  278. if (sCode = '') and FWithoutGclBills then Exit;
  279. // 含层次编号时,以层次编号为依据新增节点;反之以项目节编号为依据新增节点
  280. if not FWithLevelCode then
  281. begin
  282. if (sB_Code = '') then
  283. Node := FCacheTree.AddNodeByCodeName(sCode, sName)
  284. else
  285. Node := FCacheTree.AddLeafBillsNode(sB_Code);
  286. end
  287. else
  288. begin
  289. // 1. 从模板树中查询当前节点是否为固定ID,否则为-1
  290. iFixedID := GetFixedID(sCode, sName);
  291. // 2. 从导入树中查询是否添加过该固定ID,防止存在两个固定ID节点主键冲突
  292. // 如果已添加过固定ID节点,则其他节点未非固定ID节点
  293. Node := GetFixedIDNode(iFixedID);
  294. if Assigned(Node) then
  295. iFixedID := -1;
  296. // 3. 添加当前节点
  297. Node := FCacheTree.AddNodeByCode(sLevelCode, iFixedID);
  298. // 4. 如果当前添加的节点为固定ID节点,则添加到List中便于2快速查找
  299. if Node.ID < 100 then
  300. FFixedIDNodes.Add(Node);
  301. end;
  302. Node.Code := sCode;
  303. Node.B_Code := sB_Code;
  304. Node.Name := sName;
  305. Node.Units := GetCellTrimStr(ARow, FUnitsCol);
  306. Node.Price := GetCellFloat(ARow, FPriceCol);
  307. Node.OrgQuantity := GetCellFloat(ARow, FOrgQuantityCol);
  308. Node.MisQuantity := GetCellFloat(ARow, FMisQuantityCol);
  309. Node.OthQuantity := GetCellFloat(ARow, FOthQuantityCol);
  310. Node.DgnQuantity1 := GetCellFloat(ARow, FDgnQuantity1Col);
  311. Node.DgnQuantity2 := GetCellFloat(ARow, FDgnQuantity2Col);
  312. Node.DrawingCode := GetCellTrimStr(ARow, FDrawingCol);
  313. Node.MemoStr := GetCellTrimStr(ARow, FMemoCol);
  314. end;
  315. procedure Tdei_CustomBills.LoadNodes(ASheet: TExportWorkSheet);
  316. var
  317. iPos, iSubPos: Integer;
  318. begin
  319. while (FCurRow < ASheet.Rows.Count){ and FIsFirstPart }do
  320. begin
  321. LoadNode(ASheet.Rows[FCurRow]);
  322. Inc(FCurRow);
  323. iSubPos := (FCurRow + 1) * 100 div ASheet.Rows.Count;
  324. iPos := iSubPos div 2;
  325. UpdateProgressPosition(iPos, iSubPos);
  326. end;
  327. end;
  328. procedure Tdei_CustomBills.WriteNode(ADataSet: TsdDataSet;
  329. ANode: TBillsCacheNode);
  330. var
  331. Rec: TBillsRecord;
  332. begin
  333. if ANode.Code <> '' then
  334. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Code)
  335. else if ANode.B_Code <> '' then
  336. UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
  337. else
  338. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
  339. Rec := TBillsRecord(ADataSet.Add);
  340. Rec.ID.AsInteger := ANode.ID;
  341. Rec.ParentID.AsInteger := ANode.ParentID;
  342. Rec.NextSiblingID.AsInteger := ANode.NextSiblingID;
  343. Rec.Code.AsString := ANode.Code;
  344. Rec.B_Code.AsString := ANode.B_Code;
  345. Rec.Name.AsString := ANode.Name;
  346. Rec.Units.AsString := ANode.Units;
  347. Rec.Price.AsFloat := PriceRoundTo(ANode.Price);
  348. Rec.OrgQuantity.AsFloat := QuantityRoundTo(ANode.OrgQuantity);
  349. Rec.MisQuantity.AsFloat := QuantityRoundTo(ANode.MisQuantity);
  350. Rec.OthQuantity.AsFloat := QuantityRoundTo(ANode.OthQuantity);
  351. Rec.DgnQuantity1.AsFloat := QuantityRoundTo(ANode.DgnQuantity1);
  352. Rec.DgnQuantity2.AsFloat := QuantityRoundTo(ANode.DgnQuantity2);
  353. Rec.DrawingCode.AsString := ANode.DrawingCode;
  354. Rec.MemoStr.AsString := ANode.MemoStr;
  355. end;
  356. procedure Tdei_CustomBills.WriteNodes(ADataSet: TsdDataSet);
  357. var
  358. i, iPos, iSubPos: Integer;
  359. begin
  360. UpdateProgressHint('写入读取的Excel数据', True);
  361. UpdateProgressPosition(50, 0);
  362. ADataSet.DeleteAll;
  363. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  364. begin
  365. WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
  366. iSubPos := i*100 div FCacheTree.CacheNodes.Count;
  367. iPos := 50 + iSubPos div 2;
  368. UpdateProgressPosition(iPos, iSubPos);
  369. end;
  370. UpdateProgressPosition(100, 100);
  371. end;
  372. end.