From 94ed3edb9e96c8bfa24d808dfc690cbd111a60e6 Mon Sep 17 00:00:00 2001
From: lx <ex_lixiang17@cosl.com.cn>
Date: 星期五, 25 七月 2025 10:54:58 +0800
Subject: [PATCH] upload

---
 ErrorAnalysis.Service/WordReportHelper.cs             |  126 +++++++++++
 ErrorAnalysis.UI/Report.Designer.cs                   |  105 +++++++++
 ErrorAnalysis.UI/Report.cs                            |   48 ++++
 ErrorAnalysis.Service/ErrorAnalysis.Service.csproj    |   10 
 ErrorAnalysis.Service/ErrorRatioCalc.cs               |   14 +
 ErrorAnalysis.Service/Template/JobPlanReportTemp.docx |    0 
 ErrorAnalysis.UI/Report.resx                          |  120 ++++++++++
 ErrorAnalysis.UI/FrmMain.cs                           |  149 +++++++++----
 ErrorAnalysis.UI/FrmMain.Designer.cs                  |    6 
 ErrorAnalysis.Service/Model/ReportModel.cs            |   45 ++++
 10 files changed, 575 insertions(+), 48 deletions(-)

diff --git a/ErrorAnalysis.Service/ErrorAnalysis.Service.csproj b/ErrorAnalysis.Service/ErrorAnalysis.Service.csproj
index cfdea7f..c53131f 100644
--- a/ErrorAnalysis.Service/ErrorAnalysis.Service.csproj
+++ b/ErrorAnalysis.Service/ErrorAnalysis.Service.csproj
@@ -7,7 +7,17 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="Aspose.Words" Version="21.8.0" />
+  </ItemGroup>
+
+  <ItemGroup>
     <ProjectReference Include="..\ErrorAnalysis.Repository\ErrorAnalysis.Repository.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <None Update="Template\JobPlanReportTemp.docx">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
 </Project>
diff --git a/ErrorAnalysis.Service/ErrorRatioCalc.cs b/ErrorAnalysis.Service/ErrorRatioCalc.cs
index da2868b..af2ca04 100644
--- a/ErrorAnalysis.Service/ErrorRatioCalc.cs
+++ b/ErrorAnalysis.Service/ErrorRatioCalc.cs
@@ -86,10 +86,22 @@
                     {
                         if (wolProperty.Name.Contains("WLPu"))
                         {
+                            //if (wolProperty.Name != "WLPu0")
+                            //{
                             var interC = Utility.Interpolate(sw, 100, 0, 0, (double)wolProperty.GetValue(cWolRes));
                             var interO = Utility.Interpolate(sw, 0, 0, 100, (double)wolProperty.GetValue(oWolRes));
                             wolProperty.SetValue(cWolRes, interC);
                             wolProperty.SetValue(oWolRes, interO);
+                            //}
+                            //else
+                            //{
+                            //    var interC = Utility.Interpolate(sw, 100, 0, 0, (double)wolProperty.GetValue(cWolRes));
+                            //    var interO = Utility.Interpolate(sw, 0, 0, 100, (double)wolProperty.GetValue(oWolRes));
+                            //    var interVal = Utility.Interpolate(sw, 0, interC, 100, interO);
+                            //    wolProperty.SetValue(cWolRes, interVal);
+                            //    wolProperty.SetValue(oWolRes, interVal);
+                            //}
+
                         }
                     }
                 }
@@ -131,7 +143,7 @@
                     oRes = Utility.Interpolate(porosity, floorPorosity, floorO, ceilingPorosity, ceilingO);
                 }
 
-                var errorRatio = mergePDEV / (cRes - oRes);
+                var errorRatio = mergePDEV /( cRes > oRes ? (cRes - oRes) : (oRes - cRes));
 
                 return new ErrorRatio { Pass = 1, ErrorRatioValue = errorRatio };
             }
