质量模块: - 11 张工艺执行书表:封面、试产、选剥茧(含混茧明细)、试缫与大样、煮茧(含分车间配温、副煮车间)、自动缫(含大样)、后缫 - 10 张样茧试缫表:原料小样/综合样主表 + 选茧、解舒、茧幅、切剖、清洁洁净、茧丝百回纤度 - 服务与接口、主控指针回写(列表 √ 标记)、封面编号自增、报表数据包 - 前端 8 张报表打印版式、7 类工艺单据与 6 类调查录入弹窗、字段驱动表单/表格组件 - 菜单种子新增「质量」目录,样茧子表增加 YjssType 判别列,避免原料小样与综合样自增 Id 重号串数据 报表中心: - 报表模板管理、锐浪 grhtml5 加载与预览、全屏设计面板、数据源 Provider(落丝记录、职工花名册) 其他:同步工作进度 1-11 文档、开发数据库快照、.gitignore 忽略运行日志目录
190 lines
9.8 KiB
Markdown
190 lines
9.8 KiB
Markdown
# 工作进度-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()` 精度隐患等。
|