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+个管理页面各自重复实现:查询列表 → 表格展示 → 创建/编辑/删除。
目标
- 提取通用组件:将创建/查询/编辑逻辑抽取为 composables
- 接口渐进合并:对象类管理和业务对象管理内部共用同一套组件,界面分开(先分开,后续再考虑是否合并)
- 消除手写AML:ProductList.vue 等页面不再直接调用 SCSAI API
一、SCSAI 对象模型
SCSAI 是元数据驱动的 PLM 系统:
- ItemType(对象类):定义对象的结构(属性、关系、权限、生命周期等)
- 任何具体对象:都是某个 ItemType 的实例
- 一个螺丝 =
Part实例 - 一个项目 =
Project实例 - 一个新对象类(如
MyObject)=ItemType实例 - 属性、关系也是 ItemType 实例
所有操作本质相同:ApplyItem + 对应的 itemType + 属性/关系。 区别只在于参数不同。
二、架构现状
2.1 现有 composables
| 文件 | 行数 | 职责 |
|---|---|---|
| useCapabilityCreate.js | 1924 | 通用创建:LLM → 属性过滤 → 预创建 → 主对象 → 关系递归 → AI纠错 → 系统对象 |
| useItemTypeManagement.js | 1503 | ItemType 管理:获取/创建/删除 ItemType、Property、RelationshipType |
| useCapability.js | 1071 | 能力入口:识别 → 路由到具体能力 |
| useCapabilityWithRules.js | 1028 | 带规则的创建:加载规则模板 → 校验 → 创建 |
| useCapabilityIdentify.js 等 | 各35-185 | identify/inspect/repair/optimize/compare/generate |
| useDataCollection.js | 474 | 数据采集 |
| useRuleEngine.js | 463 | 规则引擎调用 |
2.2 现有 views
| 文件 | 行数 | 核心功能 |
|---|---|---|
| ItemTypeManagement.vue | 2682 | 对象类管理 |
| ProductList.vue | 1705 | 产品/Part列表,26处直接调用 SCSAI API,手写AML |
| AiWorkbench.vue | 2938 | AI对话框,部分直接调 SCSAI |
| ObjectDetailPanel.vue | 853 | 对象详情编辑/删除逻辑(位于 src/components/) |
2.3 现有 utils
| 文件 | 行数 | 职责 |
|---|---|---|
| SCSAI.js | 583 | SCSAI API 底层(_SCSAIApiRequest) |
| AmlBuilder.js | 219 | AML XML 构建(已支持 item_properties 和 relationships) |
| PromptBuilder.js | 659 | LLM 提示词构建 |
三、目标架构
┌──────────────────────────────────────────────────────────┐
│ 页面层(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.js 和 useItemTypeManagement.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 导入 useCreate —
grep 'from.*useCreate' src/views/返回 0 结果 - [ ] 测试1(创建 ItemType 含 Property 关系)未执行
- [ ] 测试2(创建 Part 及 BOM 关系)未执行
步骤:
- 创建
src/composables/useCreate.js
- 以
useCapabilityCreate.js第448行create()函数为主框架 - 按「流程1-7」的顺序,逐步引入同文件辅助函数
- 提取 createRelationshipsRecursive
- 从
useCapabilityCreate.js第1458行_processRelsRecursive提取 - 支持 Type A(关系本身是 Item)和 Type B(关系通过 source_id 引用父)两种模式,支持多级递归
- 提取 sanitizeProperties + resolveSequences
- 从
useCapabilityCreate.js第406行filterAndSanitize提取
- 提取 precreateItemProperties
- 从
useCapabilityCreate.js第178行precreateNestedItem提取 - 支持多级嵌套引用字段
- 提取 aiAutoCorrect
- 从
useCapabilityCreate.js末尾(约第1700行区域)提取 AI 纠错重试逻辑
- 组装 + 测试
- 测试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 }
}))
}
]
}
步骤:
- 在
ItemTypeManagement.vue中 import useCreate - 将
createItemTypeInSCSAI替换为:definition → 数据转换 →useCreate().create() - 保留原有的 UI 交互(弹窗、表单、结果显示)和 LLM 生成部分
- 移除后端
/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)— 获取对象类型 schemagetTypeTemplate(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]
generateDemoData8 处写操作 →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天) ❌ 未开始
目标: 删除冗余代码,更新架构文档。
- 删除被替代的旧函数(在确认新代码稳定后)
- 更新路由配置
- 确认 AiWorkbench.vue 的 SCSAI 调用也已走通用组件
- 更新文档
八、服务端镜像与小程序端(已实现)
这部分在 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.js | 1089 | 服务端 7 步创建镜像 |
| server.js (L1996) | - | /api/unified/ 路由注册 |
| bossagents-miniapp/src/api/unified-create.js | 30 | 小程序 API 封装 |
| bossagents-miniapp/src/pages/workbench/SCSAI-create.vue | 517 | 4 步向导创建页面 |
| 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 实践教训
- DB 适配层: 服务端必须用
db-adapter(底层 sql.js/MySQL),不能用better-sqlite3(项目未安装) - LLM Prompt 质量: 初版 prompt 仅列字段名,LLM 无法生成合理的关系数据;增强版注入关联对象字段列表 +
child_objects配置 - normalizeRelationships 必要: LLM 输出的关系格式不稳定(数组/对象混用),必须标准化
- 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/useModifyProductList.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 结构相同:。通用组件只需按 relatedItemType 和 createRelated 字段区分处理逻辑。
九、验收标准(含实际进度)
| Phase | 验收项 | 状态 |
|---|---|---|
| Phase 1 | useCreate 能创建 ItemType(含 Property + RelationshipType) | ⚠️ 代码已写,未测试 |
| Phase 1 | useCreate 能创建 Part 及 BOM 关系 | ⚠️ 代码已写,未测试 |
| Phase 1 | 有至少一个 view 导入并使用 useCreate | ✅ ItemTypeManagement.vue L975/L1063/L1306 |
| Phase 2 | ItemTypeManagement.vue 界面不变,内部走 useCreate | ✅ 完成 |
| Phase 3 | useQuery/useModify/useObjectMeta 三个组件可用 | ✅ 已完成(代码已实现,需运行时验证) |
| Phase 4 | ProductList.vue 消除手写 AML | ✅ 完成(读+写全部迁移,_SCSAIApiRequest 归零) |
| Phase 5 | 代码清理完成,文档更新 | ❌ 未开始(其他 13 个 view 仍有 55+ 处 _SCSAIApiRequest) |
| 额外 | 服务端 /api/unified/create 可用 | ✅ 已实现(1089行) |
| 额外 | 小程序 SCSAI-create.vue 4步向导 | ✅ 已实现(517行) |
BossAgents