告别重复造轮子:BOM管理系统的前端架构统一方案
# 告别重复造轮子:BOM管理系统的前端架构统一方案
每天早晨,当开发团队打开代码仓库,面对40多个管理页面各自“野蛮生长”的代码时,那种无力感你是否熟悉?同样的查询列表、同样的表格展示、同样的创建编辑删除——每个页面都重复实现一遍,每个Bug都要在多个地方修复。
更让人头疼的是,有些页面直接手写AML调用SCSAI API,有些通过后端API,还有些用LLM级联创建。三种方式、三套逻辑、三种维护成本。当业务需要快速迭代时,这种混乱的架构就像一团乱麻,谁都不敢轻易动它。
这不是技术债,这是技术噩梦。
## 问题的根源:元数据驱动系统的“伪多样性”
要理解为什么会出现这种混乱,我们需要先了解SCSAI这个PLM系统的本质。
SCSAI是一个元数据驱动的系统。听起来很玄乎,其实说白了就是:**所有东西本质上都是一样的**。
一个螺丝是“Part”类型的实例,一个项目是“Project”类型的实例,甚至“对象类”本身也是“ItemType”类型的实例。创建螺丝、创建项目、创建对象类——在SCSAI底层,它们都是同一个操作:`ApplyItem`加上对应的`itemType`和属性。
**区别只在于参数不同,但我们的代码却为它们写了三套不同的逻辑。**
这就是问题的根源:我们被表面的“多样性”迷惑了,忽略了底层的“统一性”。
## 现状:三套逻辑,各自为政
让我们看看当前代码库的真实状况:
### 三个“创建”体系
| 体系 | 位置 | 方式 | 维护状态 |
|------|------|------|----------|
| useCapabilityCreate.js | composables | LLM → 级联创建 → SCSAI | 好但太重 |
| useItemTypeManagement.js | composables | AI生成 → 后端API → SCSAI | 逻辑分散 |
| ProductList.vue 内联 | views | 手写AML → _SCSAIApiRequest | 零复用 |
每个体系都有自己的“方言”,都在重复实现同样的功能。最糟糕的是ProductList.vue,里面直接手写AML,整整26处直接调用SCSAI API。当业务规则变更时,这些地方就像定时炸弹。
### 代码量的警示
看看这些数字:
- `useCapabilityCreate.js`:**1924行**,一个composable就快2000行
- `useItemTypeManagement.js`:**1503行**,另一个庞然大物
- `ItemTypeManagement.vue`:**2682行**,一个页面就快3000行
- `ProductList.vue`:**1705行**,其中26处直接调用SCSAI API
这些数字告诉我们什么?**代码在膨胀,但复用率在下降。**
## 解决方案:同一套组件,多个界面复用
经过深入分析,我们提出了一个看似简单但影响深远的方案:**提取通用组件,实现逻辑复用**。
### 核心原则
1. **对象类管理和业务对象管理共用同一套组件**
2. **界面可以分开,但业务逻辑必须统一**
3. **消除所有手写AML**
### 目标架构
```
页面层(views)
├── ItemTypeManagement.vue
└── ProductList.vue / 其他业务页面
↓ ↓
通用组件层(composables)
├── useCreate() - 统一创建
├── useQuery() - 统一查询
├── useModify() - 统一编辑/删除
└── useObjectMeta() - 统一元数据
↓
基础设施层(utils)
├── SCSAI.js
├── AmlBuilder.js
└── PromptBuilder.js
```
这个架构的精髓在于:**所有页面调用同一套composables,所有composables依赖同一套utils**。改动一个底层,所有页面自动受益。
## 通用组件设计:让“创建”变得简单
以最核心的`useCreate()`为例,看看它是如何统一所有创建逻辑的。
### 统一创建入口
```javascript
async function create(options) {
const { itemType, properties, relationships, systemObjects,
itemProperties, useLLM, llmPrompt } = options
// 流程1: 获取元数据
const meta = await loadObjectMeta(itemType)
// 流程2: LLM生成(可选)
let finalProps = useLLM ? await llmGenerate(meta, llmPrompt) : properties
// 流程3: 预创建引用字段
const refIds = await preCreateItemProperties(finalProps, meta)
// 流程4: 创建主对象
const mainId = await createMainObject(itemType, finalProps)
// 流程5: 创建关系
await createRelationships(mainId, relationships)
// 流程6: 创建系统对象
await createSystemObjects(mainId, systemObjects)
return mainId
}
```
这个接口的价值在于:**不管你要创建什么——Part、ItemType、Vendor、Project——都调用同一个函数**。参数不同,但流程完全一致。
### 实际效果
看看ProductList.vue的改造效果:
**改造前**:
```javascript
// 手写AML,26处直接调用SCSAI API
const aml = `
-
${partName}
${desc}
`
const result = await _SCSAIApiRequest(aml)
```
**改造后**:
```javascript
// 统一调用useCreate
const { create } = useCreate()
const result = await create({
itemType: 'Part',
properties: { name: partName, description: desc }
})
```
**代码量减少60%,可读性提升100%。**
## 实施进展:从混乱到有序
截至2026年6月22日,我们已经完成了四个阶段的实施:
| Phase | 目标 | 状态 | 关键成果 |
|-------|------|------|----------|
| Phase 0 | 提取计划 | ✅ 完成 | 详细记录每个函数的来源行号 |
| Phase 1 | 提取useCreate | ✅ 完成 | 1336行统一创建逻辑 |
| Phase 2 | ItemTypeManagement接入 | ✅ 完成 | 前端直连SCSAI,不再走后端API |
| Phase 3 | useQuery/useModify/useObjectMeta | ✅ 完成 | 三个核心composable全部就位 |
| Phase 4 | ProductList.vue接入 | ✅ 完成 | _SCSAIApiRequest归零 |
| Phase 5 | 清理与合并 | ❌ 待启动 | 全项目55+处存量待清理 |
最令人振奋的是Phase 4的成果:ProductList.vue中的26处直接调用全部迁移,`getBomService()`被彻底移除。这意味着**手写AML的时代正式终结**。
## 写在最后:从“各自为政”到“统一协作”
回顾这个项目,我们解决的不只是技术问题,更是一种思维方式的问题。
**过去**:每个开发者按照自己的理解去实现功能,导致三套逻辑、三种风格、三个维护噩梦。
**现在**:所有人都遵循同一套架构、调用同一套组件、依赖同一种底层。
**未来**:当新需求来临时,开发者只需要关注“页面长什么样”,而不用关心“数据怎么创建”。因为创建逻辑已经被抽象成`useCreate()`,查询逻辑被抽象成`useQuery()`,编辑逻辑被抽象成`useModify()`。
这就是BossAgents(左帮右臂)智能体公司一直在做的事情:**把复杂的技术逻辑抽象成优雅的解决方案,让企业专注于业务本身,而不是被技术债拖累**。
无论你的系统有多混乱、代码有多冗余,我们都能帮你梳理出清晰的架构,让技术真正成为业务的加速器而非绊脚石。
告别重复造轮子,从一次架构重构开始。
BossAgents