diff --git a/ErrorAnalysis.Service/Model/ReportModel.cs b/ErrorAnalysis.Service/Model/ReportModel.cs
new file mode 100644
index 0000000..c19cfb5
--- /dev/null
+++ b/ErrorAnalysis.Service/Model/ReportModel.cs
@@ -0,0 +1,45 @@
+锘縰sing Aspose.Words;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ErrorAnalysis.Service.Model
+{
+    public class ReportModel
+    {
+        public string BIT { get; set; }
+        public string CasingOD { get; set; }
+        public string CasingID { get; set; }
+        public string ScreenOD { get; set; }
+        public string ScreenID { get; set; }
+        public string TubeOD { get; set; }
+        public string TubeID { get; set; }
+        public string GravelFillPercent { get; set; }
+        public string CementBond { get; set; }
+
+        public string BHSalinity { get; set; }
+        public string OilSalinity { get; set; }
+        public string GasSalinity { get; set; }
+        public string CasingFluid { get; set; }
+        public string CasingHoldUp { get; set; }
+        public string ScreenFluid { get; set; }
+        public string ScreenHoldUp { get; set; }
+        public string TubeFluid { get; set; }
+        public string TubeHoldUp { get; set; }
+        public string Lithology { get; set; }
+
+        public string Porosity { get; set; }
+        public string WaterSaturation { get; set; }
+        public string ReserviorSalinity { get; set; }
+        public string VSH { get; set; }
+
+        public string SoPrecisionRequired { get; set; }
+        public string Pass { get; set; }
+        public string DepthAveraging { get; set; }
+        public string TargetLoggingInterval { get; set; }
+        public string Speed { get; set; }
+        public string Duration { get; set; }
+    }
+}
diff --git a/ErrorAnalysis.Service/Template/JobPlanReportTemp.docx b/ErrorAnalysis.Service/Template/JobPlanReportTemp.docx
new file mode 100644
index 0000000..1a8a4de
--- /dev/null
+++ b/ErrorAnalysis.Service/Template/JobPlanReportTemp.docx
Binary files differ
diff --git a/ErrorAnalysis.Service/WordReportHelper.cs b/ErrorAnalysis.Service/WordReportHelper.cs
new file mode 100644
index 0000000..cfa78bb
--- /dev/null
+++ b/ErrorAnalysis.Service/WordReportHelper.cs
@@ -0,0 +1,126 @@
+锘縰sing Aspose.Words;
+using Aspose.Words.Tables;
+using Aspose.Words.Drawing;
+using SkiaSharp;
+using static System.Net.Mime.MediaTypeNames;
+using ErrorAnalysis.Service.Model;
+
+namespace ErrorAnalysis.Service
+{
+    public class WordReportHelper
+    {
+        /// <summary>
+        /// 鎶ュ憡绫诲瀷鏋氫妇鍊紁df鍜寃ord
+        /// </summary>
+        public enum ReportType
+        {
+            Pdf,
+            Word
+        }
+        /// <summary>
+        /// 闈欐�佹瀯閫犲嚱鏁�
+        /// </summary>
+        static WordReportHelper()
+        {
+            new License().SetLicense(new MemoryStream(Convert.FromBase64String("PExpY2Vuc2U+CiAgPERhdGE+CiAgICA8TGljZW5zZWRUbz5TdXpob3UgQXVuYm94IFNvZnR3YXJlIENvLiwgTHRkLjwvTGljZW5zZWRUbz4KICAgIDxFbWFpbFRvPnNhbGVzQGF1bnRlYy5jb208L0VtYWlsVG8+CiAgICA8TGljZW5zZVR5cGU+RGV2ZWxvcGVyIE9FTTwvTGljZW5zZVR5cGU+CiAgICA8TGljZW5zZU5vdGU+TGltaXRlZCB0byAxIGRldmVsb3BlciwgdW5saW1pdGVkIHBoeXNpY2FsIGxvY2F0aW9uczwvTGljZW5zZU5vdGU+CiAgICA8T3JkZXJJRD4yMDA2MDIwMTI2MzM8L09yZGVySUQ+CiAgICA8VXNlcklEPjEzNDk3NjAwNjwvVXNlcklEPgogICAgPE9FTT5UaGlzIGlzIGEgcmVkaXN0cmlidXRhYmxlIGxpY2Vuc2U8L09FTT4KICAgIDxQcm9kdWN0cz4KICAgICAgPFByb2R1Y3Q+QXNwb3NlLlRvdGFsIGZvciAuTkVUPC9Qcm9kdWN0PgogICAgPC9Qcm9kdWN0cz4KICAgIDxFZGl0aW9uVHlwZT5FbnRlcnByaXNlPC9FZGl0aW9uVHlwZT4KICAgIDxTZXJpYWxOdW1iZXI+OTM2ZTVmZDEtODY2Mi00YWJmLTk1YmQtYzhkYzBmNTNhZmE2PC9TZXJpYWxOdW1iZXI+CiAgICA8U3Vic2NyaXB0aW9uRXhwaXJ5PjIwMjEwODI3PC9TdWJzY3JpcHRpb25FeHBpcnk+CiAgICA8TGljZW5zZVZlcnNpb24+My4wPC9MaWNlbnNlVmVyc2lvbj4KICAgIDxMaWNlbnNlSW5zdHJ1Y3Rpb25zPmh0dHBzOi8vcHVyY2hhc2UuYXNwb3NlLmNvbS9wb2xpY2llcy91c2UtbGljZW5zZTwvTGljZW5zZUluc3RydWN0aW9ucz4KICA8L0RhdGE+CiAgPFNpZ25hdHVyZT5wSkpjQndRdnYxV1NxZ1kyOHFJYUFKSysvTFFVWWRrQ2x5THE2RUNLU0xDQ3dMNkEwMkJFTnh5L3JzQ1V3UExXbjV2bTl0TDRQRXE1aFAzY2s0WnhEejFiK1JIWTBuQkh1SEhBY01TL1BSeEJES0NGbWg1QVFZRTlrT0FxSzM5NVBSWmJRSGowOUNGTElVUzBMdnRmVkp5cUhjblJvU3dPQnVqT1oyeDc4WFE9PC9TaWduYXR1cmU+CjwvTGljZW5zZT4=")));
+        }
+
+        public static bool Create(string outPath, ReportModel model, ReportType reportType = ReportType.Pdf)
+        {
+            string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", "JobPlanReportTemp.docx");
+
+            Document doc = new Document(filePath);
+            var section = doc.FirstSection;
+
+            var tables = section.Body.Tables;
+
+            foreach (Table table in tables) SetContentTable(doc, table, model);
+
+
+
+
+            section.Body.Paragraphs.RemoveAt(section.Body.Paragraphs.Count - 1);
+            DocumentBuilder builder = new DocumentBuilder(doc);
+            var lastSection = doc.LastSection;
+            var pageWidth = lastSection.PageSetup.PageWidth - lastSection.PageSetup.LeftMargin - lastSection.PageSetup.RightMargin;
+
+            builder.MoveToSection(doc.IndexOf(lastSection));
+            builder.MoveToDocumentEnd();
+
+            var coImg = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "co.png");
+            var erImg = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "er.png");
+
+            AddImageToDocument(builder, pageWidth, coImg);
+
+            var para = builder.InsertParagraph();
+            var run = new Run(doc);
+            para.ParagraphFormat.Alignment = ParagraphAlignment.Left;
+            run.Font.Bold = true;
+            run.Font.Size = 14;
+            run.Text = "ERROR RATE PLOT";
+            para.AppendChild(run);
+
+            AddImageToDocument(builder, pageWidth, erImg);
+
+            doc.Save(outPath, reportType == ReportType.Word ? SaveFormat.Docx : SaveFormat.Pdf);
+
+            return true;
+        }
+
+
+        /// <summary>
+        /// 璁剧疆鍐呭琛ㄦ牸
+        /// </summary>
+        /// <param name="doc">鏂囨。</param>
+        /// <param name="table">琛ㄦ牸</param>
+        /// <param name="model">妯″瀷</param>
+        private static void SetContentTable(Document doc, Table table, object model)
+        {
+            var properties = model?.GetType().GetProperties();
+            foreach (Row row in table.Rows)
+            {
+                var cells = row.Cells;
+                foreach (Cell cell in cells)
+                {
+                    var cellText = cell.GetText().Replace(ControlChar.Cell, "").Replace(ControlChar.ParagraphBreak, "");
+                    if (cellText.StartsWith("$"))
+                    {
+                        var property = properties.FirstOrDefault(p => p.Name == cellText.Trim().Replace("$", ""));
+                        if (property != null)
+                        {
+                            var valStr = property.GetValue(model).ToString();
+
+                            cell.FirstParagraph.RemoveAllChildren();
+                            cell.FirstParagraph.AppendChild(new Run(doc, valStr));
+                            cell.FirstParagraph.ParagraphFormat.Alignment = ParagraphAlignment.Right;
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 鍚戞枃妗d腑娣诲姞鍥惧儚銆�
+        /// </summary>
+        /// <param name="builder">鏂囨。鏋勫缓鍣ㄣ��</param>
+        /// <param name="pageWidth">椤甸潰瀹藉害銆�</param>
+        /// <param name="imagePath">鍥惧儚璺緞銆�</param>
+        private static void AddImageToDocument(DocumentBuilder builder, double pageWidth, string imagePath)
+        {
+            using (FileStream picStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
+            {
+                SKBitmap image;
+                using (var skData = SKData.Create(picStream))
+                {
+                    image = SKBitmap.Decode(skData);
+                }
+                int originalWidth = image.Width;
+                int originalHeight = image.Height;
+                int height = (int)(originalHeight * (pageWidth / originalWidth));
+                picStream.Seek(0, SeekOrigin.Begin);
+
+                builder.InsertImage(image, pageWidth, height);
+            }
+        }
+    }
+}
diff --git a/ErrorAnalysis.UI/FrmMain.Designer.cs b/ErrorAnalysis.UI/FrmMain.Designer.cs
index 7228839..4c8a397 100644
--- a/ErrorAnalysis.UI/FrmMain.Designer.cs
+++ b/ErrorAnalysis.UI/FrmMain.Designer.cs
@@ -394,7 +394,6 @@
             txtAnalysisResult.ReadOnly = true;
             txtAnalysisResult.Size = new Size(317, 182);
             txtAnalysisResult.TabIndex = 1;
-            txtAnalysisResult.Text = "A total of 6 passes are recommended to maintain a 15% error rate. With the tool operating at 1.5 ft/hr, the estimated total job duration is 10 hours.";
             // 
             // btnReport
             // 
@@ -405,6 +404,7 @@
             btnReport.TabIndex = 4;
             btnReport.Text = "Report";
             btnReport.UseVisualStyleBackColor = true;
+            btnReport.Click += btnReport_Click;
             // 
             // label24
             // 
@@ -955,7 +955,7 @@
             tpFormation.Controls.Add(label16);
             tpFormation.Location = new Point(4, 26);
             tpFormation.Name = "tpFormation";
-            tpFormation.Size = new Size(747, 283);
+            tpFormation.Size = new Size(847, 283);
             tpFormation.TabIndex = 2;
             tpFormation.Text = "Formation";
             tpFormation.UseVisualStyleBackColor = true;
@@ -1110,7 +1110,7 @@
             tpPlan.Controls.Add(panel1);
             tpPlan.Location = new Point(4, 26);
             tpPlan.Name = "tpPlan";
-            tpPlan.Size = new Size(747, 283);
+            tpPlan.Size = new Size(847, 283);
             tpPlan.TabIndex = 3;
             tpPlan.Text = "Plan";
             tpPlan.UseVisualStyleBackColor = true;
diff --git a/ErrorAnalysis.UI/FrmMain.cs b/ErrorAnalysis.UI/FrmMain.cs
index ec123bf..450e498 100644
--- a/ErrorAnalysis.UI/FrmMain.cs
+++ b/ErrorAnalysis.UI/FrmMain.cs
@@ -21,6 +21,7 @@
         private List<COModelTable> _models;
         private Dictionary<string, string> _filters;
         private COModelTable _model;
+        private ReportModel _reportModel;
 
         public FrmMain()
         {
@@ -85,7 +86,6 @@
                 });
             }
         }
-
         private void btnAnalysis_Click(object sender, EventArgs e)
         {
             var curModels = GetFilterResult();
@@ -136,11 +136,22 @@
                 return;
             }
 
+            if (!decimal.TryParse(nudOilDensity.Value.ToString(), out decimal oilDensity) || nudOilDensity.Value <= 0)
+            {
+                MessageBox.Show("Please select a oil density");
+                return;
+            }
+
             if (curModels.Count == 1)
                 _model = curModels[0];
-            _model = curModels.FirstOrDefault(m => m.GravelFillPercent == nudGravelFIllPercent.Value.ToString());
+
+            _model = curModels.FirstOrDefault(m => m.GravelFillPercent == nudGravelFIllPercent.Value.ToString() && m.OilDensity == oilDensity);
+
             if (_model == null)
                 _model = curModels.First();
+
+            nudOilDensity.Value = _model.OilDensity.Value;
+            nudGravelFIllPercent.Value = Convert.ToDecimal(_model.GravelFillPercent);
 
             if (cmbTargetLoggingIntervalUnit.Text == "ft")
                 targetLoggingInterval = UnitConvert.Ft2M(targetLoggingInterval);
@@ -158,7 +169,9 @@
                 Plot(result);
 
                 double totalTime = Math.Round((targetLoggingInterval / calcSpeed / 60), 2);
-                txtAnalysisResult.Text = $"A total of {result.ErrorRatios.Count} passes are recommended to maintain a {Math.Round(result.ErrorRatios.Min(r => r.ErrorRatioValue) * 100, 2)}% error rate. With the tool operating at {speed} {cmbSpeedUnit.Text}, the estimated total job duration is {totalTime.ToString()} hours.";
+                var errorRate = Math.Round(result.ErrorRatios.Min(r => r.ErrorRatioValue) * 100, 2);
+                txtAnalysisResult.Text = $"A total of {result.ErrorRatios.Count} passes are recommended to maintain a {errorRate}% error rate. With the tool operating at {speed} {cmbSpeedUnit.Text}, the estimated total job duration is {totalTime.ToString()} hours.";
+                _reportModel = CreateReportModel(totalTime.ToString(), result.ErrorRatios.Count.ToString(), Math.Round(UnitConvert.MMin2FtHr(calcSpeed), 2).ToString(), errorRate.ToString());
             }
             else
             {
@@ -172,9 +185,19 @@
                 Plot(result);
 
                 double totalTime = Math.Round((targetLoggingInterval / speed / 60), 2);
-                txtAnalysisResult.Text = $"A total of {result.ErrorRatios.Count} passes are recommended to maintain a {Math.Round(result.ErrorRatios.Min(r => r.ErrorRatioValue) * 100, 2)}% error rate. With the tool operating at {Math.Round(UnitConvert.MMin2FtHr(speed), 2)} ft/hr, the estimated total job duration is {totalTime.ToString()} hours.";
+                var errorRate = Math.Round(result.ErrorRatios.Min(r => r.ErrorRatioValue) * 100, 2);
+                var speedFr = Math.Round(UnitConvert.MMin2FtHr(speed), 2);
+
+                txtAnalysisResult.Text = $"A total of {result.ErrorRatios.Count} passes are recommended to maintain a {errorRate}% error rate. With the tool operating at {speedFr} ft/hr, the estimated total job duration is {totalTime.ToString()} hours.";
+
+                _reportModel = CreateReportModel(totalTime.ToString(), result.ErrorRatios.Count.ToString(), speedFr.ToString(), errorRate.ToString());
             }
 
