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

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

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

6.2 KiB
Raw Blame History

工作进度-8:模板源码在线编辑(免下载 / 上传)

时间:2026-10-20(承接工作进度-7) 触发:用户提出「能不能直接编辑对应报表的模板文件然后保存,而不是下载 → 改 → 上传 → 保存」


一、结论

可以。模板本来就以文本存在库里(sys_report_files.design_content,TEXT), 之前只是没有「写回文本」的入口,只能整文件上传。本次新增:

  • 后端一个接口:PUT /api/sys/report/{id}/template/content,请求体 { "content": "<模板全文>" }
  • 前端「模板源码」由只读改为可编辑,配「保存模板 / 格式化 / 撤销修改 / 放大编辑」

原来的「上传 .grf / 下载 .grf」保留不动(用于本机设计器排版、外部模板导入)。


二、方案取舍

方案 说明 结论
现状:下载 → 本地改 → 上传 需要本地装锐浪设计器或文本编辑器,来回一次文件 保留,不再作为主路径
在线编辑模板源码 + 保存 文本表单直接改 .grf 内容,保存即入库,刷新预览立即生效 ✅ 本次实现
内嵌可视化设计器(拖控件、改属性) 需要对 .grf 全量解析 / 回写;GR7 设计器格式是 _WR 压缩文本,无解码器 不做(见工作进度-5 遗留)

三、后端

3.1 DTO(ReportDtos.cs)

public class ReportTemplateContentDto { public string? Content { get; set; } }

3.2 Service(IReportService / ReportService.SaveTemplateContentAsync)

public async Task<int> SaveTemplateContentAsync(long id, string content)
{
    var entity = ... ?? throw new F9NotFoundException("报表不存在");
    var text = NormalizeTemplateContent(content);          // 去 BOM / trim,空内容拦截
    if (head.StartsWith('{') || head.StartsWith('['))
        JsonDocument.Parse(text);                          // JSON 语法校验,失败抛 F9OperationException
    await SaveTemplateAsync(entity, text);                 // 复用「有则更新 ReportFile,无则新建并绑定」
    ...
    return text.Length;
}
  • 与上传接口走同一套落库逻辑(SaveTemplateAsync),因此「新建 / 更新 / 绑定 report_file_id」行为一致
  • 校验规则:
内容形态 服务端行为
{...} / [...](GR6 JSON 模板) 语法校验,不合法直接 400「模板 JSON 不合法:…」
_WR...(GR7 设计器压缩文本) 原样保存(无法在服务端校验)
空 / 仅空白 400「报表模板内容为空」

3.3 接口(SysReportController)

PUT /api/sys/report/{id}/template/content
Body: { "content": "..." }
200 → { code: 200, data: { id, size, hasTemplate: true }, message: "模板已保存" }
404 → 报表不存在    400 → 内容为空 / JSON 不合法

与已有接口的关系:

方法 路由 用途
GET /{id}/template 渲染库 / 前端读模板
POST /{id}/template 上传 .grf 文件(设计器回传)
PUT /{id}/template/content 在线编辑后保存文本(本次新增)
GET /{id}/template/download 下载 .grf 给本机设计器

四、前端

4.1 ReportEditor.vue —— 「模板源码」页

  • 去掉 readonly;v-model="templateSource" 直接编辑
  • 新增状态:templateSaved(已入库内容,用于判定「未保存」)、templateSaving、wrUnlocked、sourceMaximized
  • 工具条:
按钮 / 标签 行为
JSON 模板 / _WR 压缩模板 当前模板形态提示
未保存 templateSource !== templateSaved 时显示
格式化 JSON.parse + JSON.stringify(…, '\t');非 JSON 禁用
撤销修改 确认后恢复为上次保存内容
放大编辑 整屏弹窗编辑同一份文本(同一 v-model)
保存模板 前端先校验 JSON,再 PUT /sys/report/{id}/template/content
  • 保存成功后:重新拉取模板 → hasTemplate = true → 重置预览(提示点「刷新预览」)→ emit('saved')
  • 「保存报表」时若模板源码有未保存修改,会先弹确认:先保存模板 / 忽略模板修改,避免手改内容被静默丢弃
  • _WR 压缩模板默认只读,需勾「允许编辑」才可改,保存前再二次确认(无本地校验能力)
  • 报表未保存时提示「请先保存报表,再编辑模板源码」;已保存但无模板时也可以直接粘贴 JSON 保存(相当于无文件新建模板)

4.2 预览缓存

grhtml5 拉模板是普通 GET,容易被浏览器缓存。预览 URL 追加 _t=Date.now()(编辑器与报表中心都加),保证改完模板点「刷新预览」能看到新内容。

4.3 views/report/manage/index.vue —— 列表页入口

  • 每行新增「编辑模板」:选中该报表并让右侧工作台直接打开「模板源码」页(ReportEditor 新增 openSource prop,配合 designerKey 强制重载)
  • 「上传模板 / 下载模板」保留

五、验证

项 结果
后端 dotnet build(输出到独立目录避开运行中进程锁定) ✅ 0 错误
IReportService / ReportService / DTO / Controller 改动 ✅ 编译通过
前端 IDE 诊断(ReportEditor.vue、manage/index.vue、center/index.vue) ✅ 0 诊断
前端 npm run build ⚠ 当前环境无 node/npm,未执行;需在本机 cd web && npm run build 复核

运行中的 F9WebAiTest.Api 仍在用旧程序集,需重启后端后新接口才生效。


六、遗留

  1. 无语法高亮 / 行号:目前是 el-input textarea,后续可换 CodeMirror / Monaco(需新增前端依赖)。
  2. 无模板历史版本:手工改坏后无法一键回滚,只能重新「生成模板」或重新上传;建议后续给 sys_report_files 加版本表。
  3. _WR 仍不能结构化编辑:需要锐浪的解码 / 编码算法,暂以「允许编辑 + 风险提示」兜底。
  4. 保存模板不刷新明细字段 / 报表参数页签:手改 DetailGrid.Recordset.Field 后,左栏字段列表仍是旧值(点「识别明细列与报表参数」可同步)。