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

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

其他:同步工作进度 1-11 文档、开发数据库快照、.gitignore 忽略运行日志目录
2026-10-22 10:30:37 +08:00

190 lines
9.8 KiB
Markdown
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.
# 工作进度-5:新增报表「自动配置参数与列 + 默认初始化报表」
> 时间:2026-10-20(承接工作进度-4)
> 环境:后端 .NET 8 + FreeSql + MediatR(Windows/SQLite),前端 Vue3 + Element Plus + Vite
> 目标:把工作进度-4 删除内嵌设计器时一起丢失的能力补回来 —— **新增报表时自动识别数据源参数与明细列,并默认生成一张可用的报表(模板 + 配置一次落库)**
---
## 一、背景
工作进度-4 移除了自研网页设计器(`ReportDesigner.vue`),报表管理页只保留「配置 / 参数 / 预览 / 模板源码」。
结果:
- 新增报表必须先手工上传 `.grf` 才能预览,否则只有 1 个 `Field1` 占位列;
- `Config.Parms`(查询参数)全靠手填,控件类型是纯文本;
- 数据源有哪些字段(明细列)只能去下载模板里看。
本轮补齐:**选数据源 → 自动带出参数与明细列 → 保存时自动生成 `.grf` → 立即可预览**。
---
## 二、后端
### 2.1 新增文件
| 文件 | 说明 |
|---|---|
| `Application/Dtos/SYS/Reports/ReportScaffoldDtos.cs` | `ReportParameterDefDto`(参数定义) / `ReportDataSourceInfoDto`(数据源) / `ReportFieldDefDto`(明细列) / `ReportProbeRequestDto` / `ReportProbeResultDto` |
| `Application/Interfaces/Reports/IReportDataProviderMeta.cs` | **可选**元数据接口:`Label` / `GetParameters()` / `GetFieldLabels()`,未实现的 Provider 行为不变(默认接口方法) |
### 2.2 服务
`IReportService` / `ReportService` 新增两个方法:
| 方法 | 说明 |
|---|---|
| `GetDataSourcesAsync()` | 遍历 DI 注册的 `IReportDataProvider` 字典,返回 `DsName` + 中文名 + 参数定义 |
| `ProbeAsync(request)` | 按 `DsName`(优先)或 `DataSql` **执行一次查询**,返回参数定义 + 明细字段(列名/中文名/类型)+ 前 3 行样本;失败时 `Error` 带原因且不抛 500 |
探测细节:
- Provider 分支:`provider.GetData(pairs, mediator)` → 取第一个有数据的记录集 → 首行键名即列名 → `IReportDataProviderMeta.GetFieldLabels()` 提供中文标题
- SQL 分支:`ExecuteDataTable(sql)`(只绑定 SQL 里出现的 `@参数`)→ `DataTable.Columns` 即列名
- 参数取值:请求值 > `Parms[].DefaultValue`;缺少默认值直接传空,查询失败只记 `Error`
- 错误分级:有 `DsName` 但找不到实现 → `未找到数据源实现:xxx`;两者都空 → `请先选择数据源(DsName)或填写数据 SQL`
### 2.3 接口
| 端点 | 说明 |
|---|---|
| `GET api/sys/report/datasources` | 数据源清单(参数定义随附) |
| `POST api/sys/report/scaffold` | 结构探测:`{ dsName, dataSql, parms, params }` → `{ parameters, fields, rows, total, error }` |
> 路由说明:`datasources` 为字面量段,优先于 `{id}` 匹配,不影响原详情接口。
### 2.4 示例 Provider 补元数据
`RepDt_Sys_Users` 实现 `IReportDataProviderMeta`:
- 参数:`q_dep`(部门 / `AntdUI.Select` / `Ds_Service=/sys/department`)、`q_like`(关键字 / `AntdUI.Input`)
- 字段中文名:`EmployeeCode=工号, EmployeeName=姓名, Gender=性别, DepName=部门, WorktypeName=工种, Phone=电话, RuzhiDate=入职日期`
新增数据源时实现该接口即可被编辑器自动识别,未实现也能正常查询。
---
## 三、前端(`components/report/ReportEditor.vue`)
### 3.1 数据源与自动识别
| 项 | 实现 |
|---|---|
| 数据源输入 | `el-select`(`filterable + allow-create`):列出来自 `/sys/report/datasources` 的「中文名(DsName)」,也可手输未登记名称 |
| 自动触发 | 选中数据源即调用 `POST /sys/report/scaffold`(`onDsChange`) |
| 手动触发 | 配置页「自动识别参数与列」按钮;参数页 / 明细字段页也可再次识别 |
| 结果 | 覆盖 `Parms`(名称/标签/提示/控件类型/Ds_Service/Ds_Static/默认值)+ 填充明细列,并自动切到「明细字段」tab |
### 3.2 明细字段 tab
新增第三个左栏 tab(`明细字段 (n)`):
- 列卡片:启用勾选 / 字段名(可改) / 列标题(可改) / 列宽(0.8~8cm)/ 删除
- `+ 添加列` 手工补列(数据源无数据时用)
- `生成模板`:按当前字段生成 `.grf`,新建时随保存写入,编辑时点保存才覆盖(有二次确认)
- 底部展示探测返回的样本行,便于核对字段含义
编辑已有报表时,若模板是 JSON 格式,会**反解**出 `DetailGrid.Recordset.Field` + `Column.Width` + `ColumnTitleCell.Text` 回填到明细字段;`_WR7_` 压缩模板无法反解(留空,不影响继续使用)。
### 3.3 默认生成模板(`buildTemplate()`)
结构派生自内置示例模板 `employee_directory.grf`(GR7 兼容 `Version=6.8.5.0`):
| 区块 | 内容 |
|---|---|
| `DetailGrid` | 记录集字段 = 启用的明细列;`Column.Width` 按 17cm 均分(1.2~4);`ColumnTitleCell.Text` = 列标题 |
| `ReportHeader[0]` | 报表标题(名称) |
| `ReportHeader[1]` | 每个查询参数一组「标签 StaticBox + `Parameter` 绑定 StaticBox」,每行 4 组 |
| `Parameter` | 参数名 = `Parms[].Label`(与后端 `Parameter_Data` 键一致,如 `部门` / `关键字`) |
| `PageHeader` / `PageFooter` | 系统名水印 + 页码 + 打印时间(与示例一致) |
**保存语义**:
- 新建:`templateJson = buildTemplate()`(无字段时退化为单列占位,保证不会出现「未配置模板」)
- 编辑:默认不提交模板(避免覆盖设计器上传的 `.grf`);只有点了「生成模板」(`templateDirty`)才写入
### 3.4 顺带修复(工作进度-4 遗留 5 的一部分)
参数「控件类型」由纯文本输入改为**分组下拉 + 可手输**,数据来自 `utils/gridreport/controls` 注册中心(38 个 AntdUI / F9 控件),与报表中心查询面板同源。
---
## 四、验证记录
### 4.1 接口层
```
GET /api/sys/report/datasources
→ [{ dsName: RepDt_Sys_Users, label: 职工花名册,
parameters: [q_dep/部门/AntdUI.Select/Ds_Service=/sys/department, q_like/关键字/AntdUI.Input] }]
POST /api/sys/report/scaffold { dsName: RepDt_Sys_Users }
→ PARMS=2 FIELDS=7 TOTAL=942 ERR=(空)
EmployeeCode/工号, EmployeeName/姓名, Gender/性别, DepName/部门,
WorktypeName/工种, Phone/电话, RuzhiDate/入职日期
ROW0={EmployeeCode:"",EmployeeName:"付华芳",Gender:"女",DepName:"丝业生产中心",...}
POST /api/sys/report/scaffold { dataSql: "SELECT id AS Id, code AS Code, name AS Name FROM sys_rbac_menus LIMIT 5" }
→ SQL_FIELDS=3 TOTAL=5 ERR=(空) Id,Code,Name
POST /api/sys/report/scaffold { dsName: RepDt_Not_Exists }
→ BAD_ERR=未找到数据源实现:RepDt_Not_Exists
```
### 4.2 页面全链路(无头 Edge,`/report/manage`)
```
LIST_ITEMS=2 TOPBAR=新增报表
ADD_BTN=true LEFT_TABS=配置,参数 (0),明细字段 (0) ← 新增后进入空表单
DS_OPTIONS=1 [职工花名册(RepDt_Sys_Users)] ← 下拉来自注册表
选中后自动识别:
LEFT_TABS2=配置,参数 (2),明细字段 (7)
DETECT_INFO=已识别 7 列 / 2 参数
FIELD_NAMES=EmployeeCode,EmployeeName,Gender,DepName,WorktypeName,Phone,RuzhiDate
SAMPLE=EmployeeCode= | EmployeeName=付芳华 | Gender=女 | DepName=丝业生产中心 | ...
保存(未上传任何 .grf):
AFTER_SAVE_TOPBAR=编辑报表 · 诊断自动配置报表
AFTER_SAVE_TAG=模板已配置
VIEWER_CHILDREN=3
VIEWER_TEXT=诊断自动配置报表 部门:(全部) 关键字:(全部) 工号 姓名 性别 部门 工种 电话 入职日期
付芳华 女 丝业生产中心 15884942961 2012-02-01 何均 女 ...
ALERT=保存成功
后端核对:
API_ROW={ hasTemplate:true }
TPL_FIRST3={ ← 生成的是 JSON 模板(非 _WR)
TPL_FIELDS=7
TPL_COLUMNS=工号,姓名,性别,部门,工种,电话,入职日期
TPL_PARAM=部门,关键字
CFG_DS=RepDt_Sys_Users PARMS=q_dep/AntdUI.Select,q_like/AntdUI.Input
CLEANUP=200 ← 测试报表已删除
```
### 4.3 编译 / 运行
- 后端 `dotnet build`:**0 错误 0 警告**(先停 `F9WebAiTest.Api` 进程再编译,避免 MSB3027)
- 前端无 lint 诊断;无头 Edge 实跑整页(识别 → 保存 → GR7 渲染)通过
- 服务:后端 `http://localhost:3000`、前端 `http://localhost:5173` 均在运行
---
## 五、当前状态
| 项 | 状态 |
|---|---|
| 新增报表:数据源下拉 + 一键识别参数与列 | ✅ |
| 新增报表:保存自动生成 `.grf`(默认初始化),保存后直接可预览 | ✅ |
| 明细字段可编辑(字段名 / 标题 / 列宽 / 启用)并据此生成模板 | ✅ |
| 编辑已有 JSON 模板:反解明细列回填 | ✅(`_WR7_` 压缩模板无法反解) |
| SQL 数据源(无 DsName)也能探测列 | ✅ |
| 参数控件类型:38 个注册控件分组下拉 | ✅ |
| 探测失败不阻断:提示原因,仍可手工加列保存 | ✅ |
---
## 六、遗留与后续建议
1. **Provider 参数声明需手工补**:新增 `IReportDataProvider` 时建议同时实现 `IReportDataProviderMeta`,否则编辑器只能识别字段、参数要手填。
2. **`_WR7_` 模板不能反解列**:编辑这类报表时「明细字段」为空,重新生成会覆盖设计器排版(已有二次确认)。若需要,可在后端通过 GR7 库或 `gr.wr.decodeWR` 的等价实现解码后再解析。
3. **探测会执行真实查询**:大报表(如 942 条职工)识别需要等待查询完成;后续可给 Provider 增加「仅取结构」的轻量方法(如返回空参数 + `LIMIT 0`)。
4. **列宽均分**:自动生成的列宽按 17cm 均分,超宽字段(地址、备注)仍需到设计器里调整。
5. **进度-4 遗留项仍在**:`Report_FavoriteGroup` 未实现、历史废弃列未 DROP、进度-3 的 `Number()` 精度隐患等。