ExcelImport.pas 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. unit ExcelImport;
  2. interface
  3. uses
  4. Classes, SMXLS, SMCells, ProjectData, MCacheTree, ZhAPI, sdDB,
  5. Forms, Controls, ProgressHintFrm, mDataRecord;
  6. type
  7. TExcelImport = class
  8. private
  9. FMSExcel: TMSExcel;
  10. FProjectData: TProjectData;
  11. FProgresssHintFrom: TProgressHintForm;
  12. procedure BeginImport; virtual; abstract;
  13. procedure EndImport; virtual; abstract;
  14. procedure Import; virtual; abstract;
  15. function GetCellValue(ASheet: TSpreadSheet; ACol, ARow: Integer): Variant;
  16. function GetCellTrimText(ASheet: TSpreadSheet; ACol, ARow: Integer): string;
  17. public
  18. constructor Create(AProjectData: TProjectData);
  19. destructor Destroy; override;
  20. procedure ImportFile(const AExcelFile: string);
  21. property MSExcel: TMSExcel read FMSExcel;
  22. end;
  23. TBillsExcelImport = class(TExcelImport)
  24. private
  25. FCacheTree: TBillsCacheTree;
  26. FCurRow: Integer;
  27. FLevelCol: Integer;
  28. FCodeCol: Integer;
  29. FB_CodeCol: Integer;
  30. FNameCol: Integer;
  31. FUnitsCol: Integer;
  32. FFixedIDCol: Integer;
  33. FCanDeleteCol: Integer;
  34. procedure BeginImport; override;
  35. procedure EndImport; override;
  36. procedure LoadColumnsFromHead(ASheet: TSpreadSheet);
  37. procedure LoadNodes(ASheet: TSpreadSheet);
  38. procedure LoadNode(ASheet: TSpreadSheet);
  39. procedure WriteNode(ADataSet: TsdDataSet; ANode: TBillsCacheNode);
  40. procedure WriteNodes(ADataSet: TsdDataSet);
  41. procedure Import; override;
  42. public
  43. procedure ImportToTree(ACacheTree: TBillsCacheTree; const sFileName: string);
  44. end;
  45. // 代码中注释部分为导入[无层次编号]的0号台账Excel
  46. TBillsEdtExcelImport = class(TExcelImport)
  47. private
  48. FCacheTree: TBillsCacheTree;
  49. FCurRow: Integer;
  50. FIsFirstPart: Boolean;
  51. FWithLevelCode: Boolean;
  52. FWithoutGclBills: Boolean;
  53. FBaseTree: TBillsCacheTree;
  54. FFixedIDNodes: TList;
  55. FCodeCol: Integer;
  56. FB_CodeCol: Integer;
  57. FNameCol: Integer;
  58. FUnitsCol: Integer;
  59. FPriceCol: Integer;
  60. FQuantityCol: Integer;
  61. FDgnQuantity1Col: Integer;
  62. FDgnQuantity2Col: Integer;
  63. FDrawingCol: Integer;
  64. FMemoCol: Integer;
  65. FLevelCol: Integer;
  66. procedure CheckFixedIDNodes;
  67. procedure BeginImport; override;
  68. procedure EndImport; override;
  69. function GetFixedIDNode(AID: Integer): TBillsCacheNode;
  70. function GetFixedID(ACode, AName: string): Integer;
  71. procedure LoadBaseTree(ATree: TBillsCacheTree);
  72. procedure LoadColumnsFromHead(ASheet: TSpreadSheet);
  73. procedure LoadNodes(ASheet: TSpreadSheet);
  74. procedure LoadNode(ASheet: TSpreadSheet);
  75. procedure WriteNode(ADataSet: TsdDataSet; ANode: TBillsCacheNode);
  76. procedure WriteNodes(ADataSet: TsdDataSet);
  77. procedure Import; override;
  78. public
  79. property WithLevelCode: Boolean read FWithLevelCode write FWithLevelCode;
  80. property WithoutGclBills: Boolean read FWithoutGclBills write FWithoutGclBills;
  81. end;
  82. TGclBillsExcelImport = class(TExcelImport)
  83. private
  84. FParentID: Integer;
  85. FSelectSheets: TList;
  86. FCacheTree: TGclCacheTree;
  87. FCurRow: Integer;
  88. FB_CodeCol: Integer;
  89. FNameCol: Integer;
  90. FUnitsCol: Integer;
  91. FPriceCol: Integer;
  92. FQuantityCol: Integer;
  93. procedure BeginImport; override;
  94. procedure EndImport; override;
  95. procedure LoadNode(ASheet: TSpreadSheet);
  96. procedure ImportSheet(ASheet: TSpreadSheet);
  97. procedure WriteNode(ADataSet: TsdDataSet; ANode: TGclCacheNode);
  98. procedure WriteNodes(ADataSet: TsdDataSet);
  99. procedure Import; override;
  100. public
  101. property ParentID: Integer read FParentID write FParentID;
  102. end;
  103. // 清单单价
  104. TBillsPriceExcelImport = class(TExcelImport)
  105. private
  106. FCurRow: Integer;
  107. FB_CodeCol: Integer;
  108. FNameCol: Integer;
  109. FPriceCol: Integer;
  110. procedure BeginImport; override;
  111. procedure EndImport; override;
  112. procedure LoadColumnsFromHead(ASheet: TSpreadSheet);
  113. procedure UpdateBillsPrice(const AB_Code: string; APrice: Double);
  114. procedure ImportBillsPriceData(ASheet: TSpreadSheet);
  115. procedure Import; override;
  116. end;
  117. // 合同清单
  118. TDealBillsExcelImport = class(TExcelImport)
  119. private
  120. FCurRow: Integer;
  121. FBillsID: Integer;
  122. FB_CodeCol: Integer;
  123. FNameCol: Integer;
  124. FUnitsCol: Integer;
  125. FPriceCol: Integer;
  126. FQuantityCol: Integer;
  127. FTotalPriceCol: Integer;
  128. procedure BeginImport; override;
  129. procedure EndImport; override;
  130. procedure LoadColumnsFromHead(ASheet: TSpreadSheet);
  131. procedure LoadDealBillsData(ASheet: TSpreadSheet);
  132. procedure Import; override;
  133. end;
  134. implementation
  135. uses Variants, CacheTree, SysUtils, UtilMethods, sdDataSet, BillsDm,
  136. DealBillsDm, SheetSelectFrm, ADODB, Math, ConstUnit;
  137. { TExcelImport }
  138. constructor TExcelImport.Create(AProjectData: TProjectData);
  139. begin
  140. FProjectData := AProjectData;
  141. FMSExcel := TMSExcel.Create(nil);
  142. end;
  143. destructor TExcelImport.Destroy;
  144. begin
  145. FMSExcel.Free;
  146. inherited;
  147. end;
  148. function TExcelImport.GetCellTrimText(ASheet: TSpreadSheet; ACol,
  149. ARow: Integer): string;
  150. begin
  151. Result := Trim(VarToStrDef(GetCellValue(ASheet, ACol, ARow), ''));
  152. end;
  153. function TExcelImport.GetCellValue(ASheet: TSpreadSheet;
  154. ACol, ARow: Integer): Variant;
  155. begin
  156. Result := Null;
  157. if ACol <> -1 then
  158. Result := ASheet.Cells.GetValue(ACol, ARow);
  159. end;
  160. procedure TExcelImport.ImportFile(const AExcelFile: string);
  161. begin
  162. BeginImport;
  163. try
  164. FMSExcel.LoadFromFile(AExcelFile);
  165. Import;
  166. finally
  167. EndImport;
  168. end;
  169. end;
  170. { TBillsExcelImport }
  171. procedure TBillsExcelImport.BeginImport;
  172. begin
  173. FCurRow := 0;
  174. FCacheTree := TBillsCacheTree.Create;
  175. FCacheTree.NewNodeID := 101;
  176. FCacheTree.SeparateChar := '.';
  177. FCacheTree.AutoSort := True;
  178. end;
  179. procedure TBillsExcelImport.EndImport;
  180. begin
  181. FCacheTree.Free;
  182. end;
  183. procedure TBillsExcelImport.Import;
  184. begin
  185. LoadColumnsFromHead(FMSExcel.Sheets.Spreadsheet(0));
  186. LoadNodes(FMSExcel.Sheets.Spreadsheet(0));
  187. WriteNodes(FProjectData.BillsData.sddBills);
  188. end;
  189. procedure TBillsExcelImport.ImportToTree(ACacheTree: TBillsCacheTree;
  190. const sFileName: string);
  191. var
  192. sChar: Char;
  193. begin
  194. FCurRow := 0;
  195. FCacheTree := ACacheTree;
  196. sChar := FCacheTree.SeparateChar;
  197. FCacheTree.SeparateChar := '.';
  198. MSExcel.LoadFromFile(sFileName);
  199. LoadColumnsFromHead(FMSExcel.Sheets.Spreadsheet(0));
  200. LoadNodes(FMSExcel.Sheets.Spreadsheet(0));
  201. FCacheTree.SeparateChar := sChar;
  202. end;
  203. procedure TBillsExcelImport.LoadColumnsFromHead(ASheet: TSpreadSheet);
  204. var
  205. iCol: Integer;
  206. sColName: string;
  207. begin
  208. for iCol := 0 to ASheet.Cells.UsedRowCount do
  209. begin
  210. sColName := VarToStrDef(ASheet.Cells.GetValue(iCol, FCurRow), '');
  211. if sColName = '层次编号' then
  212. FLevelCol := iCol
  213. else if sColName = '项目节编号' then
  214. FCodeCol := iCol
  215. else if sColName = '清单子目号' then
  216. FB_CodeCol := iCol
  217. else if sColName = '名称' then
  218. FNameCol := iCol
  219. else if sColName = '单位' then
  220. begin
  221. FUnitsCol := iCol;
  222. FFixedIDCol := iCol + 1;
  223. FCanDeleteCol := iCol + 2;
  224. end;
  225. end;
  226. Inc(FCurRow);
  227. end;
  228. procedure TBillsExcelImport.LoadNode(ASheet: TSpreadSheet);
  229. var
  230. sLevelCode: string;
  231. iFixedID: Integer;
  232. Node: TBillsCacheNode;
  233. vValue: Variant;
  234. begin
  235. sLevelCode := GetCellTrimText(ASheet, FLevelCol, FCurRow);
  236. if sLevelCode = '' then Exit;
  237. iFixedID := StrToIntDef(GetCellTrimText(ASheet, FFixedIDCol, FCurRow), -1);
  238. Node := FCacheTree.AddNodeByCode(sLevelCode, iFixedID);
  239. Node.Code := GetCellTrimText(ASheet, FCodeCol, FCurRow);
  240. Node.B_Code := GetCellTrimText(ASheet, FB_CodeCol, FCurRow);
  241. Node.Name := GetCellTrimText(ASheet, FNameCol, FCurRow);
  242. Node.Units := GetCellTrimText(ASheet, FUnitsCol, FCurRow);
  243. Node.CanDelete := VarToIntDef(GetCellValue(ASheet, FCanDeleteCol, FCurRow), 0) = 0;
  244. end;
  245. procedure TBillsExcelImport.LoadNodes(ASheet: TSpreadSheet);
  246. begin
  247. while FCurRow < ASheet.Cells.UsedRowCount do
  248. begin
  249. LoadNode(ASheet);
  250. Inc(FCurRow);
  251. end;
  252. end;
  253. procedure TBillsExcelImport.WriteNode(ADataSet: TsdDataSet;
  254. ANode: TBillsCacheNode);
  255. var
  256. Rec: TBillsRecord;
  257. begin
  258. Rec := TBillsRecord(ADataSet.Add);
  259. Rec.ID.AsInteger := ANode.ID;
  260. Rec.ParentID.AsInteger := ANode.ParentID;
  261. Rec.NextSiblingID.AsInteger := ANode.NextSiblingID;
  262. Rec.Code.AsString := ANode.Code;
  263. Rec.B_Code.AsString := ANode.B_Code;
  264. Rec.Name.AsString := ANode.Name;
  265. Rec.Units.AsString := ANode.Units;
  266. //Rec.ValueByName('LockedLevel').AsBoolean := ANode.CanDelete;
  267. end;
  268. procedure TBillsExcelImport.WriteNodes(ADataSet: TsdDataSet);
  269. var
  270. i: Integer;
  271. begin
  272. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  273. WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
  274. end;
  275. { TBillsEdtExcelImport }
  276. procedure TBillsEdtExcelImport.BeginImport;
  277. begin
  278. Screen.Cursor := crHourGlass;
  279. ShowProgressHint('导入Excel数据', 100, '读取Excel数据', 100);
  280. FCurRow := 0;
  281. FIsFirstPart := True;
  282. FCacheTree := TBillsCacheTree.Create;
  283. FCacheTree.NewNodeID := 101;
  284. // 以层次编号为依据,分隔用'.',以项目节、清单编号为依据,分隔用'-'
  285. if WithLevelCode then
  286. FCacheTree.SeparateChar := '.'
  287. else
  288. FCacheTree.SeparateChar := '-';
  289. FCacheTree.AutoSort := True;
  290. FProjectData.DisConnectTree;
  291. FProjectData.BillsData.DisableEvents;
  292. FBaseTree := TBillsCacheTree.Create;
  293. FBaseTree.NewNodeID := 101;
  294. FBaseTree.SeparateChar := '.';
  295. FFixedIDNodes := TList.Create;
  296. end;
  297. procedure TBillsEdtExcelImport.EndImport;
  298. begin
  299. // For Test
  300. // FCacheTree.SaveTreeToFile('E:\Tree.txt');
  301. if FWithLevelCode then
  302. CheckFixedIDNodes;
  303. FFixedIDNodes.Free;
  304. FBaseTree.Free;
  305. FProjectData.BillsData.EnableEvents;
  306. FProjectData.ReConnectTree;
  307. FCacheTree.Free;
  308. FProjectData.BillsCompileData.CalculateAll;
  309. CloseProgressHint;
  310. Screen.Cursor := crDefault;
  311. end;
  312. function TBillsEdtExcelImport.GetFixedIDNode(AID: Integer): TBillsCacheNode;
  313. var
  314. i: Integer;
  315. Node: TBillsCacheNode;
  316. begin
  317. Result := nil;
  318. for i := 0 to FFixedIDNodes.Count - 1 do
  319. begin
  320. Node := TBillsCacheNode(FFixedIDNodes.Items[i]);
  321. if (AID = Node.ID) then
  322. begin
  323. Result := Node;
  324. Break;
  325. end;
  326. end;
  327. end;
  328. function TBillsEdtExcelImport.GetFixedID(ACode, AName: string): Integer;
  329. var
  330. i: Integer;
  331. Node: TBillsCacheNode;
  332. begin
  333. Result := -1;
  334. for i := 0 to FBaseTree.CacheNodes.Count - 1 do
  335. begin
  336. Node := TBillsCacheNode(FBaseTree.CacheNodes.Items[i]);
  337. if (Node.Code = ACode) and (Node.Name = AName) then
  338. begin
  339. if Node.ID < 100 then
  340. Result := Node.ID;
  341. Break;
  342. end;
  343. end;
  344. end;
  345. procedure TBillsEdtExcelImport.Import;
  346. begin
  347. if WithLevelCode then
  348. LoadBaseTree(FBaseTree)
  349. else
  350. LoadBaseTree(FCacheTree);
  351. LoadColumnsFromHead(FMSExcel.Sheets.Spreadsheet(0));
  352. LoadNodes(FMSExcel.Sheets.Spreadsheet(0));
  353. WriteNodes(FProjectData.BillsData.sddBills);
  354. end;
  355. procedure TBillsEdtExcelImport.LoadBaseTree(ATree: TBillsCacheTree);
  356. var
  357. BaseImportor: TBillsExcelImport;
  358. begin
  359. BaseImportor := TBillsExcelImport.Create(nil);
  360. try
  361. BaseImportor.ImportToTree(ATree, GetTemplateBillsFileName);
  362. finally
  363. BaseImportor.Free;
  364. end;
  365. end;
  366. procedure TBillsEdtExcelImport.LoadColumnsFromHead(ASheet: TSpreadSheet);
  367. var
  368. iCol: Integer;
  369. sColName: string;
  370. begin
  371. FCodeCol := -1;
  372. FB_CodeCol := -1;
  373. FNameCol := -1;
  374. FUnitsCol := -1;
  375. FPriceCol := -1;
  376. FQuantityCol := -1;
  377. FDgnQuantity1Col := -1;
  378. FDgnQuantity2Col := -1;
  379. FDrawingCol := -1;
  380. FMemoCol := -1;
  381. for iCol := 0 to ASheet.Cells.UsedRowCount do
  382. begin
  383. sColName := VarToStrDef(ASheet.Cells.GetValue(iCol, FCurRow), '');
  384. if (sColName = '预算项目节') or (sColName = '项目节编号') then
  385. FCodeCol := iCol
  386. else if (sColName = '清单子目号') or (sColName = '清单编号') then
  387. FB_CodeCol := iCol
  388. else if sColName = '名称' then
  389. FNameCol := iCol
  390. else if sColName = '单位' then
  391. FUnitsCol := iCol
  392. else if sColName = '单价' then
  393. FPriceCol := iCol
  394. else if (sColName = '清单数量') or (sColName = '工程量') or (sColName = '数量') then
  395. FQuantityCol := iCol
  396. else if (sColName = '设计数量1') or (sColName = '数量1') then
  397. FDgnQuantity1Col := iCol
  398. else if (sColName = '设计数量2') or (sColName = '数量2') then
  399. FDgnQuantity2Col := iCol
  400. else if sColName = '图号' then
  401. FDrawingCol := iCol
  402. else if sColName = '备注' then
  403. FMemoCol := iCol
  404. else if sColName = '层次编号' then
  405. FLevelCol := iCol;
  406. end;
  407. Inc(FCurRow);
  408. end;
  409. procedure TBillsEdtExcelImport.LoadNode(ASheet: TSpreadSheet);
  410. var
  411. sLevelCode, sCode, sB_Code, sName: string;
  412. Node: TBillsCacheNode;
  413. vValue: Variant;
  414. iFixedID: Integer;
  415. begin
  416. sLevelCode := GetCellTrimText(ASheet, FLevelCol, FCurRow);
  417. sCode := GetCellTrimText(ASheet, FCodeCol, FCurRow);
  418. sB_Code := GetCellTrimText(ASheet, FB_CodeCol, FCurRow);
  419. sName := GetCellTrimText(ASheet, FNameCol, FCurRow);
  420. // 含层次编号时,层次编号为空不导入
  421. // 不含层次编号时,仅导入第一部分,且项目节编号、清单编号均未空时不导入
  422. if WithLevelCode then
  423. begin
  424. if sLevelCode = '' then Exit;
  425. end
  426. else
  427. begin
  428. if ((sCode = '') and (sB_Code = '')) or SameText(sCode, '2') or
  429. (Pos('第二部分', sName) > 0) then
  430. begin
  431. FIsFirstPart := False;
  432. Exit;
  433. end;
  434. end;
  435. if (sCode = '') and FWithoutGclBills then Exit;
  436. // 含层次编号时,以层次编号为依据新增节点;反之以项目节编号为依据新增节点
  437. if not WithLevelCode then
  438. begin
  439. if (sCode <> '') then
  440. Node := FCacheTree.AddNodeByCode(sCode, -1)
  441. else
  442. Node := FCacheTree.AddLeafBillsNode(sB_Code);
  443. end
  444. else
  445. begin
  446. // 1. 从模板树中查询当前节点是否为固定ID,否则为-1
  447. iFixedID := GetFixedID(sCode, sName);
  448. // 2. 从导入树中查询是否添加过该固定ID,防止存在两个固定ID节点主键冲突
  449. // 如果已添加过固定ID节点,则其他节点未非固定ID节点
  450. Node := GetFixedIDNode(iFixedID);
  451. if Assigned(Node) then
  452. iFixedID := -1;
  453. // 3. 添加当前节点
  454. Node := FCacheTree.AddNodeByCode(sLevelCode, iFixedID);
  455. // 4. 如果当前添加的节点为固定ID节点,则添加到List中便于2快速查找
  456. if Node.ID < 100 then
  457. FFixedIDNodes.Add(Node);
  458. end;
  459. Node.Code := sCode;
  460. Node.B_Code := sB_Code;
  461. Node.Name := sName;
  462. Node.Units := GetCellTrimText(ASheet, FUnitsCol, FCurRow);
  463. Node.Price := StrToFloatDef(VarToStrDef(GetCellValue(ASheet, FPriceCol, FCurRow), ''), 0);
  464. Node.Quantity := StrToFloatDef(VarToStrDef(GetCellValue(ASheet, FQuantityCol, FCurRow), ''), 0);
  465. Node.DgnQuantity1 := StrToFloatDef(VarToStrDef(GetCellValue(ASheet, FDgnQuantity1Col, FCurRow), ''), 0);
  466. Node.DgnQuantity2 := StrToFloatDef(VarToStrDef(GetCellValue(ASheet, FDgnQuantity2Col, FCurRow), ''), 0);
  467. Node.DrawingCode := GetCellTrimText(ASheet, FDrawingCol, FCurRow);
  468. Node.MemoStr := GetCellTrimText(ASheet, FMemoCol, FCurRow);
  469. end;
  470. procedure TBillsEdtExcelImport.LoadNodes(ASheet: TSpreadSheet);
  471. var
  472. iPos, iSubPos: Integer;
  473. begin
  474. while (FCurRow < ASheet.Cells.UsedRowCount){ and FIsFirstPart }do
  475. begin
  476. LoadNode(ASheet);
  477. Inc(FCurRow);
  478. iSubPos := FCurRow * 100 div ASheet.Cells.UsedRowCount;
  479. iPos := iSubPos div 2;
  480. UpdateProgressPosition(iPos, iSubPos);
  481. end;
  482. end;
  483. procedure TBillsEdtExcelImport.WriteNode(ADataSet: TsdDataSet;
  484. ANode: TBillsCacheNode);
  485. var
  486. Rec: TBillsRecord;
  487. begin
  488. if ANode.Code <> '' then
  489. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Code)
  490. else if ANode.B_Code <> '' then
  491. UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
  492. else
  493. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
  494. Rec := TBillsRecord(ADataSet.Add);
  495. Rec.ID.AsInteger := ANode.ID;
  496. Rec.ParentID.AsInteger := ANode.ParentID;
  497. Rec.NextSiblingID.AsInteger := ANode.NextSiblingID;
  498. Rec.Code.AsString := ANode.Code;
  499. Rec.B_Code.AsString := ANode.B_Code;
  500. Rec.Name.AsString := ANode.Name;
  501. Rec.Units.AsString := ANode.Units;
  502. Rec.Price.AsFloat := PriceRoundTo(ANode.Price);
  503. Rec.OrgQuantity.AsFloat := QuantityRoundTo(ANode.Quantity);
  504. Rec.DgnQuantity1.AsFloat := QuantityRoundTo(ANode.DgnQuantity1);
  505. Rec.DgnQuantity2.AsFloat := QuantityRoundTo(ANode.DgnQuantity2);
  506. Rec.DrawingCode.AsString := ANode.DrawingCode;
  507. Rec.MemoStr.AsString := ANode.MemoStr;
  508. end;
  509. procedure TBillsEdtExcelImport.WriteNodes(ADataSet: TsdDataSet);
  510. var
  511. i, iPos, iSubPos: Integer;
  512. begin
  513. UpdateProgressHint('写入读取的Excel数据', True);
  514. UpdateProgressPosition(50, 0);
  515. ADataSet.DeleteAll;
  516. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  517. begin
  518. WriteNode(ADataSet, TBillsCacheNode(FCacheTree.CacheNodes[i]));
  519. iSubPos := i*100 div FCacheTree.CacheNodes.Count;
  520. iPos := 50 + iSubPos div 2;
  521. UpdateProgressPosition(iPos, iSubPos);
  522. end;
  523. UpdateProgressPosition(100, 100);
  524. end;
  525. procedure TBillsEdtExcelImport.CheckFixedIDNodes;
  526. function GetHintStr(ANode: TBillsCacheNode): string;
  527. begin
  528. Result := '';
  529. if ANode.Code <> '' then
  530. Result := Result + '编号:' + ANode.Code + ';';
  531. if ANode.Name <> '' then
  532. Result := Result + '名称:' + ANode.Name + ';';
  533. end;
  534. function GetInvalidModel(ANoPM: Boolean; ACount: Integer): string;
  535. begin
  536. if ANoPM then
  537. begin
  538. if ACount > 1 then
  539. Result := '价差功能,部分报表'
  540. else
  541. Result := '价差功能'
  542. end
  543. else
  544. Result := '部分报表';
  545. Result := Result + '将不可使用' + #13#10 + '如有疑问,请联系纵横客服,企业QQ:800003850 电话:(0756)3850888';
  546. end;
  547. var
  548. sgs: TStrings;
  549. iBase: Integer;
  550. vBase, vImport: TBillsCacheNode;
  551. sHint: string;
  552. bNoPM: Boolean;
  553. begin
  554. bNoPM := False;
  555. sgs := TStringList.Create;
  556. try
  557. sgs.Add('缺少如下固定清单节点:');
  558. for iBase := 0 to FBaseTree.FixedIDNodes.Count - 1 do
  559. begin
  560. vBase := TBillsCacheNode(FBaseTree.FixedIDNodes.Items[iBase]);
  561. vImport := FCacheTree.FindFixedIDNode(vBase.ID);
  562. if not Assigned(vImport) then
  563. begin
  564. sgs.Add(GetHintStr(vBase));
  565. if vBase.ID = iPriceMarginID then
  566. bNoPM := True;
  567. end;
  568. end;
  569. finally
  570. if sgs.Count > 1 then
  571. begin
  572. sgs.Add(GetInvalidModel(bNoPM, sgs.Count - 1));
  573. WarningMessage(sgs.Text);
  574. end;
  575. sgs.Free;
  576. end;
  577. end;
  578. { TBillsPriceExcelImport }
  579. procedure TBillsPriceExcelImport.BeginImport;
  580. begin
  581. ShowProgressHint('导入Excel清单单价', 100);
  582. FProjectData.BillsData.sddBills.BeginUpdate;
  583. end;
  584. procedure TBillsPriceExcelImport.EndImport;
  585. begin
  586. FProjectData.BillsData.sddBills.EndUpdate;
  587. UpdateProgressHint('正在计算导入后的数据');
  588. FProjectData.BillsCompileData.CalculateAll;
  589. CloseProgressHint;
  590. end;
  591. procedure TBillsPriceExcelImport.Import;
  592. begin
  593. LoadColumnsFromHead(FMSExcel.Sheets.Spreadsheet(0));
  594. ImportBillsPriceData(FMSExcel.Sheets.Spreadsheet(0));
  595. end;
  596. procedure TBillsPriceExcelImport.ImportBillsPriceData(ASheet: TSpreadSheet);
  597. function CheckIsBillsCode(ACode: string): Boolean;
  598. const
  599. FBillsCodeSet: set of char = ['0'..'9', '-', 'a'..'z', 'A'..'Z'];
  600. var
  601. I: Integer;
  602. begin
  603. Result := True;
  604. I := 1;
  605. while I < Length(ACode) do
  606. if ACode[I] in FBillsCodeSet then
  607. Inc(I)
  608. else
  609. begin
  610. Result := False;
  611. Break;
  612. end;
  613. end;
  614. var
  615. iPos: Integer;
  616. sB_Code: string;
  617. fPrice: Double;
  618. begin
  619. UpdateProgressHint('写入读取的Excel数据');
  620. UpdateProgressPosition(0);
  621. while (FCurRow < ASheet.Cells.UsedRowCount) do
  622. begin
  623. sB_Code := GetCellTrimText(ASheet, FB_CodeCol, FCurRow);
  624. if (sB_Code <> '') and CheckIsBillsCode(sB_Code) then
  625. begin
  626. fPrice := StrToFloatDef(VarToStrDef(ASheet.Cells.GetValue(FPriceCol, FCurRow), ''), 0);
  627. UpdateBillsPrice(sB_Code, fPrice);
  628. end;
  629. Inc(FCurRow);
  630. iPos := FCurRow * 100 div ASheet.Cells.UsedRowCount;
  631. UpdateProgressPosition(iPos);
  632. end;
  633. UpdateProgressPosition(100);
  634. end;
  635. procedure TBillsPriceExcelImport.LoadColumnsFromHead(ASheet: TSpreadSheet);
  636. var
  637. iCol: Integer;
  638. sColName: string;
  639. begin
  640. FB_CodeCol := -1;
  641. FNameCol := -1;
  642. FPriceCol := -1;
  643. while ((FB_CodeCol = -1) or (FPriceCol = -1)) and (FCurRow < ASheet.Cells.UsedRowCount) do
  644. begin
  645. for iCol := 0 to ASheet.Cells.UsedColCount do
  646. begin
  647. sColName := GetCellTrimText(ASheet, iCol, FCurRow);
  648. if SameText(sColName, '清单编号') or SameText(sColName, '子目号') then
  649. FB_CodeCol := iCol
  650. else if SameText(sColName, '名称') then
  651. FNameCol := iCol
  652. else if Pos('单价', sColName) = 1 then
  653. FPriceCol := iCol;
  654. end;
  655. Inc(FCurRow);
  656. end;
  657. end;
  658. procedure TBillsPriceExcelImport.UpdateBillsPrice(const AB_Code: string;
  659. APrice: Double);
  660. var
  661. iIndex: Integer;
  662. Rec: TBillsRecord;
  663. begin
  664. with FProjectData.BillsData do
  665. begin
  666. for iIndex := 0 to sddBills.RecordCount - 1 do
  667. begin
  668. Rec := TBillsRecord(sddBills.Records[iIndex]);
  669. if SameText(AB_Code, Rec.B_Code.AsString) then
  670. Rec.Price.AsFloat := PriceRoundTo(APrice);
  671. end;
  672. end;
  673. end;
  674. { TDealBillsExcelImport }
  675. procedure TDealBillsExcelImport.BeginImport;
  676. begin
  677. FProjectData.DealBillsData.sddDealBills.BeginUpdate;
  678. end;
  679. procedure TDealBillsExcelImport.EndImport;
  680. begin
  681. FProjectData.DealBillsData.sddDealBills.EndUpdate;
  682. end;
  683. procedure TDealBillsExcelImport.Import;
  684. begin
  685. LoadColumnsFromHead(FMSExcel.Sheets.Spreadsheet(0));
  686. FBillsID := 1;
  687. FProjectData.DealBillsData.Clear;
  688. FProjectData.DealBillsData.DisableEvent;
  689. LoadDealBillsData(FMSExcel.Sheets.Spreadsheet(0));
  690. FProjectData.DealBillsData.EnableEvent;
  691. end;
  692. procedure TDealBillsExcelImport.LoadColumnsFromHead(ASheet: TSpreadSheet);
  693. var
  694. iCol: Integer;
  695. sColName: string;
  696. begin
  697. FB_CodeCol := -1;
  698. FNameCol := 1;
  699. FUnitsCol := 2;
  700. FPriceCol := 3;
  701. FQuantityCol := 4;
  702. FTotalPriceCol := 5;
  703. while ((FB_CodeCol = -1) or (FPriceCol = -1)) and (FCurRow < ASheet.Cells.UsedRowCount) do
  704. begin
  705. for iCol := 0 to ASheet.Cells.UsedColCount do
  706. begin
  707. sColName := GetCellTrimText(ASheet, iCol, FCurRow);
  708. if SameText(sColName, '清单编号') or SameText(sColName, '子目号') then
  709. FB_CodeCol := iCol
  710. else if SameText(sColName, '名称') then
  711. FNameCol := iCol
  712. else if SameText(sColName, '单位') then
  713. FUnitsCol := iCol
  714. else if Pos('单价', sColName) = 1 then
  715. FPriceCol := iCol
  716. else if SameText(sColName, '数量') then
  717. FQuantityCol := iCol
  718. else if SameText(sColName, '金额') then
  719. FTotalPriceCol := iCol;
  720. end;
  721. Inc(FCurRow);
  722. end;
  723. end;
  724. procedure TDealBillsExcelImport.LoadDealBillsData(ASheet: TSpreadSheet);
  725. function CheckIsBillsCode(ACode: string): Boolean;
  726. const
  727. FBillsCodeSet: set of char = ['0'..'9', '-', 'a'..'z', 'A'..'Z'];
  728. var
  729. I: Integer;
  730. begin
  731. Result := True;
  732. I := 1;
  733. while I < Length(ACode) do
  734. if ACode[I] in FBillsCodeSet then
  735. Inc(I)
  736. else
  737. begin
  738. Result := False;
  739. Break;
  740. end;
  741. end;
  742. var
  743. sB_Code: string;
  744. Rec: TsdDataRecord;
  745. begin
  746. while (FCurRow < ASheet.Cells.UsedRowCount) do
  747. begin
  748. sB_Code := GetCellTrimText(ASheet, FB_CodeCol, FCurRow);
  749. if (sB_Code <> '') and CheckIsBillsCode(sB_Code) then
  750. begin
  751. Rec := FProjectData.DealBillsData.sddDealBills.Add;
  752. Rec.ValueByName('ID').AsInteger := FBillsID;
  753. Rec.ValueByName('B_Code').AsString := sB_Code;
  754. Rec.ValueByName('IndexCode').AsString := B_CodeToIndexCode(sB_Code);
  755. Rec.ValueByName('Name').AsString := GetCellTrimText(ASheet, FNameCol, FCurRow);
  756. Rec.ValueByName('Units').AsString := GetCellTrimText(ASheet, FUnitsCol, FCurRow);
  757. Rec.ValueByName('Price').AsFloat := PriceRoundTo(
  758. StrToFloatDef(GetCellTrimText(ASheet, FPriceCol, FCurRow), 0));
  759. Rec.ValueByName('Quantity').AsFloat := QuantityRoundTo(
  760. StrToFloatDef(GetCellTrimText(ASheet, FQuantityCol, FCurRow), 0));
  761. Rec.ValueByName('TotalPrice').AsFloat := TotalPriceRoundTo(
  762. StrToFloatDef(GetCellTrimText(ASheet, FTotalPriceCol, FCurRow), 0));
  763. Inc(FBillsID);
  764. end;
  765. Inc(FCurRow);
  766. end;
  767. end;
  768. { TGclBillsExcelImport }
  769. procedure TGclBillsExcelImport.BeginImport;
  770. begin
  771. Screen.Cursor := crHourGlass;
  772. ShowProgressHint('导入Excel数据', 100);
  773. FCacheTree := TGclCacheTree.Create;
  774. FCacheTree.NewNodeID := FProjectData.BillsData.GetMaxBillsID + 1;
  775. FProjectData.DisConnectTree;
  776. FProjectData.BillsData.DisableEvents;
  777. FSelectSheets := TList.Create;
  778. FB_CodeCol := 0;
  779. FNameCol := 1;
  780. FUnitsCol := 2;
  781. FQuantityCol := 3;
  782. FPriceCol := 4;
  783. end;
  784. procedure TGclBillsExcelImport.EndImport;
  785. var
  786. ParentRec: TsdDataRecord;
  787. begin
  788. FSelectSheets.Free;
  789. FCacheTree.Free;
  790. FProjectData.BillsData.EnableEvents;
  791. FProjectData.ReConnectTree;
  792. ParentRec := FProjectData.BillsData.sddBills.FindKey('idxID', ParentID);
  793. FProjectData.BillsCompileData.sdvBillsCompile.LocateInControl(ParentRec);
  794. FProjectData.BillsCompileData.CalculateAll;
  795. CloseProgressHint;
  796. Screen.Cursor := crDefault;
  797. end;
  798. procedure TGclBillsExcelImport.Import;
  799. var
  800. i: Integer;
  801. begin
  802. {if SelectSheets(FMSExcel, FSelectSheets) then
  803. begin
  804. for i := 0 to FSelectSheets.Count - 1 do
  805. begin
  806. UpdateProgressHint(Format('导入Excel数据--工作表[%s]', [FMSExcel.SheetNames.Strings[i]]));
  807. UpdateProgressPosition(0);
  808. ImportSheet(FSelectSheets.Items[i]);
  809. end;
  810. end;}
  811. ImportSheet(FMSExcel.Sheets.Spreadsheet(0));
  812. WriteNodes(FProjectData.BillsData.sddBills);
  813. end;
  814. procedure TGclBillsExcelImport.ImportSheet(ASheet: TSpreadSheet);
  815. var
  816. iPos: Integer;
  817. begin
  818. FCurRow := 1;
  819. while (FCurRow < ASheet.Cells.UsedRowCount) do
  820. begin
  821. LoadNode(ASheet);
  822. Inc(FCurRow);
  823. iPos := FCurRow * 100 div ASheet.Cells.UsedRowCount;
  824. UpdateProgressPosition(iPos);
  825. end;
  826. end;
  827. procedure TGclBillsExcelImport.LoadNode(ASheet: TSpreadSheet);
  828. var
  829. sB_Code, sName: string;
  830. Node: TGclCacheNode;
  831. begin
  832. with ASheet.Cells do
  833. begin
  834. sB_Code := Trim(VarToStrDef(GetValue(FB_CodeCol, FCurRow), ''));
  835. sName := Trim(VarToStrDef(GetValue(FNameCol, FCurRow), ''));
  836. Node := FCacheTree.AddNodeByData(sB_Code, sName);
  837. Node.B_Code := sB_Code;
  838. Node.Name := sName;
  839. Node.Units := Trim(VarToStrDef(GetValue(FUnitsCol, FCurRow), ''));
  840. Node.Price := StrToFloatDef(VarToStrDef(GetValue(FPriceCol, FCurRow), ''), 0);
  841. Node.Quantity := StrToFloatDef(VarToStrDef(GetValue(FQuantityCol, FCurRow), ''), 0);
  842. end;
  843. end;
  844. procedure TGclBillsExcelImport.WriteNodes(ADataSet: TsdDataSet);
  845. var
  846. i, iPos: Integer;
  847. begin
  848. UpdateProgressHint('写入读取的Excel数据');
  849. UpdateProgressPosition(0);
  850. for i := 0 to FCacheTree.CacheNodes.Count - 1 do
  851. begin
  852. WriteNode(ADataSet, TGclCacheNode(FCacheTree.CacheNodes[i]));
  853. iPos := i*100 div FCacheTree.CacheNodes.Count;
  854. UpdateProgressPosition(iPos);
  855. end;
  856. UpdateProgressPosition(100);
  857. end;
  858. procedure TGclBillsExcelImport.WriteNode(ADataSet: TsdDataSet;
  859. ANode: TGclCacheNode);
  860. var
  861. Rec: TBillsRecord;
  862. begin
  863. if ANode.B_Code <> '' then
  864. UpdateProgressHint('写入读取的Excel数据 ' + ANode.B_Code)
  865. else
  866. UpdateProgressHint('写入读取的Excel数据 ' + ANode.Name);
  867. Rec := TBillsRecord(ADataSet.Add);
  868. Rec.ID.AsInteger := ANode.ID;
  869. if ANode.ParentID = -1 then
  870. Rec.ParentID.AsInteger := ParentID
  871. else
  872. Rec.ParentID.AsInteger := ANode.ParentID;
  873. Rec.NextSiblingID.AsInteger := ANode.NextSiblingID;
  874. Rec.B_Code.AsString := ANode.B_Code;
  875. Rec.Name.AsString := ANode.Name;
  876. Rec.Units.AsString := ANode.Units;
  877. Rec.Price.AsFloat := PriceRoundTo(ANode.Price);
  878. Rec.OrgQuantity.AsFloat := QuantityRoundTo(ANode.Quantity);
  879. end;
  880. end.