+
+        }
+        private void btnReport_Click(object sender, EventArgs e)
+        {
+            new Report(_reportModel).ShowDialog();
         }
         #endregion
 
@@ -251,10 +274,10 @@
                     cmb.Text = currentItems[0];
 
             }
-
+            holdCmbInit();
             LinkageModelProperty();
         }
-        private void LinkageModelProperty()
+        private void holdCmbInit()
         {
             cmbCasingHoldUp.Items.Clear();
             _filters.Remove("CasingFluid");
@@ -264,34 +287,10 @@
             _filters.Remove("TubeFluid");
             cmbLithology.Items.Clear();
             _filters.Remove("Lithology");
+
             var curModels = GetFilterResult();
             if (curModels.Count == 0)
                 return;
-
-            var gravelFills = curModels.Select(x => x.GravelFillPercent).Distinct().ToArray();
-            if (gravelFills.Length == 1)
-                nudGravelFIllPercent.Value = Convert.ToDecimal(gravelFills[0]);
-
-            var cementBonds = curModels.Select(x => x.CementBond).Distinct().ToArray();
-            if (cementBonds.Length == 1)
-                nudCementBond.Value = Convert.ToDecimal(cementBonds[0]);
-
-            var bhSalinities = curModels.Select(x => x.BHSalinity).Distinct().ToArray();
-            if (bhSalinities.Length == 1)
-                nudBHSalinity.Value = Convert.ToDecimal(bhSalinities[0]);
-
-            var oilDensities = curModels.Select(x => x.OilDensity).Distinct().ToArray();
-            if (oilDensities.Length == 1)
-                nudOilDensity.Value = Convert.ToDecimal(oilDensities[0]);
-
-            var reservoirSalinities = curModels.Select(x => x.ReservoirSalinity).Distinct().ToArray();
-            if (reservoirSalinities.Length == 1)
-                nudReservoirSalinity.Value = Convert.ToDecimal(reservoirSalinities[0]);
-
-            var vshs = curModels.Select(x => x.VSH).Distinct().ToArray();
-            if (vshs.Length == 1)
-                nudVSH.Value = Convert.ToDecimal(vshs[0]);
-
 
             var casingFulids = curModels.Select(x => x.CasingFluid == "0" ? "water" : x.CasingFluid == "100" ? "oil" : x.CasingFluid == "200" ? "gas" : "none").Distinct().ToArray();
 
@@ -334,11 +333,45 @@
                 nudTubeHoldUp.Enabled = true;
                 cmbTubeHoldUp.Items.AddRange(tubeFluids);
             }
