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

质量模块:
- 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
+167
View File
@@ -0,0 +1,167 @@
# 工作进度-2:报表查询控件体系(Web 版 Page_ReportQueryTool 同构化)
> 时间:2026-10-19(承接工作进度-1)
> 范围:修复报表编辑器 / 报表中心缺陷 + 建立 Web 端「自定义控件注册中心」与「选择页」机制
> 参考实现:WinForms 端 `F9.Common.Report.Pages.Page_ReportQueryTool`、`F9.Common.Report.SelectPages`、`F9GlobalUIHelper`
---
## 一、本轮目标
1. 修复编辑报表页首开报「请求失败」、明细字段 / 模板参数不显示
2. 把 WinForms 端「按 `ControlType` 分发创建控件」的机制,在 Web 端做成**可注册、可扩展的控件模块**
3. 庄口类参数改为**打开选择页**(不再用下拉塞全量数据)
4. 部门控件按**口径**取数(不是一把全量)
5. 修复编辑器「添加参数后看不到新参数」
---
## 二、缺陷修复清单
| # | 现象 | 根因 | 解决 |
|---|---|---|---|
| 1 | 首次进编辑报表报「请求失败」,明细字段 / 模板参数暂无数据 | `GET /sys/report/{id}/template` 返回**裸 .grf JSON**(无 `ApiResult` 包装),`request.js` 拦截器强制 `data.code === 200` → 判失败 → 前端兜底空模板 | 拦截器放行非 ApiResult 响应(`!('code' in data)` 时原样返回) |
| 2 | 报表中心点击后**整页空白** | `select/index.js` 写了 `export { F9SelectPage } from './F9SelectPage.vue'`;**.vue 只有默认导出** → `SyntaxError` → vue-router 导航抛错 → 白屏 | 先 `import` 再具名导出 |
| 3 | 编辑器「添加参数后看不到新参数」 | `.left` 用 `max-height: calc(100% - 320px)` + 内层 `overflow`,两层滚动把新卡片截在可视区外 | 改「tab 头固定 + 内容区独立滚动」;`addParm` 后 `scrollIntoView` |
| 4 | 前缫车间控件列出**全部 38 个部门** | 部门控件直接 `GET /sys/department` 全量,未实现 F9 的口径过滤与建树 | 新建 `utils/departments.js`(Web 版 `F9GlobalUIHelper`) |
| 5 | 落丝记录庄口用下拉塞 1000 条 | 原实现 `pageSize:1000` 拉全量 | 改为打开「工艺庄口选择页」 |
---
## 三、Web 自定义控件模块
WinForms 端结构:
```
GetParamControl(prm)
├─ ControlType 以 "F9" → GetParamControlOfF9(...) // 业务选择页 / 业务下拉
└─ ControlType 以 "AntdUI" → GetParamControlOfAntdUI(...) // 基础控件
→ 每个分支创建控件 + 注册取值函数 _paramGetValudFuncs
```
Web 端同构为「**控件定义注册中心 + 统一渲染组件**」:
| 文件 | 说明 | 对应 WinForms |
|---|---|---|
| `web/src/utils/gridreport/controls/registry.js` | `registerControl / getControlDef / groupedControlOptions / resolveControlDef / fallbackDef` + 取值工具(`toOptions / apiOptions / registryOptions / pickRows / rowLabel`) | `_paramGetValudFuncs` |
| `web/src/utils/gridreport/controls/antdControls.js` | 一个 type 一个函数 + `ANTD_BUILDERS` 分发 | `GetParamControlOfAntdUI` |
| `web/src/utils/gridreport/controls/f9Controls.js` | 顶部注入数据源,一个 type 一个函数 + `F9_BUILDERS` 分发 | `GetParamControlOfF9` |
| `web/src/utils/gridreport/controls/index.js` | 装配注册两组控件;`parseStaticDs / fetchServiceDs / loadParamOptions` | `GetParamControl` |
| `web/src/components/report/F9ParamControl.vue` | 统一渲染(input / select / multiselect / date / yearmonth / year / picker / 树形下拉) | 控件实例 |
| `web/src/utils/departments.js` | 部门口径 + 建树 + 默认选中 | `F9GlobalUIHelper` |
**已注册控件 38 个**(6 个 AntdUI + 32 个 F9),编辑器「控件类型」下拉按 group 分组自动列出。
### kind 映射与取值口径
| Web kind | 渲染 | F9 对应 | 取值 |
|---|---|---|---|
| `input` | el-input | `AntdUI.Input` | 文本 |
| `select` | el-select / **el-tree-select**(`tree: true`) | `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** |
| `picker-multiple` | 同上多选 | `F9-GYZK-SELECT-MUTIPLE` | `"1,2,3"` |
选项优先级:`Ds_Static` → `Ds_Service` → 控件 `loader` → 静态 `options`;
picker 优先级:**选择页 `page`** > 内建远程搜索 `search` > 降级文本输入。
新增控件只需两步,无需改页面:
```js
registerControl({
type: 'F9-MY-SELECT', kind: KIND.SELECT, group: 'F9 自定义', label: '我的选择',
loader: async () => [{ key: '1', value: '选项一' }],
});
```
---
## 四、选择页机制(对应 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` —— 对应 `ResolvePage<T>()` |
复用方式:
```vue
<CraftZhuangKouSelect v-model="visible" @confirm="onPicked" /> <!-- 业务页面 -->
{ type: 'F9-GYZK-SELECT', kind: KIND.PICKER, page: 'CraftZhuangKou', valueField: 'id', labelField: 'productionDisplayName' } <!-- 报表控件 -->
```
已落地:**落丝记录(lsjl)庄口**改为打开选择页;`F9-GYZK-SELECT` / `F9-GYZK-SELECT-MUTIPLE` 绑定该页。
---
## 五、部门口径(Web 版 `F9GlobalUIHelper`)
| F9 方法 / 查询 | Web 实现 |
|---|---|
| `Department_GetAllCacheAsync` | `getAllDeps()`(缓存) |
| `GetDepartmentByDutyTypeWithoutRightQuery(types)` | `depsByDuty()`(只保留自身 DutyType 命中) |
| `GetDepartmentOfSiyeQuery(includeSiye)` | `depsOfSiye()`(丝业中心 + 全部子孙) |
| `GetDepartmentForEmployee/Kaoqin/XinziQuery` | `depsOfLoginUser()`(本部门 + 子孙;管理员=全部)+ `removeCompany()` |
| `Dep_GenerateSelectItems` | `buildDepTree()`(SortOrder → Code → Name,父不在集合内即为根) |
| `Dep_Select_SelectDep(sel, depId)` | `defaultFromUser: true` → 默认选中登录用户部门 |
| 控件 | 口径 | 实测(38 个部门) |
|---|---|---|
| `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`(新增) | 全部 | 完整部门树 |
lsjl 车间下拉同步改为 `depOptions({ duty: [DUTY.前缫] }, { flat: true })`,替换原 `name.includes('前缫')`。
---
## 六、交互与布局修复(编辑器)
```css
.left { display: flex; flex-direction: column; overflow: hidden; }
.left :deep(.el-tabs) { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.left :deep(.el-tabs__header) { flex: 0 0 auto; }
.left :deep(.el-tabs__content) { flex: 1 1 auto; min-height: 0; overflow: auto; }
.config-src { flex: 0 0 auto; }
```
`addParm()` 后 `activeLeftTab = 'params'` + `nextTick` 滚动到最后一张卡片(实测:连续添加 5 个后 `LAST_VISIBLE=YES`)。
---
## 七、调试方法(本轮建立的验证手段)
无 Node/npm 环境,用无头 Edge 验证 SPA 运行时:
```powershell
# 1) 临时诊断页 web/public/__diag.html:登录写 localStorage → iframe 打开目标页 → 模拟点击 → 输出 DOM 断言
# 2) 抓控制台
msedge --headless=new --virtual-time-budget=45000 --enable-logging=stderr --v=1 --dump-dom "http://localhost:5173/__diag.html"
```
用该方法定位了 #2(白屏 SyntaxError)与 #3(滚动)等问题;诊断页用完即删。
另:动态 `import('/src/utils/departments.js')` 可在诊断页内直接单测模块逻辑(验证部门口径即用此法)。
---
## 八、当前状态
| 项 | 状态 |
|---|---|
| 报表中心(树 + 查询面板 + 多 Tab 预览) | 正常,切换报表参数随报表切换 ✅ |
| 报表管理 / 全屏编辑器 | 正常(配置/参数/设计/源码/预览)✅ |
| 自定义控件注册中心 | 38 个控件,编辑器下拉自动分组 ✅ |
| 选择页(工艺庄口) | 报表控件 + lsjl 业务页均已接入 ✅ |
| 部门口径 | 前缫 / 丝业 / 职工 / 考勤 / 薪资 / 全部 ✅ |
| 落丝记录庄口 | 改为选择页 ✅ |
## 九、遗留与后续建议
1. **部门缓存**:`getAllDeps()` 有内存缓存,部门增删后需 `clearDepCache()`(可在部门管理保存后调用)
2. **选择页覆盖**:职工 / 物资目录目前用内建远程搜索弹窗,如需与 F9 一致的选择页可再注册 `EmployeeSelect` / `WuziMuluSelect`
3. **Web 端无对应接口的 F9 控件**:样茧试缫(`F9-QC-YJSS-*`)、生丝批次枚举(`SSPiciKucunStatusEnum` 等)走注册表或 `Ds_Static`,界面上有降级提示
4. **picker 取 Id**:报表 Provider 需按 Id 解析参数(庄口 / 职工 / 物资均为 Id)
5. **规范**:新增 `.vue` 再导出必须 `import X from './X.vue'` 后具名导出,禁止 `export { X } from './X.vue'`