FastReport 交流群 群 號:554714044 前言 由於公司開發新產品,前後端分離.netcore +Angular ,之前C/S項目一直使用FastReport ,考慮到員工切換比較困難,而且最最重要的是BS版少了很多內容,例如合計,函數最常用的功能都沒有,所以B/S端列印控制項繼續沿用 ...
FastReport 交流群
554714044
前言
由於公司開發新產品,前後端分離.netcore +Angular ,之前C/S項目一直使用FastReport ,考慮到員工切換比較困難,而且最最重要的是BS版少了很多內容,例如合計,函數最常用的功能都沒有,所以B/S端列印控制項繼續沿用C/S模式。
一、邏輯視圖
二、具體實現
1.Winform設計
如上圖所示,這裡做了一個列印模板與數據源的管理。在這裡可以指定具體頁面要調什麼後端介面,列印什麼數據,列印格式設計。全部WinForm實現。將數據源與列印格式模板存儲到資料庫。後端直接調取即可。
優點:1.與之前WinForm版無縫對接,開發人員不用學習即可使用。
2.做到數據源與列印格式集中化管理,而且可以根據客戶需求,實施人員自己調整添加列印格式,不需要開發程式。
3.數據源多樣化,可以根據特殊需求,自己拼接sql,也可以直接查詢資料庫表。滿足客戶多樣化,個性化需求。
4.可以根據具體單據ID,調試列印格式。
缺點:WinForm 沒有做成網路版,此設計器只能在伺服器端(內網)使用。(本來設計就是要伺服器設計,下麵的人員用不到,缺點還可以接受
)
以下是部分代碼
1 /// <summary> 2 /// 綁定數據明細 3 /// </summary> 4 public void BindGridDts() 5 { 6 SReportManageDtsRule rule = new SReportManageDtsRule(); 7 DataTable dtDts = rule.RShow(" AND DMainID=" + SysString.ToDBString(HTDataID) + " ORDER BY DSeq", ProcessGrid.GetQueryField(gridView1)); 8 9 gridView1.GridControl.DataSource = dtDts; 10 gridView1.GridControl.Show(); 11 } 12 13 /// <summary> 14 /// 新增 15 /// </summary> 16 public string EntityAdd() 17 { 18 SReportManageRule rule = new SReportManageRule(); 19 SReportManage entity = EntityGet(); 20 SReportManageDts[] entitydts = EntityDtsGet(); 21 SReportFile entityFile = new SReportFile(); 22 if (chkMB.Checked) 23 { 24 entityFile.DContext = HttSoft.WinUIBase.FastReportX.ConvertToBinaryByPath(txtFilePath.Text.Trim()); 25 entityFile.DFileName = entity.DFileName; 26 } 27 28 rule.RAdd(entity, entitydts, entityFile); 29 return entity.DID; 30 } 31 32 /// <summary> 33 /// 修改 34 /// </summary> 35 public void EntityUpdate() 36 { 37 SReportManageRule rule = new SReportManageRule(); 38 SReportManage entity = EntityGet(); 39 SReportManageDts[] entitydts = EntityDtsGet(); 40 SReportFile entityFile = new SReportFile(); 41 if (chkMB.Checked) 42 { 43 entityFile.DID = entity.DFileID; 44 entityFile.SelectByID(); 45 entityFile.DContext = HttSoft.WinUIBase.FastReportX.ConvertToBinaryByPath(txtFilePath.Text.Trim()); 46 entityFile.DFileName = entity.DFileName; 47 } 48 49 rule.RUpdate(entity, entitydts, entityFile); 50 } 51 52 /// <summary> 53 /// 設置 54 /// </summary> 55 public void EntitySet() 56 { 57 SReportManage entity = new SReportManage(); 58 entity.DID = HTDataID; 59 bool findFlag = entity.SelectByID(); 60 drpForm.Text = SysConvert.ToString(entity.DMenuID); 61 txtReportName.Text = entity.DReportName.ToString(); 62 txtDSeq.Text = entity.DSeq.ToString(); 63 txtAPI.Text = entity.DWebApi.ToString(); 64 65 BindGridDts(); 66 } 67 68 69 /// <summary> 70 /// 刪除 71 /// </summary> 72 public void EntityDelete() 73 { 74 SReportManageRule rule = new SReportManageRule(); 75 SReportManage entity = EntityGet(); 76 rule.RDelete(entity); 77 } 78 79 #region 自定義方法 80 /// <summary> 81 /// 獲得實體 82 /// </summary> 83 /// <returns></returns> 84 private SReportManage EntityGet() 85 { 86 SReportManage entity = new SReportManage(); 87 entity.DID = HTDataID; 88 entity.SelectByID(); 89 entity.DMenuID = SysConvert.ToString(drpForm.Text.Trim()); 90 entity.DReportName = txtReportName.Text.Trim(); 91 entity.DSeq = SysConvert.ToInt32(txtDSeq.Text.Trim()); 92 entity.DWebApi = txtAPI.Text.Trim(); 93 entity.DFileName = txtReportName.Text.Trim() + ".frx"; 94 95 96 return entity; 97 } 98 99 /// <summary> 100 /// 獲得實體 101 /// </summary> 102 /// <returns></returns> 103 private SReportManageDts[] EntityDtsGet() 104 { 105 106 int index = 0; 107 for (int i = 0; i < gridView1.RowCount; i++) 108 { 109 if (SysConvert.ToString(gridView1.GetRowCellValue(i, "SqlName")) != "") 110 { 111 index++; 112 } 113 } 114 SReportManageDts[] entitydts = new SReportManageDts[index]; 115 index = 0; 116 for (int i = 0; i < gridView1.RowCount; i++) 117 { 118 if (SysConvert.ToString(gridView1.GetRowCellValue(i, "SqlName")) != "") 119 { 120 entitydts[index] = new SReportManageDts(); 121 entitydts[index].DMainID = SysConvert.ToString(gridView1.GetRowCellValue(i, "DMainID")); 122 if (entitydts[index].DMainID == HTDataID && HTDataID != "")//已存在表示修改 123 { 124 entitydts[index].DID = SysConvert.ToString(gridView1.GetRowCellValue(i, "DID")); 125 entitydts[index].SelectByID(); 126 } 127 else//新增 128 { 129 entitydts[index].DMainID = HTDataID; 130 entitydts[index].DSeq = i + 1; 131 } 132 133 134 entitydts[index].DMainID = SysConvert.ToString(gridView1.GetRowCellValue(i, "DMainID")); 135 entitydts[index].DSeq = SysConvert.ToInt32(gridView1.GetRowCellValue(i, "DSeq")); 136 entitydts[index].DataSourceName = SysConvert.ToString(gridView1.GetRowCellValue(i, "DataSourceName")); 137 entitydts[index].SqlName = SysConvert.ToString(gridView1.GetRowCellValue(i, "SqlName")); 138 entitydts[index].SqlStr = SysConvert.ToString(gridView1.GetRowCellValue(i, "SqlStr")); 139 entitydts[index].QueryName = SysConvert.ToString(gridView1.GetRowCellValue(i, "QueryName")); 140 entitydts[index].SqlFlag = SysConvert.ToInt32(gridView1.GetRowCellValue(i, "SqlFlag")); 141 entitydts[index].SourceType = SysConvert.ToInt32(gridView1.GetRowCellValue(i, "SourceType")); 142 entitydts[index].Remark = SysConvert.ToString(gridView1.GetRowCellValue(i, "Remark")); 143 144 145 index++; 146 } 147 } 148 return entitydts; 149 } 150 151 #endregion 152 //添加一個基礎模板 153 private void btnLook_Click(object sender, EventArgs e) 154 { 155 try 156 { 157 if (HTFormStatus == FormStatus.新增 || HTFormStatus == FormStatus.修改) 158 { 159 openFileDialog1.FileName = ""; 160 openFileDialog1.Filter = "(*.frx)|*.frx|(*.fr3)|*.fr3|(*.*)|*.*"; 161 openFileDialog1.ShowDialog(); 162 if (openFileDialog1.FileName != string.Empty) 163 { 164 txtFilePath.Text = openFileDialog1.FileName; 165 } 166 } 167 168 } 169 catch (Exception E) 170 { 171 MessageBox.Show(E.Message); 172 } 173 } 174 //窗體載入 175 private void HSPrintEdit_Load(object sender, EventArgs e) 176 { 177 //Common.BindFormID(drpForm); 178 Common.BindReportSource(drpReportSource, true); 179 } 180 //設計 181 private void btnDesign_Click(object sender, EventArgs e) 182 { 183 try 184 { 185 if (HTDataID == "") 186 { 187 MessageBox.Show("請先保存單據"); 188 return; 189 } 190 SReportManage reportManage = new SReportManage(); 191 reportManage.DID = HTDataID; 192 reportManage.SelectByID(); 193 if (reportManage.DFileID == "") 194 { 195 MessageBox.Show("沒有找到列印格式"); 196 return; 197 } 198 199 200 201 if (!chksql.Checked) 202 { 203 if (SysConvert.ToString(txtDataID.Text.Trim()) == "") 204 { 205 MessageBox.Show("請輸入數據源ID"); 206 return; 207 } 208 FastReport.ReportRun(HTDataID, (int)ReportPrintType.設計, new string[] { "DID", "DMainID" }, new string[] { SysConvert.ToString(txtDataID.Text.Trim()), SysConvert.ToString(txtDataID.Text.Trim()) }); 209 } 210 else 211 { 212 if (SysConvert.ToString(txtsql.Text.Trim()) == "") 213 { 214 MessageBox.Show("請輸入數據源sql"); 215 return; 216 } 217 DataTable dt = SysUtils.Fill(txtsql.Text.Trim()); 218 FastReport.ReportRunTable(HTDataID, (int)ReportPrintType.設計, dt); 219 } 220 221 222 223 } 224 catch (Exception E) 225 { 226 MessageBox.Show(E.Message); 227 } 228 } 229 //預覽 230 private void btnPreview_Click(object sender, EventArgs e) 231 { 232 try 233 { 234 if (HTDataID == "") 235 { 236 MessageBox.Show("請先保存單據"); 237 return; 238 } 239 SReportManage reportManage = new SReportManage(); 240 reportManage.DID = HTDataID; 241 reportManage.SelectByID(); 242 if (reportManage.DFileID == "") 243 { 244 MessageBox.Show("沒有找到列印格式"); 245 return; 246 } 247 248 if (!chksql.Checked) 249 { 250 if (SysConvert.ToString(txtDataID.Text.Trim()) == "") 251 { 252 MessageBox.Show("請輸入數據源ID"); 253 return; 254 } 255 FastReport.ReportRun(HTDataID, (int)ReportPrintType.預覽, new string[] { "DID", "DMainID" }, new string[] { SysConvert.ToString(txtDataID.Text.Trim()), SysConvert.ToString(txtDataID.Text.Trim()) }); 256 } 257 else 258 { 259 if (SysConvert.ToString(txtsql.Text.Trim()) == "") 260 { 261 MessageBox.Show("請輸入數據源"); 262 return; 263 } 264 DataTable dt = SysUtils.Fill(txtsql.Text.Trim()); 265 FastReport.ReportRunTable(HTDataID, (int)ReportPrintType.預覽, dt); 266 } 267 268 } 269 catch (Exception E) 270 { 271 MessageBox.Show(E.Message); 272 } 273 }View Code
2.MVC端
為了將列印格式發佈出去,這裡特意做了一個mvc的程式,放在前端與後端之間,作為橋梁。
因為客戶端只需要預覽和列印,所以這裡我只做了一個預覽+列印的介面。設計在WinForm端處理,這裡不需要。
以下是Preview的代碼實現。
1 public ActionResult Preview() 2 { 3 webReport = new WebReport(); 4 webReport.Width = Unit.Percentage(100); 5 webReport.Height = Unit.Percentage(100); 6 7 string DataID = Request.QueryString["id"]; 8 9 string ReportID = Request.QueryString["rid"]; 10 11 string token = Request.QueryString["token"]; 12 13 ReportModel model = new ReportModel(); 14 model.DataID = DataID; 15 model.ReportID = ReportID; 16 17 String token2 = "Bearer " + token; 18 HttpClient client = new HttpClient(); 19 client.BaseAddress = _baseAddress; 20 client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 21 22 client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); 23 //獲取模板文件地址,獲取列印數據源webapi介面地址 24 #region 獲取模板文件地址,獲取列印數據源webapi介面地址 25 var jsonStr = JsonConvert.SerializeObject(model); 26 HttpContent cont = new StringContent(jsonStr); 27 cont.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 28 29 30 var returnStr = ""; 31 HttpResponseMessage resp = client.PostAsync("/api/SReportManage/getdataurl", cont).Result;//post提交數據, 32 if (resp.IsSuccessStatusCode) 33 { 34 returnStr = resp.Content.ReadAsStringAsync().Result; 35 } 36 ReportResult dtos = JsonConvert.DeserializeObject<ReportResult>(returnStr); 37 38 #endregion 39 40 //獲取列印數據源 41 #region 獲取列印數據源 42 43 44 HttpClient client2 = new HttpClient(); 45 client2.BaseAddress = _baseAddress; 46 client2.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 47 48 client2.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); 49 50 var jsonStr2 = JsonConvert.SerializeObject(model); 51 HttpContent cont2 = new StringContent(jsonStr2); 52 cont2.Headers.ContentType = new MediaTypeHeaderValue("application/json"); 53 54 var returnStr2 = ""; 55 HttpResponseMessage resp2 = client2.PostAsync(dtos.Data.WebApi, cont2).Result;//post提交數據, 56 if (resp2.IsSuccessStatusCode) 57 { 58 returnStr2 = resp2.Content.ReadAsStringAsync().Result; 59 } 60 ReportSourceResult result = JsonConvert.DeserializeObject<ReportSourceResult>(returnStr2); 61 if (result != null) 62 { 63 for (int i = 0; i < result.Data.Count; i++) 64 { 65 webReport.Report.RegisterData(result.Data[i].dtsource, result.Data[i].TBName); 66 webReport.Report.GetDataSource(result.Data[i].TBName).Enabled = true; 67 } 68 } 69 70 #endregion 71 72 73 74 75 //webReport.Report.Load(dtos.Data.FileUrl + "Test.frx"); 76 webReport.Report.Load(ConfigurationManager.AppSettings["ReportFilePath"] + dtos.Data.FileUrl); 77 webReport.ToolbarStyle = ToolbarStyle.Small; 78 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Blue; 79 webReport.ToolbarBackgroundStyle = ToolbarBackgroundStyle.Custom; 80 81 //webReport.PrintPdf(); 82 83 webReport.PreviewMode = true;//預覽模式 84 webReport.PrintInPdf = true;//在PDF列印 85 86 //webReport.DesignerPath = "~/WebReportDesigner/index.html"; 87 //webReport.DesignerSavePath = "~/App_Data/DesignedReports"; 88 //webReport.DesignerSaveCallBack = "~/Report/SaveDesignedReport"; 89 webReport.ID = "DesignReport"; 90 ViewBag.WebReport = webReport; 91 return View(); 92 }View Code
其中以下幾點是我做了特殊化的設置
webReport.ToolbarStyle = ToolbarStyle.Small; //將原先的圖標變小(太大太難看了)
webReport.ToolbarIconsStyle = ToolbarIconsStyle.Blue;
webReport.ToolbarBackgroundStyle = ToolbarBackgroundStyle.Custom;
(下拉菜單的漢化還沒有找到,需要研究一下。)
webReport.PreviewMode = true;//預覽模式
webReport.PrintInPdf = true;//在PDF列印
這裡就是對接前端的列印介面。前端只需要調取我發佈的網址,並且把我需要的參數(數據ID,列印模板ID,token傳送給我即可。)
3.後端
後端介面主要是實現根據MVC端傳送過來的列印模板ID,將數據源和模板傳送給MVC端。由MVC端進行拼接組裝。
主要代碼如下:
1 public List<ReportDataSource> GetDataSource(ReportModel entitydto) 2 { 3 try 4 { 5 List<ReportDataSource> lst = new List<ReportDataSource>(); 6 IDBTransAccess sqlTrans = TransSysUtils.GetDBTransAccess(); 7 try 8 { 9 sqlTrans.OpenTrans(); 10 11 lst = this.GetDataSource(entitydto, sqlTrans); 12 13 14 sqlTrans.CommitTrans(); 15 return lst; 16 } 17 catch (Exception TE) 18 { 19 sqlTrans.RollbackTrans(); 20 throw TE; 21 } 22 } 23 catch (BaseException) 24 { 25 throw; 26 } 27 catch (Exception E) 28 { 29 throw new BaseException(E.Message); 30 } 31 } 32 33 34 public List<ReportDataSource> GetDataSource(ReportModel entitydto, IDBTransAccess sqlTrans) 35 { 36 try 37 { 38 List<ReportDataSource> lst = ReportRun(entitydto.ReportID, new string[] { "DID","DMainID" }, new string[] { entitydto.DataID,entitydto.DataID }, sqlTrans); 39 40 return lst; 41 42 } 43 catch (BaseException) 44 { 45 throw; 46 } 47 catch (Exception E) 48 { 49 throw new BaseException(E.Message); 50 } 51 } 52 53 54 55 56 57 58 59 60 61 #endregion 62 63 64 public List<ReportDataSource> ReportRun(string reportID, string[] queryName, string[] queryValue, IDBTransAccess sqlTrans) 65 { 66 List<ReportDataSource> lst =