新增质量模块(工艺执行书 / 样茧试缫)与报表中心

质量模块:
- 11 张工艺执行书表:封面、试产、选剥茧(含混茧明细)、试缫与大样、煮茧(含分车间配温、副煮车间)、自动缫(含大样)、后缫
- 10 张样茧试缫表:原料小样/综合样主表 + 选茧、解舒、茧幅、切剖、清洁洁净、茧丝百回纤度
- 服务与接口、主控指针回写(列表 √ 标记)、封面编号自增、报表数据包
- 前端 8 张报表打印版式、7 类工艺单据与 6 类调查录入弹窗、字段驱动表单/表格组件
- 菜单种子新增「质量」目录,样茧子表增加 YjssType 判别列,避免原料小样与综合样自增 Id 重号串数据

报表中心:
- 报表模板管理、锐浪 grhtml5 加载与预览、全屏设计面板、数据源 Provider(落丝记录、职工花名册)

其他:同步工作进度 1-11 文档、开发数据库快照、.gitignore 忽略运行日志目录
This commit is contained in:
yanpeng200212
2026-10-22 10:30:37 +08:00
parent 8c4c464362
commit a8890c81e9
92 changed files with 14785 additions and 70 deletions
@@ -0,0 +1,130 @@
using FreeSql.DataAnnotations;
using F9WebAiTest.Domain.Events.SYS.Reports;
namespace F9WebAiTest.Domain.Entities.SYS.Reports;
/// <summary>
/// 报表定义(Grid++Report 模板)。每张报表对应一个 .grf 模板与一段数据查询 SQL。
/// 权限模型:创建/更新报表时自动同步一条 Permission(ResourceType=报表),
/// 角色在「角色管理 - 报表权限」中分配给用户后即可在报表中心查看。
/// </summary>
[Table(Name = "sys_reports")]
public class Report : AggregateRoot
{
[Column(Name = "code")]
public string Code { get; private set; } = ""; // 唯一标识,作为权限码的 resourceIdentity
[Column(Name = "name")]
public string Name { get; private set; } = ""; // 显示名称
[Column(Name = "category")]
public string Category { get; private set; } = "通用"; // 分类
[Column(Name = "description")]
public string Description { get; private set; } = ""; // 描述
/// <summary>数据集 SQL(必须以 SELECT 开头)。FreeSql ExecuteDataTable 执行。</summary>
[Column(Name = "data_sql")]
public string DataSql { get; private set; } = "";
/// <summary>数据集查询参数定义 JSON:[{"name":"deptId","label":"部门","type":"int","default":0}]</summary>
[Column(Name = "data_params")]
public string DataParams { get; private set; } = "[]";
/// <summary>
/// 查询配置 JSON(F9 ReportConfig 约定):
/// { "DsName":"查询名(后端 IReportDataProvider 解析)", "ViewerType":0,
/// "Parms":[{ "Name":"q_yearmonth","Label":"账期","Prompt":"","IsRequired":false,
/// "ControlType":"AntdUI.DatePickerYearMonth","Ds_Static":null,"Ds_Service":null,"DefaultValue":"" }] }
/// DsName 优先于 DataSql。
/// </summary>
[Column(Name = "config")]
public string Config { get; private set; } = "";
/// <summary>
/// 报表模板文件 Id(对齐 F9 Report.ReportFileId)。
/// 模板实例存储在 ReportFile(sys_report_files.DesignContent),与报表定义分离。
/// </summary>
[Column(Name = "report_file_id")]
public long ReportFileId { get; private set; }
// ---------- 以下三个字段已废弃(历史遗留列,仅供启动时把旧模板迁移到 ReportFile 读取) ----------
// 新代码一律通过 ReportFile.DesignContent 读写模板。
/// <summary>[已废弃] 旧版模板二进制,迁移到 ReportFile 后不再写入</summary>
[Column(Name = "template_data", MapType = typeof(byte[]))]
public byte[]? TemplateData { get; private set; }
[Column(Name = "template_name")]
public string TemplateName { get; private set; } = "";
[Column(Name = "template_size")]
public int TemplateSize { get; private set; }
[Column(Name = "sort_order")]
public int SortOrder { get; private set; }
[Column(Name = "is_active")]
public bool IsActive { get; private set; } = true;
public Report() { }
public Report(long id, string code, string name, string category, string description, string dataSql, string dataParams, int sortOrder, string config = "")
{
Id = id;
Code = code ?? "";
Name = name ?? "";
Category = string.IsNullOrWhiteSpace(category) ? "通用" : category.Trim();
Description = description ?? "";
DataSql = dataSql ?? "";
DataParams = string.IsNullOrWhiteSpace(dataParams) ? "[]" : dataParams;
Config = config ?? "";
SortOrder = sortOrder;
IsActive = true;
CreatedAt = DateTime.Now;
AddDomainEvent(new Report_ChangedDomainEvent(Id));
}
public void UpdateBasic(string code, string name, string category, string description, string dataSql, string dataParams, int sortOrder, string? config = null)
{
Code = code ?? Code;
Name = name ?? Name;
Category = string.IsNullOrWhiteSpace(category) ? Category : category.Trim();
Description = description ?? Description;
DataSql = dataSql ?? DataSql;
DataParams = string.IsNullOrWhiteSpace(dataParams) ? DataParams : dataParams;
Config = config ?? Config;
SortOrder = sortOrder;
UpdatedAt = DateTime.Now;
AddDomainEvent(new Report_ChangedDomainEvent(Id));
}
/// <summary>[已废弃] 旧版把模板二进制直接写在报表上;现模板存于 ReportFile.DesignContent</summary>
public void UploadTemplate(byte[] data, string fileName)
{
TemplateData = data ?? Array.Empty<byte>();
TemplateName = fileName ?? "";
TemplateSize = TemplateData.Length;
UpdatedAt = DateTime.Now;
AddDomainEvent(new Report_ChangedDomainEvent(Id));
}
/// <summary>绑定模板文件实例(对齐 F9:Report.ReportFileId → ReportFile)</summary>
public void BindReportFile(long reportFileId)
{
ReportFileId = reportFileId;
UpdatedAt = DateTime.Now;
AddDomainEvent(new Report_ChangedDomainEvent(Id));
}
/// <summary>迁移完成后清空废弃的旧模板字段</summary>
public void ClearLegacyTemplate()
{
TemplateData = null;
TemplateName = "";
TemplateSize = 0;
}
public void Activate() { IsActive = true; UpdatedAt = DateTime.Now; AddDomainEvent(new Report_ChangedDomainEvent(Id)); }
public void Deactivate() { IsActive = false; UpdatedAt = DateTime.Now; AddDomainEvent(new Report_ChangedDomainEvent(Id)); }
}