DetailExcelImport.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. unit DetailExcelImport;
  2. interface
  3. uses
  4. Classes, ProjectData, ScXlsOutput, MCacheTree, XLSAdapter, sdDB,
  5. Variants, Forms, Controls;
  6. type
  7. TDetailExcelImport = class
  8. private
  9. FProjectData: TProjectData;
  10. FTempFile: string;
  11. FExcel: TXlsOutPut;
  12. function GetCellValue(AXlsFile: TXLSFile; ARow, ACol: Integer): string;
  13. function GetCellValueFormat(AXlsFile: TXLSFile; ARow, ACol: Integer): string;
  14. procedure BeginImport; virtual; abstract;
  15. procedure EndImport; virtual; abstract;
  16. procedure Import; virtual; abstract;
  17. public
  18. constructor Create(AProjectData: TProjectData);
  19. destructor Destroy; override;
  20. procedure ImportFile(const AFileName: string);
  21. end;
  22. // 平面分项清单格式导入,导入至某项目节节点之下
  23. TPlaneFxBillsExcelImport = class(TDetailExcelImport)
  24. private
  25. FParentID: Integer;
  26. FCacheTree: TBillsCacheTree;
  27. FCurRow: Integer;
  28. FXmjLevel1Col: Integer;
  29. FXmjLevel2Col: Integer;
  30. FXmjLevel3Col: Integer;
  31. FXmjLevel4Col: Integer;
  32. FXmjLevel5Col: Integer;
  33. FXmjLevel6Col: Integer;
  34. FXmjLevel7Col: Integer;
  35. FB_CodeCol: Integer;
  36. FNameCol: Integer;
  37. FUnitCol: Integer;
  38. FQuantityCol: Integer;
  39. FPriceCol: Integer;
  40. FDrawingCol: Integer;
  41. FMemoCol: Integer;
  42. procedure LoadXmjLevel1(AXlsFile: TXLSFile);
  43. procedure LoadXmjLevel2(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
  44. procedure LoadXmjLevel3(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
  45. procedure LoadXmjLevel4(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
  46. procedure LoadXmjLevel5(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
  47. procedure LoadXmjLevel6(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
  48. procedure LoadXmjLevel7(AXlsFile: TXLSFile; AParent: TBillsCacheNode);
  49. procedure LoadBillsNode(AXlsFile: TXLSFile; AXmj: TBillsCacheNode);
  50. function LoadColumnsFromHead(AXlsFile: TXlsFile): Boolean;
  51. procedure LoadFxBills(AXlsFile: TXLSFile);
  52. procedure WriteNode(ADataSet: TsdDataSet; ANode: TBillsCacheNode);
  53. procedure WriteNodes(ADataSet: TsdDataSet);
  54. procedure BeginImport; override;
  55. procedure EndImport; override;
  56. procedure Import; override;
  57. public
  58. property ParentID: Integer read FParentID write FParentID;
  59. end;
  60. implementation
  61. uses
  62. UtilMethods, SysUtils, ZhAPI, SheetSelectFrm, UExcelAdapter, UFlxMessages,
  63. UFlxFormats, ProgressHintFrm;
  64. { TDetailExcelImport }
  65. constructor TDetailExcelImport.Create(AProjectData: TProjectData);
  66. begin
  67. FProjectData := AProjectData;
  68. FTempFile := GetTempFileName;
  69. end;
  70. destructor TDetailExcelImport.Destroy;
  71. begin
  72. if FileExists(FTempFile) then
  73. DeleteFile(FTempFile);
  74. inherited;
  75. end;
  76. function TDetailExcelImport.GetCellValue(AXlsFile: TXLSFile; ARow,
  77. ACol: Integer): string;
  78. var
  79. xlsCell: TXlsCellValue;
  80. begin
  81. Result := '';
  82. if not Assigned(AXlsFile) or (ARow = -1) or (ACol = -1) then Exit;
  83. xlsCell := AXlsFile.CellValueX[ARow, ACol];
  84. Result := xlsCell.Value;
  85. end;
  86. function TDetailExcelImport.GetCellValueFormat(AXlsFile: TXLSFile; ARow,
  87. ACol: Integer): string;
  88. function GetDigit(AFormat: WideString): Integer;
  89. var
  90. I: Integer;
  91. bDigit: Boolean;
  92. begin
  93. Result := 0;
  94. bDigit := False;
  95. for I := 1 to Length(AFormat) do
  96. begin
  97. if AFormat[I] = '.' then
  98. begin
  99. if bDigit then Break
  100. else bDigit := True;
  101. end
  102. else if AFormat[I] = ';' then Break
  103. else if bDigit and (AFormat[I] = '0') then
  104. Dec(Result);
  105. end;
  106. end;
  107. function FormatNum(AValue: Variant; AFormat: WideString): string;
  108. begin
  109. Result := AValue;
  110. if not VarIsNull(AValue) then
  111. begin
  112. if CheckNumeric(Result) then
  113. begin
  114. if Pos('%', AFormat) <> 0 then AValue := AValue * 100;
  115. if AFormat <> '' then
  116. Result := FloatToStr(AdvRoundTo(AValue, GetDigit(AFormat)))
  117. else
  118. Result := FloatToStr(AdvRoundTo(AValue, -2));
  119. if Pos('%', AFormat) <> 0 then Result := Result + '%';
  120. if AValue = '0' then Result := '';
  121. end;
  122. end;
  123. end;
  124. var
  125. xlsCell: TXlsCellValue;
  126. FlxFormat: TFlxFormat;
  127. begin
  128. Result := '';
  129. if not Assigned(AXlsFile) or (ARow = -1) or (ACol = -1) then Exit;
  130. xlsCell := AXlsFile.GetCellDataX(ARow, ACol);
  131. Result := xlsCell.Value;
  132. if xlsCell.XF <> -1 then
  133. begin
  134. FlxFormat := AXlsFile.FormatList[xlsCell.XF];
  135. Result := FormatNum(xlsCell.Value, FlxFormat.Format);
  136. end;
  137. end;
  138. procedure TDetailExcelImport.ImportFile(const AFileName: string);
  139. begin
  140. CopyFileOrFolder(AFileName, FTempFile);
  141. FExcel := TXlsOutPut.Create(FTempFile);
  142. BeginImport;
  143. try
  144. Import;
  145. finally
  146. EndImport;
  147. FExcel.Free;
  148. end;
  149. end;
  150. { TPlaneFxBillsExcelImport }
  151. procedure TPlaneFxBillsExcelImport.Import;
  152. begin
  153. FCurRow := 1;
  154. if LoadColumnsFromHead(FExcel.XlsFile) then
  155. begin
  156. LoadFxBills(FExcel.XlsFile);
  157. WriteNodes(FProjectData.BillsData.sddBills);
  158. end
  159. else
  160. ErrorMessage('导入的Excel格式有误!');
  161. end;
  162. procedure TPlaneFxBillsExcelImport.LoadBillsNode(AXlsFile: TXLSFile;
  163. AXmj: TBillsCacheNode);
  164. var
  165. sB_Code, sName, sUnits: string;
  166. vGclNode: TBillsCacheNode;
  167. fPrice: Double;
  168. begin
  169. sB_Code := Trim(GetCellValue(AXlsFile, FCurRow, FB_CodeCol));
  170. sName := Trim(GetCellValue(AXlsFile, FCurRow, FNameCol));
  171. sUnits := Trim(GetCellValue(AXlsFile, FCurRow, FUnitCol));
  172. fPrice := StrToFloatDef(GetCellValue(AXlsFile, FCurRow, FPriceCol), 0);
  173. if sB_Code <> '' then
  174. begin
  175. vGclNode := FCacheTree.FindGclChild(AXmj, sB_Code, sName, sUnits, fPrice);
  176. if not Assigned(vGclNode) then
  177. begin
  178. vGclNode := FCacheTree.AddNode(AXmj, nil);
  179. vGclNode.B_Code := sB_Code;
  180. vGclNode.Name := sName;
  181. vGclNode.Units := sUnits;
  182. vGclNode.Quantity := StrToFloatDef(GetCellValue(AXlsFile, FCurRow, FQuantityCol), 0);
  183. vGclNode.Price := fPrice;
  184. vGclNode.DrawingCode := GetCellValue(AXlsFile, FCurRow, FDrawingCol);
  185. vGclNode.MemoStr := GetCellValue(AXlsFile, FCurRow, FMemoCol);
  186. end
  187. else
  188. vGclNode.Quantity := vGclNode.Quantity + StrToFloatDef(GetCellValue(AXlsFile, FCurRow, FQuantityCol), 0);
  189. end;
  190. Inc(FCurRow);
  191. end;
  192. function TPlaneFxBillsExcelImport.LoadColumnsFromHead(AXlsFile: TXlsFile): Boolean;
  193. var
  194. iCol: Integer;
  195. sColName: string;
  196. begin
  197. Result := False;
  198. FXmjLevel1Col := -1;
  199. FXmjLevel2Col := -1;
  200. FXmjLevel3Col := -1;
  201. FXmjLevel4Col := -1;
  202. FXmjLevel5Col := -1;
  203. FXmjLevel6Col := -1;
  204. FXmjLevel7Col := -1;
  205. FB_CodeCol := -1;
  206. FNameCol := -1;
  207. FUnitCol := -1;
  208. FQuantityCol := -1;
  209. FPriceCol := -1;
  210. FDrawingCol := -1;
  211. FMemoCol := -1;
  212. UpdateProgressHint('正在识别Excel数据格式');
  213. UpdateProgressPosition(0);
  214. while not Result and (FCurRow <= AXlsFile.MaxRow) do
  215. begin
  216. for iCol := 1 to AXlsFile.MaxCol do
  217. begin
  218. sColName := GetCellValue(AXlsFile, FCurRow, iCol);
  219. if sColName = '第1层' then
  220. FXmjLevel1Col := iCol
  221. else if sColName = '第2层' then
  222. FXmjLevel2Col := iCol
  223. else if sColName = '第3层' then
  224. FXmjLevel3Col := iCol
  225. else if sColName = '第4层' then
  226. FXmjLevel4Col := iCol
  227. else if sColName = '第5层' then
  228. FXmjLevel5Col := iCol
  229. else if sColName = '第6层' then
  230. FXmjLevel6Col := iCol
  231. else if sColName = '第7层' then
  232. FXmjLevel7Col := iCol
  233. else if sColName = '清单号' then
  234. FB_CodeCol := iCol
  235. else if sColName = '清单名称' then
  236. FNameCol := iCol
  237. else if sColName = '单位' then
  238. FUnitCol := iCol
  239. else if sColName = '数量' then
  240. FQuantityCol := iCol
  241. else if sColName = '单价' then
  242. FPriceCol := iCol
  243. else if sColName = '图号' then
  244. FDrawingCol := iCol
  245. else if sColName = '备注' then
  246. FMemoCol := iCol
  247. end;
  248. Result := FXmjLevel1Col <> -1;
  249. Inc(FCurRow);
  250. end;
  251. end;
  252. procedure TPlaneFxBillsExcelImport.LoadFxBills(AXlsFile: TXLSFile);
  253. var
  254. iPos: Integer;
  255. begin
  256. UpdateProgressHint('正在解析平面台账数据');
  257. while FCurRow <= AXlsFile.MaxRow do
  258. begin
  259. iPos := FCurRow*100 div AXlsFile.MaxRow;
  260. UpdateProgressPosition(iPos);
  261. LoadXmjLevel1(AXlsFile);
  262. end;
  263. end;
  264. procedure TPlaneFxBillsExcelImport.LoadXmjLevel1(AXlsFile: TXLSFile);
  265. var
  266. sName: string;
  267. vXmj: TBillsCacheNode;
  268. iEndRow: Integer;
  269. begin
  270. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel1Col));
  271. if sName = '' then Exit;
  272. vXmj := FCacheTree.FindXmjChild(nil, '', sName);
  273. if not Assigned(vXmj) then
  274. begin
  275. vXmj := FCacheTree.AddNode(nil);
  276. vXmj.Name := sName;
  277. end;
  278. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel1Col] do
  279. iEndRow := FCurRow + Bottom - Top;
  280. if FXmjLevel2Col <> -1 then
  281. begin
  282. while FCurRow <= iEndRow do
  283. LoadXmjLevel2(AXlsFile, vXmj);
  284. end
  285. else
  286. begin
  287. while FCurRow <= iEndRow do
  288. LoadBillsNode(AXlsFile, vXmj);
  289. end;
  290. end;
  291. procedure TPlaneFxBillsExcelImport.LoadXmjLevel2(AXlsFile: TXLSFile;
  292. AParent: TBillsCacheNode);
  293. var
  294. sName: string;
  295. vXmj: TBillsCacheNode;
  296. iEndRow: Integer;
  297. begin
  298. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel2Col));
  299. if sName = '' then Exit;
  300. vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
  301. if not Assigned(vXmj) then
  302. begin
  303. vXmj := FCacheTree.AddNode(AParent);
  304. vXmj.Name := sName;
  305. end;
  306. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel2Col] do
  307. iEndRow := FCurRow + Bottom - Top;
  308. if FXmjLevel3Col <> -1 then
  309. begin
  310. while FCurRow <= iEndRow do
  311. LoadXmjLevel3(AXlsFile, vXmj);
  312. end
  313. else
  314. begin
  315. while FCurRow <= iEndRow do
  316. LoadBillsNode(AXlsFile, vXmj);
  317. end;
  318. end;
  319. procedure TPlaneFxBillsExcelImport.LoadXmjLevel3(AXlsFile: TXLSFile;
  320. AParent: TBillsCacheNode);
  321. var
  322. sName: string;
  323. vXmj: TBillsCacheNode;
  324. iEndRow: Integer;
  325. begin
  326. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel3Col));
  327. if sName = '' then Exit;
  328. vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
  329. if not Assigned(vXmj) then
  330. begin
  331. vXmj := FCacheTree.AddNode(AParent);
  332. vXmj.Name := sName;
  333. end;
  334. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel3Col] do
  335. iEndRow := FCurRow + Bottom - Top;
  336. if FXmjLevel4Col <> -1 then
  337. begin
  338. while FCurRow <= iEndRow do
  339. LoadXmjLevel4(AXlsFile, vXmj);
  340. end
  341. else
  342. begin
  343. while FCurRow <= iEndRow do
  344. LoadBillsNode(AXlsFile, vXmj);
  345. end;
  346. end;
  347. procedure TPlaneFxBillsExcelImport.LoadXmjLevel4(AXlsFile: TXLSFile;
  348. AParent: TBillsCacheNode);
  349. var
  350. sName: string;
  351. vXmj: TBillsCacheNode;
  352. iEndRow: Integer;
  353. begin
  354. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel4Col));
  355. if sName = '' then Exit;
  356. vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
  357. if not Assigned(vXmj) then
  358. begin
  359. vXmj := FCacheTree.AddNode(AParent);
  360. vXmj.Name := sName;
  361. end;
  362. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel4Col] do
  363. iEndRow := FCurRow + Bottom - Top;
  364. if FXmjLevel5Col <> -1 then
  365. begin
  366. while FCurRow <= iEndRow do
  367. LoadXmjLevel5(AXlsFile, vXmj);
  368. end
  369. else
  370. begin
  371. while FCurRow <= iEndRow do
  372. LoadBillsNode(AXlsFile, vXmj);
  373. end;
  374. end;
  375. procedure TPlaneFxBillsExcelImport.LoadXmjLevel5(AXlsFile: TXLSFile;
  376. AParent: TBillsCacheNode);
  377. var
  378. sName: string;
  379. vXmj: TBillsCacheNode;
  380. iEndRow: Integer;
  381. begin
  382. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel5Col));
  383. if sName = '' then Exit;
  384. vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
  385. if not Assigned(vXmj) then
  386. begin
  387. vXmj := FCacheTree.AddNode(AParent);
  388. vXmj.Name := sName;
  389. end;
  390. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel5Col] do
  391. iEndRow := FCurRow + Bottom - Top;
  392. if FXmjLevel6Col <> -1 then
  393. begin
  394. while FCurRow <= iEndRow do
  395. LoadXmjLevel6(AXlsFile, vXmj);
  396. end
  397. else
  398. begin
  399. while FCurRow <= iEndRow do
  400. LoadBillsNode(AXlsFile, vXmj);
  401. end;
  402. end;
  403. procedure TPlaneFxBillsExcelImport.LoadXmjLevel6(AXlsFile: TXLSFile;
  404. AParent: TBillsCacheNode);
  405. var
  406. sName: string;
  407. vXmj: TBillsCacheNode;
  408. iEndRow: Integer;
  409. begin
  410. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel6Col));
  411. if sName = '' then Exit;
  412. vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
  413. if not Assigned(vXmj) then
  414. begin
  415. vXmj := FCacheTree.AddNode(AParent);
  416. vXmj.Name := sName;
  417. end;
  418. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel6Col] do
  419. iEndRow := FCurRow + Bottom - Top;
  420. if FXmjLevel7Col <> -1 then
  421. begin
  422. while FCurRow <= iEndRow do
  423. LoadXmjLevel7(AXlsFile, vXmj);
  424. end
  425. else
  426. begin
  427. while FCurRow <= iEndRow do
  428. LoadBillsNode(AXlsFile, vXmj);
  429. end;
  430. end;
  431. procedure TPlaneFxBillsExcelImport.LoadXmjLevel7(AXlsFile: TXLSFile;
  432. AParent: TBillsCacheNode);
  433. var
  434. sName: string;
  435. vXmj: TBillsCacheNode;
  436. iEndRow: Integer;
  437. begin
  438. sName := Trim(GetCellValue(AXlsFile, FCurRow, FXmjLevel7Col));
  439. if sName = '' then Exit;
  440. vXmj := FCacheTree.FindXmjChild(AParent, '', sName);
  441. if not Assigned(vXmj) then
  442. begin
  443. vXmj := FCacheTree.AddNode(AParent);
  444. vXmj.Name := sName;
  445. end;
  446. with AXlsFile.CellMergedBounds[FCurRow, FXmjLevel7Col] do
  447. iEndRow := FCurRow + Bottom - Top;
  448. while FCurRow <= iEndRow do
  449. LoadBillsNode(AXlsFile, vXmj);
  450. end;
  451. procedure TPlaneFxBillsExcelImport.WriteNodes(ADataSet: TsdDataSet);
  452. var
  453. i, iPos: Integer;
  454. begin
  455. UpdateProgressHint('写入读取的Excel数据');
  456. UpdateProgressPosition(0);
  457. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  458. begin
  459. WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
  460. iPos := i*100 div FCacheTree.CacheNodes.Count;
  461. UpdateProgressPosition(iPos);
  462. end;
  463. UpdateProgressPosition(100);
  464. end;
  465. procedure TPlaneFxBillsExcelImport.WriteNode(ADataSet: TsdDataSet;
  466. ANode: TBillsCacheNode);
  467. var
  468. Rec: TsdDataRecord;
  469. begin
  470. if ANode.B_Code <> '' then
  471. UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
  472. else
  473. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
  474. Rec := ADataSet.Add;
  475. Rec.ValueByName('ID').AsInteger := ANode.ID;
  476. if ANode.ParentID = -1 then
  477. Rec.ValueByName('ParentID').AsInteger := ParentID
  478. else
  479. Rec.ValueByName('ParentID').AsInteger := ANode.ParentID;
  480. Rec.ValueByName('NextSiblingID').AsInteger := ANode.NextSiblingID;
  481. Rec.ValueByName('B_Code').AsString := ANode.B_Code;
  482. Rec.ValueByName('Name').AsString := ANode.Name;
  483. Rec.ValueByName('Units').AsString := ANode.Units;
  484. Rec.ValueByName('Price').AsFloat := PriceRoundTo(ANode.Price);
  485. Rec.ValueByName('OrgQuantity').AsFloat := QuantityRoundTo(ANode.Quantity);
  486. Rec.ValueByName('DrawingCode').AsString := ANode.DrawingCode;
  487. Rec.ValueByName('MemoStr').AsString := ANode.MemoStr;
  488. end;
  489. procedure TPlaneFxBillsExcelImport.BeginImport;
  490. begin
  491. Screen.Cursor := crHourGlass;
  492. ShowProgressHint('导入Excel数据', 100);
  493. FCacheTree := TBillsCacheTree.Create;
  494. FCacheTree.NewNodeID := FProjectData.BillsData.GetMaxBillsID + 1;
  495. FProjectData.DisConnectTree;
  496. FProjectData.BillsData.DisableEvents;
  497. end;
  498. procedure TPlaneFxBillsExcelImport.EndImport;
  499. begin
  500. FCacheTree.Free;
  501. FProjectData.BillsData.EnableEvents;
  502. FProjectData.ReConnectTree;
  503. FProjectData.BillsCompileData.CalculateAll;
  504. CloseProgressHint;
  505. Screen.Cursor := crDefault;
  506. end;
  507. end.