From 258a8dacd274c19a75dc5ade7b0b094cdb4da270 Mon Sep 17 00:00:00 2001 From: WeiCHEN Date: Tue, 8 Sep 2026 20:36:02 +0800 Subject: [PATCH] feat(engine): add project template cloning factory and unit tests Co-authored-by: Cursor --- web/src/engine/templateFactory.test.ts | 64 +++++ web/src/engine/templateFactory.ts | 308 +++++++++++++++++++++++++ 2 files changed, 372 insertions(+) create mode 100644 web/src/engine/templateFactory.test.ts create mode 100644 web/src/engine/templateFactory.ts diff --git a/web/src/engine/templateFactory.test.ts b/web/src/engine/templateFactory.test.ts new file mode 100644 index 00000000..947757b8 --- /dev/null +++ b/web/src/engine/templateFactory.test.ts @@ -0,0 +1,64 @@ +import test from 'node:test'; +import assert from 'node:assert'; +import { + createProjectTemplateDeliverables, + STANDARD_WORKFLOW_TEMPLATES, +} from './templateFactory'; + +test('createProjectTemplateDeliverables: 必须精确生成 7 份全生命周期受控文档副本', () => { + assert.strictEqual(STANDARD_WORKFLOW_TEMPLATES.length, 7); + + const result = createProjectTemplateDeliverables({ + projectId: 999, + projectName: '微创智能吻合吻合器系统', + deviceType: '腔镜吻合器', + creatorId: 10, + creatorName: '赵工程师', + }); + + // 1. 验证数量与任务映射 + assert.strictEqual(result.deliverables.length, 7); + assert.strictEqual(Object.keys(result.docASTMap).length, 7); + + const expectedTaskKeys = [ + 'intake', + 'research', + 'feasibility_reg', + 'feasibility_dev', + 'user_requirements', + 'prelim_design', + 'cdo_quote', + ]; + const actualTaskKeys = result.deliverables.map((d) => d.taskKey); + assert.deepStrictEqual(actualTaskKeys, expectedTaskKeys); + + // 2. 验证阶段覆盖 (V0.1, V0.5, V1.0) + const stages = new Set(result.deliverables.map((d) => d.stage)); + assert.ok(stages.has('V0.1')); + assert.ok(stages.has('V0.5')); + assert.ok(stages.has('V1.0')); + + // 3. 验证元数据装配与模板标记 + result.deliverables.forEach((doc) => { + assert.strictEqual(doc.projectId, 999); + assert.strictEqual(doc.isTemplateOnly, true); + assert.strictEqual(doc.lifecycleState, 'template'); + assert.strictEqual(doc.isFixedWorkflow, true); + assert.strictEqual(doc.creatorId, 10); + assert.strictEqual(doc.creatorName, '赵工程师'); + assert.ok(doc.docId.startsWith('doc-p999-')); + + const ast = result.docASTMap[doc.docId]; + assert.ok(ast, `AST for ${doc.docId} should exist`); + assert.ok(ast.rootBlock.children && ast.rootBlock.children.length > 0, `AST for ${doc.docId} should have blocks`); + }); + + // 4. 验证变量注入 (项目名、器械类型注入成功,无裸露的宏占位符) + const intakeDoc = result.deliverables.find((d) => d.taskKey === 'intake')!; + const intakeAst = result.docASTMap[intakeDoc.docId]; + const fullText = JSON.stringify(intakeAst); + assert.ok(fullText.includes('微创智能吻合吻合器系统')); + assert.ok(fullText.includes('腔镜吻合器')); + assert.ok(!fullText.includes('{{project_name}}')); + assert.ok(!fullText.includes('{{device_type}}')); +}); diff --git a/web/src/engine/templateFactory.ts b/web/src/engine/templateFactory.ts new file mode 100644 index 00000000..10b0e4a2 --- /dev/null +++ b/web/src/engine/templateFactory.ts @@ -0,0 +1,308 @@ +import { DeliverableItem, StageKey } from '../types/workbench'; +import { DocumentAST } from '../types/block'; +import { markdownToBlockAST } from './markdownToBlock'; + +export interface TemplateFactoryParams { + projectId: number; + projectName: string; + deviceType: string; + creatorId: number; + creatorName: string; + customerName?: string; + authorName?: string; + reviewerName?: string; + approverName?: string; +} + +export interface TemplateFactoryResult { + deliverables: DeliverableItem[]; + docASTMap: Record; +} + +export interface TemplateDefinition { + taskKey: string; + title: string; + stage: StageKey; + summary: string; + markdownSkeleton: string; +} + +export const STANDARD_WORKFLOW_TEMPLATES: TemplateDefinition[] = [ + { + taskKey: 'intake', + title: '用户初始需求收集表', + stage: 'V0.1', + summary: '梳理客户原始临床需求与约束条件,提炼事实清单、技术假设与待确认缺口。', + markdownSkeleton: `# 用户初始需求收集表 (项目模板副本) + +- 项目名称:{{project_name}} +- 申报器械:{{device_type}} +- 客户单位:{{customer_name}} +- 创建时间:{{generated_at}} +- 状态:【初始模板待填报】 + +## 1. 临床背景与预期用途 +本项目针对微创临床应用场景,计划研制符合法规规范的 {{device_type}}。 +> [待确认] 临床科室、主要适应症与操作痛点待智能体小队与客户进一步摸底确认。 + +## 2. 客户诉求与关键约束 +- 预算目标:待确认 +- 研发周期:预计 6~12 个月 +- 目标市场:中国 NMPA(重点关注) + +## 3. 已有输入材料摘要 +当前项目已就绪基础信息,待导入技术规格、竞品参数及医院现场调研纪要。 + +## 4. 阻塞与待确认清单 +- [ ] 确定产品核心工作模式与工作频段 +- [ ] 明确预期配套使用耗材或附件 +- [ ] 确认是否需符合专用安全标准 +`, + }, + { + taskKey: 'research', + title: '全球竞品技术与临床深度调研报告', + stage: 'V0.5', + summary: '国内外主流竞品性能对标、临床痛点反思、FTO专利侵权风险排查与差异化突破建议。', + markdownSkeleton: `# 全球竞品技术与临床深度调研报告 (项目模板副本) + +- 项目名称:{{project_name}} +- 分析对象:{{device_type}} +- 生成基准:{{generated_at}} + +## 1. 全球主要竞品横向性能对标 +针对国际一线品牌同类器械开展多维度技术参数对比: + +| 关键技术指标 | 国际竞品 A | 国际竞品 B | 本项目技术指标 (目标) | +| :--- | :--- | :--- | :--- | +| 成像/测量精度 | 待填报 | 待填报 | 待智能体结合基线生成 | +| 接口通信延时 | 待填报 | 待填报 | < 35 ms | +| 探头工作端温升 | 待填报 | 待填报 | ≤ 38.5 ℃ | +| 市场参考售价 | 待填报 | 待填报 | 高性价比国产化替代 | + +## 2. 外科临床核心痛点 +1. 现有进口设备操作学习曲线陡峭; +2. 极端工况下长期稳定性不足; +3. 配套高值耗材采购成本高昂。 + +## 3. 自由实施 (FTO) 专利回避流程 +\`\`\`mermaid +flowchart TD + Search[专利数据库初步检索] --> Filter[锁定涉案核心权项] + Filter --> RiskCheck{是否存在侵权涉案特征?} + RiskCheck -- 是 --> Redesign[提出回避设计方案] + RiskCheck -- 否 --> Clear[合规绿灯:免除侵权风险] +\`\`\` + +## 4. 商业化突破与市场定位建议 +建议采取“精准平替+临床增强”双轮驱动策略,切入国内地市级三甲微创中心。 +`, + }, + { + taskKey: 'feasibility_reg', + title: '注册路径与合规可行性评估报告', + stage: 'V0.5', + summary: '医疗器械分类界定依据、强制性国行标检测要求、临床评价路径与注册审评审批规划。', + markdownSkeleton: `# 注册路径与合规可行性评估报告 (项目模板副本) + +- 项目名称:{{project_name}} +- 申报器械:{{device_type}} +- 基线时间:{{generated_at}} + +## 1. 监管分类界定与依据条目 +依据国家药品监督管理局《医疗器械分类目录》,初步判定如下: +> [合规引证] 待智能体小队依据知识库最新版分类目录条目进行精确比对与推荐。 + +## 2. 强制性合规标准矩阵 +经查验国家医疗器械强制性国家标准库与行业标准库,本项目预研规划需满足: + +| 标准编号 | 标准名称 | 适用等级 | 拟采取合规工程措施 | +| :--- | :--- | :--- | :--- | +| GB 9706.1-2020 | 医用电气设备 第1部分:基本安全和基本性能的通用要求 | 强制性国标 | 隔离电源设计与微安级漏电流控制 | +| YY 9706.102-2021 | 医用电气设备 第1-2部分:电磁兼容要求和试验 | 强制性行标 | 滤波隔离阵列与抗扰度 Class B 防护 | +| GB/T 16886.1 | 医疗器械生物学评价 第1部分:风险管理过程中的评价与试验 | 生物相容性 | 人体接触部位材料无毒性检验 | + +## 3. 成像与探测信噪比物理判据模型 +$$ +SNR = \\frac{S_{signal}}{\\sqrt{\\sigma_{ambient}^2 + \\sigma_{dark}^2 + \\sigma_{read}^2}} \\ge 18.5\\,\\text{dB} +$$ + +## 4. 结论与申报建议 +(待智能体小队检索法规库后填报正式合规结论)。 +`, + }, + { + taskKey: 'feasibility_dev', + title: '设计开发可行性评估报告', + stage: 'V0.5', + summary: '工程化差距分析、核心元器件供应链自控能力、软硬件技术路线与潜在失效风险应对。', + markdownSkeleton: `# 设计开发可行性评估报告 (项目模板副本) + +- 项目名称:{{project_name}} +- 评估对象:{{device_type}} +- 报告时间:{{generated_at}} + +## 1. 技术路线可行性概述 +针对 {{device_type}} 的研制目标,工程团队对核心光电/传感方案与算法架构进行可行性论证。 + +## 2. 关键工程化差距评估表 + +| 研发模块 | 当前技术现状 | 量产目标指标 | 工程差距等级 | 解决途径 | +| :--- | :--- | :--- | :--- | :--- | +| 前端传感采集 | 实验室原理样件 | 工业级高灵敏度探头 | 中等差距 | 选型车规/医疗级芯片 | +| 高速算法处理 | 软件算法离线运行 | FPGA硬件级超低延时 | 重点突破 | 定制硬件并行处理流水线 | +| 整机热平衡 | 局部温升超标 | 工作端面 ≤ 41℃ | 必须达标 | 全金属微通道导热设计 | + +## 3. 潜在技术风险与缓解措施 +1. **核心芯片交期风险**:在硬件主板预留引脚兼容的国产替代芯片接口; +2. **算法实时性风险**:采用双缓冲乒乓流水架构,压减内存搬移开销。 +`, + }, + { + taskKey: 'user_requirements', + title: '医疗器械用户需求规范表 (URS)', + stage: 'V0.5', + summary: '明确术者与护士核心角色画像,建立可追溯的工程需求条目与临床验收准则。', + markdownSkeleton: `# 医疗器械用户需求规范表 (URS) (项目模板副本) + +- 项目名称:{{project_name}} +- 受控编号:URS-{{project_name}}-V1.0 +- 基线日期:{{generated_at}} + +## 1. 临床角色画像与操作流程 +- **主要术者 (主任医师)**:要求手术过程中无感知延迟,视觉色彩真实无拖影; +- **巡回护士**:要求设备快速开机,线缆连接具备防呆设计,移动轻便。 + +## 2. 可追溯用户需求条目清单 + +| 需求 ID | 需求陈述 | 临床来源 | 优先级 | 验收准则与思路 | +| :--- | :--- | :--- | :--- | :--- | +| UR-001 | 系统从冷机加电到输出稳定画面时间必须小于 15 秒 | 手术室快速急救准备 | 高 | 计时器实测加电启动时间 | +| UR-002 | 手持探头工作面接触人体部分温升不得引起组织灼伤 | GB 9706.1 强标要求 | 高 (强制) | 热成像仪全负荷 4 小时温升实测 | +| UR-003 | 支持脚踏控制一键切换工作显示模式 | 术者术中无菌操作要求 | 中 | 模拟手术操作盲按切换试验 | +`, + }, + { + taskKey: 'prelim_design', + title: '系统初步架构与电路规格设计书', + stage: 'V0.5', + summary: '硬件拓扑、高速数据链路传输拓扑、算法数学配准模型与关键元器件BOM选型。', + markdownSkeleton: `# 系统初步架构与电路规格设计书 (项目模板副本) + +- 项目名称:{{project_name}} +- 架构对象:{{device_type}} +- 日期:{{generated_at}} + +## 1. 硬件系统拓扑与数据链路 +\`\`\`mermaid +graph LR + Sensor["前端医用传感器组件"] -->|高速差分传输| ISP["专用图像与信号调理单元"] + ISP --> Processing["FPGA/DSP 核心数字处理引擎"] + Processing --> UI["医用高分监视器 & 医生控制台"] +\`\`\` + +## 2. 核心传感器像素配准算法矩阵 +$$ +\\begin{bmatrix} x_{aligned} \\\\ y_{aligned} \\\\ 1 \\end{bmatrix} = \\begin{bmatrix} h_{11} & h_{12} & h_{13} \\\\ h_{21} & h_{22} & h_{23} \\\\ h_{31} & h_{32} & 1 \\end{bmatrix} \\times \\begin{bmatrix} x_{raw} \\\\ y_{raw} \\\\ 1 \\end{bmatrix} +$$ + +## 3. 整板功耗与散热设计 +预计整机工作功耗约 28W,采用自然对流与铝合金阳极氧化外壳导热。 +`, + }, + { + taskKey: 'cdo_quote', + title: 'CDO商业报价单与工时测算清单', + stage: 'V1.0', + summary: '依据 CDO 医疗器械定价模型,对立项、研发、样品打样、型式检验与 DHF 进行精准工时拆解。', + markdownSkeleton: `# CDO商业报价单与工时测算清单 (项目模板副本) + +- 报价项目:{{project_name}} +- 目标产品:{{device_type}} +- 报价日期:{{generated_at}} +- 结算货币:人民币 (RMB) + +## 1. 全阶段 WBS 研发工时与预算分解表 + +| 阶段代码 | 里程碑任务分解 | 负责工程角色 | 预算工时 (h) | 预算人工 (万元) | 核心受控交付物 | +| :--- | :--- | :--- | :--- | :--- | :--- | +| V0.1 | 需求摸底、临床痛点与分类界定 | 法规专家 + 产品经理 | 80 | 4.20 | 《用户初始需求收集表》 | +| V0.5 | 方案设计、合规初评与专利检索 | 光学/架构师 + 注册专家 | 280 | 15.60 | 《注册可行性与设计规格书》 | +| V1.0 | 原型试制、型检跟进与全套DHF | 结构技师 + 验证工程师 | 380 | 18.00 | 《功能性工程样机与DHF文卷》 | +| **合计** | **全生命周期核心工作包** | **协同工程团队** | **740 h** | **37.80 万元** | **全套医疗器械申报技术卷宗** | + +## 2. 商业报价核算模型 +$$ +Total_{Price} = (Cost_{Labor} + Cost_{Material} + Cost_{Testing}) \\times (1 + Margin_{Risk}) +$$ +按标准模型测算,预估总报价区间为 48.00 ~ 65.00 万元(待正式锁定)。 +`, + }, +]; + +export function createProjectTemplateDeliverables( + params: TemplateFactoryParams +): TemplateFactoryResult { + const deliverables: DeliverableItem[] = []; + const docASTMap: Record = {}; + const nowStr = new Date().toISOString().replace('T', ' ').substring(0, 16); + const customerName = params.customerName || '委托开发客户企业'; + const author = params.authorName || params.creatorName || '编制工程师'; + const reviewer = params.reviewerName || '质量负责人'; + const approver = params.approverName || '技术委员会总监'; + + STANDARD_WORKFLOW_TEMPLATES.forEach((tmpl) => { + const docId = `doc-p${params.projectId}-${tmpl.taskKey}`; + + // 1. 变量宏替换 + let md = tmpl.markdownSkeleton; + md = md.replaceAll('{{project_name}}', params.projectName); + md = md.replaceAll('{{device_type}}', params.deviceType); + md = md.replaceAll('{{customer_name}}', customerName); + md = md.replaceAll('{{generated_at}}', nowStr); + md = md.replaceAll('{{snapshot_id}}', `SNAP-INIT-${params.projectId}`); + + // 2. 实例化 DeliverableItem + const item: DeliverableItem = { + docId, + projectId: params.projectId, + taskKey: tmpl.taskKey, + title: tmpl.title, + stage: tmpl.stage, + category: 'workflow', + creatorId: params.creatorId, + creatorName: params.creatorName, + isFixedWorkflow: true, + isTemplateOnly: true, + lifecycleState: 'template', + isClaimed: false, + author, + reviewer, + approver, + updatedAt: '刚刚', + summary: tmpl.summary, + }; + deliverables.push(item); + + // 3. 解析为块状 AST 并缓存 + const ast = markdownToBlockAST(md, { + docId, + title: tmpl.title, + taskKey: tmpl.taskKey, + version: 'V0.1 (模板)', + category: 'workflow', + creatorId: params.creatorId, + creatorName: params.creatorName, + lifecycleState: 'template', + isClaimed: false, + author, + reviewer, + approver, + updatedAt: '刚刚', + summary: tmpl.summary, + }); + docASTMap[docId] = ast; + }); + + return { deliverables, docASTMap }; +}