iT邦幫忙

6

【.NET MVC報表系統】#1 集合物件轉HTML Table

先上結果圖片跟測試連結: 線上測試連結


第一版(JsonNet and DataTable):

目前要寫一個內部使用的報表系統,維護人員只要寫SQL從DB撈取資料
或是在其他程式邏輯中組成的集合
系統就會自動把集合物件轉成table html的字串
所以寫了一個簡單的table generator
code不長但需要用到JsonNetDataTable

原理:

  1. 先藉由JsonCovert序列化集合物件
  2. 再反序列化成DataTable物件
  3. 藉由DataTabl的Columns跟Rows來組合出table的表頭表身
  4. 做成擴充方法,方便使用
  5. 假如已經是DataTable物件會直接呼叫ConvertDataTableToHTML方法就可以(省去JSON轉換過程)

Code:

	public static string ToHtmlTable(this HashSet<dynamic> obj)
	{
		return ToHtmlTableConverter(obj);
	}
	
	public static string ToHtmlTable(this ICollection obj) {
		return ToHtmlTableConverter(obj);
	}

	public static string ToHtmlTable(this System.Data.DataTable obj)
	{
		return ConvertDataTableToHTML(obj);
	}

	private static string ToHtmlTableConverter( object obj  )  
	{
		var jsonStr = JsonConvert.SerializeObject(obj);
		var data = JsonConvert.DeserializeObject<System.Data.DataTable>(jsonStr);
		var html = ConvertDataTableToHTML(data);
		return html;
	}

	private static string ConvertDataTableToHTML(System.Data.DataTable dt)
	{
		var html = new StringBuilder("<table>");
		
		//表頭
		html.Append("<thead><tr>");
		for (int i = 0; i < dt.Columns.Count; i++)
			html.Append("<th>" + dt.Columns[i].ColumnName + "</th>");
		html.Append("</tr></thead>");
		
		//表身
		html.Append("<tbody>");
		for (int i = 0; i < dt.Rows.Count; i++)
		{
			html.Append("<tr>");
			for (int j = 0; j < dt.Columns.Count; j++)
				html.Append("<td>" + dt.Rows[i][j].ToString() + "</td>");
			html.Append( "</tr>");
		}
		
		html.Append("</tbody>");
		html.Append("</table>");
		return html.ToString();
	}

經過以下實測,支援Array、HashSet、List、不支援Enumerable

	var colls1 = collections.ToArray().ToHtmlTable(); //Run Success
	var colls2 = collections.ToHashSet().ToHtmlTable();//Run Succes
	var colls_list = collections.ToList().ToHtmlTable();//Run Succes
	var colls3 = collections.AsEnumerable().ToHtmlTable();//Error doesn't contain defined 

補充:

因為包含html標籤
所以在cshtml要使用@Html.Raw(生成字串)來填寫(注意安全性喔!)


第二版(JS版本):

直接轉JSON讓前端用JS去轉成Table
效能可以讓使用者來吃下,節省Server負擔
結果圖片跟測試連結: 線上測試連結

View改成:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
var myList = @Html.Raw(ViewBag.Table);

// Builds the HTML Table out of myList.
function buildHtmlTable(selector) {
  var columns = addAllColumnHeaders(myList, selector);

  for (var i = 0; i < myList.length; i++) {
    var row$ = $('<tr/>');
    for (var colIndex = 0; colIndex < columns.length; colIndex++) {
      var cellValue = myList[i][columns[colIndex]];
      if (cellValue == null) cellValue = "";
      row$.append($('<td/>').html(cellValue));
    }
    $(selector).append(row$);
  }
}

// Adds a header row to the table and returns the set of columns.
// Need to do union of keys from all records as some records may not contain
// all records.
function addAllColumnHeaders(myList, selector) {
  var columnSet = [];
  var headerTr$ = $('<tr/>');

  for (var i = 0; i < myList.length; i++) {
    var rowHash = myList[i];
    for (var key in rowHash) {
      if ($.inArray(key, columnSet) == -1) {
        columnSet.push(key);
        headerTr$.append($('<th/>').html(key));
      }
    }
  }
  $(selector).append(headerTr$);

  return columnSet;
}	
	
</script>
<body onLoad="buildHtmlTable('#DataTable')">
  <table id="DataTable" border="1">
  </table>
</body>	

以上JS CODE是Manish Mulani大大的:
javascript - Convert json data to a html table - Stack Overflow


以上是粗糙的版本
假如大大們有更好的做法都可以討論、糾正.


1 則留言

1
攻城屍
iT邦新手 5 級 ‧ 2018-06-15 10:03:47

我會建議寫成 Helper 讓 View 專心做畫面相關邏輯

HtmlHelper

public static class HtmlHelper
{
	public static HtmlString ToHtmlTable<T>(this IHtmlHelper htmlString, IEnumerable<T> list)
	{
		string json = JsonConvert.SerializeObject(list);
		return htmlString.ToHtmlTable(json);
	}

	public static HtmlString ToHtmlTable(this IHtmlHelper htmlString, string json)
	{
		var list = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(json);

		if (list == null || !list.Any())
		{
			throw new Exception("json 字串有誤");
		}

		var title = list.First().Select(x => x.Key);

		var content = list.Select(x => x.Select(y => (y.Value == null) ?
											string.Empty : y.Value.ToString()));

		string html = convertToHTML(title, content);
		return new HtmlString(html);
	}


	private static string convertToHTML(IEnumerable<string> title, IEnumerable<IEnumerable<string>> content)
	{
		StringBuilder sb = new StringBuilder();

		sb.Append("<table border='1'>");

		// 表頭
		sb.Append("<thead><tr>");
		sb.Append(string.Join(string.Empty, title.Select(x => string.Format("<th>{0}</th>", x))));
		sb.Append("</tr></thead>");

		// 表身
		sb.Append("<tbody>");
		foreach (var item in content)
		{
			sb.Append("<tr>");
			sb.Append(string.Join(string.Empty, item.Select(x => string.Format("<td>{0}</td>", x))));
			sb.Append("</tr>");
		}
		sb.Append("</tbody>");

		sb.Append("</table>");

		return sb.ToString();
	}
}

Model

public class TestModel
{
	[JsonProperty("姓名")]
	public string Name { get; set; }

	[JsonProperty("帳號")]
	public string Acc { get; set; }

	[JsonProperty("密碼")]
	public string Pwd { get; set; }
}

Controller

public ActionResult Index()
{
	var list = Enumerable.Range(0, 15).Select(x => new TestModel
	{
		Name = string.Format("測試 - {0}", x),
		Acc = x.ToString(),
		Pwd = Guid.NewGuid().ToString()
	});

	ViewBag.List = list;

	return View();
}

View

@Html.ToHtmlTable(ViewBag.List as IEnumerable<TestModel>))
暐翰 iT邦大師 7 級‧ 2018-06-15 10:17:52 檢舉

大大的模組分離的概念很扎實!
可以額外加一個IHtmlHelper的方法Overload

因為個人報表還有生成html檔案功能
當初只做成一個方法給View跟生成器共同使用
我這樣考量不周全的

謝謝大大 /images/emoticon/emoticon41.gif

我要留言

立即登入留言