质量模块: - 11 张工艺执行书表:封面、试产、选剥茧(含混茧明细)、试缫与大样、煮茧(含分车间配温、副煮车间)、自动缫(含大样)、后缫 - 10 张样茧试缫表:原料小样/综合样主表 + 选茧、解舒、茧幅、切剖、清洁洁净、茧丝百回纤度 - 服务与接口、主控指针回写(列表 √ 标记)、封面编号自增、报表数据包 - 前端 8 张报表打印版式、7 类工艺单据与 6 类调查录入弹窗、字段驱动表单/表格组件 - 菜单种子新增「质量」目录,样茧子表增加 YjssType 判别列,避免原料小样与综合样自增 Id 重号串数据 报表中心: - 报表模板管理、锐浪 grhtml5 加载与预览、全屏设计面板、数据源 Provider(落丝记录、职工花名册) 其他:同步工作进度 1-11 文档、开发数据库快照、.gitignore 忽略运行日志目录
338 lines
20 KiB
Markdown
338 lines
20 KiB
Markdown
# 工作进度-1:报表中心模块(Grid++Report 6 集成)
|
||
|
||
> 时间:2026-10-19
|
||
> 环境:后端 .NET 8 + FreeSql + MediatR(Windows),前端 Vue3 + Element Plus + Vite
|
||
> 本机 Grid++Report 版本:**6.8.23.0618**(设计器 `grdesigner6.exe`)
|
||
|
||
---
|
||
|
||
## 一、目标
|
||
|
||
在系统(智慧缫丝 / F9WebAiTest)中嵌入报表系统:
|
||
|
||
1. 报表中心作为菜单页面,支持报表的**新增 / 删除 / 修改**
|
||
2. 每张报表有独立权限,管理员需在「角色管理 → 权限分配」中给角色授权后,用户才能看到
|
||
3. 报表支持 F9 的 `ReportConfig` 约定:动态查询控件 + 按 `DsName` 解析后端查询
|
||
|
||
---
|
||
|
||
## 二、Grid++Report 6 Web 嵌入方案调研(结论)
|
||
|
||
本机安装目录 `C:\Grid++Report 6` 关键发现:
|
||
|
||
| 项 | 结论 |
|
||
|---|---|
|
||
| 浏览器插件方案(NPAPI/ActiveX) | Chrome / Edge 已不支持,**弃用** |
|
||
| `grhtml5-6.8-min.js` | HTML5 浏览器内渲染,免插件、跨浏览器 ✅ |
|
||
| `grwebapp.js` + `grwebapp6.exe` | 本机 WEB 报表客户端,支持 preview/print/pdf/xls/csv/img/grd 等 |
|
||
| `.grf` 文件格式 | **UTF-8 BOM + JSON 文本**(可程序化生成) |
|
||
| `.grf` 版本 | 官方设计器保存为 `6.8.5.0`;`WebSamples` 里的样本是 `6.6.8.1` |
|
||
| `.grf` 文件关联 | `GR.Template` → `"C:\Grid++Report 6\grdesigner6.exe" "%1"` |
|
||
| 已有 URL 协议 | `grwebapp://` → `grwebapp6.exe` |
|
||
|
||
采用方案:**HTML5 网页内预览为主 + 本机客户端打印导出为辅 + f9designer 协议唤起设计器编辑**。
|
||
|
||
---
|
||
|
||
## 三、后端实现
|
||
|
||
### 1. 领域实体
|
||
|
||
| 文件 | 说明 |
|
||
|---|---|
|
||
| `Domain/Entities/SYS/Reports/Report.cs` | 报表实体(表 `sys_reports`),继承 `AggregateRoot` 自动建表 |
|
||
| `Domain/Events/SYS/Reports/Report_ChangedDomainEvent.cs` | 报表变更领域事件 |
|
||
|
||
`Report` 字段:`Code / Name / Category / Description / DataSql / DataParams / Config / TemplateData(byte[]) / TemplateName / TemplateSize / SortOrder / IsActive`
|
||
|
||
### 2. 权限模型(与现有 RBAC 完全契合)
|
||
|
||
现有 `Resource_Type_Enum` 已内置 `报表 = 3`,直接复用:
|
||
|
||
- 新建报表 → 自动创建 `Permission`(`ResourceType=报表`, `ResourceId=Report.Id`, `Code=report:{code}:visble`)
|
||
- 改编码 → 同步权限 Code;删除报表 → 级联删除权限单元 + `RolePermission` 关联
|
||
- 授权入口:角色管理 → 权限分配 → 「报表权限」tab(复用现有 `resourceType=3` 接口)
|
||
- 用户可见性:`AuthService.GetUserPermissionsAsync` 原生返回所有类型权限码 → 前端按 `report:{code}:visble` 过滤
|
||
|
||
### 3. 数据查询架构(F9 同构)
|
||
|
||
```
|
||
报表 Config.DsName
|
||
→ IReportDataProvider 注册表(静态 ReportName 解析)
|
||
→ MediatR CQRS Query → QueryHandler(注入业务读仓储)
|
||
→ ReportDto_DataSource(Report_Data: 数据集名 → ReportDataDto_Data)
|
||
→ ToGridReportJson() 转成 Grid++ JSON 数据
|
||
```
|
||
|
||
| 文件 | 说明 |
|
||
|---|---|
|
||
| `Application/Dtos/SYS/Reports/ReportDataSourceDto.cs` | `ReportDto_DataSource` + `ReportDataDto_Data`(`Field_Data` / `Parameter_Data`) |
|
||
| `Application/Interfaces/Reports/IReportDataProvider.cs` | `ReportName` + `GetData(pairs, mediator)` |
|
||
| `Application/CQRS/SYS/Reports/Queries/GetEmployeeDirectoryRepQuery.cs` | 职工花名册查询(注入 `IEmployeeReadRepository`) |
|
||
| `Application/Services/Reports/Providers/RepDt_Sys_Users.cs` | 示例 Provider(DsName = `RepDt_Sys_Users`) |
|
||
| `Application/Services/Reports/ReportService.cs` | CRUD + 权限联动 + 数据执行 + JSON 转换 |
|
||
| `Application/Services/Reports/IReportService.cs` | 服务接口 |
|
||
| `Application/Dtos/SYS/Reports/ReportDtos.cs` | 列表/详情/视图/增删改 DTO |
|
||
| `Api/Controllers/SysReportController.cs` | REST 控制器(详见下) |
|
||
|
||
### 4. 控制器端点
|
||
|
||
| 端点 | 说明 |
|
||
|---|---|
|
||
| `GET api/sys/report` | 分页(管理) |
|
||
| `GET api/sys/report/all` | 全部启用报表(角色授权树用) |
|
||
| `GET api/sys/report/{id}` | 详情(含 DataSql / Config) |
|
||
| `POST api/sys/report` | 新增(自动创建权限单元) |
|
||
| `PUT api/sys/report/{id}` | 修改(同步权限 Code) |
|
||
| `DELETE api/sys/report/{id}` | 删除(级联清理权限) |
|
||
| `POST api/sys/report/{id}/template` | 上传 .grf(multipart,限 .grf,50MB) |
|
||
| `GET api/sys/report/{id}/template/download` | 下载 .grf |
|
||
| `GET api/sys/report/{id}/template[.json\|.grf]` | 模板下载(供 HTML5 / 客户端,支持 `?access_token=`) |
|
||
| `GET/POST api/sys/report/{id}/data[.json]` | 报表数据(Grid++ JSON 格式) |
|
||
| `GET api/sys/report/visible` | 当前用户可见报表(按权限过滤) |
|
||
| `GET api/sys/report/{id}/preview` | 预览(模板 URL + 数据,包 `ApiResult`) |
|
||
|
||
### 5. 种子
|
||
|
||
`Infrastructure/Data/DbSeeder.cs`:
|
||
- `SeedReportMenus()`:`/report` 目录 + `/report/center`(报表中心)+ `/report/manage`(报表管理),自动授权 admin
|
||
- `SeedSampleReport()`:示例报表「职工花名册」(code `employee_directory`)
|
||
- `LoadEmbeddedTemplate()`:从嵌入资源读取 `.grf`
|
||
|
||
### 6. 其他后端改动
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `Api/Program.cs` | JwtBearer `OnMessageReceived` 支持 `/api/sys/report` 路径的 query token |
|
||
| `Application/DependencyInjection.cs` | 注册 `IReportService` + 自动扫描注册所有 `IReportDataProvider` |
|
||
| `Infrastructure/F9WebAiTest.Infrastructure.csproj` | `.grf` 模板作为嵌入资源 |
|
||
| `Application/F9WebAiTest.Application.csproj` | 新增 `System.Data.SQLite.Core`(与 FreeSql 驱动一致) |
|
||
| `Infrastructure/Assets/ReportTemplates/employee_directory.grf` | 基于官方 6.8.5.0 结构派生的示例模板 |
|
||
|
||
---
|
||
|
||
## 四、前端实现
|
||
|
||
| 文件 | 说明 |
|
||
|---|---|
|
||
| `web/public/grlib/grhtml5-6.8-min.js` | 官方 HTML5 渲染库(246KB) |
|
||
| `web/src/utils/gridreport/grwebapp.js` | 官方 WEB 客户端通信库 |
|
||
| `web/src/utils/gridreport/loadGrhtml5.js` | 动态加载 HTML5 库脚本 |
|
||
| `web/src/utils/gridreport/reportConfig.js` | F9 ReportConfig 解析 + 动态控件渲染映射 |
|
||
| `web/src/views/report/center/index.vue` | 报表中心(左侧分类树 + 动态查询面板,右侧多 Tab 报表区) |
|
||
| `web/src/views/report/manage/index.vue` | 报表管理(列表 + 打开全屏编辑器) |
|
||
| `web/src/views/report/manage/editor.vue` | 全屏报表编辑器(配置 / 设计 / 源码 / 预览) |
|
||
| `web/src/router/index.js` | componentMap 增加 `report/center/index`、`report/manage/index` |
|
||
| `web/src/views/sys/role/index.vue` | 权限分配对话框增加「报表权限」tab(`RESOURCE_TYPE.report = 3`) |
|
||
|
||
### 报表编辑器(editor.vue)页面结构
|
||
|
||
```
|
||
┌─────────────┬──────────────────────────────────────────┐
|
||
│ [配置][参数] │ [设计][源码 JSON][预览视图] │
|
||
│ │ 本机设计器 | 上传.grf | 下载.grf | 保存 │
|
||
│ 分组 │ 设计视图:报表标题 + 明细字段表格 │
|
||
│ 编号 │ 源码视图:完整 .grf JSON │
|
||
│ 名称 │ 预览视图:grhtml5 实时渲染(切换即渲染) │
|
||
│ 顺序 │ │
|
||
│ 数据源DsName │ │
|
||
│ 数据SQL │ │
|
||
│ 备注 │ │
|
||
│ Config JSON │ │
|
||
└─────────────┴──────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 五、本机设计器直连(f9designer:// 协议)
|
||
|
||
| 文件 | 说明 |
|
||
|---|---|
|
||
| `tools/report-designer/F9ReportDesignerHandler.ps1` | 协议处理器:下载模板 → 打开设计器 → 关闭后自动回传 |
|
||
| `tools/report-designer/install-f9designer-protocol.reg` | 注册协议(**HKCU 用户级,无需管理员**,已在本机注册) |
|
||
|
||
流程:
|
||
```
|
||
浏览器 --f9designer://open?base=..&rid=..&token=..&code=..--> Windows Shell
|
||
--> .ps1:curl 下载 .grf 到 %TEMP%\F9ReportDesigner\
|
||
--> 启动 grdesigner6.exe(等待关闭)
|
||
--> 关闭后 curl POST 回传模板 + 弹窗提示
|
||
```
|
||
|
||
---
|
||
|
||
## 六、踩坑与解决方案(重要)
|
||
|
||
| # | 问题 | 根因 | 解决 |
|
||
|---|---|---|---|
|
||
| 1 | 点击报表报「报表加载失败 请求失败」 | `/preview` 返回裸对象,而 `request.js` 拦截器要求 `data.code === 200` | 后端 Preview 包 `ApiResult` |
|
||
| 2 | 报表中心页面白屏 | `buildTree` 中根节点未初始化 `reports`,`node.reports.forEach` 抛 TypeError | 根/目录节点补 `reports: []` + 防御性兜底;目录 id 改为基于路径稳定值 |
|
||
| 3 | HTML5 取模板报 400「请选择要上传的 .grf 模板文件」 | grhtml5 库约定:**URL 不含 `.json` 就用 POST**(`/\.json/.test(url) ? "GET" : "POST"`),POST 撞上上传接口 | 模板增加 `.json` 路由别名,前端 URL 以 `.json` 结尾 |
|
||
| 4 | 客户端打印导出报「报表模板已经被破坏」 | grwebapp.js 同样约定(`.grf/.txt/.xml/.json` 才用 GET),且传给客户端的是相对 URL | 增加 `template.grf` / `data.json` 别名;前端传绝对 URL(`location.origin`) |
|
||
| 5 | 下载的 .grf 设计器打不开 | 手写模板标 `Version: 6.6.8.1` 且结构不完整,设计器 6.8 无法解析 | 改为基于官方 6.8.5.0 模板派生,作为嵌入资源 |
|
||
| 6 | 报表参数不生效 | 键名写成小写 `parameter`;且 HTML5 不解析文本内 `[#Parameter(xx)#]` 表达式 | 数据键名改 **`Parameter`**(大写);模板改用 `StaticBox` 的 `"Parameter":"关键字"` 属性绑定,并在模板顶层声明 `Parameter` 节点 |
|
||
| 7 | 字段值渲染为空 | ASP.NET 默认 camelCase 序列化把 `EmployeeName` 输出成 `employeeName`,与模板字段不符 | 数据行改用 `Dictionary` 承载(字典键不受命名策略影响),反射 + PropertyInfo 缓存 |
|
||
| 8 | 切到预览视图空白 | `watch(activeView)` 未触发渲染 | 切换到 preview 时自动调用 `renderPreview()` |
|
||
| 9 | 协议唤起脚本不执行 | `.ps1` 为 UTF-8 **无 BOM**,PowerShell 5.1 按 GBK 读取致中文乱码、语法破坏 | 转为 **UTF-8 BOM** |
|
||
| 10 | 注册表写入失败 | `HKEY_CLASSES_ROOT` 需管理员 | 改注册到 `HKEY_CURRENT_USER\Software\Classes`(免管理员) |
|
||
| 11 | 第一次进编辑报表页报「请求失败」,明细字段/模板参数暂无数据 | 编辑器 `GET /sys/report/{id}/template` 返回**裸 .grf JSON**(无 ApiResult 包装),`request.js` 拦截器要求 `data.code === 200`,判定失败 reject → 前端兜底为空模板(字段/参数全空) | 拦截器增加放行:响应无 `code` 字段(非 ApiResult 包装,如模板原文/文件流)直接原样返回 |
|
||
|
||
### Grid++ 数据 JSON 格式约定(已验证)
|
||
|
||
```jsonc
|
||
// 单数据集
|
||
{ "recordset": [ {...}, {...} ] }
|
||
|
||
// 多数据集(顶层键 = 数据集名)
|
||
{ "Master": [ {...} ], "Detail": [ {...} ] }
|
||
|
||
// 报表参数(键名必须与模板 Parameter 节点一致,渲染器取数组第一项)
|
||
{ "recordset": [...], "Parameter": [ { "账期": "2026年10月", "车间": "前缫" } ] }
|
||
```
|
||
|
||
---
|
||
|
||
## 七、新增报表的标准流程
|
||
|
||
1. 建 CQRS:`XXXRepQuery` + Handler,Handler 内注入业务**读仓储**查询,组装 `ReportDto_DataSource`
|
||
- `Field_Data`:每行匿名对象的属性名 = 模板字段名
|
||
- `Parameter_Data`:账期 / 车间 / 查询时间等报表参数
|
||
2. 建 Provider:`RepDt_XXX : IReportDataProvider`,`ReportName` 常量 + 解析 `pairs` → `mediator.Send(query)`(DI 自动发现,无需注册)
|
||
3. 报表管理 → 新增报表,填 `Config`:
|
||
```json
|
||
{
|
||
"DsName": "RepDt_XXX",
|
||
"ViewerType": 0,
|
||
"Parms": [
|
||
{ "Name": "q_yearmonth", "Label": "账期", "Prompt": "", "IsRequired": false,
|
||
"ControlType": "AntdUI.DatePickerYearMonth", "Ds_Static": null, "Ds_Service": null, "DefaultValue": "默认值" }
|
||
]
|
||
}
|
||
```
|
||
4. 用设计器做 `.grf`(记录集字段对齐 `Field_Data`;显示查询条件的控件设 `"Parameter":"账期"`,模板顶层声明 `Parameter` 节点)
|
||
5. 上传模板 → 角色管理分配报表权限 → 打开即可
|
||
|
||
**ControlType 支持**:`AntdUI.Input` / `AntdUI.Select` / `AntdUI.SelectMultiple` / `AntdUI.DatePicker` / `AntdUI.DatePickerYearMonth` / `AntdUI.DatePickerYear`;`F9-*` 业务控件见下方「自定义控件模块」。
|
||
|
||
---
|
||
|
||
## 七之二、Web 自定义控件模块(对应 F9 `Page_ReportQueryTool.GetParamControl`)
|
||
|
||
WinForms 端按 `ControlType` 字符串 if/else 分发创建控件(`GetParamControlOfF9` / `GetParamControlOfAntdUI`),
|
||
Web 端同构为**注册中心 + 统一渲染组件**:新增控件只注册一次,查询面板与编辑器下拉同时生效。
|
||
|
||
| 文件 | 说明 | 对应 WinForms |
|
||
|---|---|---|
|
||
| `web/src/utils/gridreport/controls/registry.js` | 注册中心:`registerControl / getControlDef / groupedControlOptions / resolveControlDef / fallbackDef` + 取值工具(`toOptions / apiOptions / registryOptions / pickRows`) | `_paramGetValudFuncs` 注册表 |
|
||
| `web/src/utils/gridreport/controls/antdControls.js` | AntdUI 基础控件(一个 type 一个函数 + `ANTD_BUILDERS` 分发) | `GetParamControlOfAntdUI` |
|
||
| `web/src/utils/gridreport/controls/f9Controls.js` | F9 业务控件(一个 type 一个函数 + `F9_BUILDERS` 分发) | `GetParamControlOfF9` |
|
||
| `web/src/utils/gridreport/controls/index.js` | 装配入口:注册 AntdUI + F9 两组控件;`parseStaticDs / fetchServiceDs / loadParamOptions` | `GetParamControl` |
|
||
| `web/src/components/report/F9ParamControl.vue` | 统一渲染:input / select / multiselect / date / yearmonth / year / picker(选择页 / 远程搜索 / 降级输入) | 控件实例 |
|
||
|
||
### 选择页(对应 F9.Common.Report.SelectPages)
|
||
|
||
| 文件 | 说明 |
|
||
|---|---|
|
||
| `web/src/components/select/F9SelectPage.vue` | 通用选择页弹窗:过滤条件 + 关键字 + 分页表格 + 单选/多选 + 校验(对应 `F9ModalPageUserControl_Medium` + `f9AntdUITable` 的 `QueryData` / `ValidCustom`) |
|
||
| `web/src/components/select/CraftZhuangKouSelect.vue` | 工艺庄口选择页(对应 `Page_CraftZhuangKou_SelectV2`:庄口编号/名称/产地/排序/备注/年度,年度过滤,数据 `GET /api/craftzhuangkou`) |
|
||
| `web/src/components/select/index.js` | 选择页注册中心:`registerSelectPage / getSelectPage` |
|
||
|
||
控件绑定选择页:控件定义里写 `page: 'CraftZhuangKou'`,`F9ParamControl` 即打开该页(优先级:选择页 > 内建远程搜索 > 降级文本输入)。
|
||
业务页面直接复用:`<CraftZhuangKouSelect v-model="visible" @confirm="onPicked" />`(**落丝记录 lsjl 的庄口已改为打开选择页**)。
|
||
|
||
控件定义字段:`{ type, kind, label, group, hint, useDs, options, loader(prm), search(kw), columns, valueField, labelField, multiple }`
|
||
|
||
### kind 与 F9 的映射
|
||
|
||
| Web kind | 渲染 | F9 对应 | 取值 |
|
||
|---|---|---|---|
|
||
| `input` | el-input | `AntdUI.Input` | 文本 |
|
||
| `select` | el-select | `AntdUI.Select` / 各 `F9-*-SELECT` | key(部门为 Id) |
|
||
| `multiselect` | el-select multiple | `AntdUI.SelectMultiple` / `F9-WMS-SS-PICI-KCSTATUS` | `"a,b,c"`(对齐 `string.Join(",")`) |
|
||
| `date` / `yearmonth` / `year` | el-date-picker | `AntdUI.DatePicker*` | `YYYY-MM-DD` / `YYYY-MM` / `YYYY` |
|
||
| `picker` | 只读框 + 选择按钮 → 弹窗表格远程搜索 | `ShowModalPage(Page_XXX_Select)` | 记录 **Id**(与 F9 一致) |
|
||
| `picker-multiple` | 同上多选 | `F9-GYZK-SELECT-MUTIPLE` | `"1,2,3"` |
|
||
|
||
选项优先级:`Ds_Static` → `Ds_Service` → 控件 `loader` → 静态 `options`;picker 无 `search` 实现时自动降级为文本输入。
|
||
|
||
### 部门控件:Web 版 F9GlobalUIHelper
|
||
|
||
WinForms 端部门下拉不是一把全量,而是**按口径取数 + ParentId 建树**(`F9GlobalUIHelper` + 各 `GetDepartment*Query`)。
|
||
Web 端同构实现:`web/src/utils/departments.js`
|
||
|
||
| F9 方法 / 查询 | Web 实现 |
|
||
|---|---|
|
||
| `Department_GetAllCacheAsync` | `getAllDeps()`(缓存,`GET /api/sys/department`) |
|
||
| `GetDepartmentByDutyTypeWithoutRightQuery(types)` | `depsByDuty(deps, types)`(只保留自身 DutyType 命中) |
|
||
| `GetDepartmentOfSiyeQuery(includeSiye)` | `depsOfSiye(deps, true)`(丝业中心 + 全部子孙) |
|
||
| `GetDepartmentForEmployee/Kaoqin/XinziQuery` | `depsOfLoginUser()`(本部门 + 子孙;管理员=全部)+ `removeCompany()` |
|
||
| `Dep_GenerateSelectItems` | `buildDepTree()`(SortOrder → Code → Name,父不在集合内即为根) |
|
||
| `Dep_Select_SelectDep(sel, depId)` | `defaultFromUser: true` → 默认选中登录用户部门 |
|
||
|
||
| 控件 | 口径 | 实测结果 |
|
||
|---|---|---|
|
||
| `F9-DEP-QS-SELECT` | DutyType=前缫(25) | 前缫车间#26 → 前缫一~四车间#31-34 |
|
||
| `F9-DEPARTMENT_SIYE` | 丝业 | 丝业生产中心#2 + 全部子孙 |
|
||
| `F9-DEP-EMPLOYEE-SELECT` / `F9-DEP-XZ-SELECT` / `F9-DEPARTMENT_KAOQIN` | 职工 / 薪资 / 考勤口径(默认登录部门) | 管理员=全部,否则本部门+子孙 |
|
||
| `F9-DEP-ALL-SELECT`(新增) | 全部 | 完整部门树 |
|
||
|
||
渲染:控件定义 `tree: true` → `F9ParamControl` 用 `el-tree-select`(层级展示,取值仍为部门 Id)。
|
||
落丝记录(lsjl)的车间下拉也改为 `depOptions({ duty: [DUTY.前缫] }, { flat: true })`,替换掉原来的 `name.includes('前缫')`。
|
||
|
||
### 已内置的 F9 控件
|
||
|
||
- 庄口:`F9-GYZK-SELECT`(**打开工艺庄口选择页**)、`F9-GYZK-SELECT-MUTIPLE`(多选,取值 `"1,2,3"`)
|
||
- 部门/职工:`F9-DEP-QS-SELECT`、`F9-DEPARTMENT_SIYE`、`F9-DEP-EMPLOYEE-SELECT`、`F9-DEP-XZ-SELECT`、`F9-DEPARTMENT_KAOQIN`、`F9-EMPLOYEE-SELECT`(picker)、`F9-EMPLOYEE-WORKSTATUS`、`F9-EMPLOYEE-CHANGE_TYPE_SELECT`、`F9-Employee-isXuegong`
|
||
- 物资/原料:`F9-WZ-SS/FP/ZJP/WJ-SELECT`(picker)、`F9-YLZK-SELECT`(picker)、`F9-WMS-YL-CD/JIBIE/CANPINZHONG`(注册表)
|
||
- 生产/质量:`F9-YEXIAN-SOURCE-SELECT`、`F9-GUIGE-SELECT`、`F9-PROD-QS-LSCD-YICHANG`、`F9-PROD-QS-ZHJJ-COUNT`、`F9-QC-YJSS-YLXY/ZHY-SELECT`(降级输入)
|
||
- 仓储:`F9-WMS-CRKTYPE`、`F9-WMS-SS-PICI-KCSTATUS`(多选)、`F9-WMS-SS-PICI-SSTYPE`、`F9-WMS-YL-RK/CK-TYPE-SELECT`
|
||
|
||
Web 端无对应枚举/接口的走注册表或 `Ds_Static`,并在编辑器/查询面板显示降级提示。
|
||
|
||
### 扩展新控件(两步,无需改页面)
|
||
|
||
```js
|
||
import { registerControl, KIND } from '@/utils/gridreport/controls';
|
||
registerControl({
|
||
type: 'F9-MY-SELECT', kind: KIND.SELECT, group: 'F9 自定义', label: '我的选择',
|
||
loader: async () => [{ key: '1', value: '选项一' }],
|
||
});
|
||
// 弹窗选择类:再给 search / columns / valueField / labelField
|
||
```
|
||
|
||
报表管理 → 参数 → 「控件类型」下拉自动按 group 分组列出所有已注册控件。
|
||
|
||
---
|
||
|
||
## 八、当前状态
|
||
|
||
| 项 | 状态 |
|
||
|---|---|
|
||
| 后端编译 | 0 错误 0 警告 ✅ |
|
||
| 后端服务 | 运行中 `http://localhost:3000` ✅ |
|
||
| 前端服务 | 运行中 `http://localhost:5173` ✅ |
|
||
| 报表中心页面 | 正常(分类树 + 查询面板 + 多 Tab 预览)✅ |
|
||
| 报表管理 + 全屏编辑器 | 正常(配置/设计/源码/预览)✅ |
|
||
| 职工花名册示例 | 942 条职工数据 + 报表参数正常渲染 ✅ |
|
||
| 本机设计器协议 | 已注册,下载→编辑→自动回传全链路验证通过 ✅ |
|
||
| 角色授权(报表权限 tab) | 已实现 ✅ |
|
||
|
||
### 启动方式
|
||
|
||
```powershell
|
||
# 后端
|
||
cd backend/F9WebAiTest.Api
|
||
dotnet run
|
||
|
||
# 前端
|
||
cd web
|
||
npm run dev
|
||
```
|
||
|
||
默认账号:`admin / 123456`
|
||
|
||
### 备注
|
||
|
||
- 日志目录 `.run-logs/`(backend.log、frontend.log、start-web.bat)
|
||
- 协议脚本日志:`%TEMP%\F9ReportDesigner\handler.log`
|