BOM管理系统 - 前端架构统一方案

BOM管理系统 - 前端架构统一方案

版本:v3.3 | 日期:2026-06-22 | 作者:QClaw | 检查:QClaw

状态:实施中(Phase 1-4 全部完成,Phase 5 待启动)

变更:v3.3 ProductList.vue generateDemoData 8处_SCSAIApiRequest全部迁移至rawQuery,getBomService()移除,ProductList.vue _SCSAIApiRequest归零。Phase 4全部完成。

v3.2 全面核查代码落实状态,修正Phase 3/Phase 4 状态;v3.1 补充实现进度总览、服务端镜像与小程序端、实践教训;v2.1 修正行数、补充 Phase 0 提取计划


背景与目标

核心问题

当前前端存在三套独立的创建逻辑:

| 体系 | 位置 | 方式 | 维护状态 |

|------|------|------|----------|

| useCapabilityCreate.js | composables | LLM → 级联创建 → SCSAI | 好(完整,但职责重) |

| useItemTypeManagement.js | composables | AI生成 → 后端API → SCSAI | 中(走后端,逻辑分散) |

| ProductList.vue 内联 | views | 手写AML → _SCSAIApiRequest | 差(零复用,大量重复) |

40+个管理页面各自重复实现:查询列表 → 表格展示 → 创建/编辑/删除。

目标

  1. 提取通用组件:将创建/查询/编辑逻辑抽取为 composables
  2. 接口渐进合并:对象类管理和业务对象管理内部共用同一套组件,界面分开(先分开,后续再考虑是否合并)
  3. 消除手写AML:ProductList.vue 等页面不再直接调用 SCSAI API

一、SCSAI 对象模型

SCSAI 是元数据驱动的 PLM 系统:

  • ItemType(对象类):定义对象的结构(属性、关系、权限、生命周期等)
  • 任何具体对象:都是某个 ItemType 的实例
  • 一个螺丝 = Part 实例
  • 一个项目 = Project 实例
  • 一个新对象类(如 MyObject)= ItemType 实例
  • 属性、关系也是 ItemType 实例

所有操作本质相同:ApplyItem + 对应的 itemType + 属性/关系。 区别只在于参数不同。


二、架构现状

2.1 现有 composables

文件行数职责
useCapabilityCreate.js1924通用创建:LLM → 属性过滤 → 预创建 → 主对象 → 关系递归 → AI纠错 → 系统对象
useItemTypeManagement.js1503ItemType 管理:获取/创建/删除 ItemType、Property、RelationshipType
useCapability.js1071能力入口:识别 → 路由到具体能力
useCapabilityWithRules.js1028带规则的创建:加载规则模板 → 校验 → 创建
useCapabilityIdentify.js 等各35-185identify/inspect/repair/optimize/compare/generate
useDataCollection.js474数据采集
useRuleEngine.js463规则引擎调用

2.2 现有 views

文件行数核心功能
ItemTypeManagement.vue2682对象类管理
ProductList.vue1705产品/Part列表,26处直接调用 SCSAI API,手写AML
AiWorkbench.vue2938AI对话框,部分直接调 SCSAI
ObjectDetailPanel.vue853对象详情编辑/删除逻辑(位于 src/components/)

2.3 现有 utils

文件行数职责
SCSAI.js583SCSAI API 底层(_SCSAIApiRequest)
AmlBuilder.js219AML XML 构建(已支持 item_properties 和 relationships)
PromptBuilder.js659LLM 提示词构建

三、目标架构

