EnergyEfficiencyManagement/Assets/Zion/Scripts/Utils/PdfExportManager.cs

397 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using SK.Framework;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
// 注意使用此功能前需要安装iTextSharp库
// 可以通过NuGet包管理器安装iTextSharp 5.5.13.3 或更高版本
using iTextSharp.text;
using iTextSharp.text.pdf;
using UnityEngine.Networking;
/// <summary>
/// PDF导出管理器
/// </summary>
public class PdfExportManager : MonoSingleton<PdfExportManager>
{
[Header("PDF导出设置")]
public float margin = 50f; // 页面边距
public float fontSize = 12f; // 正文字体大小
public float titleFontSize = 18f; // 标题字体大小
public float headerFooterFontSize = 10f; // 页眉页脚字体大小
// 存储已选择的附件文件路径列表
private List<string> attachedFiles = new List<string>();
/// <summary>
/// 添加附件
/// </summary>
/// <param name="filePath">附件文件路径</param>
public void AddAttachment(string filePath)
{
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
{
if (!attachedFiles.Contains(filePath))
{
attachedFiles.Add(filePath);
Debug.Log($"附件已添加: {filePath}");
}
}
else
{
Debug.LogWarning($"文件不存在: {filePath}");
}
}
/// <summary>
/// 移除附件
/// </summary>
/// <param name="filePath">要移除的附件文件路径</param>
public void RemoveAttachment(string filePath)
{
attachedFiles.Remove(filePath);
Debug.Log($"附件已移除: {filePath}");
}
/// <summary>
/// 清空所有附件
/// </summary>
public void ClearAttachments()
{
attachedFiles.Clear();
Debug.Log("所有附件已清空");
}
/// <summary>
/// 获取附件列表
/// </summary>
/// <returns>附件文件路径列表</returns>
public List<string> GetAttachments()
{
return new List<string>(attachedFiles);
}
/// <summary>
/// 导出PDF文档
/// </summary>
/// <param name="title">PDF标题</param>
/// <param name="content">PDF内容</param>
/// <param name="outputPath">输出路径</param>
/// <param name="onComplete">完成回调</param>
public void ExportPdf(string title, string content, string outputPath, Action<bool, string> onComplete = null)
{
StartCoroutine(ExportPdfCoroutine(title, content, outputPath, onComplete));
}
/// <summary>
/// 导出PDF协程
/// </summary>
private IEnumerator ExportPdfCoroutine(string title, string content, string outputPath, Action<bool, string> onComplete)
{
yield return new WaitForEndOfFrame(); // 确保在帧结束时执行
try
{
bool success = CreatePdfDocument(title, content, outputPath);
string message = success ? $"PDF已保存至: {outputPath}" : "PDF导出失败";
onComplete?.Invoke(success, message);
}
catch (System.Exception ex)
{
Debug.LogError($"PDF导出过程中发生错误: {ex.Message}\n{ex.StackTrace}");
onComplete?.Invoke(false, $"PDF导出错误: {ex.Message}");
}
}
/// <summary>
/// 创建PDF文档
/// </summary>
/// <param name="title">PDF标题</param>
/// <param name="content">PDF内容</param>
/// <param name="outputPath">输出路径</param>
/// <returns>是否成功创建</returns>
private bool CreatePdfDocument(string title, string content, string outputPath)
{
try
{
// 确保输出目录存在
string directory = Path.GetDirectoryName(outputPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 创建文档
Document document = new Document(PageSize.A4, margin, margin, margin, margin);
// 创建PDF writer
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(outputPath, FileMode.Create));
// 打开文档
document.Open();
// 添加标题
if (!string.IsNullOrEmpty(title))
{
iTextSharp.text.Font titleFont = SetFont(16);
if (titleFont == null)
{
titleFont = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 16, iTextSharp.text.Font.BOLD);
}
Paragraph titleParagraph = new Paragraph(title, titleFont)
{
Alignment = Element.ALIGN_CENTER,
SpacingAfter = 20f
};
document.Add(titleParagraph);
}
// 添加当前时间戳
iTextSharp.text.Font timestampFont = SetFont(10);
if (timestampFont == null)
{
timestampFont = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 10, iTextSharp.text.Font.NORMAL);
}
Paragraph timestamp = new Paragraph($"生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}", timestampFont)
{
Alignment = Element.ALIGN_RIGHT,
SpacingAfter = 20f
};
document.Add(timestamp);
// 添加内容
if (!string.IsNullOrEmpty(content))
{
iTextSharp.text.Font contentFont = SetFont();
if (contentFont == null)
{
contentFont = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, fontSize, iTextSharp.text.Font.NORMAL);
}
// 将换行符转换为段落
string[] paragraphs = content.Split(new[] { "\n", "\r\n" }, StringSplitOptions.None);
foreach (string paragraphText in paragraphs)
{
if (!string.IsNullOrEmpty(paragraphText.Trim()))
{
Paragraph paragraph = new Paragraph(paragraphText, contentFont)
{
SpacingAfter = 10f
};
document.Add(paragraph);
}
else
{
// 添加空行
Paragraph emptyLine = new Paragraph(" ", contentFont);
document.Add(emptyLine);
}
}
}
// 添加附件信息(核心修改部分)
if (attachedFiles.Count > 0)
{
iTextSharp.text.Font contentFont = SetFont();
if (contentFont == null)
{
contentFont = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, fontSize, iTextSharp.text.Font.NORMAL);
}
document.Add(new Paragraph(" ", contentFont)); // 空行分隔
iTextSharp.text.Font sectionTitleFont = SetFont(14);
if (sectionTitleFont == null)
{
sectionTitleFont = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 14, iTextSharp.text.Font.BOLD);
}
Paragraph attachmentsTitle = new Paragraph("附件列表:", sectionTitleFont)
{
SpacingBefore = 20f,
SpacingAfter = 10f
};
document.Add(attachmentsTitle);
iTextSharp.text.Font attachmentFont = SetFont(12);
if (attachmentFont == null)
{
attachmentFont = new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 12, iTextSharp.text.Font.NORMAL);
}
for (int i = 0; i < attachedFiles.Count; i++)
{
string fullPath = attachedFiles[i];
string fileName = Path.GetFileName(fullPath);
string fileSize = FormatFileSize(new FileInfo(fullPath).Length);
// ======================
// 纯 Unity 中文路径编码
// ======================
string unifiedPath = fullPath.Replace('\\', '/');
string encodedPath = UnityWebRequest.EscapeURL(unifiedPath);
encodedPath = encodedPath.Replace("%2F", "/").Replace("%3A", ":");
string fileUrl = "file:///" + encodedPath;
// ======================
// 蓝色下划线链接字体
// ======================
iTextSharp.text.Font linkFont = new iTextSharp.text.Font(attachmentFont.BaseFont, 12, iTextSharp.text.Font.UNDERLINE, BaseColor.BLUE);
Anchor fileLink = new Anchor(fileName, linkFont);
fileLink.Reference = fileUrl; // 使用编码后的链接
Paragraph attachmentItem = new Paragraph($"{i + 1}. ", attachmentFont)
{
SpacingAfter = 5f,
IndentationLeft = 20f
};
attachmentItem.Add(fileLink);
attachmentItem.Add(new Chunk($" ({fileSize})", attachmentFont));
document.Add(attachmentItem);
}
}
// 添加页码
PdfPageEventHelper pageEvent = new PdfPageEventHandler();
writer.PageEvent = pageEvent;
// 关闭文档
document.Close();
Debug.Log($"PDF文档已成功创建: {outputPath}");
return true;
}
catch (System.Exception ex)
{
Debug.LogError($"创建PDF文档时发生错误: {ex.Message}\n{ex.StackTrace}");
return false;
}
}
public iTextSharp.text.Font SetFont(float _fontsize = 12)
{
try
{
// 创建 BaseFont支持中文
string fontPath = Path.Combine(Application.streamingAssetsPath, "songTi.ttf");
if (File.Exists(fontPath))
{
BaseFont baseFont = BaseFont.CreateFont(
fontPath,
BaseFont.IDENTITY_H,
BaseFont.EMBEDDED
);
// 创建 iText 字体
iTextSharp.text.Font chineseFont = new iTextSharp.text.Font(baseFont, _fontsize, iTextSharp.text.Font.NORMAL);
return chineseFont;
}
else
{
// 如果指定字体不存在,使用默认字体
return new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, _fontsize, iTextSharp.text.Font.NORMAL);
}
}
catch
{
// 如果出现任何错误,返回默认字体
return new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, _fontsize, iTextSharp.text.Font.NORMAL);
}
}
/// <summary>
/// 选择并添加附件
/// </summary>
/// <param name="onComplete">选择完成回调</param>
public void SelectAndAddAttachment(Action<bool, string> onComplete = null)
{
FileUploadManager.Instance.SelectAndUploadFile((filePath) =>
{
if (!string.IsNullOrEmpty(filePath))
{
AddAttachment(filePath);
onComplete?.Invoke(true, $"附件已添加: {Path.GetFileName(filePath)}");
}
else
{
onComplete?.Invoke(false, "未选择文件");
}
});
}
/// <summary>
/// 格式化文件大小
/// </summary>
/// <param name="bytes">字节数</param>
/// <returns>格式化的文件大小字符串</returns>
private string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double len = bytes;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:F2} {sizes[order]}";
}
/// <summary>
/// 选择保存路径并导出PDF
/// </summary>
/// <param name="title">PDF标题</param>
/// <param name="content">PDF内容</param>
/// <param name="onComplete">完成回调</param>
public void SelectAndExportPdf(string title, string content, Action<bool, string> onComplete = null)
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
string defaultFileName = $"{title}_{DateTime.Now:yyyyMMdd_HHmmss}.pdf";
string outputPath = EditorUtility.SaveFilePanel("保存PDF文件", "", defaultFileName, "pdf");
if (!string.IsNullOrEmpty(outputPath))
{
ExportPdf(title, content, outputPath, onComplete);
}
else
{
onComplete?.Invoke(false, "未选择保存路径");
}
#else
// 对于其他平台,使用默认路径或应用持久化数据路径
string fileName = $"{title}_{DateTime.Now:yyyyMMdd_HHmmss}.pdf";
string outputPath = Path.Combine(Application.persistentDataPath, fileName);
ExportPdf(title, content, outputPath, onComplete);
#endif
}
}
/// <summary>
/// PDF页面事件处理器用于添加页码
/// </summary>
public class PdfPageEventHandler : PdfPageEventHelper
{
public override void OnEndPage(PdfWriter writer, Document document)
{
base.OnEndPage(writer, document);
PdfContentByte canvas = writer.DirectContent;
ColumnText.ShowTextAligned(
canvas,
Element.ALIGN_CENTER,
new Phrase($"第 {writer.PageNumber} 页", new iTextSharp.text.Font(iTextSharp.text.Font.FontFamily.HELVETICA, 8)),
(document.PageSize.Left + document.PageSize.Right) / 2,
document.PageSize.Bottom + 15,
0
);
}
}