ExcelHelper.cs 89 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Reflection;
  8. using System.Runtime.CompilerServices;
  9. using System.Security.Cryptography;
  10. using System.Text;
  11. using System.Text.RegularExpressions;
  12. using IwbZero.ToolCommon.LogHelpers;
  13. using NPOI.HSSF.UserModel;
  14. using NPOI.HSSF.Util;
  15. using NPOI.SS.UserModel;
  16. using NPOI.SS.Util;
  17. using NPOI.XSSF.UserModel;
  18. namespace IwbZero.ToolCommon.FileHelpers
  19. {
  20. public static class ExcelHelper
  21. {
  22. #region Excel导入
  23. /// <summary>
  24. /// 从Excel取数据并记录到List集合里
  25. /// </summary>
  26. /// <param name="cellHeader">单元头的值和名称:{ { "UserName", "姓名" }, { "Age", "年龄" } };</param>
  27. /// <param name="filePath">保存文件绝对路径</param>
  28. /// <param name="errMsg">错误信息</param>
  29. /// <param name="startIndex">数据行开始序列,默认为1(即第二列,从0开始)</param>
  30. /// <returns>转换后的List对象集合</returns>
  31. public static List<T> ExcelToEntityList<T>(this Dictionary<string, string> cellHeader, string filePath, out string errMsg, int startIndex = 1) where T : new()
  32. {
  33. List<T> enlist = new List<T>();
  34. var errorMsg = new StringBuilder();
  35. try
  36. {
  37. if (Regex.IsMatch(filePath, ".xls$")) // 2003
  38. {
  39. enlist = Excel2003ToEntityList<T>(cellHeader, filePath, out errorMsg, startIndex);
  40. }
  41. else if (Regex.IsMatch(filePath, ".xlsx$")) // 2007
  42. {
  43. enlist = Excel2007ToEntityList<T>(cellHeader, filePath, out errorMsg, startIndex);
  44. }
  45. }
  46. catch (Exception ex)
  47. {
  48. errMsg = ex.Message;
  49. typeof(ExcelHelper).LogError(ex);
  50. return default(List<T>);
  51. }
  52. errMsg = errorMsg.ToString();
  53. return enlist;
  54. }
  55. /// <summary>
  56. /// 从Excel2003取数据并记录到List集合里
  57. /// </summary>
  58. /// <param name="cellHeader">单元头的Key和Value:{ { "UserName", "姓名" }, { "Age", "年龄" } };</param>
  59. /// <param name="filePath">保存文件绝对路径</param>
  60. /// <param name="errorMsg">错误信息</param>
  61. /// <param name="startIndex"></param>
  62. /// <returns>转换好的List对象集合</returns>
  63. private static List<T> Excel2003ToEntityList<T>(this Dictionary<string, string> cellHeader, string filePath, out StringBuilder errorMsg, int startIndex = 1) where T : new()
  64. {
  65. errorMsg = new StringBuilder(); // 错误信息,Excel转换到实体对象时,会有格式的错误信息
  66. List<T> enlist = new List<T>(); // 转换后的集合
  67. try
  68. {
  69. using (FileStream fs = File.OpenRead(filePath))
  70. {
  71. HSSFWorkbook workbook = new HSSFWorkbook(fs);
  72. HSSFSheet sheet = (HSSFSheet)workbook.GetSheetAt(0); // 获取此文件第一个Sheet页
  73. for (int rowIndex = startIndex; rowIndex <= sheet.LastRowNum; rowIndex++)
  74. {
  75. // 1.判断当前行是否空行,若空行就不在进行读取下一行操作,结束Excel读取操作
  76. IRow row = sheet.GetRow(rowIndex);
  77. if (row == null)
  78. {
  79. break;
  80. }
  81. // 2.每一个Excel row转换为一个实体对象
  82. T en = new T();
  83. ExcelRowToEntity(cellHeader, row, rowIndex, en, ref errorMsg);
  84. enlist.Add(en);
  85. }
  86. }
  87. return enlist;
  88. }
  89. catch (Exception ex)
  90. {
  91. typeof(ExcelHelper).LogError(ex);
  92. return default(List<T>);
  93. }
  94. }
  95. /// <summary>
  96. /// 从Excel2007取数据并记录到List集合里
  97. /// </summary>
  98. /// <param name="cellHeader">单元头的Key和Value:{ { "UserName", "姓名" }, { "Age", "年龄" } };</param>
  99. /// <param name="filePath">保存文件绝对路径</param>
  100. /// <param name="errorMsg">错误信息</param>
  101. /// <param name="startIndex">数据行开始序列,默认为1(即第二列,从0开始)</param>
  102. /// <returns>转换好的List对象集合</returns>
  103. private static List<T> Excel2007ToEntityList<T>(this Dictionary<string, string> cellHeader, string filePath, out StringBuilder errorMsg, int startIndex = 1)
  104. where T : new()
  105. {
  106. errorMsg = new StringBuilder(); // 错误信息,Excel转换到实体对象时,会有格式的错误信息
  107. List<T> enlist = new List<T>(); // 转换后的集合
  108. try
  109. {
  110. using (FileStream fs = File.OpenRead(filePath))
  111. {
  112. XSSFWorkbook workbook = new XSSFWorkbook(fs);
  113. XSSFSheet sheet = (XSSFSheet)workbook.GetSheetAt(0); // 获取此文件第一个Sheet页
  114. for (int rowIndex = startIndex; rowIndex <= sheet.LastRowNum; rowIndex++)
  115. {
  116. // 1.判断当前行是否空行,若空行就不在进行读取下一行操作,结束Excel读取操作
  117. IRow row = sheet.GetRow(rowIndex);
  118. if (row == null)
  119. {
  120. break;
  121. }
  122. // 2.每一个Excel row转换为一个实体对象
  123. T en = new T();
  124. ExcelRowToEntity(cellHeader, row, rowIndex, en, ref errorMsg);
  125. enlist.Add(en);
  126. }
  127. }
  128. return enlist;
  129. }
  130. catch (Exception ex)
  131. {
  132. typeof(ExcelHelper).LogError(ex);
  133. return default(List<T>);
  134. }
  135. }
  136. #endregion Excel导入
  137. #region Excel导出
  138. /// <summary>
  139. /// 实体类集合导出到EXCEL2003
  140. /// </summary>
  141. /// <param name="cellHeader">单元头的Key和Value:{ { "UserName", "姓名" }, { "Age", "年龄" } };</param>
  142. /// <param name="enList">数据源</param>
  143. /// <param name="sheetName">工作表名称</param>
  144. /// <param name="filePath">文件的下载地址</param>
  145. /// <returns></returns>
  146. public static string EntityListToExcel2003(this Dictionary<string, string> cellHeader, IList enList, string sheetName, string filePath)
  147. {
  148. var lcRetVal = "error@";
  149. try
  150. {
  151. string fileName = $"D-{sheetName}-{DateTime.Now:yyyyMMddHHmmssfff}.xls"; // 文件名称
  152. filePath = filePath.StartsWith("/") ? filePath : ("/" + filePath);
  153. filePath = filePath.EndsWith("/") ? filePath : (filePath + "/");
  154. string path = $"{AppDomain.CurrentDomain.BaseDirectory}{filePath}";
  155. if (!Directory.Exists(path))
  156. Directory.CreateDirectory(path);
  157. // 2.解析单元格头部,设置单元头的中文名称
  158. HSSFWorkbook workbook = new HSSFWorkbook(); // 工作簿
  159. ISheet sheet = workbook.CreateSheet(sheetName); // 工作表
  160. IRow row = sheet.CreateRow(0);
  161. List<string> keys = cellHeader.Keys.ToList();
  162. for (int i = 0; i < keys.Count; i++)
  163. {
  164. row.CreateCell(i).SetCellValue(cellHeader[keys[i]]); // 列名为Key的值
  165. }
  166. // 3.List对象的值赋值到Excel的单元格里
  167. int rowIndex = 1; // 从第二行开始赋值(第一行已设置为单元头)
  168. object propertyValue = null;
  169. foreach (var en in enList)
  170. {
  171. IRow rowTmp = sheet.CreateRow(rowIndex);
  172. for (int i = 0; i < keys.Count; i++) // 根据指定的属性名称,获取对象指定属性的值
  173. {
  174. string cellValue = "";
  175. PropertyInfo propertyInfo = null; // 属性的信息
  176. // 3.1 若属性头的名称包含'.',就表示是子类里的属性,那么就要遍历子类,eg:UserEn.UserName
  177. string[] propertyArray = keys[i].Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
  178. if (keys[i].IndexOf(".", StringComparison.Ordinal) >= 0)
  179. {
  180. // 3.1.1 解析子类属性(这里只解析1层子类,多层子类未处理)
  181. string subClassName = propertyArray[0]; // '.'前面的为子类的名称
  182. string subClassPropertyName = propertyArray[1]; // '.'后面的为子类的属性名称
  183. PropertyInfo subClassInfo = en.GetType().GetProperty(subClassName); // 获取子类的类型
  184. if (subClassInfo != null)
  185. {
  186. // 3.1.2 获取子类的实例
  187. var subClassEn = en.GetType().GetProperty(subClassName)?.GetValue(en, null);
  188. // 3.1.3 根据属性名称获取子类里的属性类型
  189. propertyInfo = subClassInfo.PropertyType.GetProperty(subClassPropertyName);
  190. if (propertyInfo != null)
  191. {
  192. propertyValue = propertyInfo.GetValue(subClassEn, null); // 获取子类属性的值
  193. }
  194. }
  195. }
  196. else
  197. {
  198. // 3.2 若不是子类的属性,直接根据属性名称获取对象对应的属性
  199. propertyInfo = en.GetType().GetProperty(keys[i]);
  200. if (propertyInfo != null)
  201. {
  202. propertyValue = propertyInfo.GetValue(en, null);
  203. }
  204. }
  205. // 3.3 属性值经过转换赋值给单元格值
  206. if (propertyValue != null)
  207. {
  208. if (propertyInfo?.PropertyType.Name == "int" || propertyInfo?.PropertyType.Name == "float" || propertyInfo?.PropertyType.Name == "double" || propertyInfo?.PropertyType.Name == "decimal")
  209. {
  210. var value = Convert.ToDouble(propertyValue);
  211. rowTmp.CreateCell(i).SetCellValue(value);
  212. }
  213. else if (propertyInfo?.PropertyType.Name == "bool")
  214. {
  215. var value = Convert.ToBoolean(propertyValue);
  216. rowTmp.CreateCell(i).SetCellValue(value);
  217. }
  218. else
  219. {
  220. cellValue = propertyValue.ToString();
  221. // 3.3.1 对时间初始值赋值为空
  222. if (cellValue.Trim() == "0001/1/1 0:00:00" || cellValue.Trim() == "0001/1/1 23:59:59")
  223. {
  224. cellValue = "";
  225. }
  226. // 3.4 填充到Excel的单元格里
  227. rowTmp.CreateCell(i).SetCellValue(cellValue);
  228. }
  229. }
  230. else
  231. {
  232. // 3.4 填充到Excel的单元格里
  233. rowTmp.CreateCell(i).SetCellValue(cellValue);
  234. }
  235. }
  236. rowIndex++;
  237. }
  238. // 4.生成文件
  239. FileStream file = new FileStream($"{path}{fileName}", FileMode.Create);
  240. workbook.Write(file);
  241. file.Close();
  242. lcRetVal = $"{filePath}{fileName}";
  243. }
  244. catch (Exception ex)
  245. {
  246. lcRetVal += ex.Message;
  247. typeof(ExcelHelper).LogError(ex);
  248. }
  249. return lcRetVal;
  250. }
  251. public static string EntityListToExcel2003(this HSSFWorkbook workbook,
  252. string sheetName, string filePath)
  253. {
  254. var lcRetVal = "error@";
  255. try
  256. {
  257. string fileName = $"D-{sheetName}-{DateTime.Now:yyyyMMddHHmmssfff}.xls"; // 文件名称
  258. filePath = filePath.StartsWith("/") ? filePath : ("/" + filePath);
  259. filePath = filePath.EndsWith("/") ? filePath : (filePath + "/");
  260. string path = $"{AppDomain.CurrentDomain.BaseDirectory}{filePath}";
  261. if (!Directory.Exists(path))
  262. Directory.CreateDirectory(path);
  263. FileStream file = new FileStream($"{path}{fileName}", FileMode.Create);
  264. workbook.Write(file);
  265. file.Close();
  266. lcRetVal = $"{filePath}{fileName}";
  267. }
  268. catch (Exception ex)
  269. {
  270. lcRetVal += ex.Message;
  271. typeof(ExcelHelper).LogError(ex);
  272. }
  273. return lcRetVal;
  274. }
  275. public static HSSFWorkbook EntityListToExcel2003Book(this Dictionary<string, string> cellHeader, IList enList,
  276. string sheetName)
  277. {
  278. HSSFWorkbook workbook = new HSSFWorkbook(); // 工作簿
  279. ISheet sheet = workbook.CreateSheet(sheetName); // 工作表
  280. IRow row = sheet.CreateRow(0);
  281. List<string> keys = cellHeader.Keys.ToList();
  282. for (int i = 0; i < keys.Count; i++)
  283. {
  284. row.CreateCell(i).SetCellValue(cellHeader[keys[i]]); // 列名为Key的值
  285. }
  286. // 3.List对象的值赋值到Excel的单元格里
  287. int rowIndex = 1; // 从第二行开始赋值(第一行已设置为单元头)
  288. foreach (var en in enList)
  289. {
  290. IRow rowTmp = sheet.CreateRow(rowIndex);
  291. for (int i = 0; i < keys.Count; i++) // 根据指定的属性名称,获取对象指定属性的值
  292. {
  293. string cellValue = ""; // 单元格的值
  294. object propertyValue = null; // 属性的值
  295. PropertyInfo propertyInfo; // 属性的信息
  296. // 3.1 若属性头的名称包含'.',就表示是子类里的属性,那么就要遍历子类,eg:UserEn.UserName
  297. if (keys[i].IndexOf(".", StringComparison.Ordinal) >= 0)
  298. {
  299. // 3.1.1 解析子类属性(这里只解析1层子类,多层子类未处理)
  300. string[] propertyArray = keys[i].Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
  301. string subClassName = propertyArray[0]; // '.'前面的为子类的名称
  302. string subClassPropertyName = propertyArray[1]; // '.'后面的为子类的属性名称
  303. PropertyInfo subClassInfo = en.GetType().GetProperty(subClassName); // 获取子类的类型
  304. if (subClassInfo != null)
  305. {
  306. // 3.1.2 获取子类的实例
  307. var subClassEn = en.GetType().GetProperty(subClassName)?.GetValue(en, null);
  308. // 3.1.3 根据属性名称获取子类里的属性类型
  309. propertyInfo = subClassInfo.PropertyType.GetProperty(subClassPropertyName);
  310. if (propertyInfo != null)
  311. {
  312. propertyValue = propertyInfo.GetValue(subClassEn, null); // 获取子类属性的值
  313. }
  314. }
  315. }
  316. else
  317. {
  318. // 3.2 若不是子类的属性,直接根据属性名称获取对象对应的属性
  319. propertyInfo = en.GetType().GetProperty(keys[i]);
  320. if (propertyInfo != null)
  321. {
  322. propertyValue = propertyInfo.GetValue(en, null);
  323. }
  324. }
  325. // 3.3 属性值经过转换赋值给单元格值
  326. if (propertyValue != null)
  327. {
  328. cellValue = propertyValue.ToString();
  329. // 3.3.1 对时间初始值赋值为空
  330. if (cellValue.Trim() == "0001/1/1 0:00:00" || cellValue.Trim() == "0001/1/1 23:59:59")
  331. {
  332. cellValue = "";
  333. }
  334. }
  335. // 3.4 填充到Excel的单元格里
  336. rowTmp.CreateCell(i).SetCellValue(cellValue);
  337. }
  338. rowIndex++;
  339. }
  340. return workbook;
  341. }
  342. /// <summary>
  343. /// 实体类集合导出到EXCEL2007
  344. /// </summary>
  345. /// <param name="cellHeader">单元头的Key和Value:{ { "UserName", "姓名" }, { "Age", "年龄" } };</param>
  346. /// <param name="enList">数据源</param>
  347. /// <param name="sheetName">工作表名称</param>
  348. /// <param name="filePath">文件的下载地址</param>
  349. /// <returns></returns>
  350. public static string EntityListToExcel2007(this Dictionary<string, string> cellHeader, IList enList, string sheetName, string filePath)
  351. {
  352. var lcRetVal = "error@";
  353. try
  354. {
  355. string fileName = $"D-{sheetName}-{DateTime.Now:yyyyMMddHHmmssfff}.xlsx"; // 文件名称
  356. filePath = filePath.StartsWith("/") ? filePath : ("/" + filePath);
  357. filePath = filePath.EndsWith("/") ? filePath : (filePath + "/");
  358. string path = $"{AppDomain.CurrentDomain.BaseDirectory}{filePath}";
  359. if (!Directory.Exists(path))
  360. Directory.CreateDirectory(path);
  361. // 2.解析单元格头部,设置单元头的中文名称
  362. XSSFWorkbook workbook = new XSSFWorkbook(); // 工作簿
  363. ISheet sheet = workbook.CreateSheet(sheetName); // 工作表
  364. IRow row = sheet.CreateRow(0);
  365. List<string> keys = cellHeader.Keys.ToList();
  366. for (int i = 0; i < keys.Count; i++)
  367. {
  368. row.CreateCell(i).SetCellValue(cellHeader[keys[i]]); // 列名为Key的值
  369. }
  370. // 3.List对象的值赋值到Excel的单元格里
  371. int rowIndex = 1; // 从第二行开始赋值(第一行已设置为单元头)
  372. foreach (var en in enList)
  373. {
  374. IRow rowTmp = sheet.CreateRow(rowIndex);
  375. for (int i = 0; i < keys.Count; i++) // 根据指定的属性名称,获取对象指定属性的值
  376. {
  377. string cellValue = ""; // 单元格的值
  378. object propertyValue = null; // 属性的值
  379. PropertyInfo propertyInfo = null; // 属性的信息
  380. // 3.1 若属性头的名称包含'.',就表示是子类里的属性,那么就要遍历子类,eg:UserEn.UserName
  381. if (keys[i].IndexOf(".", StringComparison.Ordinal) >= 0)
  382. {
  383. // 3.1.1 解析子类属性(这里只解析1层子类,多层子类未处理)
  384. string[] propertyArray = keys[i].Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
  385. string subClassName = propertyArray[0]; // '.'前面的为子类的名称
  386. var subClassPropertyName = propertyArray[1]; // '.'后面的为子类的属性名称
  387. PropertyInfo subClassInfo = en.GetType().GetProperty(subClassName); // 获取子类的类型
  388. if (subClassInfo != null)
  389. {
  390. // 3.1.2 获取子类的实例
  391. var subClassEn = en.GetType().GetProperty(subClassName)?.GetValue(en, null);
  392. // 3.1.3 根据属性名称获取子类里的属性类型
  393. propertyInfo = subClassInfo.PropertyType.GetProperty(subClassPropertyName);
  394. if (propertyInfo != null)
  395. {
  396. propertyValue = propertyInfo.GetValue(subClassEn, null); // 获取子类属性的值
  397. }
  398. }
  399. }
  400. else
  401. {
  402. // 3.2 若不是子类的属性,直接根据属性名称获取对象对应的属性
  403. propertyInfo = en.GetType().GetProperty(keys[i]);
  404. if (propertyInfo != null)
  405. {
  406. propertyValue = propertyInfo.GetValue(en, null);
  407. }
  408. }
  409. // 3.3 属性值经过转换赋值给单元格值
  410. if (propertyValue != null)
  411. {
  412. if (propertyInfo.PropertyType.Name.ToLower() == "int" || propertyInfo.PropertyType.Name.ToLower() == "int16" || propertyInfo.PropertyType.Name.ToLower() == "int32" || propertyInfo.PropertyType.Name.ToLower() == "int64" || propertyInfo.PropertyType.Name.ToLower() == "double" || propertyInfo.PropertyType.Name.ToLower() == "decimal")
  413. {
  414. var value = Convert.ToDouble(propertyValue);
  415. rowTmp.CreateCell(i).SetCellValue(value);
  416. }
  417. else if (propertyInfo.PropertyType.Name.ToLower() == "bool")
  418. {
  419. var value = Convert.ToBoolean(propertyValue);
  420. rowTmp.CreateCell(i).SetCellValue(value);
  421. }
  422. else if (propertyInfo.PropertyType.Name.ToLower() == "nullable`1")
  423. {
  424. if (propertyInfo.PropertyType.FullName == null)
  425. {
  426. }
  427. else if (propertyInfo.PropertyType.FullName.ToLower().Contains("datetime"))
  428. {
  429. cellValue = propertyValue.ToString();
  430. // 3.3.1 对时间初始值赋值为空
  431. if (cellValue.Trim() == "0001/1/1 0:00:00" || cellValue.Trim() == "0001/1/1 23:59:59")
  432. {
  433. cellValue = "";
  434. }
  435. rowTmp.CreateCell(i).SetCellValue(cellValue);
  436. }
  437. else if (propertyInfo.PropertyType.FullName.ToLower().Contains("int"))
  438. {
  439. var value = (int)Convert.ChangeType(propertyValue, typeof(int));
  440. rowTmp.CreateCell(i).SetCellValue(value);
  441. }
  442. else if (propertyInfo.PropertyType.FullName.ToLower().Contains("float") || propertyInfo.PropertyType.FullName.ToLower().Contains("double") || propertyInfo.PropertyType.FullName.ToLower().Contains("decimal") || propertyInfo.PropertyType.FullName.ToLower().Contains("single"))
  443. {
  444. var value = (float)Convert.ChangeType(propertyValue, typeof(float));
  445. rowTmp.CreateCell(i).SetCellValue(value);
  446. }
  447. else if (propertyInfo.PropertyType.FullName.ToLower().Contains("bool"))
  448. {
  449. var value = (bool)Convert.ChangeType(propertyValue, typeof(bool));
  450. rowTmp.CreateCell(i).SetCellValue(value);
  451. }
  452. }
  453. else
  454. {
  455. cellValue = propertyValue.ToString();
  456. // 3.3.1 对时间初始值赋值为空
  457. if (cellValue.Trim() == "0001/1/1 0:00:00" || cellValue.Trim() == "0001/1/1 23:59:59")
  458. {
  459. cellValue = "";
  460. }
  461. // 3.4 填充到Excel的单元格里
  462. rowTmp.CreateCell(i).SetCellValue(cellValue);
  463. }
  464. }
  465. else
  466. {
  467. // 3.4 填充到Excel的单元格里
  468. rowTmp.CreateCell(i).SetCellValue(cellValue);
  469. }
  470. }
  471. rowIndex++;
  472. }
  473. // 4.生成文件
  474. FileStream file = new FileStream($"{path}{fileName}", FileMode.Create);
  475. workbook.Write(file);
  476. file.Close();
  477. lcRetVal = $"{filePath}{fileName}";
  478. }
  479. catch (Exception ex)
  480. {
  481. lcRetVal += ex.Message;
  482. typeof(ExcelHelper).LogError(ex);
  483. }
  484. return lcRetVal;
  485. }
  486. #endregion Excel导出
  487. #region Common
  488. /// <summary>
  489. /// Excel row转换为实体对象
  490. /// </summary>
  491. /// <typeparam name="T"></typeparam>
  492. /// <param name="cellHeader">单元头的Key和Value:{ { "UserName", "姓名" }, { "Age", "年龄" } };</param>
  493. /// <param name="row">Excel row</param>
  494. /// <param name="rowIndex">row index</param>
  495. /// <param name="en">实体</param>
  496. /// <param name="errorMsg">错误信息</param>
  497. private static void ExcelRowToEntity<T>(Dictionary<string, string> cellHeader, IRow row, int rowIndex, T en, ref StringBuilder errorMsg)
  498. {
  499. List<string> keys = cellHeader.Keys.ToList(); // 要赋值的实体对象属性名称
  500. string errStr = ""; // 当前行转换时,是否有错误信息,格式为:第1行数据转换异常:XXX列;
  501. for (int i = 0; i < keys.Count; i++)
  502. {
  503. // 1.若属性头的名称包含'.',就表示是子类里的属性,那么就要遍历子类,eg:UserEn.TrueName
  504. if (keys[i].IndexOf(".", StringComparison.Ordinal) >= 0)
  505. {
  506. // 1)解析子类属性
  507. string[] propertyArray = keys[i].Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
  508. string subClassName = propertyArray[0]; // '.'前面的为子类的名称
  509. string classPropertyName = propertyArray[1]; // '.'后面的为子类的属性名称
  510. PropertyInfo subClassInfo = en.GetType().GetProperty(subClassName); // 获取子类的类型
  511. if (subClassInfo != null)
  512. {
  513. // 2)获取子类的实例
  514. var subClassEn = en.GetType().GetProperty(subClassName)?.GetValue(en, null);
  515. // 3)根据属性名称获取子类里的属性信息
  516. PropertyInfo propertyInfo = subClassInfo.PropertyType.GetProperty(classPropertyName);
  517. if (propertyInfo != null)
  518. {
  519. try
  520. {
  521. // Excel单元格的值转换为对象属性的值,若类型不对,记录出错信息
  522. propertyInfo.SetValue(subClassEn, GetExcelCellToProperty(propertyInfo.PropertyType, row.GetCell(i)), null);
  523. }
  524. catch (Exception e)
  525. {
  526. typeof(ExcelHelper).LogError(e);
  527. if (errStr.Length == 0)
  528. {
  529. errStr = "第" + rowIndex + "行数据转换异常:";
  530. }
  531. errStr += cellHeader[keys[i]] + "列;";
  532. }
  533. }
  534. }
  535. }
  536. else
  537. {
  538. // 2.给指定的属性赋值
  539. PropertyInfo propertyInfo = en.GetType().GetProperty(keys[i]);
  540. if (propertyInfo != null)
  541. {
  542. try
  543. {
  544. // Excel单元格的值转换为对象属性的值,若类型不对,记录出错信息
  545. propertyInfo.SetValue(en, GetExcelCellToProperty(propertyInfo.PropertyType, row.GetCell(i)), null);
  546. }
  547. catch (Exception e)
  548. {
  549. typeof(ExcelHelper).LogError(e);
  550. if (errStr.Length == 0)
  551. {
  552. errStr = "第" + rowIndex + "行数据转换异常:";
  553. }
  554. errStr += cellHeader[keys[i]] + "列;";
  555. }
  556. }
  557. }
  558. }
  559. // 若有错误信息,就添加到错误信息里
  560. if (errStr.Length > 0)
  561. {
  562. errorMsg.AppendLine(errStr);
  563. }
  564. }
  565. /// <summary>
  566. /// Excel Cell转换为实体的属性值
  567. /// </summary>
  568. /// <param name="distanceType">目标对象类型</param>
  569. /// <param name="sourceCell">对象属性的值</param>
  570. private static object GetExcelCellToProperty(Type distanceType, ICell sourceCell)
  571. {
  572. object rs = distanceType.IsValueType ? Activator.CreateInstance(distanceType) : null;
  573. // 1.判断传递的单元格是否为空
  574. if (sourceCell == null || string.IsNullOrEmpty(sourceCell.ToString()))
  575. {
  576. return rs;
  577. }
  578. // 2.Excel文本和数字单元格转换,在Excel里文本和数字是不能进行转换,所以这里预先存值
  579. object sourceValue = null;
  580. switch (sourceCell.CellType)
  581. {
  582. case CellType.Blank:
  583. break;
  584. case CellType.Boolean:
  585. sourceValue = sourceCell.BooleanCellValue;
  586. break;
  587. case CellType.Error:
  588. break;
  589. case CellType.Formula:
  590. break;
  591. case CellType.Numeric:
  592. sourceValue = sourceCell.NumericCellValue;
  593. break;
  594. case CellType.String:
  595. sourceValue = sourceCell.StringCellValue;
  596. break;
  597. case CellType.Unknown:
  598. break;
  599. default:
  600. sourceValue = sourceCell.StringCellValue;
  601. break;
  602. }
  603. string valueDataType = distanceType.Name;
  604. // 在这里进行特定类型的处理
  605. switch (valueDataType.ToLower()) // 以防出错,全部小写
  606. {
  607. case "string":
  608. rs = sourceValue?.ToString();
  609. break;
  610. case "int":
  611. case "int32":
  612. rs = (int)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  613. break;
  614. case "int16":
  615. rs = (short)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  616. break;
  617. case "int64":
  618. rs = (long)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  619. break;
  620. case "float":
  621. case "single":
  622. rs = (float)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  623. break;
  624. case "double":
  625. rs = (double)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  626. break;
  627. case "decimal":
  628. rs = (decimal)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  629. break;
  630. case "datetime":
  631. rs = (DateTime)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  632. break;
  633. case "guid":
  634. rs = (Guid)Convert.ChangeType(sourceValue?.ToString() ?? "", distanceType);
  635. break;
  636. case "nullable`1":
  637. if (distanceType.FullName == null)
  638. {
  639. rs = "";
  640. }
  641. else if (distanceType.FullName.ToLower().Contains("datetime"))
  642. {
  643. rs = (DateTime)Convert.ChangeType(sourceValue?.ToString() ?? "", typeof(DateTime));
  644. }
  645. else if ((bool)distanceType.FullName?.ToLower().Contains("int"))
  646. {
  647. rs = (int)Convert.ChangeType(sourceValue?.ToString() ?? "", typeof(int));
  648. }
  649. else if ((bool)distanceType.FullName?.ToLower().Contains("float") || (bool)distanceType.FullName?.ToLower().Contains("double") || (bool)distanceType.FullName?.ToLower().Contains("decimal") || (bool)distanceType.FullName?.ToLower().Contains("single"))
  650. {
  651. rs = (float)Convert.ChangeType(sourceValue?.ToString() ?? "", typeof(float));
  652. }
  653. else if ((bool)distanceType.FullName?.ToLower().Contains("bool"))
  654. {
  655. rs = (bool)Convert.ChangeType(sourceValue?.ToString() ?? "", typeof(bool));
  656. }
  657. break;
  658. }
  659. return rs;
  660. }
  661. #endregion Common
  662. public static IWorkbook CreateWorkBook(string filePath = "")
  663. {
  664. return filePath.ToLower().EndsWith(".xlsx") ? CreateWorkBook07(filePath) :
  665. filePath.ToLower().EndsWith(".xls") ? (IWorkbook)CreateWorkBook03(filePath) : new XSSFWorkbook();
  666. }
  667. public static HSSFWorkbook CreateWorkBook03(string filePath = null)
  668. {
  669. if (string.IsNullOrEmpty(filePath))
  670. {
  671. return new HSSFWorkbook();
  672. }
  673. FileStream file = new FileStream(filePath, FileMode.Open);
  674. return new HSSFWorkbook(file);
  675. }
  676. public static XSSFWorkbook CreateWorkBook07(string filePath = null)
  677. {
  678. if (string.IsNullOrEmpty(filePath))
  679. {
  680. return new XSSFWorkbook();
  681. }
  682. return new XSSFWorkbook(filePath);
  683. }
  684. /// <summary>
  685. /// 创建Sheet
  686. /// </summary>
  687. /// <param name="sheetName"></param>
  688. /// <param name="defaultWidth"></param>
  689. /// <param name="defaultHeight"></param>
  690. /// <param name="is07"></param>
  691. /// <param name="workbook"></param>
  692. /// <returns></returns>
  693. public static ISheet GenerateSheet(this string sheetName, int defaultWidth = 20, int defaultHeight = 20, bool is07 = true, IWorkbook workbook = null)
  694. {
  695. workbook = is07 ? workbook ?? CreateWorkBook07() : workbook ?? CreateWorkBook03();
  696. var sheet = workbook.CreateSheet(sheetName);
  697. sheet.DefaultColumnWidth = defaultWidth;
  698. sheet.DefaultRowHeight = (short)(defaultHeight * 20);
  699. return sheet;
  700. }
  701. /// <summary>
  702. /// 创建行
  703. /// </summary>
  704. /// <param name="sheet">表</param>
  705. /// <param name="rowIndex">第几行(从1开始计数)</param>
  706. /// <returns></returns>
  707. public static IRow GenerateRow(this ISheet sheet, int rowIndex)
  708. {
  709. rowIndex = rowIndex <= 0 ? 1 : rowIndex;
  710. var row = sheet.GetRow(rowIndex - 1) ?? sheet.CreateRow(rowIndex - 1);
  711. return row;
  712. }
  713. /// <summary>
  714. /// 插入行
  715. /// </summary>
  716. /// <param name="sheet">表</param>
  717. /// <param name="startRow">第几行后开始插入(源行)</param>
  718. /// <param name="count">插入的行数</param>
  719. /// <returns></returns>
  720. public static void InsertRows(this ISheet sheet, int startRow, int count)
  721. {
  722. var rowSource = sheet.GenerateRow(startRow);
  723. sheet.ShiftRows(startRow, sheet.LastRowNum, count, true, false);
  724. if (rowSource == null)
  725. return;
  726. var rowStyle = rowSource.RowStyle;
  727. for (int i = startRow + 1; i <= startRow + count; i++)
  728. {
  729. var rowInsert = sheet.GenerateRow(i);
  730. rowInsert.RowStyle = rowStyle;
  731. rowInsert.Height = rowSource.Height;
  732. for (int col = 1; col <= rowSource.LastCellNum; col++)
  733. {
  734. var cellSource = rowSource.GenerateCell(col);
  735. var cellInsert = rowInsert.GenerateCell(col);
  736. var cellStyle = cellSource.CellStyle;
  737. //设置单元格样式    
  738. if (cellStyle != null)
  739. cellInsert.CellStyle = cellSource.CellStyle;
  740. }
  741. }
  742. }
  743. /// <summary>
  744. /// 创建单元格
  745. /// </summary>
  746. /// <param name="sheet">表</param>
  747. /// <param name="rowIndex">第几行(从1开始计数)</param>
  748. /// <param name="columnIndex">第几列(从1开始计数)</param>
  749. /// <param name="val">值</param>
  750. /// <param name="cellType">单元格类型</param>
  751. /// <returns></returns>
  752. public static ICell GenerateCell(this ISheet sheet, int rowIndex, int columnIndex, string val = null, CellType cellType = CellType.String)
  753. {
  754. var row = sheet.GenerateRow(rowIndex);
  755. var cell = GenerateCell(row, columnIndex, val, cellType);
  756. return cell;
  757. }
  758. /// <summary>
  759. /// 创建单元格
  760. /// </summary>
  761. /// <param name="row">行</param>
  762. /// <param name="columnIndex">第几列(从1开始计数)</param>
  763. /// <param name="val">值</param>
  764. /// <param name="cellType">单元格类型</param>
  765. /// <returns></returns>
  766. public static ICell GenerateCell(this IRow row, int columnIndex, string val = null, CellType cellType = CellType.String)
  767. {
  768. columnIndex = columnIndex <= 0 ? 1 : columnIndex;
  769. var cell = row.GetCell(columnIndex - 1) ?? row.CreateCell(columnIndex - 1);
  770. if (!string.IsNullOrEmpty(val))
  771. {
  772. cell.SetCellValue(val);
  773. cell.SetCellType(cellType);
  774. }
  775. return cell;
  776. }
  777. /// <summary>
  778. /// 设置列宽度
  779. /// </summary>
  780. /// <param name="sheet">表</param>
  781. /// <param name="columnIndex">第几列(从1开始计数)</param>
  782. /// <param name="width">宽度</param>
  783. /// <returns></returns>
  784. public static ISheet SetCellWidth(this ISheet sheet, int columnIndex, int width)
  785. {
  786. sheet.SetColumnWidth(columnIndex - 1, width * 256);
  787. return sheet;
  788. }
  789. /// <summary>
  790. /// 设置列宽度
  791. /// </summary>
  792. /// <param name="row">行</param>
  793. /// <param name="columnIndex">第几列(从1开始计数)</param>
  794. /// <param name="width">宽度</param>
  795. /// <returns></returns>
  796. public static IRow SetCellWidth(this IRow row, int columnIndex, int width)
  797. {
  798. row.Sheet.SetColumnWidth(columnIndex - 1, width * 256);
  799. return row;
  800. }
  801. /// <summary>
  802. /// 设置列宽度
  803. /// </summary>
  804. /// <param name="cell">单元格</param>
  805. /// <param name="columnIndex">第几列(从1开始计数)</param>
  806. /// <param name="width">宽度</param>
  807. /// <returns></returns>
  808. public static ICell SetCellWidth(this ICell cell, int columnIndex, int width)
  809. {
  810. cell.Sheet.SetColumnWidth(columnIndex - 1, width * 256);
  811. return cell;
  812. }
  813. /// <summary>
  814. /// 设置行高度
  815. /// </summary>
  816. /// <param name="sheet">表</param>
  817. /// <param name="rowIndex">第几行(从1开始计数)</param>
  818. /// <param name="height">宽度</param>
  819. /// <returns></returns>
  820. public static ISheet SetRowHeight(this ISheet sheet, int rowIndex, int height)
  821. {
  822. sheet.GetRow(rowIndex - 1).SetRowHeight(height);
  823. return sheet;
  824. }
  825. /// <summary>
  826. /// 设置行高度
  827. /// </summary>
  828. /// <param name="row">行</param>
  829. /// <param name="height">宽度</param>
  830. /// <returns></returns>
  831. public static IRow SetRowHeight(this IRow row, int height)
  832. {
  833. row.Height = (short)(height * 20);
  834. return row;
  835. }
  836. /// <summary>
  837. /// 设置行高度
  838. /// </summary>
  839. /// <param name="cell">单元格</param>
  840. /// <param name="height">宽度</param>
  841. /// <returns></returns>
  842. public static ICell SetRowHeight(this ICell cell, int height)
  843. {
  844. cell.Row.SetRowHeight(height);
  845. return cell;
  846. }
  847. /// <summary>
  848. /// 设置单元格样式
  849. /// </summary>
  850. /// <param name="cell"></param>
  851. /// <param name="styleStr">样式字符串</param>
  852. /// <param name="instants">样式转换器</param>
  853. /// <returns></returns>
  854. public static ICell SetCellCss(this ICell cell, CellStyleCss instants = null, string styleStr = null)
  855. {
  856. instants = instants ?? CellStyleCss.Instants;
  857. return instants.Css(cell, styleStr);
  858. }
  859. /// <summary>
  860. /// 设置单元格的值
  861. /// </summary>
  862. /// <param name="cell"></param>
  863. /// <param name="obj"></param>
  864. /// <returns></returns>
  865. public static ICell SetValue(this ICell cell, string obj)
  866. {
  867. return SetValue<string>(cell, obj);
  868. }
  869. /// <summary>
  870. /// 设置单元格的值
  871. /// </summary>
  872. /// <typeparam name="T">值类型(sting,bool,double,DateTime)</typeparam>
  873. /// <param name="cell"></param>
  874. /// <param name="obj"></param>
  875. /// <returns></returns>
  876. public static ICell SetValue<T>(this ICell cell, object obj)
  877. {
  878. Type type = typeof(T);
  879. if (type == typeof(string))
  880. {
  881. cell.SetCellValue(obj.ToString());
  882. }
  883. else if (type == typeof(bool) && bool.TryParse(obj.ToString(), out var bValue))
  884. {
  885. cell.SetCellValue(bValue);
  886. }
  887. else if ((type == typeof(int) || type == typeof(double) || type == typeof(decimal)) && double.TryParse(obj.ToString(), out var iValue))
  888. {
  889. cell.SetCellValue(iValue);
  890. }
  891. else if (type == typeof(DateTime) && DateTime.TryParse(obj.ToString(), out var dValue))
  892. {
  893. cell.SetCellValue(dValue);
  894. }
  895. return cell;
  896. }
  897. #region DATA-FORMAT
  898. public static ICellStyle SetCellDateTime(this ICell cell, DateTime value, string formatStr = "yyyy-MM-dd HH:mm:ss")
  899. {
  900. cell.SetCellValue(value);
  901. cell.SetDataFormat(formatStr);
  902. return cell.CellStyle;
  903. }
  904. public static ICellStyle SetCellString(this ICell cell, double value, string formatStr = "@")
  905. {
  906. cell.SetCellValue(value);
  907. cell.SetDataFormat(formatStr);
  908. return cell.CellStyle;
  909. }
  910. public static ICellStyle SetCellDouble(this ICell cell, double value, string formatStr = "0.00")
  911. {
  912. cell.SetCellValue(value);
  913. cell.SetDataFormat(formatStr);
  914. return cell.CellStyle;
  915. }
  916. public static ICellStyle SetCellCurrency(this ICell cell, double value, string formatStr = "¥#,###.##")
  917. {
  918. cell.SetCellValue(value);
  919. cell.SetDataFormat(formatStr);
  920. return cell.CellStyle;
  921. }
  922. public static ICellStyle SetCellPercent(this ICell cell, double value, string formatStr = "0.00%")
  923. {
  924. cell.SetCellValue(value);
  925. cell.SetDataFormat(formatStr);
  926. return cell.CellStyle;
  927. }
  928. public static void SetDataFormat(this ICell cell, string formatStr = "¥#,##0.00")
  929. {
  930. var cellStyle = cell.CellStyle ?? GetCellStyle(cell);
  931. var format = cell.Sheet.Workbook.CreateDataFormat();
  932. cellStyle.DataFormat = format.GetFormat(formatStr);
  933. cell.SetCellStyle(cellStyle);
  934. }
  935. #endregion DATA-FORMAT
  936. #region 合并单元格
  937. /// <summary>
  938. /// 合并单元格
  939. /// </summary>
  940. /// <param name="sheet"></param>
  941. /// <param name="firstRow">开始行数(从1开始计数)</param>
  942. /// <param name="lastRow">结束行数(从1开始计数)</param>
  943. /// <param name="firstColumn">开始列数(从1开始计数)</param>
  944. /// <param name="lastColumn">结束列数(从1开始计数)</param>
  945. /// <returns></returns>
  946. public static ISheet MergedRegion(this ISheet sheet, int firstRow, int lastRow, int firstColumn, int lastColumn)
  947. {
  948. var region = GetCellRegion(firstRow, lastRow, firstColumn, lastColumn);
  949. sheet.MergedRegion(region);
  950. return sheet;
  951. }
  952. public static ISheet MergedRegion(this ISheet sheet, CellRangeAddress region)
  953. {
  954. sheet.AddMergedRegion(region);
  955. //SetRegionBorder(sheet, region, borderTypeStr, borderColorStr);
  956. return sheet;
  957. }
  958. public static CellRangeAddress GetCellRegion(this int firstRow, int lastRow, int firstColumn, int lastColumn)
  959. {
  960. firstRow = firstRow <= 0 ? 1 : firstRow;
  961. firstColumn = firstColumn <= 0 ? 1 : firstColumn;
  962. lastRow = lastRow <= 0 ? 1 : lastRow;
  963. lastColumn = lastColumn <= 0 ? 1 : lastColumn;
  964. return new CellRangeAddress(firstRow - 1, lastRow - 1, firstColumn - 1, lastColumn - 1);
  965. }
  966. public static ISheet SetRegionBorder(this CellRangeAddress region, ISheet sheet, string borderTypeStr, string borderColorStr)
  967. {
  968. ICellStyle style = sheet.Workbook.CreateCellStyle();
  969. borderTypeStr = borderTypeStr ?? "Thin";
  970. borderColorStr = borderColorStr ?? "Black";
  971. style.BorderColors(borderColorStr);
  972. style.BorderTypes(borderTypeStr);
  973. for (int i = region.FirstRow; i <= region.LastRow; i++)
  974. {
  975. IRow row = sheet.GenerateRow(i + 1);
  976. if (i == region.FirstRow)
  977. {
  978. }
  979. else if (i == region.LastRow)
  980. {
  981. }
  982. var leftCell = row.GenerateCell(region.FirstColumn + 1);
  983. leftCell.CellStyle.BorderLeft = style.BorderLeft;
  984. leftCell.CellStyle.LeftBorderColor = style.LeftBorderColor;
  985. var rightCell = row.GenerateCell(region.LastColumn + 1);
  986. rightCell.CellStyle.BorderRight = style.BorderRight;
  987. rightCell.CellStyle.RightBorderColor = style.RightBorderColor;
  988. //for (int j = region.FirstColumn; j <= region.LastColumn; j++)
  989. //{
  990. // ICell singleCell = row.GenerateCell((short)j);
  991. //}
  992. }
  993. return sheet;
  994. }
  995. #endregion 合并单元格
  996. public static ICellStyle GetCellStyle(this ICell cell)
  997. {
  998. return cell.CellStyle ?? cell.Sheet.Workbook.CreateCellStyle();
  999. }
  1000. public static void SetCellStyle(this ICell cell, ICellStyle cellStyle)
  1001. {
  1002. cell.CellStyle = cellStyle;
  1003. }
  1004. /// <summary>
  1005. /// 保存工作簿
  1006. /// </summary>
  1007. /// <param name="sheet"></param>
  1008. /// <param name="filePath"></param>
  1009. /// <param name="fileName"></param>
  1010. /// <returns></returns>
  1011. public static string SaveWorkBook(this ISheet sheet, string filePath, string fileName)
  1012. {
  1013. try
  1014. {
  1015. if (!Directory.Exists(filePath))
  1016. {
  1017. Directory.CreateDirectory(filePath);
  1018. }
  1019. filePath = filePath.EndsWith("\\") ? filePath : filePath + "\\";
  1020. FileStream file = new FileStream(filePath + fileName, FileMode.Create);
  1021. sheet.Workbook.Write(file);
  1022. file.Close();
  1023. return "";
  1024. }
  1025. catch (Exception e)
  1026. {
  1027. return e.Message;
  1028. }
  1029. }
  1030. /// <summary>
  1031. /// 保存工作簿
  1032. /// </summary>
  1033. /// <param name="workbook"></param>
  1034. /// <param name="filePath"></param>
  1035. /// <param name="fileName"></param>
  1036. /// <returns></returns>
  1037. public static string SaveWorkBook(this IWorkbook workbook, string filePath, string fileName)
  1038. {
  1039. try
  1040. {
  1041. if (!Directory.Exists(filePath))
  1042. {
  1043. Directory.CreateDirectory(filePath);
  1044. }
  1045. filePath = filePath.EndsWith("\\") ? filePath : filePath + "\\";
  1046. FileStream file = new FileStream(filePath + fileName, FileMode.Create);
  1047. workbook.Write(file);
  1048. file.Close();
  1049. return "";
  1050. }
  1051. catch (Exception e)
  1052. {
  1053. return e.Message;
  1054. }
  1055. }
  1056. }
  1057. public class CellStyleCss
  1058. {
  1059. public static CellStyleCss Instants => new CellStyleCss()
  1060. {
  1061. //缩写
  1062. DefaultStyle = $"bgc:{ColorType.White.ToString()};" +
  1063. $"warp:{HorizontalAlignment.Left.ToString()};" +
  1064. $"align:{HorizontalAlignment.Left.ToString()};" +
  1065. $"v-align:{VerticalAlignment.Center.ToString()};" +
  1066. //$"b:{BorderStyle.None.ToString()};" +
  1067. //$"bc:{ColorType.Black.ToString()};" +
  1068. "inden:0;" +
  1069. "df:@;"
  1070. };
  1071. public void SetDefaultStyle(string styleStr)
  1072. {
  1073. var dic = new SortedDictionary<string, string>();
  1074. DefaultStyle = dic.GetCleanStyle("");
  1075. DefaultStyle = dic.GetCleanStyle(styleStr);
  1076. }
  1077. /// <summary>
  1078. /// 默认样式css
  1079. /// </summary>
  1080. private string DefaultStyle { get; set; }
  1081. //标准写法
  1082. //private static readonly string DefaultFontStyle = "font-color:black;" +
  1083. // "font-name:Arial;" +
  1084. // "font-size:10;" +
  1085. // "font-weight:normal;" +
  1086. // "font-underline:none;" +
  1087. // "font-italic:false;" +
  1088. // "font-strikeout:false;" +
  1089. // "font-superscript:none;"+
  1090. // "background-color:white;"+
  1091. // "text-align:none;"+
  1092. // "vertical-align:none;"+
  1093. // "data-format:none;border-type:Thin";
  1094. /// <summary>
  1095. /// 把css样式设置给单元格
  1096. /// </summary>
  1097. /// <param name="cell"></param>
  1098. /// <param name="styleStr"></param>
  1099. /// <returns></returns>
  1100. public ICell Css(ICell cell, string styleStr = null)
  1101. {
  1102. var dic = new SortedDictionary<string, string>();
  1103. var sortedCss = dic.GetCleanStyle(DefaultStyle);
  1104. if (!string.IsNullOrEmpty(styleStr))
  1105. sortedCss = dic.GetCleanStyle(styleStr);
  1106. var cssKey = $"CellStyle_{sortedCss.Md5()}";
  1107. var workbook = cell.Sheet.Workbook;
  1108. ICellStyle cellStyle = workbook.GetCellStyle(cssKey);
  1109. if (cellStyle == null)
  1110. {
  1111. cellStyle = workbook.GetCellStyle(dic, cell);
  1112. workbook.AttachedCellStyle(cssKey, cellStyle);
  1113. }
  1114. cell.CellStyle = cellStyle;
  1115. //cell.CellStyle = workbook.GetCellStyle(dic, cell);
  1116. return cell;//返回单元格方便流水式编程
  1117. }
  1118. public ICellStyle GetCssStyle(IWorkbook workbook, string styleStr)
  1119. {
  1120. var dic = new SortedDictionary<string, string>();
  1121. var sortedCss = dic.GetCleanStyle(DefaultStyle);
  1122. if (!string.IsNullOrEmpty(styleStr))
  1123. sortedCss = dic.GetCleanStyle(styleStr);
  1124. var cssKey = $"CellStyle_{sortedCss.Md5()}";
  1125. var cellStyle = workbook.GetCellStyle(cssKey);
  1126. if (cellStyle == null)
  1127. {
  1128. cellStyle = workbook.GetCellStyle(dic);
  1129. workbook.AttachedCellStyle(cssKey, cellStyle);
  1130. }
  1131. return cellStyle;
  1132. }
  1133. }
  1134. internal static class CellStyleRender
  1135. {
  1136. #region 解析css样式
  1137. /// <summary>
  1138. /// 默认字体样式
  1139. /// </summary>
  1140. private static string DefaultFontStyle { get; } = $"fc:{ColorType.Black.ToString()};" +//font-color
  1141. "fn:宋体;" +//font-name
  1142. "fs:12;" +//font-size
  1143. "fw:normal;" +//font-weight
  1144. "fu:none;" +//font-underline
  1145. "fi:false;" +//font-italic
  1146. "fst:false;" +//font-strikeout
  1147. "fss:none;";//font-superscript
  1148. #region 设置样式
  1149. /// <summary>
  1150. /// 缓存
  1151. /// </summary>
  1152. private static readonly ConditionalWeakTable<IWorkbook, Dictionary<string, ICellStyle>> Table =
  1153. new ConditionalWeakTable<IWorkbook, Dictionary<string, ICellStyle>>();
  1154. /// <summary>
  1155. /// 获取CellStyle
  1156. /// </summary>
  1157. /// <param name="workbook"></param>
  1158. /// <param name="dic"></param>
  1159. /// <param name="cell"></param>
  1160. /// <returns></returns>
  1161. public static ICellStyle GetCellStyle(this IWorkbook workbook, SortedDictionary<string, string> dic, ICell cell = null)
  1162. {
  1163. ICellStyle cellStyle = workbook.CreateCellStyle();
  1164. //if (cell != null)
  1165. //{
  1166. // cellStyle.CloneStyleFrom(cell.CellStyle);
  1167. //}
  1168. var fontStyles = dic.Where(w => w.Key.StartsWith("font-")).ToArray();
  1169. var fontDic = new SortedDictionary<string, string>();
  1170. foreach (var kv in fontStyles)
  1171. {
  1172. fontDic.Add(kv.Key, kv.Value);
  1173. }
  1174. var font = workbook.GetFont(fontDic);
  1175. cellStyle.SetFont(font);//TODO 在基于style.xls基础的样式上增加css时,会造成原字体设置的丢失
  1176. var xdic = dic.Where(w => !w.Key.StartsWith("font-")).ToArray();
  1177. foreach (var kvp in xdic)
  1178. {
  1179. FireCssAccess(cellStyle, workbook, kvp);
  1180. }
  1181. return cellStyle;
  1182. }
  1183. /// <summary>
  1184. /// 从缓存读取CellStyle
  1185. /// </summary>
  1186. /// <param name="workbook"></param>
  1187. /// <param name="propertyName"></param>
  1188. /// <returns></returns>
  1189. public static ICellStyle GetCellStyle(this IWorkbook workbook, string propertyName)
  1190. {
  1191. if (!Table.TryGetValue(workbook, out var values)) return null;
  1192. if (values.TryGetValue(propertyName, out var temp))
  1193. return temp;
  1194. return null;
  1195. }
  1196. /// <summary>
  1197. /// 缓存CellStyle
  1198. /// </summary>
  1199. /// <param name="workbook"></param>
  1200. /// <param name="propertyName"></param>
  1201. /// <param name="value"></param>
  1202. public static void AttachedCellStyle(this IWorkbook workbook, string propertyName, ICellStyle value)
  1203. {
  1204. if (!Table.TryGetValue(workbook, out var values))
  1205. {
  1206. values = new Dictionary<string, ICellStyle>();
  1207. Table.Add(workbook, values);
  1208. }
  1209. values[propertyName] = value;
  1210. }
  1211. /// <summary>
  1212. /// Md5 key
  1213. /// </summary>
  1214. /// <param name="input"></param>
  1215. /// <returns></returns>
  1216. public static string Md5(this string input)
  1217. {
  1218. if (input == null)
  1219. input = string.Empty;
  1220. byte[] data = Encoding.UTF8.GetBytes(input.Trim().ToLowerInvariant());
  1221. using (var md5 = new MD5CryptoServiceProvider())
  1222. {
  1223. data = md5.ComputeHash(data);
  1224. }
  1225. var ret = new StringBuilder();
  1226. foreach (byte b in data)
  1227. {
  1228. ret.Append(b.ToString("x2").ToLowerInvariant());
  1229. }
  1230. return ret.ToString();
  1231. }
  1232. /// <summary>
  1233. /// 设置不是字体的样式
  1234. /// </summary>
  1235. /// <param name="style"></param>
  1236. /// <param name="workbook"></param>
  1237. /// <param name="kvp"></param>
  1238. private static void FireCssAccess(ICellStyle style, IWorkbook workbook, KeyValuePair<string, string> kvp)
  1239. {
  1240. switch (kvp.Key)
  1241. {
  1242. case "WrapText":
  1243. style.TextWrap(kvp.Value);
  1244. break;
  1245. case "Indention":
  1246. style.TextIndention(kvp.Value);
  1247. break;
  1248. case "text-align":
  1249. style.TextAlign(kvp.Value);
  1250. break;
  1251. case "vertical-align":
  1252. style.VerticalAlign(kvp.Value);
  1253. break;
  1254. case "background-color":
  1255. style.BackgroundColor(kvp.Value);
  1256. break;
  1257. case "border-type":
  1258. style.BorderTypes(kvp.Value);
  1259. break;
  1260. case "top-border-type":
  1261. style.BorderTopTypes(kvp.Value);
  1262. break;
  1263. case "right-border-type":
  1264. style.BorderRightTypes(kvp.Value);
  1265. break;
  1266. case "bottom-border-type":
  1267. style.BorderBottomTypes(kvp.Value);
  1268. break;
  1269. case "left-border-type":
  1270. style.BorderLeftTypes(kvp.Value);
  1271. break;
  1272. case "border-color":
  1273. style.BorderColors(kvp.Value);
  1274. break;
  1275. case "top-border-color":
  1276. style.BorderTopColors(kvp.Value);
  1277. break;
  1278. case "right-border-color":
  1279. style.BorderRightColors(kvp.Value);
  1280. break;
  1281. case "bottom-border-color":
  1282. style.BorderBottomColors(kvp.Value);
  1283. break;
  1284. case "left-border-color":
  1285. style.BorderLeftColors(kvp.Value);
  1286. break;
  1287. case "data-format":
  1288. style.DataFormat(workbook, kvp.Value);
  1289. break;
  1290. }
  1291. }
  1292. /// <summary>
  1293. /// 获取字体样式
  1294. /// </summary>
  1295. /// <param name="workbook"></param>
  1296. /// <param name="fontdic"></param>
  1297. /// <returns></returns>
  1298. private static IFont GetFont(this IWorkbook workbook, SortedDictionary<string, string> fontdic)
  1299. {
  1300. var weight = fontdic.FontWeight();
  1301. var color = fontdic.FontColor();
  1302. var size = fontdic.FontSize();
  1303. var name = fontdic.FontName();
  1304. var underline = fontdic.FontUnderline();
  1305. var italic = fontdic.FontItalic();
  1306. var strikeout = fontdic.FontStrikeout();
  1307. var offset = fontdic.ConvertToSuperScript();
  1308. var findHeight = (short)(size * 20);
  1309. var font = workbook.FindFont(weight, color, findHeight, name, italic, strikeout, offset, underline);
  1310. if (font == null)
  1311. {
  1312. font = workbook.CreateFont();
  1313. font.Boldweight = weight;
  1314. font.Color = color;
  1315. font.FontHeightInPoints = size;
  1316. font.FontName = name;
  1317. font.Underline = underline;
  1318. font.IsItalic = italic;
  1319. font.IsStrikeout = strikeout;
  1320. font.TypeOffset = offset;
  1321. }
  1322. return font;
  1323. }
  1324. #endregion 设置样式
  1325. #region 获取样式
  1326. /// <summary>
  1327. /// 默认设置
  1328. /// </summary>
  1329. /// <param name="dic"></param>
  1330. public static void InitStyleDic(this SortedDictionary<string, string> dic)
  1331. {
  1332. var cssItems = GetCssItems(DefaultFontStyle);
  1333. foreach (var cssitem in cssItems)
  1334. {
  1335. var kvp = GetCssKeyValue(cssitem);
  1336. if (dic.ContainsKey(kvp.Key))
  1337. dic[kvp.Key] = kvp.Value; //覆盖相同key的值
  1338. else
  1339. dic.Add(kvp.Key, kvp.Value);
  1340. }
  1341. }
  1342. /// <summary>
  1343. /// 获取样式简洁字符串
  1344. /// </summary>
  1345. /// <param name="dic"></param>
  1346. /// <param name="style"></param>
  1347. /// <returns></returns>
  1348. public static string GetCleanStyle(this SortedDictionary<string, string> dic, string style)
  1349. {
  1350. style = Regex.Replace(style.Trim(), "\\s+", " ");
  1351. style = Regex.Replace(style, "\\s;\\s", ";");
  1352. style = Regex.Replace(style, "\\s:\\s", ":");
  1353. InitStyleDic(dic);
  1354. var cssItems = GetCssItems(style.TrimEnd(';'));
  1355. foreach (var cssitem in cssItems)
  1356. {
  1357. var kvp = GetCssKeyValue(cssitem);
  1358. if (dic.ContainsKey(kvp.Key))
  1359. dic[kvp.Key] = kvp.Value; //覆盖相同key的值
  1360. else
  1361. dic.Add(kvp.Key, kvp.Value);
  1362. }
  1363. var sortedCss = string.Join(";", dic.Select(s => $"{s.Key}:{s.Value}").ToArray());
  1364. return sortedCss;
  1365. }
  1366. /// <summary>
  1367. /// 获取样式数组
  1368. /// </summary>
  1369. /// <param name="style"></param>
  1370. /// <returns></returns>
  1371. private static string[] GetCssItems(string style)
  1372. {
  1373. var cssItems = Regex.Split(style, ";");
  1374. cssItems = cssItems.Where(w => !string.IsNullOrWhiteSpace(w)).ToArray();
  1375. return cssItems;
  1376. }
  1377. /// <summary>
  1378. /// 获取css样式
  1379. /// </summary>
  1380. /// <param name="css"></param>
  1381. /// <returns></returns>
  1382. private static KeyValuePair<string, string> GetCssKeyValue(string css)
  1383. {
  1384. var cssKeyValueArray = Regex.Split(css, ":").ToArray();
  1385. var cssKey = cssKeyValueArray[0].StandardCssKey();
  1386. var cssValue = cssKey == "font-name" ? cssKeyValueArray[1] : cssKeyValueArray[1].ToUpper(); //字体不应变大写
  1387. var kv = new KeyValuePair<string, string>(cssKey, cssValue);
  1388. return kv;
  1389. }
  1390. #endregion 获取样式
  1391. #region 转换Css的 Key
  1392. /// <summary>
  1393. /// 缩写Key 转换成标准Key
  1394. /// </summary>
  1395. /// <param name="csskey"></param>
  1396. /// <returns></returns>
  1397. private static string StandardCssKey(this string csskey)
  1398. {
  1399. if (CssKeyDic.ContainsKey(csskey))
  1400. {
  1401. var sKey = CssKeyDic[csskey];
  1402. return sKey;
  1403. }
  1404. return csskey;
  1405. }
  1406. /// <summary>
  1407. /// key 转换字典
  1408. /// </summary>
  1409. private static Dictionary<string, string> CssKeyDic => new Dictionary<string, string>
  1410. {
  1411. {"color", "font-color"},
  1412. {"fc", "font-color"},
  1413. {"fw", "font-weight"},
  1414. {"fn", "font-name"},
  1415. {"fs", "font-size"},
  1416. {"italic", "font-italic"},
  1417. {"fi", "font-italic"},
  1418. {"underline", "font-underline"},
  1419. {"fu", "font-underline"},
  1420. {"u", "font-underline"},
  1421. {"deleteline", "font-strikeout"},
  1422. {"d-line", "font-strikeout"},
  1423. {"strikeout", "font-strikeout"},
  1424. {"fst", "font-strikeout"},
  1425. {"d", "font-strikeout"},
  1426. {"font-offset", "font-superscript"},
  1427. {"superscript", "font-superscript"},
  1428. {"fss", "font-superscript"},
  1429. {"ss", "font-superscript"},
  1430. {"bg-color", "background-color"},
  1431. {"bg-c", "background-color"},
  1432. {"bgc", "background-color"},
  1433. {"align", "text-align"},
  1434. {"wrap", "WrapText"},
  1435. {"inden", "Indention"},
  1436. {"in", "Indention"},
  1437. {"v-align", "vertical-align"},
  1438. {"b-t", "border-type"},
  1439. {"b", "border-type"},
  1440. {"bt", "top-border-type"},
  1441. {"br", "right-border-type"},
  1442. {"bb", "bottom-border-type"},
  1443. {"bl", "left-border-type"},
  1444. {"b-c", "border-color"},
  1445. {"bc", "border-color"},
  1446. {"btc", "top-border-color"},
  1447. {"brc", "right-border-color"},
  1448. {"bbc", "bottom-border-color"},
  1449. {"blc", "left-border-color"},
  1450. {"format", "data-format"},
  1451. {"df", "data-format"}
  1452. };
  1453. #endregion 转换Css的 Key
  1454. #region 样式转换
  1455. #region font-weight
  1456. private static short FontWeight(this SortedDictionary<string, string> fontdic)
  1457. {
  1458. switch (fontdic["font-weight"])
  1459. {
  1460. case "NORMAL":
  1461. return 400;
  1462. case "BOLD":
  1463. return 700;
  1464. default:
  1465. return 0;
  1466. }
  1467. }
  1468. #endregion font-weight
  1469. #region font-name
  1470. private static string FontName(this SortedDictionary<string, string> fontdic)
  1471. {
  1472. return fontdic["font-name"];
  1473. }
  1474. #endregion font-name
  1475. #region font-size
  1476. private static short FontSize(this SortedDictionary<string, string> fontdic)
  1477. {
  1478. return short.TryParse(fontdic["font-size"], out var value) ? value : (short)10;
  1479. }
  1480. #endregion font-size
  1481. #region font-color
  1482. private static short FontColor(this SortedDictionary<string, string> fontdic)
  1483. {
  1484. var color = fontdic["font-color"].ConvertToColor();
  1485. return color;
  1486. }
  1487. #endregion font-color
  1488. #region font-italic
  1489. private static bool FontItalic(this SortedDictionary<string, string> fontdic)
  1490. {
  1491. return fontdic["font-italic"] == "TRUE";
  1492. }
  1493. #endregion font-italic
  1494. #region font-strikeout
  1495. /// <summary>
  1496. /// 删除线
  1497. /// </summary>
  1498. /// <param name="fontdic"></param>
  1499. /// <returns></returns>
  1500. private static bool FontStrikeout(this SortedDictionary<string, string> fontdic)
  1501. {
  1502. return fontdic["font-strikeout"] == "TRUE";
  1503. }
  1504. #endregion font-strikeout
  1505. #region WrapText
  1506. private static void TextWrap(this ICellStyle style, string v)
  1507. {
  1508. style.WrapText = v.ToUpper() == "TRUE";
  1509. }
  1510. #endregion WrapText
  1511. #region TextIndention
  1512. /// <summary>
  1513. /// 缩进
  1514. /// </summary>
  1515. /// <param name="style"></param>
  1516. /// <param name="v"></param>
  1517. private static void TextIndention(this ICellStyle style, string v)
  1518. {
  1519. if (short.TryParse(v, out var value))
  1520. {
  1521. style.Indention = value;
  1522. }
  1523. }
  1524. #endregion TextIndention
  1525. #region text-align
  1526. private static void TextAlign(this ICellStyle style, string v)
  1527. {
  1528. style.Alignment = v.ConvertToHorizontalAlignment();
  1529. }
  1530. #endregion text-align
  1531. #region vertical-align
  1532. private static void VerticalAlign(this ICellStyle style, string v)
  1533. {
  1534. style.VerticalAlignment = v.ConvertToVerticalAlignment();
  1535. }
  1536. #endregion vertical-align
  1537. #region boder-type / boder-color
  1538. internal static void BorderTypes(this ICellStyle style, string v)
  1539. {
  1540. if (string.IsNullOrEmpty(v))
  1541. return;
  1542. string[] borderTypeNames = { string.Empty, string.Empty, string.Empty, string.Empty };
  1543. v = v.ToUpper();
  1544. var vs = v.Split(' ');
  1545. switch (vs.Length)
  1546. {
  1547. case 1:
  1548. borderTypeNames[0] = borderTypeNames[1] = borderTypeNames[2] = borderTypeNames[3] = vs[0];
  1549. break;
  1550. case 2:
  1551. borderTypeNames[0] = borderTypeNames[2] = vs[0];
  1552. borderTypeNames[1] = borderTypeNames[3] = vs[1];
  1553. break;
  1554. case 3:
  1555. borderTypeNames[0] = vs[0];
  1556. borderTypeNames[1] = borderTypeNames[3] = vs[1];
  1557. borderTypeNames[2] = vs[2];
  1558. break;
  1559. case 4:
  1560. borderTypeNames[0] = vs[0];
  1561. borderTypeNames[1] = vs[1];
  1562. borderTypeNames[2] = vs[2];
  1563. borderTypeNames[3] = vs[3];
  1564. break;
  1565. }
  1566. var borderTopTypeName = borderTypeNames[0];
  1567. var borderRightTypeName = borderTypeNames[1];
  1568. var borderBottomTypeName = borderTypeNames[2];
  1569. var borderLeftTypeName = borderTypeNames[3];
  1570. if (!string.IsNullOrWhiteSpace(borderTopTypeName))
  1571. style.BorderTop = borderTopTypeName.ConvertToBorderStyle();
  1572. if (!string.IsNullOrWhiteSpace(borderRightTypeName))
  1573. style.BorderRight = borderRightTypeName.ConvertToBorderStyle();
  1574. if (!string.IsNullOrWhiteSpace(borderBottomTypeName))
  1575. style.BorderBottom = borderBottomTypeName.ConvertToBorderStyle();
  1576. if (!string.IsNullOrWhiteSpace(borderLeftTypeName))
  1577. style.BorderLeft = borderLeftTypeName.ConvertToBorderStyle();
  1578. }
  1579. private static void BorderTopTypes(this ICellStyle style, string v)
  1580. {
  1581. if (!string.IsNullOrWhiteSpace(v))
  1582. style.BorderTop = v.ConvertToBorderStyle();
  1583. }
  1584. private static void BorderBottomTypes(this ICellStyle style, string v)
  1585. {
  1586. if (!string.IsNullOrWhiteSpace(v))
  1587. style.BorderBottom = v.ConvertToBorderStyle();
  1588. }
  1589. private static void BorderLeftTypes(this ICellStyle style, string v)
  1590. {
  1591. if (!string.IsNullOrWhiteSpace(v))
  1592. style.BorderLeft = v.ConvertToBorderStyle();
  1593. }
  1594. private static void BorderRightTypes(this ICellStyle style, string v)
  1595. {
  1596. if (!string.IsNullOrWhiteSpace(v))
  1597. style.BorderRight = v.ConvertToBorderStyle();
  1598. }
  1599. internal static void BorderColors(this ICellStyle style, string v)
  1600. {
  1601. if (string.IsNullOrEmpty(v))
  1602. return;
  1603. string[] borderColors = { string.Empty, string.Empty, string.Empty, string.Empty };
  1604. v = v.ToUpper();
  1605. var vs = v.Split(' ');
  1606. switch (vs.Length)
  1607. {
  1608. case 1:
  1609. borderColors[0] = borderColors[1] = borderColors[2] = borderColors[3] = vs[0];
  1610. break;
  1611. case 2:
  1612. borderColors[0] = borderColors[2] = vs[0];
  1613. borderColors[1] = borderColors[3] = vs[1];
  1614. break;
  1615. case 3:
  1616. borderColors[0] = vs[0];
  1617. borderColors[1] = borderColors[3] = vs[1];
  1618. borderColors[2] = vs[2];
  1619. break;
  1620. case 4:
  1621. borderColors[0] = vs[0];
  1622. borderColors[1] = vs[1];
  1623. borderColors[2] = vs[2];
  1624. borderColors[3] = vs[3];
  1625. break;
  1626. }
  1627. var borderTopColor = borderColors[0];
  1628. var borderRightColor = borderColors[1];
  1629. var borderBottomColor = borderColors[2];
  1630. var borderLeftColor = borderColors[3];
  1631. if (!string.IsNullOrWhiteSpace(borderTopColor))
  1632. style.TopBorderColor = borderTopColor.ConvertToColor();
  1633. if (!string.IsNullOrWhiteSpace(borderRightColor))
  1634. style.RightBorderColor = borderRightColor.ConvertToColor();
  1635. if (!string.IsNullOrWhiteSpace(borderBottomColor))
  1636. style.BottomBorderColor = borderBottomColor.ConvertToColor();
  1637. if (!string.IsNullOrWhiteSpace(borderLeftColor))
  1638. style.LeftBorderColor = borderLeftColor.ConvertToColor();
  1639. }
  1640. private static void BorderTopColors(this ICellStyle style, string v)
  1641. {
  1642. if (!string.IsNullOrWhiteSpace(v))
  1643. style.TopBorderColor = v.ConvertToColor();
  1644. }
  1645. private static void BorderBottomColors(this ICellStyle style, string v)
  1646. {
  1647. if (!string.IsNullOrWhiteSpace(v))
  1648. style.BottomBorderColor = v.ConvertToColor();
  1649. }
  1650. private static void BorderLeftColors(this ICellStyle style, string v)
  1651. {
  1652. if (!string.IsNullOrWhiteSpace(v))
  1653. style.LeftBorderColor = v.ConvertToColor();
  1654. }
  1655. private static void BorderRightColors(this ICellStyle style, string v)
  1656. {
  1657. if (!string.IsNullOrWhiteSpace(v))
  1658. style.RightBorderColor = v.ConvertToColor();
  1659. }
  1660. #endregion boder-type / boder-color
  1661. #region data-format
  1662. private static void DataFormat(this ICellStyle style, IWorkbook workbook, string v)
  1663. {
  1664. if (string.IsNullOrEmpty(v))
  1665. return;
  1666. var df = workbook.CreateDataFormat();
  1667. style.DataFormat = df.GetFormat(v);
  1668. }
  1669. #endregion data-format
  1670. #region BackgroundColor
  1671. private static void BackgroundColor(this ICellStyle style, string v)
  1672. {
  1673. if (string.IsNullOrEmpty(v))
  1674. return;
  1675. style.FillPattern = FillPattern.SolidForeground;
  1676. style.FillForegroundColor = v.ConvertToColor();
  1677. }
  1678. #endregion BackgroundColor
  1679. private static FontSuperScript ConvertToSuperScript(this SortedDictionary<string, string> fontdic)
  1680. {
  1681. var v = fontdic["font-superscript"];
  1682. switch (v)
  1683. {
  1684. case "SUPER":
  1685. return FontSuperScript.Super;
  1686. case "SUB":
  1687. return FontSuperScript.Sub;
  1688. default:
  1689. return FontSuperScript.None;
  1690. }
  1691. }
  1692. private static FontUnderlineType FontUnderline(this SortedDictionary<string, string> fontdic)
  1693. {
  1694. var v = fontdic["font-underline"];
  1695. switch (v)
  1696. {
  1697. case "SINGLE":
  1698. return FontUnderlineType.Single;
  1699. case "DOUBLE":
  1700. return FontUnderlineType.Double;
  1701. case "SINGLEACCOUNTING":
  1702. case "SINGLE_ACCOUNTING":
  1703. return FontUnderlineType.SingleAccounting;
  1704. case "DOUBLEACCOUNTING":
  1705. case "DOUBLE_ACCOUNTING":
  1706. return FontUnderlineType.DoubleAccounting;
  1707. default:
  1708. return FontUnderlineType.None;
  1709. }
  1710. }
  1711. public static short ConvertToColor(this string v)
  1712. {
  1713. if (string.IsNullOrEmpty(v))
  1714. return 32767;
  1715. switch (v.ToUpper())
  1716. {
  1717. case "AQUA":
  1718. return (short)ColorType.Aqua;
  1719. case "AUTOMATIC":
  1720. return (short)ColorType.Automatic;
  1721. case "BLACK":
  1722. return (short)ColorType.Black;
  1723. case "BLUE":
  1724. return (short)ColorType.Blue;
  1725. case "BLUE_GREY":
  1726. case "BLUEGREY":
  1727. return (short)ColorType.BlueGrey;
  1728. case "BRIGHT_GREEN":
  1729. case "BRIGHTGREEN":
  1730. return (short)ColorType.BrightGreen;
  1731. case "BROWN":
  1732. return (short)ColorType.Brown;
  1733. case "CORAL":
  1734. return (short)ColorType.Coral;
  1735. case "CORNFLOWER_BLUE":
  1736. case "CORNFLOWERBLUE":
  1737. return (short)ColorType.CornflowerBlue;
  1738. case "DARK_BLUE":
  1739. case "DARKBLUE":
  1740. return (short)ColorType.DarkBlue;
  1741. case "DARK_GREEN":
  1742. case "DARKGREEN":
  1743. return (short)ColorType.DarkGreen;
  1744. case "DARK_RED":
  1745. case "DARKRED":
  1746. return (short)ColorType.DarkRed;
  1747. case "DARK_TEAL":
  1748. case "DARKTEAL":
  1749. return (short)ColorType.DarkTeal;
  1750. case "DARK_YELLOW":
  1751. case "DARKYELLOW":
  1752. return (short)ColorType.DarkYellow;
  1753. case "GOLD":
  1754. return (short)ColorType.Gold;
  1755. case "GREEN":
  1756. return (short)ColorType.Green;
  1757. case "GREY_25_PERCENT":
  1758. case "GREY25PERCENT":
  1759. return (short)ColorType.Grey25Percent;
  1760. case "GREY_40_PERCENT":
  1761. case "GREY40PERCENT":
  1762. return (short)ColorType.Grey40Percent;
  1763. case "GREY_50_PERCENT":
  1764. case "GREY50PERCENT":
  1765. return (short)ColorType.Grey50Percent;
  1766. case "GREY_80_PERCENT":
  1767. case "GREY80PERCENT":
  1768. return (short)ColorType.Grey80Percent;
  1769. case "INDIGO":
  1770. return (short)ColorType.Indigo;
  1771. case "LAVENDER":
  1772. return (short)ColorType.Lavender;
  1773. case "LEMON_CHIFFON":
  1774. case "LEMONCHIFFON":
  1775. return (short)ColorType.LemonChiffon;
  1776. case "LIGHT_BLUE":
  1777. case "LIGHTBLUE":
  1778. return (short)ColorType.LightBlue;
  1779. case "LIGHT_CORNFLOWERBLUE":
  1780. case "LIGHTCORNFLOWERBLUE":
  1781. return (short)ColorType.LightCornflowerBlue;
  1782. case "LIGHT_GREEN":
  1783. case "LIGHTGREEN":
  1784. return (short)ColorType.LightGreen;
  1785. case "LIGHT_ORANGE":
  1786. case "LIGHTORANGE":
  1787. return (short)ColorType.LightOrange;
  1788. case "LIGHT_TURQUOISE":
  1789. case "LIGHTTURQUOISE":
  1790. return (short)ColorType.LightTurquoise;
  1791. case "LIGHT_YELLOW":
  1792. case "LIGHTYELLOW":
  1793. return (short)ColorType.LightYellow;
  1794. case "LIME":
  1795. return (short)ColorType.Lime;
  1796. case "MAROON":
  1797. return (short)ColorType.Maroon;
  1798. case "OLIVE_GREEN":
  1799. case "OLIVEGREEN":
  1800. return (short)ColorType.OliveGreen;
  1801. case "ORANGE":
  1802. return (short)ColorType.Orange;
  1803. case "ORCHID":
  1804. return (short)ColorType.Orchid;
  1805. case "PALE_BLUE":
  1806. case "PALEBLUE":
  1807. return (short)ColorType.PaleBlue;
  1808. case "PINK":
  1809. return (short)ColorType.Pink;
  1810. case "PLUM":
  1811. return (short)ColorType.Plum;
  1812. case "RED":
  1813. return (short)ColorType.Red;
  1814. case "ROSE":
  1815. return (short)ColorType.Rose;
  1816. case "ROYAL_BLUE":
  1817. case "ROYALBLUE":
  1818. return (short)ColorType.RoyalBlue;
  1819. case "SEA_GREEN":
  1820. case "SEAGREEN":
  1821. return (short)ColorType.SeaGreen;
  1822. case "SKY_BLUE":
  1823. case "SKYBLUE":
  1824. return (short)ColorType.SkyBlue;
  1825. case "TAN":
  1826. return (short)ColorType.Tan;
  1827. case "TEAL":
  1828. return (short)ColorType.Teal;
  1829. case "TURQUOISE":
  1830. return (short)ColorType.Turquoise;
  1831. case "VIOLET":
  1832. return (short)ColorType.Violet;
  1833. case "WHITE":
  1834. return (short)ColorType.White;
  1835. case "YELLOW":
  1836. return (short)ColorType.Yellow;
  1837. default:
  1838. return 32767;
  1839. }
  1840. }
  1841. private static HorizontalAlignment ConvertToHorizontalAlignment(this string v)
  1842. {
  1843. if (string.IsNullOrEmpty(v))
  1844. return HorizontalAlignment.General;
  1845. switch (v.ToUpper())
  1846. {
  1847. case "LEFT":
  1848. return HorizontalAlignment.Left;
  1849. case "CENTER":
  1850. return HorizontalAlignment.Center;
  1851. case "CENTERSELECTION":
  1852. case "CENTER_SELECTION":
  1853. return HorizontalAlignment.CenterSelection;
  1854. case "RIGHT":
  1855. return HorizontalAlignment.Right;
  1856. case "DISTRIBUTED":
  1857. return HorizontalAlignment.Distributed;
  1858. case "FILL":
  1859. return HorizontalAlignment.Fill;
  1860. case "JUSTIFY":
  1861. return HorizontalAlignment.Justify;
  1862. default:
  1863. return HorizontalAlignment.General;
  1864. }
  1865. }
  1866. private static VerticalAlignment ConvertToVerticalAlignment(this string v)
  1867. {
  1868. if (string.IsNullOrEmpty(v))
  1869. return VerticalAlignment.Justify;
  1870. switch (v.ToUpper())
  1871. {
  1872. case "TOP":
  1873. return VerticalAlignment.Top;
  1874. case "CENTER":
  1875. return VerticalAlignment.Center;
  1876. case "BOTTOM":
  1877. return VerticalAlignment.Bottom;
  1878. case "DISTRIBUTED":
  1879. return VerticalAlignment.Distributed;
  1880. default:
  1881. return VerticalAlignment.Justify;
  1882. }
  1883. }
  1884. public static BorderStyle ConvertToBorderStyle(this string v)
  1885. {
  1886. if (string.IsNullOrEmpty(v))
  1887. return BorderStyle.None;
  1888. switch (v.ToUpper())
  1889. {
  1890. case "THIN":
  1891. return BorderStyle.Thin;
  1892. case "MEDIUM":
  1893. return BorderStyle.Medium;
  1894. case "DASHED":
  1895. return BorderStyle.Dashed;
  1896. case "HAIR":
  1897. return BorderStyle.Hair;
  1898. case "THICK":
  1899. return BorderStyle.Thick;
  1900. case "DOUBLE":
  1901. return BorderStyle.Double;
  1902. case "DOTTED":
  1903. return BorderStyle.Dotted;
  1904. case "MEDIUMDASHED":
  1905. case "MEDIUM_DASHED":
  1906. return BorderStyle.MediumDashed;
  1907. case "DASHDOT":
  1908. case "DASH_DOT":
  1909. return BorderStyle.DashDot;
  1910. case "MEDIUMDASHDOT":
  1911. case "MEDIUM_DASH_DOT":
  1912. return BorderStyle.MediumDashDot;
  1913. case "DASHDOTDOT":
  1914. case "DASH_DOT_DOT":
  1915. return BorderStyle.DashDotDot;
  1916. case "MEDIUMDASHDOTDOT":
  1917. case "MEDIUM_DASH_DOT_DOT":
  1918. return BorderStyle.MediumDashDotDot;
  1919. case "SLANTEDDASHDOT":
  1920. case "SLANTED_DASH_DOT":
  1921. return BorderStyle.SlantedDashDot;
  1922. default:
  1923. return BorderStyle.None;
  1924. }
  1925. }
  1926. #endregion 样式转换
  1927. #endregion 解析css样式
  1928. }
  1929. public enum ColorType
  1930. {
  1931. Black = HSSFColor.Black.Index,
  1932. Brown = HSSFColor.Brown.Index,
  1933. OliveGreen = HSSFColor.OliveGreen.Index,
  1934. DarkGreen = HSSFColor.DarkGreen.Index,
  1935. DarkTeal = HSSFColor.DarkTeal.Index,
  1936. DarkBlue = HSSFColor.DarkBlue.Index,
  1937. Indigo = HSSFColor.Indigo.Index,
  1938. Grey80Percent = HSSFColor.Grey80Percent.Index,
  1939. Orange = HSSFColor.Orange.Index,
  1940. DarkYellow = HSSFColor.DarkYellow.Index,
  1941. Green = HSSFColor.Green.Index,
  1942. Teal = HSSFColor.Teal.Index,
  1943. Blue = HSSFColor.Blue.Index,
  1944. BlueGrey = HSSFColor.BlueGrey.Index,
  1945. Grey50Percent = HSSFColor.Grey50Percent.Index,
  1946. Red = HSSFColor.Red.Index,
  1947. LightOrange = HSSFColor.LightOrange.Index,
  1948. Lime = HSSFColor.Lime.Index,
  1949. SeaGreen = HSSFColor.SeaGreen.Index,
  1950. Aqua = HSSFColor.Aqua.Index,
  1951. LightBlue = HSSFColor.LightBlue.Index,
  1952. Violet = HSSFColor.Violet.Index,
  1953. Grey40Percent = HSSFColor.Grey40Percent.Index,
  1954. Pink = HSSFColor.Pink.Index,
  1955. Gold = HSSFColor.Gold.Index,
  1956. Yellow = HSSFColor.Yellow.Index,
  1957. BrightGreen = HSSFColor.BrightGreen.Index,
  1958. Turquoise = HSSFColor.Turquoise.Index,
  1959. DarkRed = HSSFColor.DarkRed.Index,
  1960. SkyBlue = HSSFColor.SkyBlue.Index,
  1961. Plum = HSSFColor.Plum.Index,
  1962. Grey25Percent = HSSFColor.Grey25Percent.Index,
  1963. Rose = HSSFColor.Rose.Index,
  1964. LightYellow = HSSFColor.LightYellow.Index,
  1965. LightGreen = HSSFColor.LightGreen.Index,
  1966. LightTurquoise = HSSFColor.LightTurquoise.Index,
  1967. PaleBlue = HSSFColor.PaleBlue.Index,
  1968. Lavender = HSSFColor.Lavender.Index,
  1969. White = HSSFColor.White.Index,
  1970. CornflowerBlue = HSSFColor.CornflowerBlue.Index,
  1971. LemonChiffon = HSSFColor.LemonChiffon.Index,
  1972. Maroon = HSSFColor.Maroon.Index,
  1973. Orchid = HSSFColor.Orchid.Index,
  1974. Coral = HSSFColor.Coral.Index,
  1975. RoyalBlue = HSSFColor.RoyalBlue.Index,
  1976. LightCornflowerBlue = HSSFColor.LightCornflowerBlue.Index,
  1977. Tan = HSSFColor.Tan.Index,
  1978. Automatic = HSSFColor.Automatic.Index
  1979. }
  1980. public static class TransExp<TIn, TOut>
  1981. {
  1982. private static readonly Func<TIn, TOut> Cache = GetFunc();
  1983. private static Func<TIn, TOut> GetFunc()
  1984. {
  1985. ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
  1986. List<MemberBinding> memberBindingList = new List<MemberBinding>();
  1987. foreach (var item in typeof(TOut).GetProperties())
  1988. {
  1989. if (!item.CanWrite)
  1990. continue;
  1991. MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name) ?? throw new InvalidOperationException());
  1992. MemberBinding memberBinding = Expression.Bind(item, property);
  1993. memberBindingList.Add(memberBinding);
  1994. }
  1995. MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
  1996. Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
  1997. return lambda.Compile();
  1998. }
  1999. public static TOut Trans(TIn tIn)
  2000. {
  2001. return Cache(tIn);
  2002. }
  2003. }
  2004. }