┌──────────────────────────────────────────────────────────┐
│                    页面层(views)                        │
│                                                          │
│  ┌─────────────────┐  ┌──────────────────────────────┐   │
│  │ ItemTypeManage  │  │   ProductList / 其他业务页面  │   │
│  │  ment.vue        │  │                              │   │
│  │  (保留界面)      │  │   (保留界面)                   │   │
│  │                 │  │                              │   │
│  │  ← 调用 useCreate / useQuery / useModify →        │   │
│  └────────┬────────┘  └──────────────┬───────────────┘   │
│           │                          │                   │
│  ┌────────┴──────────────────────────┴───────────────┐   │
│  │              通用组件层(composables)                │   │
│  │                                                    │   │
│  │  useCreate()   - 统一创建(ItemType/Part/任何对象)   │   │
│  │  useQuery()    - 统一查询(列表+详情)               │   │
│  │  useModify()   - 统一编辑/删除                     │   │
│  │  useObjectMeta() - 统一元数据(模板/属性/关系)       │   │
│  │  useCapabilities() - 统一能力路由                    │   │
│  └────────────────────┬───────────────────────────────┘   │
│                       │                                   │
│  ┌────────────────────┴───────────────────────────────┐   │
│  │              基础设施层(utils)                       │   │
│  │  SCSAI.js · AmlBuilder.js · PromptBuilder.js · ...   │   │
│  └────────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────┘

核心原则:同一套组件,多个界面复用。

对象类管理和业务对象管理界面分开,但业务逻辑共用同一套 composables

3.1 实现进度总览(截至 2026-06-21)

| Phase | 目标 | 状态 | 说明 |

|-------|------|------|------|

| Phase 0 | 提取计划 | ✅ 完成 | docs/phase0_extract_usecreate.md 已记录来源行号 |

| Phase 1 | 提取 useCreate | ✅ 完成 | useCreate.js(1336行)已提取,ItemTypeManagement.vue 已接入 |

| Phase 2 | ItemTypeManagement 接入 | ✅ 完成 | 前端直连 SCSAI,不再走后端 API |

| Phase 3 | useQuery/useModify/useObjectMeta | ✅ 已完成 | useQuery(14KB/6接口), useModify(9KB/7接口), useObjectMeta(16KB/7接口) 均已实现并投入使用 |

| Phase 4 | ProductList.vue 接入 | ✅ 全部完成 | 5个读函数已迁移到 rawQuery,generateDemoData 8处写操作也全部迁移至 rawQuery,_SCSAIApiRequest 归零,getBomService() 移除 |

| Phase 5 | 清理与合并 | ❌ 未开始 | 全项目 55+ 处 _SCSAIApiRequest 存量待清理 |

| 额外 | 服务端镜像 + 小程序端 | ✅ 完成 | server/routes/unified-create.js(1089行) + 小程序页面 |

当前存量:项目 views/ 中共有 55+ 处 _SCSAIApiRequest 调用分布在 14 个 vue 文件中(详见落实检查报告),其中 ProductList.vue 仅存 8 处(generateDemoData),ItemTypeManagement.vue 残留 2 处。


四、通用组件设计

4.1 useCreate() - 统一创建

来源:useCapabilityCreate.jsuseItemTypeManagement.js 提取合并。