+        }
+        private void LinkageModelProperty()
+        {
+            var curLithology = cmbLithology.Text;
+            cmbLithology.Items.Clear();
+            _filters.Remove("Lithology");
+
+            var curModels = GetFilterResult();
+            if (curModels.Count == 0)
+                return;
+
+            var gravelFills = curModels.Select(x => x.GravelFillPercent).Distinct().ToArray();
+            if (gravelFills.Length == 1)
+                nudGravelFIllPercent.Value = Convert.ToDecimal(gravelFills[0]);
+
+            var cementBonds = curModels.Select(x => x.CementBond).Distinct().ToArray();
+            if (cementBonds.Length == 1)
+                nudCementBond.Value = Convert.ToDecimal(cementBonds[0]);
+
+            var bhSalinities = curModels.Select(x => x.BHSalinity).Distinct().ToArray();
+            if (bhSalinities.Length == 1)
+                nudBHSalinity.Value = Convert.ToDecimal(bhSalinities[0]);
+
+            var oilDensities = curModels.Select(x => x.OilDensity).Distinct().ToArray();
+            if (oilDensities.Length == 1)
+                nudOilDensity.Value = Convert.ToDecimal(oilDensities[0]);
+
+            var reservoirSalinities = curModels.Select(x => x.ReservoirSalinity).Distinct().ToArray();
+            if (reservoirSalinities.Length == 1)
+                nudReservoirSalinity.Value = Convert.ToDecimal(reservoirSalinities[0]);
+
+            var vshs = curModels.Select(x => x.VSH).Distinct().ToArray();
+            if (vshs.Length == 1)
+                nudVSH.Value = Convert.ToDecimal(vshs[0]);
 
             var lithology = curModels.Select(x => x.Lithology).Distinct().ToArray();
-            var curLithology = cmbLithology.Text;
             cmbLithology.Items.AddRange(lithology);
-            cmbLithology.Text = curLithology;
+            if (cmbLithology.Items.Contains(curLithology))
+                cmbLithology.Text = curLithology;
 
             if (lithology.Length == 1)
                 cmbLithology.SelectedIndex = 0;
@@ -396,6 +429,7 @@
                 }
 
             }
