ABP + Verify(快照) 驱动的 PDF/Excel 导出回归

ABP + Verify(快照) 驱动的 PDF/Excel 导出回归 🚀



0) TL;DR ✨

  • 将导出回归拆为两条通路:

    1. 文本/结构层:用 PdfPig 提取 PDF 文本/坐标生成 JSON 快照;
    2. 像素层ImageMagick 将 PDF 每页栅格化为 PNG 做阈值化对比。
  • 启用 Strict JSON、按 runtime 隔离快照,CI 中 禁 GUI diff;失败产出 .received.*,审阅通过晋级 .verified.*

  • EPPlus 8 必须显式设置 License;Excel 以结构快照为主,必要时加视觉抽样

  • Magick.NET 读取 PDF 需要 Ghostscript(Linux CI 尤其要装)。


1) 背景与目标 🎯

导出常见问题:字体回退、行高/分页漂移、二维码清晰度下降、Excel 样式/公式摇摆、跨机结果不一致。
目标:用 确定性渲染 + 规范化快照 + 阈值化对比,让改动看得见、量得出、可回滚.received.verified)。


2) 架构与职责(解耦渲染器) 🧩

QA / Snapshot Harness(测试层)
Infra(渲染器层)
App / Domain(业务层)
规范化
PDF→文本JSON / PNG
Excel→结构JSON
Verify · 文本/结构(JSON)
Verify · 像素(PNG)
工件:.verified/.received
IReportRenderer
QuestPdfRenderer
产出 PDF bytes
EpplusRenderer
产出 XLSX bytes
Exporter
中立 DTO
  • Exporter:产出中立 DTO,不绑定库。
  • Renderer:仅负责 PDF/Excel 渲染。
  • Snapshot Harness:统一转 JSON/PNG 并交给 Verify 断言与基线管理。

3) “确定性”前置条件(去伪差异) 🔒

PDF 文本层
PDF 像素层
Excel 结构
<think>好的,我现在需要帮助用户找到在ABP框架中使用EasyUI显示后端数据的示例教程。首先,我得回忆一下ABP框架的基本结构和EasyUI的特点。ABP框架是基于DDD和分层架构的,通常包含应用层、领域层、基础设施层和表示层。而EasyUI是一个基于jQuery的前端UI框架,主要用于快速开发后台管理系统。 用户的问题涉及到如何将后端数据通过EasyUI展示,所以重点应该在表示层如何与后端交互。根据用户提供的引用内容,视图需要注册监视的模型,以便刷新数据。这可能涉及到ABP中的动态Web API,前端如何调用这些API获取数据,然后使用EasyUI的组件如datagrid来显示。 接下来,我需要考虑ABP后端如何创建应用服务暴露数据。通常ABP的应用服务会返回DTO,然后通过动态JavaScript代理生成API端点。前端部分需要使用EasyUI的组件,比如通过Ajax调用这些API获取数据,并绑定到datagrid上。 可能的步骤包括:创建应用服务、定义DTO、配置路由、前端页面引入EasyUI库、编写JavaScript调用API,以及数据绑定。此外,可能需要处理权限问题,比如在ABP中配置权限,确保前端能访问相应的API。 用户可能需要具体的代码示例,比如应用服务的代码、前端HTML和JavaScript的示例。同时,需要注意ABP的版本,不同版本可能有不同的配置方式,但用户没有提到版本,所以需要假设是最新的或者通用的方法。 另外,可能涉及到的ABP功能包括动态Web API、自动API控制器生成、以及Ajax响应封装。EasyUI方面,需要展示如何使用datagrid组件,设置URL参数指向ABP的API端点,并处理返回的数据格式是否符合EasyUI的要求,比如可能需要调整数据格式为包含rows和total的结构。 最后,用户可能需要教程链接或进一步的学习资源,但目前无法提供外部链接,所以需要描述具体步骤和代码示例,确保用户能根据说明自行实现。</think>在ABP框架中结合EasyUI展示后端数据,需要遵循分层架构并实现数据绑定。以下是具体实现步骤: ### 一、后端数据服务搭建 1. **创建应用服务** ```csharp public interface IProductAppService : IApplicationService { Task<PagedResultDto<ProductDto>> GetListAsync(PagedAndSortedResultRequestDto input); } public class ProductAppService : ApplicationService, IProductAppService { private readonly IRepository<Product> _repository; public ProductAppService(IRepository<Product> repository) { _repository = repository; } public async Task<PagedResultDto<ProductDto>> GetListAsync(PagedAndSortedResultRequestDto input) { var query = await _repository.GetQueryableAsync(); var total = query.Count(); var items = query.OrderBy(input.Sorting) .Skip(input.SkipCount) .Take(input.MaxResultCount) .ToList(); return new PagedResultDto<ProductDto>(total, ObjectMapper.Map<List<ProductDto>>(items)); } } ``` ### 二、前端数据绑定 1. **创建EasyUI数据表格视图** ```html <!-- Views/Product/Index.cshtml --> <table id="dg" class="easyui-datagrid" title="产品列表" url="/api/app/product" pagination="true" rownumbers="true" fitColumns="true"> <thead> <tr> <th field="name" width="150">产品名称</th> <th field="price" width="100">价格</th> <th field="creationTime" width="180">创建时间</th> </tr> </thead> </table> ``` 2. **配置ABP动态代理(需启用自动API控制器)** ```javascript // 在ABP启动配置中启用 abp.ajax.setXMLHttpRequestResolver(function (options) { return $.ajax(options); }); ``` ### 三、关键配置项 1. **跨域配置(Startup.cs)** ```csharp services.AddCors(options => { options.AddPolicy("EasyUICors", builder => { builder.WithOrigins("http://localhost:62114") .AllowAnyHeader() .AllowAnyMethod(); }); }); ``` 2. **响应格式适配** ```javascript // 在EasyUI初始化时适配ABP的响应格式 $('#dg').datagrid({ loader: function(param, success, error){ $.ajax({ type: 'GET', url: this.url, data: { skipCount: (param.page - 1) * param.rows, maxResultCount: param.rows }, dataType: "json", success: function(data){ success({ total: data.totalCount, rows: data.items }); } }); } }); ``` ### 四、权限控制 在ABP权限系统中配置: ```csharp Configuration.Modules.AbpAspNetCore().CreateControllersForAppServices( typeof(ProductAppService).Assembly, moduleName: "app", useConventionalHttpVerbs: true); ``` [^1]: 视图需要访问被监视的模型数据,这通过ABP的动态Web API和EasyUI的数据绑定机制实现 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kookoos

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值