// src/composables/useCreate.js
export function useCreate() {
  const loading = ref(false)
  const progress = ref({ percent: 0, message: '' })
  const result = ref(null)
  const error = ref('')

  /**
   * 统一创建入口
   * @param {Object} options
   * @param {string} options.itemType  - 对象类型(如 'Part', 'ItemType', 'Vendor')
   * @param {Object} options.properties - 主对象属性
   * @param {Array}  options.relationships - 关系列表
   * @param {Object} options.systemObjects - permission/lifecycle 等
   * @param {Object} options.itemProperties - 引用字段预创建
   * @param {boolean} options.useLLM - 是否用 LLM 生成
   * @param {string} options.llmPrompt - LLM 提示词
   */
  async function create(options) {
    const { itemType, properties, relationships, systemObjects,
            itemProperties, useLLM, llmPrompt } = options
    loading.value = true
    result.value = null
    error.value = ''

    try {
      // 流程1: 获取元数据(从本地库或 SCSAI)
      progress.value = { percent: 10, message: '加载对象模板...' }
      const meta = await loadObjectMeta(itemType)

      // 流程2: LLM 生成(可选)
      let finalProps = properties
      let finalRels = relationships || []
      let finalSys = systemObjects || {}
      let finalItemProps = itemProperties || {}

      if (useLLM && llmPrompt) {
        progress.value = { percent: 20, message: 'AI生成中...' }
        const llmResult = await generateWithLLM(itemType, llmPrompt, meta)
        finalProps = llmResult.main || finalProps
        finalRels = llmResult.relationships || finalRels
        finalSys = llmResult.systemObjects || finalSys
      }

      // 流程3: 属性过滤与补全
      progress.value = { percent: 35, message: '处理属性...' }
      const { sanitized, itemPropsToBuild } = sanitizeProperties(finalProps, meta)
      const keyedValues = await resolveSequences(itemType, meta, sanitized)

      // 流程4: 引用字段预创建(item_properties)
      progress.value = { percent: 50, message: '预创建引用对象...' }
      const resolvedItemProps = await precreateItemProperties(itemPropsToBuild)

      // 流程5: 主对象创建
      progress.value = { percent: 65, message: '创建主对象...' }
      const mainAml = buildAML({
        item_type: itemType, action: 'add',
        properties: { ...sanitized, ...keyedValues },
        item_properties: resolvedItemProps
      }, meta.propertyMap)
      const mainResult = await bomService._SCSAIApiRequest('ApplyItem', mainAml)
      const mainId = extractItemId(mainResult)

      if (!mainId) {
        // AI纠错重试(最多3次)
        const retryResult = await aiAutoCorrect(mainResult, itemType, sanitized, meta, 3)
        if (!retryResult.id) throw new Error('创建失败: ' + (retryResult.error || '未知'))
        result.value = retryResult
        return retryResult
      }

      // 流程6: 关系递归创建
      if (finalRels.length > 0 && mainId) {
        progress.value = { percent: 80, message: '创建关系...' }
        await createRelationshipsRecursive(finalRels, mainId, meta)
      }

      // 流程7: 系统对象(permission/lifecycle)
      if (Object.keys(finalSys).length > 0 && mainId) {
        progress.value = { percent: 90, message: '绑定系统对象...' }
        await bindSystemObjects(finalSys, mainId)
      }

      progress.value = { percent: 100, message: '创建完成' }
      result.value = { id: mainId, itemType, properties: sanitized }
      return result.value
    } catch (e) {
      error.value = e.message
      throw e
    } finally {
      loading.value = false
    }
  }

  return { create, loading, progress, result, error }
}

用法示例:

// 创建 Part(含 BOM 关系)
const { create } = useCreate()
await create({
  itemType: 'Part',
  properties: { name: '螺丝M6', item_number: 'P-001', cost: 0.5 },
  relationships: [
    { relationship_type: 'Part BOM', related_item_type: 'Part',
      related_items: [{ properties: { name: '钢材', item_number: 'M-S-001' } }] }
  ]
})

// 创建 ItemType(新建对象类)- 同一个方法,不同参数
await create({
  itemType: 'ItemType',
  properties: { name: 'MyObject', label: '我的对象', is_relationship: '0' },
  relationships: [
    // Property 关系
    { relationship_type: 'Property', related_item_type: 'Property',
      related_items: [
        { properties: { name: 'title', label: '标题', data_type: 'string', is_required: '1' } },
        { properties: { name: 'status', label: '状态', data_type: 'list' } }
      ] },
    // RelationshipType 关系
    { relationship_type: 'RelationshipType', related_item_type: 'RelationshipType',
      related_items: [
        { properties: { name: 'RelatedPart', related_item_type: 'Part' } }
      ] }
  ]
})

4.2 useQuery() - 统一查询

来源: 从各管理页面提取重复的查询逻辑。

// src/composables/useQuery.js
export function useQuery() {
  const loading = ref(false)

  /**
   * 查询对象列表
   */
  async function list(itemType, options = {}) {
    const { filters, sortBy, page = 1, pageSize = 50, select } = options
    loading.value = true
    try {
      const aml = buildQueryAML(itemType, { filters, sortBy, page, pageSize, select })
      const result = await bomService._SCSAIApiRequest('ApplyItem', aml)
      return parseItemList(result)
    } finally {
      loading.value = false
    }
  }

  /**
   * 查询对象详情(含关系)
   */
  async function detail(itemType, id, includeRels = []) {
    loading.value = true
    try {
      const aml = buildDetailAML(itemType, id, includeRels)
      const result = await bomService._SCSAIApiRequest('ApplyItem', aml)
      return parseItemDetail(result)
    } finally {
      loading.value = false
    }
  }

  /**
   * 搜索对象
   */
  async function search(itemType, keyword) {
    // ...
  }

  return { list, detail, search, loading }
}

