ExportExcel.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. unit ExportExcel;
  2. interface
  3. uses
  4. Classes, ZjGrid, ScXlsOutput, ScXlsCustomUD, Windows, StdCtrls,
  5. sdIDTree, sdDB, Graphics, SysUtils, ProgressHintFrm, Forms, Controls;
  6. type
  7. TExcelExportor = class
  8. private
  9. FXlsOutPut: TXlsOutPut;
  10. FGrid: TZJGrid;
  11. FTempFile: string;
  12. FFileName: string;
  13. procedure InitialPage(AGrid: TZJGrid; AXlsPage: TXlsCustomPage);
  14. protected
  15. procedure BeforeExport;
  16. procedure EndExport;
  17. public
  18. constructor Create;
  19. destructor Destroy; override;
  20. procedure ExportToXlsPage(AGrid: TZJGrid; AXlsPage: TXlsCustomPage);
  21. procedure ExportToFile(AGrid: TZJGrid; const AFileName: string);
  22. end;
  23. PColInfo = ^TColInfo;
  24. TColInfo = record
  25. // 字段名
  26. FieldName: string;
  27. // 查询字段名,应用于联合几个数据库的情况,参照dataset的Lookup方式
  28. KeyField: string;
  29. LookupKeyField: string;
  30. // 查询数据库ID
  31. LookupDataSetIndex: Integer;
  32. // 列名
  33. TitleCaption: string;
  34. // 列宽
  35. Width: Integer;
  36. // 对齐方式
  37. HorTextAlign: TUDHTextAlign;
  38. //VerTextAlign: TUDVTextAlign;
  39. end;
  40. PColInfos = ^TColInfos;
  41. TColInfos = array [0..30] of TColInfo;
  42. // 仿照DataSet的Lookup以及数据库的AutoUpdate已达到关于sdIDTree导出数据至Excel的普适性
  43. // 导出前须根据所需列信息,以及查询数据库(列信息须与查询数据库对等,否则将会报错,并不检查列与数据库是否匹配)
  44. TIDTreeExcelExportor = class
  45. private
  46. FXlsOutPut: TXlsOutPut;
  47. FDataSetList: TList;
  48. FColInfos: PColInfos;
  49. FColCount: Integer;
  50. FHasLevelCode: Boolean;
  51. FTree: TsdIDTree;
  52. FTempFile: string;
  53. // 当清单数超过3w3k行时,使用Variant会内存溢出
  54. function GetCellValue(ANode: TsdIDTreeNode; ColInfo: TColInfo): Variant;
  55. // 故换成直接使用String
  56. function GetCellStr(ANode: TsdIDTreeNode; ColInfo: TColInfo): string;
  57. procedure ExportNodeData(ANode: TsdIDTreeNode; AXlsPage: TXlsCustomPage; const ALevelCode: string);
  58. procedure ExportTreeNode(ANode: TsdIDTreeNode; AXlsPage: TXlsCustomPage; const ALevelCode: string);
  59. procedure DefineHeader(AXlsPage: TXlsCustomPage);
  60. protected
  61. procedure BeforeExport;
  62. procedure EndExport;
  63. public
  64. constructor Create;
  65. destructor Destroy; override;
  66. procedure AddLookupDataSet(ADataSet: TsdDataSet);
  67. procedure DefineCol(AColInfos: PColInfos; AColCount: Integer);
  68. procedure ExportToXlsPage(ATree: TsdIDTree; AXlsPage: TXlsCustomPage);
  69. procedure ExportToFile(ATree: TsdIDTree; const AFileName: string);
  70. property HasLevelCode: Boolean read FHasLevelCode write FHasLevelCode;
  71. end;
  72. TMasterExcelExportor = class
  73. private
  74. FXlsOutPut: TXlsOutPut;
  75. FColInfos: PColInfos;
  76. FRelaColInfos: PColInfos;
  77. FColCount: Integer;
  78. FTempFile: string;
  79. FMasterDataSet: TsdDataSet;
  80. FKeyFieldName: string;
  81. FRelaDataSet: TsdDataSet;
  82. FMasterFieldName: string;
  83. function GetCellValue(ARec: TsdDataRecord; ColInfo: TColInfo): Variant;
  84. procedure ExportRecord(ARec: TsdDataRecord; AXlsPage: TXlsCustomPage; ARow: Integer; AColInfos: PColInfos);
  85. procedure ExportData(AXlsPage: TXlsCustomPage);
  86. procedure DefineHeader(AXlsPage: TXlsCustomPage);
  87. protected
  88. procedure BeforeExport;
  89. procedure EndExport;
  90. public
  91. constructor Create;
  92. destructor Destroy; override;
  93. procedure DefineCol(AColInfos: PColInfos; AColCount: Integer; ARelaColInfo: PColInfos = nil);
  94. procedure DefineMasterDataSet(ADataSet: TsdDataSet; const AKeyFieldName: string);
  95. procedure DefineRelaDataSet(ADataSet: TsdDataSet; const AMasterFieldName: string);
  96. procedure ExportToXlsPage(AXlsPage: TXlsCustomPage);
  97. procedure ExportToFile(const AFileName: string);
  98. end;
  99. const
  100. ciLedger: array [0..8] of TColInfo =(
  101. (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '项目节编号'; Width: 120; HorTextAlign: htaLeft),
  102. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单编号'; Width: 80; HorTextAlign: htaLeft),
  103. (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  104. (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  105. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  106. (FieldName: 'OrgQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '数量'; Width: 80; HorTextAlign: htaRight),
  107. (FieldName: 'OrgTotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '金额'; Width: 80; HorTextAlign: htaRight),
  108. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 100; HorTextAlign: htaLeft),
  109. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  110. );
  111. ciLedgerWithMis: array [0..10] of TColInfo =(
  112. (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '项目节编号'; Width: 120; HorTextAlign: htaLeft),
  113. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单编号'; Width: 80; HorTextAlign: htaLeft),
  114. (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  115. (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  116. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  117. (FieldName: 'OrgQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '施工图数量'; Width: 90; HorTextAlign: htaRight),
  118. (FieldName: 'MisQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计错漏数量'; Width: 90; HorTextAlign: htaRight),
  119. (FieldName: 'OthQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '其他错漏数量'; Width: 90; HorTextAlign: htaRight),
  120. (FieldName: 'TotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '金额'; Width: 80; HorTextAlign: htaRight),
  121. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 100; HorTextAlign: htaLeft),
  122. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  123. );
  124. ciFxBills: array [0..10] of TColInfo =(
  125. (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '预算项目节'; Width: 120; HorTextAlign: htaLeft),
  126. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单子目号'; Width: 80; HorTextAlign: htaLeft),
  127. (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  128. (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  129. (FieldName: 'OrgQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单数量'; Width: 80; HorTextAlign: htaRight),
  130. (FieldName: 'DgnQuantity1'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计数量1'; Width: 80; HorTextAlign: htaRight),
  131. (FieldName: 'DgnQuantity2'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计数量2'; Width: 80; HorTextAlign: htaRight),
  132. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  133. (FieldName: 'OrgTotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '合价'; Width: 80; HorTextAlign: htaRight),
  134. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 100; HorTextAlign: htaLeft),
  135. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  136. );
  137. ciFxBillsWithMis: array [0..12] of TColInfo =(
  138. (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '预算项目节'; Width: 120; HorTextAlign: htaLeft),
  139. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单子目号'; Width: 80; HorTextAlign: htaLeft),
  140. (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  141. (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  142. (FieldName: 'OrgQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单数量'; Width: 90; HorTextAlign: htaRight),
  143. (FieldName: 'MisQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计错漏数量'; Width: 90; HorTextAlign: htaRight),
  144. (FieldName: 'OthQuantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '其他错漏数量'; Width: 90; HorTextAlign: htaRight),
  145. (FieldName: 'DgnQuantity1'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计数量1'; Width: 80; HorTextAlign: htaRight),
  146. (FieldName: 'DgnQuantity2'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '设计数量2'; Width: 80; HorTextAlign: htaRight),
  147. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  148. (FieldName: 'TotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '合价'; Width: 80; HorTextAlign: htaRight),
  149. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 100; HorTextAlign: htaLeft),
  150. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  151. );
  152. ciTpPegGcl: array [0..9] of TColInfo =(
  153. (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '项目节编号'; Width: 120; HorTextAlign: htaLeft),
  154. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单编号'; Width: 80; HorTextAlign: htaLeft),
  155. (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  156. (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  157. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  158. (FieldName: 'Quantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '数量'; Width: 90; HorTextAlign: htaRight),
  159. (FieldName: 'TotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '金额'; Width: 80; HorTextAlign: htaRight),
  160. (FieldName: 'Peg'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '桩号'; Width: 80; HorTextAlign: htaLeft),
  161. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 80; HorTextAlign: htaLeft),
  162. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  163. );
  164. ciTpGclPeg_Gcl: array [0..9] of TColInfo =(
  165. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单编号'; Width: 80; HorTextAlign: htaLeft),
  166. (FieldName: 'Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '项目节编号'; Width: 120; HorTextAlign: htaLeft),
  167. (FieldName: 'Name'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  168. (FieldName: 'Units'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  169. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  170. (FieldName: 'Quantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '数量'; Width: 90; HorTextAlign: htaRight),
  171. (FieldName: 'TotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '金额'; Width: 80; HorTextAlign: htaRight),
  172. (FieldName: 'Peg'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '桩号'; Width: 80; HorTextAlign: htaLeft),
  173. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 80; HorTextAlign: htaLeft),
  174. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  175. );
  176. ciTpGclPeg_Peg: array [0..9] of TColInfo =(
  177. (FieldName: 'B_Code'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '清单编号'; Width: 80; HorTextAlign: htaLeft),
  178. (FieldName: 'PegXmjCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '项目节编号'; Width: 120; HorTextAlign: htaLeft),
  179. (FieldName: 'PegXmjName'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '名称'; Width: 200; HorTextAlign: htaLeft),
  180. (FieldName: 'PegXmjUnits'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单位'; Width: 40; HorTextAlign: htaCenter),
  181. (FieldName: 'Price'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '单价'; Width: 60; HorTextAlign: htaRight),
  182. (FieldName: 'Quantity'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '数量'; Width: 90; HorTextAlign: htaRight),
  183. (FieldName: 'TotalPrice'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '金额'; Width: 80; HorTextAlign: htaRight),
  184. (FieldName: 'Peg'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '桩号'; Width: 80; HorTextAlign: htaLeft),
  185. (FieldName: 'DrawingCode'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '图号'; Width: 80; HorTextAlign: htaLeft),
  186. (FieldName: 'MemoStr'; KeyField: ''; LookupKeyField: ''; LookupDataSetIndex: -1; TitleCaption: '备注'; Width: 80; HorTextAlign: htaLeft)
  187. );
  188. implementation
  189. uses
  190. ZhAPI, Variants, UtilMethods, Math;
  191. { TExcelExportor }
  192. procedure TExcelExportor.BeforeExport;
  193. begin
  194. Screen.Cursor := crHourGlass;
  195. ShowProgressHint('导出Excel表格数据', FGrid.RowCount);
  196. end;
  197. constructor TExcelExportor.Create;
  198. begin
  199. FXlsOutPut := TXlsOutPut.Create;
  200. FTempFile := GetTempFileName;
  201. end;
  202. destructor TExcelExportor.Destroy;
  203. begin
  204. if FileExists(FTempFile) then
  205. DeleteFileOrFolder(FTempFile);
  206. FXlsOutPut.Free;
  207. inherited;
  208. end;
  209. procedure TExcelExportor.EndExport;
  210. begin
  211. CloseProgressHint;
  212. Screen.Cursor := crDefault;
  213. end;
  214. procedure TExcelExportor.ExportToFile(AGrid: TZJGrid;
  215. const AFileName: string);
  216. begin
  217. FFileName := AFileName;
  218. FGrid := AGrid;
  219. BeforeExport;
  220. try
  221. ExportToXlsPage(AGrid, FXlsOutPut.AddPage);
  222. FXlsOutPut.SaveToFile(FTempFile);
  223. if not FileExists(FFileName) or QuestMessage('存在同名文件,是否替换?') then
  224. CopyFile(PChar(FTempFile), PChar(FFileName), False);
  225. finally
  226. EndExport;
  227. end;
  228. end;
  229. procedure TExcelExportor.ExportToXlsPage(AGrid: TZJGrid;
  230. AXlsPage: TXlsCustomPage);
  231. procedure SetXlsCellTextAlign(AXlsCell: TXlsCustomCell; AGridCell: TzjCell);
  232. begin
  233. case AGridCell.TextAlign of
  234. gaTopLeft:
  235. begin
  236. AXlsCell.VTextAlign := vtaTop;
  237. AXlsCell.HTextAlign := htaLeft;
  238. end;
  239. gaTopCenter:
  240. begin
  241. AXlsCell.VTextAlign := vtaTop;
  242. AXlsCell.HTextAlign := htaCenter;
  243. end;
  244. gaTopRight:
  245. begin
  246. AXlsCell.VTextAlign := vtaTop;
  247. AXlsCell.HTextAlign := htaRight;
  248. end;
  249. gaCenterLeft:
  250. begin
  251. AXlsCell.VTextAlign := vtaCenter;
  252. AXlsCell.HTextAlign := htaLeft;
  253. end;
  254. gaCenterCenter:
  255. begin
  256. AXlsCell.VTextAlign := vtaCenter;
  257. AXlsCell.HTextAlign := htaCenter;
  258. end;
  259. gaCenterRight:
  260. begin
  261. AXlsCell.VTextAlign := vtaCenter;
  262. AXlsCell.HTextAlign := htaRight;
  263. end;
  264. gaBottomLeft:
  265. begin
  266. AXlsCell.VTextAlign := vtaBottom;
  267. AXlsCell.HTextAlign := htaLeft;
  268. end;
  269. gaBottomCenter:
  270. begin
  271. AXlsCell.VTextAlign := vtaBottom;
  272. AXlsCell.HTextAlign := htaCenter;
  273. end;
  274. gaBottomRight:
  275. begin
  276. AXlsCell.VTextAlign := vtaBottom;
  277. AXlsCell.HTextAlign := htaRight;
  278. end;
  279. end;
  280. if goWarpText in AGridCell.Grid.Options then
  281. AXlsCell.WartText := True;
  282. end;
  283. procedure ExportGridCell(AGridCell: TzjCell);
  284. var
  285. XlsCell: TXlsCustomCell;
  286. begin
  287. if AGridCell = nil then Exit;
  288. XlsCell := AXlsPage.AddCell(AGridCell.Col, AGridCell.Row, AGridCell.Text);
  289. SetXlsCellTextAlign(XlsCell, AGridCell);
  290. XlsCell.Font.Name := AGridCell.Font.Name;
  291. XlsCell.Font.Size := AGridCell.Font.Size;
  292. XlsCell.Width := AGridCell.Width;
  293. XlsCell.Height := AGridCell.Height;
  294. end;
  295. var
  296. iColumn, iRow: Integer;
  297. begin
  298. InitialPage(AGrid, AXlsPage);
  299. for iRow := 0 to AGrid.RowCount - 1 do
  300. begin
  301. UpdateProgressHint(Format('导出第%d行数据', [iRow + 1]));
  302. UpdateProgressHint(1);
  303. for iColumn := 0 to AGrid.ColCount - 1 do
  304. ExportGridCell(AGrid.Cells[iColumn, iRow]);
  305. end;
  306. end;
  307. procedure TExcelExportor.InitialPage(AGrid: TZJGrid;
  308. AXlsPage: TXlsCustomPage);
  309. procedure InitialColumnWidth;
  310. var
  311. iColumn: Integer;
  312. begin
  313. for iColumn := 0 to AGrid.ColCount - 1 do
  314. AXlsPage.Widths[iColumn] := AGrid.ColWidths[iColumn];
  315. end;
  316. procedure InitialRowHeight;
  317. var
  318. iRow: Integer;
  319. begin
  320. for iRow := 0 to AGrid.RowCount - 1 do
  321. AXlsPage.Heights.Items[iRow] := AGrid.RowHeights[iRow];
  322. end;
  323. begin
  324. InitialColumnWidth;
  325. InitialRowHeight;
  326. end;
  327. { TIDTreeExcelExportor }
  328. constructor TIDTreeExcelExportor.Create;
  329. begin
  330. FXlsOutPut := TXlsOutPut.Create;
  331. FDataSetList := TList.Create;
  332. FTempFile := GetTempFileName;
  333. end;
  334. destructor TIDTreeExcelExportor.Destroy;
  335. begin
  336. if FileExists(FTempFile) then
  337. DeleteFileOrFolder(FTempFile);
  338. FDataSetList.Free;
  339. FXlsOutPut.Free;
  340. inherited;
  341. end;
  342. procedure TIDTreeExcelExportor.ExportToFile(ATree: TsdIDTree;
  343. const AFileName: string);
  344. begin
  345. FTree := ATree;
  346. BeforeExport;
  347. try
  348. ExportToXlsPage(ATree, FXlsOutPut.AddPage);
  349. UpdateProgressHint('保存0号台账Excel数据');
  350. FXlsOutPut.SaveToFile(FTempFile);
  351. if not FileExists(AFileName) or QuestMessage('存在同名文件,是否替换?') then
  352. CopyFile(PChar(FTempFile), PChar(AFileName), False);
  353. finally
  354. EndExport;
  355. end;
  356. end;
  357. procedure TIDTreeExcelExportor.ExportTreeNode(ANode: TsdIDTreeNode;
  358. AXlsPage: TXlsCustomPage; const ALevelCode: string);
  359. function GetFirstChildLevelCode(const ACode: string): string;
  360. begin
  361. Result := ACode + '.1';
  362. end;
  363. function GetNextSiblingLevelCode(const ACode: string): string;
  364. var
  365. strPreCode, strLastCode: string;
  366. iNextCode: Integer;
  367. begin
  368. if Pos('.', ACode) = 0 then
  369. Result := IntToStr(StrToIntDef(ACode, 1) + 1)
  370. else
  371. begin
  372. strPreCode := GetPrefixOfCode(ACode, '.');
  373. strLastCode := GetLastSetmentOfCode(ACode, '.');
  374. iNextCode := StrToIntDef(strLastCode, 1) + 1;
  375. Result := strPreCode + '.' + IntToStr(iNextCode);
  376. end;
  377. end;
  378. var
  379. sHint: string;
  380. begin
  381. if not Assigned(ANode) then Exit;
  382. if ANode.Rec.ValueByName('Code').AsString <> '' then
  383. sHint := '正在导出清单 ' + ANode.Rec.ValueByName('Code').AsString
  384. else if ANode.Rec.ValueByName('B_Code').AsString <> '' then
  385. sHint := '正在导出清单 ' + ANode.Rec.ValueByName('B_Code').AsString
  386. else
  387. sHint := '正在导出清单 ' + ANode.Rec.ValueByName('Name').AsString;
  388. UpdateProgressHint(sHint);
  389. UpdateProgressHint(1);
  390. ExportNodeData(ANode, AXlsPage, ALevelCode);
  391. ExportTreeNode(ANode.FirstChild, AXlsPage, GetFirstChildLevelCode(ALevelCode));
  392. ExportTreeNode(ANode.NextSibling, AXlsPage, GetNextSiblingLevelCode(ALevelCode));
  393. end;
  394. procedure TIDTreeExcelExportor.ExportNodeData(ANode: TsdIDTreeNode;
  395. AXlsPage: TXlsCustomPage; const ALevelCode: string);
  396. function ExportCell(ACol, ARow: Integer; AValue: Variant): TXlsCustomCell;
  397. begin
  398. Result := nil;
  399. // -----------
  400. if VarIsNull(AValue) then Exit;
  401. // -----------
  402. // 当数据超过3w3k行时,运行至某行时,AddCell会内存溢出
  403. // 可能是Cell的数目超过某个限度时,报错
  404. // 如果AValue为Null时不AddCell,则3w3k行可以安全度过
  405. case VarType(AValue) of
  406. varSmallInt, varInteger, varSingle, varDouble,
  407. varCurrency, varShortInt, varByte, varWord,
  408. varLongWord, varInt64:
  409. begin
  410. if AValue <> 0 then
  411. Result := AXlsPage.AddCell(ACol, ARow, AValue);
  412. end
  413. else Result := AXlsPage.AddCell(ACol, ARow, AValue);
  414. end;
  415. end;
  416. var
  417. iCol: Integer;
  418. ColInfo: TColInfo;
  419. XlsCell: TXlsCustomCell;
  420. sStr: string;
  421. begin
  422. if not Assigned(ANode) then Exit;
  423. for iCol := 0 to FColCount - 1 do
  424. begin
  425. ColInfo := FColInfos[iCol];
  426. XlsCell := ExportCell(iCol, ANode.MajorIndex + 1, GetCellValue(ANode, ColInfo));
  427. {sStr := GetCellStr(ANode, ColInfo);
  428. if sStr = '' then Continue;
  429. XlsCell := AXlsPage.AddCell(iCol, ANode.MajorIndex + 1, sStr);}
  430. if Assigned(XlsCell) then
  431. begin
  432. XlsCell.HTextAlign := ColInfo.HorTextAlign;
  433. //XlsCell.VTextAlign := ColInfo.VerTextAlign;
  434. XlsCell.Font.Name := 'SmartSimSun';
  435. XlsCell.Font.Size := 9;
  436. end;
  437. end;
  438. if HasLevelCode then
  439. begin
  440. XlsCell := ExportCell(FColCount, ANode.MajorIndex + 1, ALevelCode);
  441. XlsCell.Font.Name := 'SmartSimSun';
  442. XlsCell.Font.Size := 9;
  443. end;
  444. end;
  445. procedure TIDTreeExcelExportor.ExportToXlsPage(ATree: TsdIDTree;
  446. AXlsPage: TXlsCustomPage);
  447. begin
  448. DefineHeader(AXlsPage);
  449. ExportTreeNode(ATree.FirstNode, AXlsPage, '1');
  450. end;
  451. function TIDTreeExcelExportor.GetCellValue(ANode: TsdIDTreeNode;
  452. ColInfo: TColInfo): Variant;
  453. function GetRec: TsdDataRecord;
  454. var
  455. DataSet: TsdDataSet;
  456. begin
  457. Result := nil;
  458. DataSet := TsdDataSet(FDataSetList.Items[ColInfo.LookupDataSetIndex]);
  459. if not Assigned(DataSet) then Exit;
  460. Result := DataSet.Locate(ColInfo.LookupKeyField, ANode.Rec.ValueByName(ColInfo.KeyField).Value);
  461. end;
  462. var
  463. ARec: TsdDataRecord;
  464. begin
  465. Result := '';
  466. if not Assigned(ANode) then Exit;
  467. if ColInfo.LookupDataSetIndex = -1 then
  468. ARec := ANode.Rec
  469. else
  470. ARec := GetRec;
  471. if Assigned(ARec) then
  472. Result := ARec.ValueByName(ColInfo.FieldName).Value;
  473. end;
  474. procedure TIDTreeExcelExportor.DefineHeader(AXlsPage: TXlsCustomPage);
  475. var
  476. iCol: Integer;
  477. ColInfo: TColInfo;
  478. XlsCell: TXlsCustomCell;
  479. begin
  480. for iCol := 0 to FColCount - 1 do
  481. begin
  482. ColInfo := FColInfos[iCol];
  483. XlsCell := AXlsPage.AddCell(iCol, 0, ColInfo.TitleCaption);
  484. XlsCell.HTextAlign := htaCenter;
  485. XlsCell.Font.Name := '黑体';
  486. XlsCell.Font.Size := 10;
  487. XlsCell.Font.Style := [fsBold];
  488. AXlsPage.Widths[iCol] := ColInfo.Width;
  489. end;
  490. if HasLevelCode then
  491. begin
  492. XlsCell := AXlsPage.AddCell(iCol, 0, '层次编号');
  493. XlsCell.HTextAlign := htaCenter;
  494. XlsCell.Font.Name := '黑体';
  495. XlsCell.Font.Size := 10;
  496. XlsCell.Font.Style := [fsBold];
  497. end;
  498. end;
  499. procedure TIDTreeExcelExportor.AddLookupDataSet(ADataSet: TsdDataSet);
  500. begin
  501. FDataSetList.Add(ADataSet);
  502. end;
  503. procedure TIDTreeExcelExportor.DefineCol(AColInfos: PColInfos;
  504. AColCount: Integer);
  505. begin
  506. FColInfos := AColInfos;
  507. FColCount := AColCount;
  508. end;
  509. procedure TIDTreeExcelExportor.BeforeExport;
  510. begin
  511. Screen.Cursor := crHourGlass;
  512. ShowProgressHint('导出0号台账Excel数据', FTree.Count);
  513. end;
  514. procedure TIDTreeExcelExportor.EndExport;
  515. begin
  516. CloseProgressHint;
  517. Screen.Cursor := crDefault;
  518. end;
  519. function TIDTreeExcelExportor.GetCellStr(ANode: TsdIDTreeNode;
  520. ColInfo: TColInfo): string;
  521. function GetRec: TsdDataRecord;
  522. var
  523. DataSet: TsdDataSet;
  524. begin
  525. Result := nil;
  526. DataSet := TsdDataSet(FDataSetList.Items[ColInfo.LookupDataSetIndex]);
  527. if not Assigned(DataSet) then Exit;
  528. Result := DataSet.Locate(ColInfo.LookupKeyField, ANode.Rec.ValueByName(ColInfo.KeyField).Value);
  529. end;
  530. var
  531. ARec: TsdDataRecord;
  532. begin
  533. Result := '';
  534. if not Assigned(ANode) then Exit;
  535. if ColInfo.LookupDataSetIndex = -1 then
  536. ARec := ANode.Rec
  537. else
  538. ARec := GetRec;
  539. if Assigned(ARec) then
  540. Result := ARec.ValueByName(ColInfo.FieldName).AsString;
  541. if SameText(Result, '0') then
  542. Result := '';
  543. end;
  544. { TMasterExcelExportor }
  545. procedure TMasterExcelExportor.BeforeExport;
  546. begin
  547. Screen.Cursor := crHourGlass;
  548. end;
  549. constructor TMasterExcelExportor.Create;
  550. begin
  551. FXlsOutPut := TXlsOutPut.Create;
  552. FTempFile := GetTempFileName;
  553. end;
  554. procedure TMasterExcelExportor.DefineCol(AColInfos: PColInfos;
  555. AColCount: Integer; ARelaColInfo: PColInfos);
  556. begin
  557. FColInfos := AColInfos;
  558. FColCount := AColCount;
  559. FRelaColInfos := ARelaColInfo;
  560. end;
  561. procedure TMasterExcelExportor.DefineHeader(AXlsPage: TXlsCustomPage);
  562. var
  563. iCol: Integer;
  564. ColInfo: TColInfo;
  565. XlsCell: TXlsCustomCell;
  566. begin
  567. for iCol := 0 to FColCount - 1 do
  568. begin
  569. ColInfo := FColInfos[iCol];
  570. XlsCell := AXlsPage.AddCell(iCol, 0, ColInfo.TitleCaption);
  571. XlsCell.HTextAlign := htaCenter;
  572. XlsCell.Font.Name := '黑体';
  573. XlsCell.Font.Size := 10;
  574. XlsCell.Font.Style := [fsBold];
  575. AXlsPage.Widths[iCol] := ColInfo.Width;
  576. end;
  577. end;
  578. procedure TMasterExcelExportor.DefineMasterDataSet(ADataSet: TsdDataSet;
  579. const AKeyFieldName: string);
  580. begin
  581. FMasterDataSet := ADataSet;
  582. FKeyFieldName := AKeyFieldName;
  583. end;
  584. procedure TMasterExcelExportor.DefineRelaDataSet(ADataSet: TsdDataSet;
  585. const AMasterFieldName: string);
  586. begin
  587. FRelaDataSet := ADataSet;
  588. FMasterFieldName := AMasterFieldName;
  589. end;
  590. destructor TMasterExcelExportor.Destroy;
  591. begin
  592. if FileExists(FTempFile) then
  593. DeleteFileOrFolder(FTempFile);
  594. FXlsOutPut.Free;
  595. inherited;
  596. end;
  597. procedure TMasterExcelExportor.EndExport;
  598. begin
  599. CloseProgressHint;
  600. end;
  601. procedure TMasterExcelExportor.ExportData(AXlsPage: TXlsCustomPage);
  602. var
  603. i, j, iRow: Integer;
  604. Rec, RelaRec: TsdDataRecord;
  605. begin
  606. iRow := 1;
  607. for i := 0 to FMasterDataSet.RecordCount - 1 do
  608. begin
  609. Rec := FMasterDataSet.Records[i];
  610. ExportRecord(Rec, AXlsPage, iRow, FColInfos);
  611. Inc(iRow);
  612. for j := 0 to FRelaDataSet.RecordCount - 1 do
  613. begin
  614. RelaRec := FRelaDataSet.Records[j];
  615. if (RelaRec.ValueByName(FMasterFieldName).Value = Rec.ValueByName(FKeyFieldName).Value) then
  616. begin
  617. if Assigned(FRelaColInfos) then
  618. ExportRecord(RelaRec, AXlsPage, iRow, FRelaColInfos)
  619. else
  620. ExportRecord(RelaRec, AXlsPage, iRow, FColInfos);
  621. Inc(iRow);
  622. end;
  623. end;
  624. end;
  625. end;
  626. procedure TMasterExcelExportor.ExportRecord(ARec: TsdDataRecord;
  627. AXlsPage: TXlsCustomPage; ARow: Integer; AColInfos: PColInfos);
  628. function ExportCell(ACol, ARow: Integer; AValue: Variant): TXlsCustomCell;
  629. begin
  630. Result := nil;
  631. // -----------
  632. if VarIsNull(AValue) then Exit;
  633. // -----------
  634. // 当数据超过3w3k行时,运行至某行时,AddCell会内存溢出
  635. // 可能是Cell的数目超过某个限度时,报错
  636. // 如果AValue为Null时不AddCell,则3w3k行可以安全度过
  637. case VarType(AValue) of
  638. varSmallInt, varInteger, varSingle, varDouble,
  639. varCurrency, varShortInt, varByte, varWord,
  640. varLongWord, varInt64:
  641. begin
  642. if AValue <> 0 then
  643. Result := AXlsPage.AddCell(ACol, ARow, AValue);
  644. end
  645. else Result := AXlsPage.AddCell(ACol, ARow, AValue);
  646. end;
  647. end;
  648. var
  649. iCol: Integer;
  650. ColInfo: TColInfo;
  651. XlsCell: TXlsCustomCell;
  652. sStr: string;
  653. begin
  654. if not Assigned(ARec) then Exit;
  655. for iCol := 0 to FColCount - 1 do
  656. begin
  657. ColInfo := AColInfos[iCol];
  658. XlsCell := ExportCell(iCol, ARow, GetCellValue(ARec, ColInfo));
  659. if Assigned(XlsCell) then
  660. begin
  661. XlsCell.HTextAlign := ColInfo.HorTextAlign;
  662. XlsCell.Font.Name := 'SmartSimSun';
  663. XlsCell.Font.Size := 9;
  664. end;
  665. end;
  666. end;
  667. procedure TMasterExcelExportor.ExportToFile(const AFileName: string);
  668. begin
  669. if not Assigned(FMasterDataSet) then Exit;
  670. BeforeExport;
  671. try
  672. ExportToXlsPage(FXlsOutPut.AddPage);
  673. FXlsOutPut.SaveToFile(FTempFile);
  674. if not FileExists(AFileName) or QuestMessage('存在同名文件,是否替换?') then
  675. CopyFile(PChar(FTempFile), PChar(AFileName), False);
  676. finally
  677. EndExport;
  678. end;
  679. end;
  680. procedure TMasterExcelExportor.ExportToXlsPage(AXlsPage: TXlsCustomPage);
  681. begin
  682. if not Assigned(FMasterDataSet) then Exit;
  683. DefineHeader(AXlsPage);
  684. ExportData(AXlsPage);
  685. end;
  686. function TMasterExcelExportor.GetCellValue(ARec: TsdDataRecord;
  687. ColInfo: TColInfo): Variant;
  688. var
  689. Value: TsdValue;
  690. begin
  691. Result := '';
  692. if Assigned(ARec) then
  693. begin
  694. Value := ARec.ValueByName(ColInfo.FieldName);
  695. if Assigned(Value) then
  696. Result := Value.AsVariant;
  697. end;
  698. end;
  699. end.