+            LinkageModelProperty();
             //foreach (var cmb in allCmb)
             //{
             //    if (cmb.Name != control.Name)
@@ -411,15 +445,6 @@
 
             //    }
             //}
-
-            var lithology = curModels.Select(x => x.Lithology).Distinct().ToArray();
-            cmbLithology.Items.Clear();
-            cmbLithology.Items.AddRange(lithology);
-
-            if (_filters.ContainsKey("Lithology") && lithology.Contains(_filters["Lithology"]))
-                cmbLithology.Text = _filters["Lithology"];
-            else
-                _filters.Remove("Lithology");
         }
         private void cmbLithology_SelectedIndexChanged(object sender, EventArgs e)
         {
@@ -447,7 +472,6 @@
             }
         }
         #endregion
-
         private List<COModelTable> GetFilterResult()
         {
             var type = typeof(COModelTable);
@@ -457,7 +481,6 @@
 
             return result;
         }
-
         private void Plot(ErrorRatioResult errorResult)
         {
             pnlCOPic.Controls.Clear();
@@ -523,5 +546,43 @@
             plotView.Dock = DockStyle.Fill;
             pnlErrorRatioPic.Controls.Add(plotView);
         }
+
+        private ReportModel CreateReportModel(string duration, string pass, string speed, string soPrecision)
+        {
+            return new ReportModel
+            {
+                BHSalinity = nudBHSalinity.Value.ToString(),
+                BIT = cmbBit.Text,
+                CasingFluid = cmbCasingHoldUp.Text,
+                CasingHoldUp = nudCasingHoldUp.Value.ToString(),
+                CasingID = cmbCasingID.Text,
+                CasingOD = cmbCasingOD.Text,
+                CementBond = nudCementBond.Text,
+                DepthAveraging = nudDepth.Value.ToString(),
+                Duration = duration,
+                GasSalinity = nudGasDensity.Value.ToString(),
+                GravelFillPercent = nudGravelFIllPercent.Value.ToString(),
+                Lithology = cmbLithology.Text,
+                OilSalinity = nudOilDensity.Value.ToString(),
+                Pass = pass,
+                Porosity = nudPorosity.Value.ToString(),
+                ReserviorSalinity = nudReservoirSalinity.Value.ToString(),
+                ScreenFluid = cmbScreenHoldUp.Text,
+                ScreenHoldUp = nudScreenHoldUp.Value.ToString(),
+                ScreenID = cmbScreenID.Text,
+                ScreenOD = cmbScreenOD.Text,
+                SoPrecisionRequired = soPrecision,
+                Speed = speed,
+                TargetLoggingInterval = nudTargetLoggingInterval.Value.ToString(),
+                TubeFluid = cmbTubeHoldUp.Text,
+                TubeHoldUp = nudTubeHoldUp.Value.ToString(),
+                TubeID = cmbTubeID.Text,
+                TubeOD = cmbTubeOD.Text,
+                VSH = nudVSH.Value.ToString(),
+                WaterSaturation = nudSw.Value.ToString()
+            };
+        }
+
+
     }
 }