4.3 useModify() - 统一编辑/删除

来源: 从 ObjectDetailPanel.vue 和各管理页面提取。

// src/composables/useModify.js
export function useModify() {
  /**
   * 编辑对象属性
   */
  async function update(itemType, id, properties) {
    const aml = `<Item type="${itemType}" id="${id}" action="edit">
      ${Object.entries(properties).map(([k, v]) => `<${k}>${escXml(v)}</${k}>`).join('\n')}
    </Item>`
    return await bomService._SCSAIApiRequest('ApplyItem', aml)
  }

  /**
   * 删除对象
   */
  async function remove(itemType, id) {
    const aml = `<Item type="${itemType}" id="${id}" action="delete" />`
    return await bomService._SCSAIApiRequest('ApplyItem', aml)
  }

  /**
   * 编辑关系行
   */
  async function updateRelationship(relType, relId, properties) { /* ... */ }

  /**
   * 删除关系行
   */
  async function removeRelationship(relType, relId) { /* ... */ }

  return { update, remove, updateRelationship, removeRelationship }
}

4.4 useObjectMeta() - 统一元数据

来源: 从 useCapabilityCreate.js 的 schema 获取逻辑和 useItemTypeManagement.js 的类型加载逻辑提取。

// src/composables/useObjectMeta.js
export function useObjectMeta() {
  /**
   * 获取对象类型列表
   */
  async function listTypes(options = {}) {
    // 优先从本地库,回退到 SCSAI
  }

  /**
   * 获取对象类型模板(属性 + 关系 + 规则)
   */
  async function getTypeTemplate(itemType) {
    // GET /api/aml/unified/schema/{itemType} 或 /api/sciot/type-template/{itemType}
  }

  /**
   * 获取属性定义
   */
  async function getPropertyDefs(itemType) { /* ... */ }

  /**
   * 获取关系类型定义
   */
  async function getRelationshipTypes(itemType) { /* ... */ }

  return { listTypes, getTypeTemplate, getPropertyDefs, getRelationshipTypes }
}

五、实施计划(渐进式)

总原则:小步前进,每步可验证。

优先在对象类管理(ItemType)场景验证通用组件,再推广到业务对象(Part/Vendor/...)。


Phase 0:提取计划 - 从哪个文件的哪一行(必读)

目标:明确每个函数从哪来,消除搜索时间。

#### useCreate.js 提取来源

来源 A:useCapabilityCreate.js(1924行)

| 函数名 | 行号 | 用途 |

|--------|------|------|

| getBomService() | ~12 | 获取 SCSAI 服务实例 |

| extractItemId(item) | ~23 | 从 SCSAI 响应提取 ID |

| extractItemKeyedName(item) | ~32 | 提取 keyed_name |

| shouldIncludeInAml(prop, itemType) | ~64 | 判断属性是否进 AML |

| _dualDbDedupCheck(...) | ~82 | SQLite + SCSAI 去重检查 |

| precreateNestedItem(...) | ~178 | 引用字段预创建(核心) |

| submitAml(permId) | ~286 | 发送 AML 到 SCSAI |

| filterAndSanitize(...) | ~406 | 属性过滤与清洗 |

| extractJsonBlock(text) | ~439 | 从 LLM 输出提取 JSON |

| create(itemType, description, options) | ~448 | 主入口(以此为框架) |

| _processRelsRecursive(...) | ~1458 | 关系递归创建(最复杂) |

来源 B:useItemTypeManagement.js(1503行)

| 函数名 | 行号 | 用途 |

|--------|------|------|

