| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- using UnityEngine;
- using System.IO;
- using iTextSharp.text;
- using iTextSharp.text.pdf;
- using System.Collections.Generic;
- using UnityEngine.UI;
- using PdfFont = iTextSharp.text.Font;
- using QFramework;
- using System.IO;
- public class SimplePDFReport : MonoBehaviour
- {
- UserProxy userProxy = DAL.Instance.Get<UserProxy>();
- [Header("UI绑定")]
- public Button Btn_Export;
- [Header("基础信息")]
- public string studentName = "Chiva";
- private string experimentName = OperateSetting.Instance.m_CourseName;
- public string date = "2025-10-16";
- // 可外部替换 Logo
- public string logoFileName = "logo.png"; // 放在 StreamingAssets 下
- private ScoreInfo scorePanel; // 动态获取成绩信息
- private List<StepScore> stepScores = new List<StepScore>();
- private float totalScore;
- private string useTime;
-
- [System.Serializable]
- public class StepScore
- {
- public int index;
- public string stepName;
- public float score;
- }
- private void Start()
- {
- studentName = userProxy.userInfo.userName;
- Btn_Export.onClick.AddListener(ExportPDF);
- }
- [ContextMenu("导出成绩单 PDF")]
- public void ExportPDF()
- {
- scorePanel = UIKit.GetPanel<PC_OperatePanel>().ScoreInfo;
- if (scorePanel == null)
- {
- Debug.LogError("❌ 未找到 ScoreInfo 面板,请确保在当前场景中存在。");
- return;
- }
- totalScore = float.Parse(scorePanel.Score.text);
- useTime = scorePanel.UseTime.text;
- date = System.DateTime.Now.ToString("yyyy-MM-dd");
- // 生成步骤表数据
- Transform content = scorePanel.Content;
- stepScores.Clear();
- for (int i = 0; i < content.childCount; i++)
- {
- var item = content.GetChild(i).GetComponent<ScoreInfoItem>();
- if (item != null)
- {
- stepScores.Add(new StepScore()
- {
- //index = i + 1,
- index = int.Parse(item.stepIdText.text),
- stepName = item.stepDescriptText.text, // 步骤名
- score = float.Parse(item.scoreSituationText.text) // 分数
- });
- }
- }
- // ====== PDF导出路径 ======
- string tmpSavePath = FolderBrowserHelper.GetPathFromWindowsExplorer("请选择成绩导出位置");
- string savePath = Path.Combine(Application.dataPath, $"{studentName}_成绩单.pdf");
- if (File.Exists(savePath)) File.Delete(savePath);
- Document doc = new Document(PageSize.A4, 60, 60, 80, 60); // 上边距略大,留页眉空间
- PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(savePath, FileMode.Create));
- // ===== 页脚和页码 =====
- writer.PageEvent = new PdfPageEvents();
- doc.Open();
- // ====== 字体设置 ======
- string fontPath = Path.Combine(Application.dataPath, "Fonts/SIMHEI.ttf");
- if (!File.Exists(fontPath))
- {
- Debug.LogError("字体文件未找到:" + fontPath);
- return;
- }
- BaseFont bfChinese = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
- PdfFont smallFont = new PdfFont(bfChinese, 10) { Color = new BaseColor(100, 100, 100) }; // 灰色
- PdfFont normalFont = new PdfFont(bfChinese, 12);
- PdfFont boldFont = new PdfFont(bfChinese, 12, PdfFont.BOLD);
- PdfFont titleFont = new PdfFont(bfChinese, 30, PdfFont.BOLD);
- PdfContentByte cb = writer.DirectContent;
- // ===== 横线 =====
- float lineY = doc.Top - 20f;
- cb.MoveTo(doc.Left, lineY);
- cb.LineTo(doc.Right, lineY);
- cb.Stroke();
- // ===== 页眉在横线之上 =====
- string headerText = "虚拟仿真实验中心";
- ColumnText.ShowTextAligned(
- cb,
- Element.ALIGN_CENTER,
- new Phrase(headerText, smallFont),
- (doc.Left + doc.Right) / 2,
- lineY + 10, // 横线上方 10pt
- 0
- );
- // ===== LOGO 横线上方左侧 =====
- string logoPath = Path.Combine(Application.streamingAssetsPath, logoFileName);
- // 统一去除 URL 前缀(特别是 file://)
- if (logoPath.StartsWith("file://"))
- logoPath = logoPath.Replace("file://", "");
- if (!File.Exists(logoPath))
- {
- // Unity Editor 下 StreamingAssets 在项目路径内
- logoPath = Path.Combine(Application.dataPath, "StreamingAssets", logoFileName);
- }
- float logoBottomY = lineY; // 用于计算标题位置
- if (File.Exists(logoPath))
- {
- try
- {
- byte[] logoBytes = File.ReadAllBytes(logoPath);
- iTextSharp.text.Image logo = iTextSharp.text.Image.GetInstance(logoBytes);
- // 👉 只固定高度,让宽度按比例缩放
- float targetHeight = 50f; // 设定统一显示宽度
- float scaleFactor = targetHeight / logo.Height; // 缩放比例
- logo.ScalePercent(scaleFactor * 100); // iTextSharp 用百分比
- // 保证顶部距离横线 5pt
- float logoTopY = lineY + 5f + logo.ScaledHeight;
- float logoPosY = logoTopY - logo.ScaledHeight;
- logoBottomY = logoPosY;
- // 让左下角对齐页边距
- logo.SetAbsolutePosition(doc.Left, logoPosY);
- doc.Add(logo);
- Debug.Log($"✅ Logo 添加成功(原始大小: {logo.Width}x{logo.Height}, 缩放比例: {scaleFactor:F2})");
- }
- catch (System.Exception e)
- {
- Debug.LogError("❌ 读取 Logo 出错:" + e.Message);
- }
- }
- else
- {
- Debug.LogWarning("⚠️ 未找到 Logo 文件:" + logoPath);
- }
- // ===== 主标题(单独一行居中) =====
- Paragraph title = new Paragraph("成 绩 单", titleFont);
- title.Alignment = Element.ALIGN_CENTER;
- title.SpacingBefore = 30f;
- title.SpacingAfter = 20f;
- doc.Add(title);
- // ===== 基本信息表格 =====
- PdfPTable infoTable = new PdfPTable(4);
- infoTable.WidthPercentage = 100;
- infoTable.SpacingBefore = 10f;
- infoTable.SpacingAfter = 15f;
- infoTable.SetWidths(new float[] { 1.2f, 2f, 1.2f, 2f });
- AddCell(infoTable, "姓名", boldFont, new BaseColor(235, 235, 235));
- AddCell(infoTable, studentName, normalFont);
- AddCell(infoTable, "实验日期", boldFont, new BaseColor(235, 235, 235));
- AddCell(infoTable, date, normalFont);
- AddCell(infoTable, "实验名称", boldFont, new BaseColor(235, 235, 235));
- AddCell(infoTable, experimentName, normalFont);
- AddCell(infoTable, "总成绩", boldFont, new BaseColor(235, 235, 235));
- AddCell(infoTable, totalScore.ToString("F1") + " 分", normalFont);
- AddCell(infoTable, "用时", boldFont, new BaseColor(235, 235, 235));
- AddCell(infoTable, useTime, normalFont);
- AddCell(infoTable, "", normalFont);
- AddCell(infoTable, "", normalFont);
- doc.Add(infoTable);
- // ===== 操作步骤表格 =====
- PdfPTable stepTable = new PdfPTable(3);
- stepTable.WidthPercentage = 100;
- stepTable.SetWidths(new float[] { 1f, 3f, 1f });
- AddHeaderCell(stepTable, "序号", boldFont);
- AddHeaderCell(stepTable, "操作步骤", boldFont);
- AddHeaderCell(stepTable, "分数", boldFont);
- foreach (var s in stepScores)
- {
- AddCell(stepTable, s.index.ToString(), normalFont);
- AddCell(stepTable, s.stepName, normalFont);
- AddCell(stepTable, s.score.ToString("F1"), normalFont);
- }
- doc.Add(stepTable);
- // ===== 评语 =====
- doc.Add(new Paragraph("\n"));
- string commentText = GenerateComment(totalScore);
- Paragraph comment = new Paragraph($"评语:{commentText}", normalFont);
- comment.SpacingBefore = 10;
- doc.Add(comment);
- doc.Close();
- writer.Close();
- Debug.Log($"✅ 成绩单导出成功:{savePath}");
- }
- private string GenerateComment(float score)
- {
- if (score >= 90f)
- return "表现优秀,操作熟练,理解深入。";
- else if (score >= 75f)
- return "完成良好,掌握较为扎实,可继续巩固。";
- else if (score >= 60f)
- return "基本达标,但仍需加强理解与操作细节。";
- else
- return "需改进,建议复习实验步骤并提高熟练度。";
- }
- private void AddHeaderCell(PdfPTable table, string text, PdfFont font)
- {
- PdfPCell cell = new PdfPCell(new Phrase(text, font));
- cell.BackgroundColor = new BaseColor(220, 220, 220);
- cell.HorizontalAlignment = Element.ALIGN_CENTER;
- cell.MinimumHeight = 25;
- table.AddCell(cell);
- }
- private void AddCell(PdfPTable table, string text, PdfFont font, BaseColor bg = null)
- {
- PdfPCell cell = new PdfPCell(new Phrase(text, font));
- cell.HorizontalAlignment = Element.ALIGN_CENTER;
- cell.VerticalAlignment = Element.ALIGN_MIDDLE;
- cell.MinimumHeight = 22;
- if (bg != null) cell.BackgroundColor = bg;
- table.AddCell(cell);
- }
- // ===== 页脚页码事件类 =====
- private class PdfPageEvents : PdfPageEventHelper
- {
- BaseFont bf;
- PdfFont footerFont;
- public PdfPageEvents()
- {
- string fontPath = Path.Combine(Application.dataPath, "Fonts/simhei.ttf");
- if (File.Exists(fontPath))
- {
- bf = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
- footerFont = new PdfFont(bf, 10);
- }
- }
- public override void OnEndPage(PdfWriter writer, Document document)
- {
- int pageN = writer.PageNumber;
- string text = "第 " + pageN + " 页 / 共 " + writer.PageNumber + " 页";
- PdfContentByte cb = writer.DirectContent;
- // 右下页码
- ColumnText.ShowTextAligned(
- cb,
- Element.ALIGN_RIGHT,
- new Phrase(text, footerFont),
- document.Right,
- document.Bottom - 20,
- 0
- );
- // 左下固定文字
- ColumnText.ShowTextAligned(
- cb,
- Element.ALIGN_LEFT,
- new Phrase("虚拟仿真实验考核系统 © 2025", footerFont),
- document.Left,
- document.Bottom - 20,
- 0
- );
- }
- }
- }
|