diff --git a/ErrorAnalysis.UI/Report.Designer.cs b/ErrorAnalysis.UI/Report.Designer.cs
new file mode 100644
index 0000000..ad8a85a
--- /dev/null
+++ b/ErrorAnalysis.UI/Report.Designer.cs
@@ -0,0 +1,105 @@
+锘縩amespace ErrorAnalysis.UI
+{
+    partial class Report
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            btnExport = new Button();
+            btnCancel = new Button();
+            rdoWord = new RadioButton();
+            rdoPdf = new RadioButton();
+            SuspendLayout();
+            // 
+            // btnExport
+            // 
+            btnExport.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
+            btnExport.Location = new Point(147, 52);
+            btnExport.Name = "btnExport";
+            btnExport.Size = new Size(75, 23);
+            btnExport.TabIndex = 1;
+            btnExport.Text = "Export";
+            btnExport.UseVisualStyleBackColor = true;
+            btnExport.Click += btnExport_Click;
+            // 
+            // btnCancel
+            // 
+            btnCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
+            btnCancel.Location = new Point(66, 52);
+            btnCancel.Name = "btnCancel";
+            btnCancel.Size = new Size(75, 23);
+            btnCancel.TabIndex = 2;
+            btnCancel.Text = "Cancel";
+            btnCancel.UseVisualStyleBackColor = true;
+            btnCancel.Click += btnCancel_Click;
+            // 
+            // rdoWord
+            // 
+            rdoWord.AutoSize = true;
+            rdoWord.Location = new Point(109, 12);
+            rdoWord.Name = "rdoWord";
+            rdoWord.Size = new Size(65, 21);
+            rdoWord.TabIndex = 4;
+            rdoWord.Text = "WORD";
+            rdoWord.UseVisualStyleBackColor = true;
+            // 
+            // rdoPdf
+            // 
+            rdoPdf.AutoSize = true;
+            rdoPdf.Checked = true;
+            rdoPdf.Location = new Point(31, 12);
+            rdoPdf.Name = "rdoPdf";
+            rdoPdf.Size = new Size(48, 21);
+            rdoPdf.TabIndex = 3;
+            rdoPdf.TabStop = true;
+            rdoPdf.Text = "PDF";
+            rdoPdf.UseVisualStyleBackColor = true;
+            // 
+            // Report
+            // 
+            AutoScaleDimensions = new SizeF(7F, 17F);
+            AutoScaleMode = AutoScaleMode.Font;
+            ClientSize = new Size(226, 81);
+            Controls.Add(rdoWord);
+            Controls.Add(rdoPdf);
+            Controls.Add(btnCancel);
+            Controls.Add(btnExport);
+            MaximizeBox = false;
+            MinimizeBox = false;
+            Name = "Report";
+            StartPosition = FormStartPosition.CenterScreen;
+            Text = "Report";
+            ResumeLayout(false);
+            PerformLayout();
+        }
+
+        #endregion
+        private Button btnExport;
+        private Button btnCancel;
+        private RadioButton rdoWord;
+        private RadioButton rdoPdf;
+    }
+}
\ No newline at end of file
diff --git a/ErrorAnalysis.UI/Report.cs b/ErrorAnalysis.UI/Report.cs
new file mode 100644
index 0000000..356ca55
--- /dev/null
+++ b/ErrorAnalysis.UI/Report.cs
@@ -0,0 +1,48 @@
+锘縰sing ErrorAnalysis.Service;
+using ErrorAnalysis.Service.Model;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErrorAnalysis.UI
+{
+    public partial class Report : Form
+    {
+        ReportModel _reportModel;
+        public Report(ReportModel model)
+        {
+            _reportModel = model;
+            InitializeComponent();
+        }
+
+        private void btnExport_Click(object sender, EventArgs e)
+        {
+            btnExport.Enabled = false;
+            var saveFileDialog = new SaveFileDialog();
+            saveFileDialog.Filter = rdoPdf.Checked ? "Report |*.pdf" : "Report |*.docx";
+            saveFileDialog.FilterIndex = 1;
+            saveFileDialog.FileName = "JobPlanReport";
+            if (saveFileDialog.ShowDialog() == DialogResult.OK)
+            {
+                WordReportHelper.Create(saveFileDialog.FileName, _reportModel, rdoPdf.Checked ? WordReportHelper.ReportType.Pdf : WordReportHelper.ReportType.Word);
+                
+                MessageBox.Show("Export success!");
+                Dispose();
+                Close();
+            }
+            btnExport.Enabled = true;
+        }
+
+        private void btnCancel_Click(object sender, EventArgs e)
+        {
+            Dispose();
+            Close();
+        }
+    }
+}
diff --git a/ErrorAnalysis.UI/Report.resx b/ErrorAnalysis.UI/Report.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/ErrorAnalysis.UI/Report.resx
@@ -0,0 +1,120 @@
+锘�<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema 
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file

--
Gitblit v1.9.3