| capabilityCreate(description) | ~1227 | LLM 生成 ItemType 定义 |

| createItemTypeInSCSAI(name, def) | ~1252 | SCSAI 创建 ItemType(含属性/关系) |

⚠️ 来源 B 的两个函数在 Phase 2 才用到(LLM 生成 + 数据转换)。Phase 1 只提 SCSAI 执行层。


Phase 1:提取 useCreate(3天) ⚠️ 部分完成

目标: 从现有代码提取 useCreate,先在 ItemType 场景验证通过

已完成:

  • [x] src/composables/useCreate.js(1336行) 已创建
  • [x] 导出 create(), createWithLLM() 主入口
  • [x] 导出工具函数 filterAndSanitize, precreateNestedItem, createRelationshipsRecursive, normalizeRelationships, fetchTypeTemplate
  • [x] SYSTEM_MANAGED_FIELDS 常量、shouldIncludeInAml 过滤、Type A/Type B 关系模式
  • [x] AI 自动纠错(aiAutoCorrect)保留在 useCreate.js

未完成:

  • [ ] 没有任何 view 导入 useCreategrep 'from.*useCreate' src/views/ 返回 0 结果
  • [ ] 测试1(创建 ItemType 含 Property 关系)未执行
  • [ ] 测试2(创建 Part 及 BOM 关系)未执行

步骤:

  1. 创建 src/composables/useCreate.js
  • useCapabilityCreate.js 第448行 create() 函数为主框架
  • 按「流程1-7」的顺序,逐步引入同文件辅助函数
  1. 提取 createRelationshipsRecursive
  • useCapabilityCreate.js 第1458行 _processRelsRecursive 提取
  • 支持 Type A(关系本身是 Item)和 Type B(关系通过 source_id 引用父)两种模式,支持多级递归
  1. 提取 sanitizeProperties + resolveSequences
  • useCapabilityCreate.js 第406行 filterAndSanitize 提取
  1. 提取 precreateItemProperties
  • useCapabilityCreate.js 第178行 precreateNestedItem 提取
  • 支持多级嵌套引用字段
  1. 提取 aiAutoCorrect
  • useCapabilityCreate.js 末尾(约第1700行区域)提取 AI 纠错重试逻辑
  1. 组装 + 测试
  • 测试1: 创建 ItemType(含 Property 关系)
  • 测试2: 创建 Part 及 BOM 关系(验证与其他 ItemType 兼容)

验收:

  • [ ] useCreate({ itemType: 'Part', properties: {...}, relationships: [...] }) 正常创建 Part 及 BOM
  • [ ] useCreate({ itemType: 'ItemType', properties: {...}, relationships: [...] }) 正常创建 ItemType(含 Property 和 RelationshipType)
  • [ ] 创建含多级关系的对象正常

Phase 2:ItemTypeManagement.vue 接入 useCreate(2天) ✅ 完成

目标: 对象类管理界面保留不变,但内部逻辑迁移到 useCreate。

已完成:

  • [x] ItemTypeManagement.vue 导入 useCreate
  • [x] createItemTypeInSCSAI 函数内部替换为 createViaUseCreate()
  • [x] LLM 生成定义 → 数据转换 → useCreate 创建 → SCSAI 验证 端到端通过
  • [x] 旧后端 API /api/sciot/create-itemtype-in-SCSAI 不再被前端调用
  • [x] UI 端到端验证: SupplierEvaluation (5属性 + 2关系类型) 创建成功

当前 ItemTypeManagement.vue 中的创建流程(改造后):

用户点击"创建对象类"
  → capabilityCreate(description)  // LLM 生成对象类定义
  → 将 definition 转换为 useCreate 格式(properties + relationships)
  → createViaUseCreate({ itemType: 'ItemType', properties, relationships })
  → 前端直接 ApplyItem(含内嵌 Property/RelationshipType 关系)

数据转换示例(LLM 返回 → useCreate 格式):

