|
|
@@ -32311,7 +32311,478 @@ ORDER BY
|
|
|
}
|
|
|
|
|
|
|
|
|
+ [HttpPost]
|
|
|
+ public async Task<IActionResult> InspectionReportFileDown(InspectionReportFileDownDto Dto)
|
|
|
+ {
|
|
|
+ var di = _sqlSugar.Queryable<Grp_DelegationInfo>()
|
|
|
+ .Where(x => x.IsDel == 0 && x.Id == Dto.Diid)
|
|
|
+ .First();
|
|
|
+
|
|
|
+ if (di == null)
|
|
|
+ {
|
|
|
+ return Ok(JsonView(false, "团组信息不存在!"));
|
|
|
+ }
|
|
|
+
|
|
|
+ //书签dic
|
|
|
+ var bookmarks = new Dictionary<string, string>();
|
|
|
+ bookmarks.Add("TeamName", di.TeamName);
|
|
|
+ bookmarks.Add("TeamName1", di.TeamName);
|
|
|
+ bookmarks.Add("ClientUnit", di.ClientUnit);
|
|
|
+ bookmarks.Add("ClientUnit1", di.ClientUnit);
|
|
|
+ bookmarks.Add("thisTime", DateTime.Now.ToString("yyyy年MM月dd日"));
|
|
|
+
|
|
|
+ //读取word模板
|
|
|
+ var templatePath = $"{AppSettingsHelper.Get("WordBasePath")}/template/活动验收报告.docx";
|
|
|
+ var doc = new Document(templatePath);
|
|
|
+
|
|
|
+ var chiList = _sqlSugar.Queryable<Grp_ConferenceAffairsCostChild>()
|
|
|
+ .Where(x => x.IsDel == 0 && x.Diid == Dto.Diid)
|
|
|
+ .Select(x => new
|
|
|
+ {
|
|
|
+ x.Index,
|
|
|
+ x.PriceName,
|
|
|
+ PriceType = SqlFunc.Subqueryable<Sys_SetData>().Where(y => y.IsDel == 0 && y.Id == x.PriceType).Select(y => y.Name),
|
|
|
+ x.Count,
|
|
|
+ x.Remark,
|
|
|
+ x.Imgs
|
|
|
+ })
|
|
|
+ .OrderBy(x => x.Index)
|
|
|
+ .ToList();
|
|
|
+
|
|
|
+ //获取word所有表格
|
|
|
+ var allTables = doc.GetChildNodes(NodeType.Table, true);
|
|
|
+ //获取word第一个表格
|
|
|
+ var table = allTables[0] as Aspose.Words.Tables.Table;
|
|
|
+
|
|
|
+ //内容行索引
|
|
|
+ var startIndex = 2;
|
|
|
+
|
|
|
+ var copyRow = table.Rows[startIndex].Clone(true);
|
|
|
+
|
|
|
+ for (int i = 0; i < chiList.Count; i++)
|
|
|
+ {
|
|
|
+ var chi = chiList[i];
|
|
|
+
|
|
|
+ //插入复制的行(从第2次开始插入新行,第1次使用模板行)
|
|
|
+ if (i > 0)
|
|
|
+ {
|
|
|
+ var newRow = copyRow.Clone(true) as Aspose.Words.Tables.Row;
|
|
|
+ table.Rows.Insert(startIndex, newRow);
|
|
|
+ }
|
|
|
+
|
|
|
+ //word 表格 赋值
|
|
|
+ var row = table.Rows[startIndex];
|
|
|
+ row.Cells[0].FirstParagraph.Runs.Clear();
|
|
|
+ row.Cells[0].FirstParagraph.AppendChild(new Run(doc, (i + 1).ToString()));
|
|
|
+
|
|
|
+ row.Cells[1].FirstParagraph.Runs.Clear();
|
|
|
+ row.Cells[1].FirstParagraph.AppendChild(new Run(doc, chi.PriceName));
|
|
|
+
|
|
|
+ row.Cells[2].FirstParagraph.Runs.Clear();
|
|
|
+ row.Cells[2].FirstParagraph.AppendChild(new Run(doc, chi.PriceType));
|
|
|
+
|
|
|
+ row.Cells[3].FirstParagraph.Runs.Clear();
|
|
|
+ row.Cells[3].FirstParagraph.AppendChild(new Run(doc, chi.Count.ToString()));
|
|
|
+
|
|
|
+ row.Cells[4].FirstParagraph.Runs.Clear();
|
|
|
+ row.Cells[4].FirstParagraph.AppendChild(new Run(doc, chi.Remark));
|
|
|
+
|
|
|
+ if (!string.IsNullOrWhiteSpace(chi.Imgs))
|
|
|
+ {
|
|
|
+ var imgs = chi.Imgs.Split(',').Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
|
|
|
+
|
|
|
+ if (imgs.Length > 0)
|
|
|
+ {
|
|
|
+ // 获取图片基础路径配置
|
|
|
+ string baseUrl = AppSettingsHelper.Get("ConferenceCostImageBaseUrl");
|
|
|
+ string basePath = AppSettingsHelper.Get("ConferenceCostImageBasePath");
|
|
|
+
|
|
|
+ // 按图片方向分类,同时缓存图片字节数据
|
|
|
+ var imageInfos = new List<(string url, bool isWide, int width, int height, byte[] imageData)>();
|
|
|
+
|
|
|
+ _logger.LogInformation($"开始处理图片,配置 - BaseUrl: {baseUrl}, BasePath: {basePath}, 索引: {chi.Index}");
|
|
|
+
|
|
|
+ using (var httpClient = new HttpClient())
|
|
|
+ {
|
|
|
+ httpClient.Timeout = TimeSpan.FromSeconds(30);
|
|
|
+
|
|
|
+ foreach (var imgUrl in imgs)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ string fullUrl = imgUrl;
|
|
|
+ string localPath = "";
|
|
|
+
|
|
|
+ // 判断是否为完整URL
|
|
|
+ if (imgUrl.StartsWith("http://") || imgUrl.StartsWith("https://"))
|
|
|
+ {
|
|
|
+ fullUrl = imgUrl;
|
|
|
+ // 尝试从URL转换为本地路径
|
|
|
+ if (imgUrl.Contains("/child/"))
|
|
|
+ {
|
|
|
+ var pathPart = imgUrl.Substring(imgUrl.IndexOf("/child/"));
|
|
|
+ localPath = Path.Combine(basePath, pathPart.TrimStart('/').Replace("/", "\\"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 文件名,构造本地路径和完整URL
|
|
|
+ localPath = Path.Combine(basePath, "child", chi.Index.ToString(), imgUrl);
|
|
|
+ fullUrl = $"{baseUrl.TrimEnd('/')}/child/{chi.Index}/{imgUrl}";
|
|
|
+ }
|
|
|
+
|
|
|
+ _logger.LogInformation($"处理图片 [{imgUrl}] - 本地路径: {localPath}, URL: {fullUrl}");
|
|
|
+
|
|
|
+ // 优先使用本地文件,如果不存在则尝试下载
|
|
|
+ byte[] imageBytes = null;
|
|
|
+
|
|
|
+ if (!string.IsNullOrEmpty(localPath) && System.IO.File.Exists(localPath))
|
|
|
+ {
|
|
|
+ imageBytes = System.IO.File.ReadAllBytes(localPath);
|
|
|
+ _logger.LogInformation($"从本地加载成功,大小: {imageBytes.Length} 字节");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 从URL下载图片
|
|
|
+ try
|
|
|
+ {
|
|
|
+ _logger.LogInformation($"本地文件不存在,尝试从URL下载: {fullUrl}");
|
|
|
+ imageBytes = await httpClient.GetByteArrayAsync(fullUrl);
|
|
|
+ _logger.LogInformation($"从URL下载成功,大小: {imageBytes.Length} 字节");
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogWarning($"下载图片失败: {fullUrl}, 错误: {ex.Message}");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (imageBytes != null && imageBytes.Length > 0)
|
|
|
+ {
|
|
|
+ // 获取图片尺寸
|
|
|
+ using (var ms = new MemoryStream(imageBytes))
|
|
|
+ {
|
|
|
+ using (var image = System.Drawing.Image.FromStream(ms))
|
|
|
+ {
|
|
|
+ bool isWide = image.Width >= image.Height;
|
|
|
+ // 缓存图片数据,避免后续重复加载
|
|
|
+ imageInfos.Add((imgUrl, isWide, image.Width, image.Height, imageBytes));
|
|
|
+ _logger.LogInformation($"图片分析完成 - 宽度: {image.Width}px, 高度: {image.Height}px, 类型: {(isWide ? "横图" : "竖图")}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogError(ex, $"处理图片失败: {imgUrl}");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _logger.LogInformation($"图片处理完成,成功加载 {imageInfos.Count} 张图片");
|
|
|
+
|
|
|
+ // 插入图片行
|
|
|
+ if (imageInfos.Count > 0)
|
|
|
+ {
|
|
|
+ var builder = new DocumentBuilder(doc);
|
|
|
+ // 从数据模板行获取正确的列数,而不是标题行(标题行可能是合并单元格)
|
|
|
+ int totalColumns = table.Rows[startIndex].Cells.Count;
|
|
|
+
|
|
|
+ _logger.LogInformation($"表格总列数: {totalColumns}(从第{startIndex}行获取)");
|
|
|
+
|
|
|
+ for (int imgIndex = 0; imgIndex < imageInfos.Count;)
|
|
|
+ {
|
|
|
+ var currentImg = imageInfos[imgIndex];
|
|
|
+
|
|
|
+ // 在当前行后插入新行(使用复制的模板行)
|
|
|
+ var newRow = copyRow.Clone(true) as Aspose.Words.Tables.Row;
|
|
|
+ table.Rows.Insert(startIndex + 1, newRow);
|
|
|
+ startIndex++; // 更新startIndex,因为插入了新行
|
|
|
+
|
|
|
+ // 重置所有单元格的合并状态(关键:清除克隆行的原有格式)
|
|
|
+ for (int col = 0; col < totalColumns; col++)
|
|
|
+ {
|
|
|
+ if (col < newRow.Cells.Count)
|
|
|
+ {
|
|
|
+ newRow.Cells[col].CellFormat.HorizontalMerge = CellMerge.None;
|
|
|
+ newRow.Cells[col].CellFormat.VerticalMerge = CellMerge.None;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (currentImg.isWide)
|
|
|
+ {
|
|
|
+ _logger.LogInformation($"开始插入宽图 [{currentImg.url}],宽度: {currentImg.width}px");
|
|
|
+
|
|
|
+ // 宽图:先设置所有单元格的合并状态
|
|
|
+ for (int col = 0; col < totalColumns; col++)
|
|
|
+ {
|
|
|
+ if (col < newRow.Cells.Count)
|
|
|
+ {
|
|
|
+ var cell = newRow.Cells[col];
|
|
|
+ cell.RemoveAllChildren();
|
|
|
+
|
|
|
+ if (col == 0)
|
|
|
+ {
|
|
|
+ cell.CellFormat.HorizontalMerge = CellMerge.First;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cell.CellFormat.HorizontalMerge = CellMerge.Previous;
|
|
|
+ }
|
|
|
+ cell.CellFormat.PreferredWidth = PreferredWidth.Auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 然后在第一个单元格插入图片
|
|
|
+ var firstCell = newRow.Cells[0];
|
|
|
+ var para = new Paragraph(doc);
|
|
|
+ para.ParagraphFormat.Alignment = ParagraphAlignment.Center;
|
|
|
+ firstCell.AppendChild(para);
|
|
|
+ builder.MoveTo(para);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 使用缓存的图片数据
|
|
|
+ byte[] imageBytes = currentImg.imageData;
|
|
|
+
|
|
|
+ if (imageBytes != null && imageBytes.Length > 0)
|
|
|
+ {
|
|
|
+ using (var imgStream = new MemoryStream(imageBytes))
|
|
|
+ {
|
|
|
+ // 插入图片,设置合理的宽度和最大高度
|
|
|
+ var shape = builder.InsertImage(imgStream);
|
|
|
|
|
|
+ // 使用预先获取的原始尺寸
|
|
|
+ double originalWidth = currentImg.width;
|
|
|
+ double originalHeight = currentImg.height;
|
|
|
+
|
|
|
+ // 设置最大宽度(约表格宽度的85%,避免超出)
|
|
|
+ double maxWidth = 380;
|
|
|
+ double maxHeight = 300; // 限制最大高度,避免图片过高
|
|
|
+
|
|
|
+ // 计算缩放比例
|
|
|
+ double widthScale = originalWidth > maxWidth ? maxWidth / originalWidth : 1;
|
|
|
+ double heightScale = originalHeight > maxHeight ? maxHeight / originalHeight : 1;
|
|
|
+ double scale = Math.Min(widthScale, heightScale);
|
|
|
+
|
|
|
+ shape.Width = originalWidth * scale;
|
|
|
+ shape.Height = originalHeight * scale;
|
|
|
+
|
|
|
+ _logger.LogInformation($"宽图插入成功,原始尺寸: {originalWidth}x{originalHeight}, 缩放后: {shape.Width:F0}x{shape.Height:F0},已合并 {totalColumns} 个单元格");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _logger.LogWarning($"图片数据为空");
|
|
|
+ para.AppendChild(new Run(doc, "[图片数据为空]"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogError(ex, $"插入宽图失败: {currentImg.url}");
|
|
|
+ para.AppendChild(new Run(doc, "[图片加载失败]"));
|
|
|
+ }
|
|
|
+
|
|
|
+ imgIndex++; // 处理下一张图片
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _logger.LogInformation($"开始插入高图 [{currentImg.url}],高度: {currentImg.height}px");
|
|
|
+
|
|
|
+ // 高图:合并一半单元格
|
|
|
+ int halfColumns = totalColumns / 2;
|
|
|
+ _logger.LogInformation($"高图模式 - 前半部分列数: {halfColumns}, 后半部分列数: {totalColumns - halfColumns}");
|
|
|
+
|
|
|
+ // 先设置前一半单元格的合并状态
|
|
|
+ for (int col = 0; col < halfColumns; col++)
|
|
|
+ {
|
|
|
+ if (col < newRow.Cells.Count)
|
|
|
+ {
|
|
|
+ var cell = newRow.Cells[col];
|
|
|
+ cell.RemoveAllChildren();
|
|
|
+
|
|
|
+ if (col == 0)
|
|
|
+ {
|
|
|
+ cell.CellFormat.HorizontalMerge = CellMerge.First;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cell.CellFormat.HorizontalMerge = CellMerge.Previous;
|
|
|
+ }
|
|
|
+ cell.CellFormat.PreferredWidth = PreferredWidth.Auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置后一半单元格的合并状态
|
|
|
+ for (int col = halfColumns; col < totalColumns; col++)
|
|
|
+ {
|
|
|
+ if (col < newRow.Cells.Count)
|
|
|
+ {
|
|
|
+ var cell = newRow.Cells[col];
|
|
|
+ cell.RemoveAllChildren();
|
|
|
+
|
|
|
+ if (col == halfColumns)
|
|
|
+ {
|
|
|
+ cell.CellFormat.HorizontalMerge = CellMerge.First;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cell.CellFormat.HorizontalMerge = CellMerge.Previous;
|
|
|
+ }
|
|
|
+ cell.CellFormat.PreferredWidth = PreferredWidth.Auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在第一个单元格插入第一张高图
|
|
|
+ var firstCell = newRow.Cells[0];
|
|
|
+ var para1 = new Paragraph(doc);
|
|
|
+ para1.ParagraphFormat.Alignment = ParagraphAlignment.Center;
|
|
|
+ firstCell.AppendChild(para1);
|
|
|
+ builder.MoveTo(para1);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ // 使用缓存的图片数据
|
|
|
+ byte[] imageBytes = currentImg.imageData;
|
|
|
+
|
|
|
+ if (imageBytes != null && imageBytes.Length > 0)
|
|
|
+ {
|
|
|
+ using (var imgStream = new MemoryStream(imageBytes))
|
|
|
+ {
|
|
|
+ var shape = builder.InsertImage(imgStream);
|
|
|
+
|
|
|
+ // 使用预先获取的原始尺寸
|
|
|
+ double originalWidth = currentImg.width;
|
|
|
+ double originalHeight = currentImg.height;
|
|
|
+
|
|
|
+ // 设置最大宽度和高度(约表格一半宽度)
|
|
|
+ double maxWidth = 180;
|
|
|
+ double maxHeight = 300; // 限制最大高度
|
|
|
+
|
|
|
+ // 计算缩放比例
|
|
|
+ double widthScale = originalWidth > maxWidth ? maxWidth / originalWidth : 1;
|
|
|
+ double heightScale = originalHeight > maxHeight ? maxHeight / originalHeight : 1;
|
|
|
+ double scale = Math.Min(widthScale, heightScale);
|
|
|
+
|
|
|
+ shape.Width = originalWidth * scale;
|
|
|
+ shape.Height = originalHeight * scale;
|
|
|
+
|
|
|
+ _logger.LogInformation($"第一张高图插入成功,原始尺寸: {originalWidth}x{originalHeight}, 缩放后: {shape.Width:F0}x{shape.Height:F0},已合并前 {halfColumns} 个单元格");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _logger.LogWarning($"图片数据为空");
|
|
|
+ para1.AppendChild(new Run(doc, "[图片数据为空]"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogError(ex, $"插入高图失败: {currentImg.url}");
|
|
|
+ para1.AppendChild(new Run(doc, "[图片加载失败]"));
|
|
|
+ }
|
|
|
+
|
|
|
+ imgIndex++; // 第一张高图已处理
|
|
|
+
|
|
|
+ // 检查是否还有下一张高图,如果有则插入到后一半单元格
|
|
|
+ if (imgIndex < imageInfos.Count && !imageInfos[imgIndex].isWide)
|
|
|
+ {
|
|
|
+ var secondCell = newRow.Cells[halfColumns];
|
|
|
+ var para2 = new Paragraph(doc);
|
|
|
+ para2.ParagraphFormat.Alignment = ParagraphAlignment.Center;
|
|
|
+ secondCell.AppendChild(para2);
|
|
|
+ builder.MoveTo(para2);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var nextImg = imageInfos[imgIndex];
|
|
|
+ _logger.LogInformation($"开始插入第二张高图 [{nextImg.url}]");
|
|
|
+
|
|
|
+ // 使用缓存的图片数据
|
|
|
+ byte[] imageBytes = nextImg.imageData;
|
|
|
+
|
|
|
+ if (imageBytes != null && imageBytes.Length > 0)
|
|
|
+ {
|
|
|
+ using (var imgStream = new MemoryStream(imageBytes))
|
|
|
+ {
|
|
|
+ var shape = builder.InsertImage(imgStream);
|
|
|
+
|
|
|
+ // 使用预先获取的原始尺寸
|
|
|
+ double originalWidth = nextImg.width;
|
|
|
+ double originalHeight = nextImg.height;
|
|
|
+
|
|
|
+ // 设置最大宽度和高度
|
|
|
+ double maxWidth = 180;
|
|
|
+ double maxHeight = 300;
|
|
|
+
|
|
|
+ // 计算缩放比例
|
|
|
+ double widthScale = originalWidth > maxWidth ? maxWidth / originalWidth : 1;
|
|
|
+ double heightScale = originalHeight > maxHeight ? maxHeight / originalHeight : 1;
|
|
|
+ double scale = Math.Min(widthScale, heightScale);
|
|
|
+
|
|
|
+ shape.Width = originalWidth * scale;
|
|
|
+ shape.Height = originalHeight * scale;
|
|
|
+
|
|
|
+ _logger.LogInformation($"第二张高图插入成功,原始尺寸: {originalWidth}x{originalHeight}, 缩放后: {shape.Width:F0}x{shape.Height:F0},已合并后 {totalColumns - halfColumns} 个单元格");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _logger.LogWarning($"第二张高图数据为空");
|
|
|
+ para2.AppendChild(new Run(doc, "[图片数据为空]"));
|
|
|
+ }
|
|
|
+
|
|
|
+ imgIndex++; // 第二张高图已处理
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ _logger.LogError(ex, $"插入第二张高图失败");
|
|
|
+ para2.AppendChild(new Run(doc, "[图片加载失败]"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ startIndex++;
|
|
|
+ }
|
|
|
+
|
|
|
+ //替换书签
|
|
|
+ foreach (var key in bookmarks.Keys)
|
|
|
+ {
|
|
|
+ if (doc.Range.Bookmarks[key] != null)
|
|
|
+ {
|
|
|
+ Bookmark mark = doc.Range.Bookmarks[key];
|
|
|
+ mark.Text = bookmarks[key];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //去水印
|
|
|
+ new Aspose.Words.License().SetLicense(new MemoryStream(Convert.FromBase64String(AsposeHelper.asposeKey)));
|
|
|
+
|
|
|
+ //保存word
|
|
|
+ string fileName = $"活动验收报告_{di.TeamName}_{DateTime.Now:yyyyMMddHHmmss}.docx";
|
|
|
+ string filePath = $"InspectionReport/{fileName}";
|
|
|
+ string fullPath = AppSettingsHelper.Get("WordBasePath") + filePath;
|
|
|
+
|
|
|
+ //确保目录存在
|
|
|
+ string directory = Path.GetDirectoryName(fullPath);
|
|
|
+ if (!Directory.Exists(directory))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(directory);
|
|
|
+ }
|
|
|
+
|
|
|
+ //保存文档
|
|
|
+ doc.Save(fullPath, Aspose.Words.SaveFormat.Docx);
|
|
|
+
|
|
|
+ //返回文件路径http
|
|
|
+ string url = AppSettingsHelper.Get("WordBaseUrl") + $"Office/Word/{filePath}";
|
|
|
+
|
|
|
+ return Ok(JsonView(true, "SUCCESS!", new { Url = url, FileName = fileName }));
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|