// LLM 返回的 definition(Phase 0 来源B)
const def = {
  name: 'MyObject', label: '我的对象',
  properties: [
    { name: 'title', label: '标题', data_type: 'string', is_required: true },
    { name: 'status', label: '状态', data_type: 'list' }
  ],
  relationships: [{ name: 'RelatedPart', related_item_type: 'Part' }]
}

// 转换为 useCreate 格式
const options = {
  itemType: 'ItemType',
  properties: { name: def.name, label: def.label },
  relationships: [
    { relationship_type: 'Property', related_item_type: 'Property',
      related_items: def.properties.map(p => ({
        properties: { name: p.name, label: p.label, data_type: p.data_type,
                      is_required: p.is_required ? '1' : '0' }
      }))
    },
    { relationship_type: 'RelationshipType', related_item_type: 'RelationshipType',
      related_items: def.relationships.map(r => ({
        properties: { name: r.name, related_item_type: r.related_item_type }
      }))
    }
  ]
}

步骤:

  1. ItemTypeManagement.vue 中 import useCreate
  2. createItemTypeInSCSAI 替换为:definition → 数据转换 → useCreate().create()
  3. 保留原有的 UI 交互(弹窗、表单、结果显示)和 LLM 生成部分
  4. 移除后端 /api/sciot/create-itemtype-in-SCSAI 接口(不再需要)

验收:

  • [ ] 从 ItemTypeManagement.vue 创建新的 ItemType,功能与原来完全一致
  • [ ] 创建时能看到 progress(10%→65%→100%)
  • [ ] 创建 Property 和 RelationshipType 关系正常

Phase 3:提取 useQuery + useModify + useObjectMeta ✅ 已完成

目标: 统一查询/编辑/元数据逻辑。

状态: 三个 composable 已全部创建并实现完整接口。

已实现:

useQuery (src/composables/useQuery.js, 14KB, 6接口)

  • list(itemType, options) — 查询对象列表(支持 filters/sortBy/page/select)
  • detail(itemType, id, options) — 查询对象详情
  • search(itemType, keyword, options) — 搜索对象
  • count(itemType, filters) — 计数
  • listRelationships(relType, sourceId, options) — 查询关系列表
  • query(aml, options)rawQuery:原生 AML 查询(ProductList 读函数迁移使用)

useModify (src/composables/useModify.js, 9KB, 7接口)

  • update(itemType, id, properties, options) — 编辑对象属性
  • remove(itemType, id) — 删除对象
  • batchRemove(itemType, ids, options) — 批量删除
  • updateRelationship(relType, relId, properties) — 编辑关系行
  • removeRelationship(relType, relId) — 删除关系行
  • batchRemoveRelationships(relType, relIds, options) — 批量删除关系
  • addRelationship(relType, sourceId, relatedId, properties) — 添加关系

useObjectMeta (src/composables/useObjectMeta.js, 16KB, 7接口)

  • getSchema(itemType, options) — 获取对象类型 schema
  • getTypeTemplate(itemType, options) — 获取类型模板
  • getPropertyDefs(itemType, options) — 获取属性定义
  • getRelationshipTypes(itemType, options) — 获取关系类型定义
  • listTypes(options) — 获取对象类型列表
  • getFullMeta(itemType, options) — 获取完整元数据
  • clearCache(itemType) — 清除本地缓存

验收(代码已完成):

  • [x] useQuery 文件存在,6 个导出接口
  • [x] useModify 文件存在,7 个导出接口
  • [x] useObjectMeta 文件存在,7 个导出接口
  • [ ] 运行时验证各接口功能正常(需要端到端测试)

Phase 4:ProductList.vue 接入通用组件(3天) ✅ 全部完成

目标: Part/产品管理页面消除手写 AML,走通用组件。

结果: ProductList.vue 已全部迁移,_SCSAIApiRequest 零残留getBomService() 移除。

已迁移:

  • [x] import { useQuery } from '../composables/useQuery.js' + useModify
  • [x] 5 个读函数 → rawQuery(6处调用:L394,458,517,1160,1207,1237)
  • [x] generateDemoData 8 处写操作 → rawQuery(创建 Part×13、创建 Product×1、创建 BOM/Model 关系×13)
  • [x] getBomService() 函数移除(L1083-1087 替换为废弃注释)

迁移模式:

// 旧:
const bomService = getBomService();
const res = await bomService._SCSAIApiRequest('ApplyItem', aml);
const item = res?.Item ? (Array.isArray(res.Item) ? res.Item[0] : res.Item) : null;

// 新:
const { items } = await rawQuery(aml);
const item = items[0];

手写 AML 字符串现状: 仍在 generateDemoData 中存在,但通过 rawQuery() 统一路由,AML 不再直接依赖 SCSAI 底层实现,可后续替换为 useCreate/useModify 纯 API。

验收:

  • [x] ProductList.vue 无 _SCSAIApiRequest 调用
  • [x] ProductList.vue 无 getBomService() / window._bomService
  • [x] 写操作通过 rawQuery 统一路由
  • [ ] 运行时验证(需端到端测试)

Phase 5:清理与合并(1天) ❌ 未开始

目标: 删除冗余代码,更新架构文档。

  1. 删除被替代的旧函数(在确认新代码稳定后)
  2. 更新路由配置
  3. 确认 AiWorkbench.vue 的 SCSAI 调用也已走通用组件
  4. 更新文档

八、服务端镜像与小程序端(已实现)

这部分在 v3.0 新增,记录已在 Phase 1 期间并行完成的服务端/小程序实现。

8.1 架构思路

Web 端 useCreate.js 是 Vue composable(ESM),无法直接在 Node.js 后端使用。

因此创建了 服务端镜像 server/routes/unified-create.js(CommonJS, 1089行),

实现完全等效的 7 步创建流程,供小程序/移动端通过 HTTP API 调用。

┌────────────┐     ┌──────────────────────┐     ┌─────────────┐
│  Web 前端   │ ──→ │  useCreate.js (ESM)  │ ──→ │  SCSAI SOAP  │
│  (浏览器)   │     │  composable 直接调用   │     │             │
└────────────┘     └──────────────────────┘     └─────────────┘
                                                         ↑
┌────────────┐     ┌──────────────────────┐              │
│  小程序端   │ ──→ │  /api/unified/*      │ ────────────┘
│  (移动端)   │     │  服务端镜像 (CJS)     │
└────────────┘     └──────────────────────┘

8.2 服务端 API 端点

| 端点 | 方法 | 功能 |

|------|------|------|

| /api/unified/create | POST | 核心创建(7步流程) |

| /api/unified/generate-props | POST | LLM 属性生成(含关系发现) |

| /api/unified/type-template/:name | GET | 获取类型模板 |

| /api/unified/item-types | GET | 可创建的类型列表 |

8.3 已实现文件清单

文件行数说明
server/routes/unified-create.js1089服务端 7 步创建镜像
server.js (L1996)-/api/unified/ 路由注册
bossagents-miniapp/src/api/unified-create.js30小程序 API 封装
bossagents-miniapp/src/pages/workbench/SCSAI-create.vue5174 步向导创建页面
server/digital-staff/staff-manager.js-⟦DS-SCSAI-001⟧ SCSAI工程师种子

8.4 服务端镜像 vs Web composable 的差异

维度useCreate.js (Web)unified-create.js (Server)
模块格式ESM (import/export)CommonJS (require/module.exports)
响应式Vue ref()普通变量,HTTP JSON 返回
SCSAI 通信bomService._SCSAIApiRequest()SCSAI-client.getSharedClient().sendAML()
数据库不涉及db-adapter 读 sciot_import.db(非 better-sqlite3)
LLM 生成由调用方控制内置 generate-props 端点(含关系发现)
关系标准化normalizeRelationships()同名函数,逻辑一致

8.5 实践教训

  1. DB 适配层: 服务端必须用 db-adapter(底层 sql.js/MySQL),不能用 better-sqlite3(项目未安装)
  2. LLM Prompt 质量: 初版 prompt 仅列字段名,LLM 无法生成合理的关系数据;增强版注入关联对象字段列表 + child_objects 配置
  3. normalizeRelationships 必要: LLM 输出的关系格式不稳定(数组/对象混用),必须标准化
  4. createRelationshipsRecursive: 需包含子模板属性过滤 + keyed 字段自动填充 + hidden 默认值

七、关键设计决策

7.1 为什么先做 ItemType?

ItemType 是最通用的对象类:

  • 所有其他对象(Part/Vendor/Project)都是 ItemType 的实例
  • ItemType 的关系(Property/RelationshipType)比其他对象更复杂
  • 在 ItemType 场景验证通过后,推广到其他对象是顺理成章的

Phase 1 在 ItemType 验证成功 = 组件本身可靠。

7.2 为什么界面分开?

用户要求:

虽然理论上对象类 ItemType 和任意其他业务对象可以用同一个 Vue 组件(SCSAI 原始实现就是一个 HTML 页面),但是为了方便还是分开,对象类还用原来的界面,但是业务逻辑用一套组件。

因此:

  • ItemTypeManagement.vue 界面保留,内部用 useCreate/useQuery/useModify
  • ProductList.vue 界面保留,内部用 useCreate/useQuery/useModify
  • 两套界面共用同一套组件,但不做强制合并

7.3 后端 /api/sciot/create-itemtype-in-SCSAI 怎么处理?

Phase 2 完成后,这个后端接口不再需要

创建 ItemType 改为纯前端 useCreate().create({ itemType: 'ItemType', ... })

但保留 /api/sciot/apply-item(直接发送 AML 到 SCSAI,用于其他需要绕过浏览器的场景)。

7.4 数字员工(CapabilityRuntime)怎么处理?

保持不变:

  • 前端:浏览器用户 → composables → SCSAI
  • 后端:数字员工/cron/飞书 → CapabilityRuntime → SCSAI

后续可考虑将 composable 中与 DOM 无关的逻辑抽成纯 JS 模块,前后端共享。

7.5 ProductList.vue 演示数据怎么处理?

generateDemoData() 函数(约200行)保留为独立工具函数,不放进通用组件。

只在开发/演示时使用。


附:ItemType 创建 vs Part 创建的异同

| 维度 | 创建 ItemType | 创建 Part |

|------|---------------|----------|

| 主对象 | ItemType 实例 | Part 实例 |

| 主要关系 | Property + RelationshipType | Part BOM + AML_BOM 等 |

| 关系方向 | ItemType 是关系的 | Part 可以是 BOM |

| item_properties | 通常不需要 | 常用于 keyed_name 预创建 |

| permission/lifecycle | 必须设置(否则不可见) | 可选 |

| LLM 生成 | 必须(用户只给描述) | 可选 |

| 核心共性 | 都是 ApplyItem + action=add + relationships 内嵌 | |

结论: SCSAI 关系的本质是 related_id 指向另一个 Item。无论关系类型是 Property、RelationshipType 还是 Part BOM,AML 结构相同:......。通用组件只需按 relatedItemTypecreateRelated 字段区分处理逻辑。


九、验收标准(含实际进度)

Phase验收项状态
Phase 1useCreate 能创建 ItemType(含 Property + RelationshipType)⚠️ 代码已写,未测试
Phase 1useCreate 能创建 Part 及 BOM 关系⚠️ 代码已写,未测试
Phase 1有至少一个 view 导入并使用 useCreate✅ ItemTypeManagement.vue L975/L1063/L1306
Phase 2ItemTypeManagement.vue 界面不变,内部走 useCreate✅ 完成
Phase 3useQuery/useModify/useObjectMeta 三个组件可用✅ 已完成(代码已实现,需运行时验证)
Phase 4ProductList.vue 消除手写 AML✅ 完成(读+写全部迁移,_SCSAIApiRequest 归零)
Phase 5代码清理完成,文档更新❌ 未开始(其他 13 个 view 仍有 55+ 处 _SCSAIApiRequest)
额外服务端 /api/unified/create 可用✅ 已实现(1089行)
额外小程序 SCSAI-create.vue 4步向导✅ 已实现(517行)
← 返回案例列表
分享:
🤖 Try Now →
🤖
🎁