SCSAI PLM 前端集成方案 — Shim 架构
概述
将 SCSAI Agent PLM 的前端能力集成到任意 Web 应用中,无需加载 SCSAI 原生的 30+ 个 JS 文件(~2MB),只需一个 5KB 的存根(shim) + 一个 Node.js 代理路由。
架构
┌────────────────────────────────────────────────────────┐
│ 你的 Web 应用 │
│ │
│ Vue 视图 │
│ ┌─────────────────────┐ 直接调用 │
│ │ CustomerManagement │ ───→ window._bomService │
│ │ InventoryManagement │ ._SCSAIApiRequest() │
│ │ OrderManagement │ ↓ │
│ │ Dashboard │ fetch(/SCSAI-api/) │
│ └─────────────────────┘ ↓ │
│ ┌────────────────┐ │
│ index.html │ Node.js 服务端 │ │
│ ┌──────────────┐ │ (你的后端) │ │
│ │ SCSAI-shim │ │ │ │
│ │ (inline) │ │ /SCSAI-api/ │────→ SCSAI │
│ │ │ │ → Agent │ Server │
│ │ Sciot 存根 │ │ Server.aspx │ │
│ │ MD5Util │ │ │ │
│ │ IomFactory │ │ AuthHeaders: │ │
│ │ CacheUtil │ │ AUTHUSER │ │
│ └──────┬───────┘ │ AUTHPASSWORD │ │
│ │ │ DATABASE │ │
│ ↓ └────────────────┘ │
│ index.js │
│ (SCSAIBomService) │
│ 4005行 · 保留不变 │
└────────────────────────────────────────────────────────┘
数据流
Vue 组件
→ window._bomService._SCSAIApiRequest('ApplyItem', aml)
→ fetch('/SCSAI-api/', {
method: 'POST',
headers: { AUTHUSER, AUTHPASSWORD (MD5), DATABASE },
body: aml
})
→ 你的 Node.js 服务端 /SCSAI-api/ 路由
→ http.request → http://SCSAI-server/InnovatorServer.aspx
→ XML 响应
→ _parseAMLResponse() 解析为 JSON
→ 返回给 Vue 组件
整条链路不经过任何 SCSAI 浏览器端 JS 文件。
集成步骤(5 分钟)
1. 复制以下文件到你的项目
你的项目/
├── index.html # 入口(只需 4 个 script)
├── index.js # SCSAIBomService(4005 行,不动)
├── utils/
│ └── md5.js # MD5 哈希(242 行)
├── src/
│ ├── SCSAI-shim.js # Vue 模块加载的额外存根(后备)
│ └── main.js # import './SCSAI-shim.js'
└── server.js (或你的后端) # 需要 /SCSAI-api/ 代理路由
2. index.html 模板
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- 1. MD5(必须,用于密码哈希) -->
<script src="./utils/md5.js"></script>
<!-- 2. SCSAI 存根(必须,在 index.js 之前加载) -->
<script>
// ── Sciot 最小存根 ──
function SciotStub() {
this.commonProperties = {
loginName: '', password: '', database: 'SCPLM',
userID: '', identityList: [], serverBaseURL: ''
};
this.varsStorage = {};
}
SciotStub.prototype.SetupURLs = function(url) {
try { var m = url.match(/^(https?:\/\/[^/]+)\/([^/]+)\//);
if (m) this.commonProperties.serverBaseURL = m[1]+'/'+m[2]+'/server/';
} catch(e){}
};
SciotStub.prototype.validateUser = function() {
return { then: function(r) { r({ ok: false, message: 'shim' }); } };
};
SciotStub.prototype.logout = function() {
this.commonProperties.loginName = '';
this.commonProperties.password = '';
};
window.Sciot = window.Sciot || SciotStub;
window.sciot = window.sciot || new SciotStub();
// ── 其他全局存根 ──
window.IomFactory = window.IomFactory || {
CreateAgent: function(){ return {
apply: function(){ return {getResult:function(){return''},isError:function(){return false}} },
getNewItem: function(){ return {setProperty:function(){},setID:function(){},
apply:function(){return{isError:function(){return false}}}} }
} }
};
window.SciotModules = window.SciotModules || {
soap: function(){ return {status:200,responseText:'<Envelope><Body><Result></Result></Body></Envelope>'} },
Dialog: { show: function(){ return {promise:Promise.resolve()} },
alert: function(m){ alert(m) },
confirm: function(m){ return confirm(m) } }
};
window.CacheUtil = window.CacheUtil || function(){
this.get=function(){}; this.set=function(){};
this.generateKey=function(){return''};
this.wrap=function(k,fn){return fn()};
};
console.log('[SCSAI-shim] 存根就绪');
</script>
<!-- 3. SCSAIBomService(核心业务逻辑,4005 行) -->
<script src="./index.js"></script>
</head>
<body>
<div id="app"></div>
<!-- 4. Vue 应用入口 -->
<script type="module" src="/src/main.js"></script>
</body>
</html>
3. Node.js 服务端 — /SCSAI-api/ 代理
在你的后端(Express / Fastify / Node http)中添加:
// /SCSAI-api/ 代理 — 转发 AML 到 SCSAI InnovatorServer.aspx
app.post('/SCSAI-api/', async (req, res) => {
const username = req.headers['authuser'];
const password = req.headers['authpassword']; // MD5 哈希
const database = req.headers['database'] || 'SCPLM';
const aml = req.body;
const SCSAIUrl = new URL('http://114.113.153.234/scplm/server/InnovatorServer.aspx');
const options = {
hostname: SCSAIUrl.hostname,
port: SCSAIUrl.port || 80,
path: SCSAIUrl.pathname,
method: 'POST',
headers: {
'Content-Type': 'text/xml',
'Content-Length': Buffer.byteLength(aml),
'SOAPAction': 'ApplyItem',
'AUTHUSER': username,
'AUTHPASSWORD': password,
'DATABASE': database
},
timeout: 30000
};
const proxyReq = http.request(options, (proxyRes) => {
let body = '';
proxyRes.on('data', chunk => body += chunk);
proxyRes.on('end', () => {
res.writeHead(proxyRes.statusCode, {
'Content-Type': 'text/xml; charset=UTF-8'
});
res.end(body);
});
});
proxyReq.on('error', (e) => {
res.status(500).json({ error: e.message });
});
proxyReq.write(aml);
proxyReq.end();
});
4. 前端登录流程
Vue 组件中调用登录:
const credentials = {
username: 'root',
password: 'gyc123456;',
database: 'SCPLM',
serverUrl: 'http://114.113.153.234/scplm/server'
};
// 方式一:使用 SCSAIBomService(推荐)
const result = await window._bomService.login(credentials);
// 方式二:直接 AML 调用
const aml = '<AML><Item type="Part" action="get" select="id,name" pagesize="5"/></AML>';
const data = await window._bomService._SCSAIApiRequest('ApplyItem', aml);
文件职责
| 文件 | 大小 | 职责 | 必须? |
|------|------|------|--------|
| index.html 内联存根 | ~2KB | 定义 Sciot/IomFactory/CacheUtil 等全局对象 | 是 |
| utils/md5.js | 242行 | MD5 哈希(SCSAI 认证用 AuthHeaders MD5 mode) | 是 |
| index.js | 4005行 | SCSAIBomService 类:_SCSAIApiRequest、login、CRUD | 是 |
| src/SCSAI-shim.js | ~3KB | Vue 模块加载时的后备存根 | 推荐 |
| server.js /SCSAI-api/ 路由 | ~30行 | 转发 AML → SCSAI | 是 |
原始文件 vs Shim 对照
| 原始 SCSAI 文件 | 大小 | 替代方式 |
|---|---|---|
| mscorlib.js | 1行 (min) | 不需要 |
| IOM.ScriptSharp.debug.js | 4334行 | window.IomFactory 空对象 |
| core/sciot_object.js | 6938行 (218KB) | SciotStub 构造器 + 5 个方法 |
| sciot_user.js | 893行 | SciotStub.prototype.validateUser |
| sciot_modules.js | 149行 | window.SciotModules 空对象 |
| core/GlobalObjectsPatch.js | 879行 | 已内联进 inline 存根 |
| cryptoJS.js + md5.js + cryptohash.js | 多文件 | utils/md5.js(保留) |
| 其余 20+ 文件 (Utils/Soap/XML/UI) | 大量 | 全部不需要 |
关键约束
加载顺序(必须严格遵守)
1. utils/md5.js ← 提供 window.MD5Util
2. inline shim ← 提供 window.Sciot / IomFactory 等
3. index.js ← window.SCSAIBomSkill = new SCSAIBomService()
4. /src/main.js ← Vue 挂载(import SCSAI-shim.js 作为后备)
MD5 哈希必须与 SCSAI 兼容
SCSAI Agent 使用 MD5 对密码进行哈希后通过 AUTHPASSWORD 头发送。必须使用与 utils/md5.js 一致的实现:
// 正确(项目已验证)
MD5Util.hash('gyc123456;') === '0d1d076e1b9baa7a04f7ad9b315296f9'
// 错误(字节序不对的 MD5 会产生错误的哈希,认证会失败)
SCSAIBomService 不变
index.js 是一个 4005 行的自包含类,定义 window.SCSAIBomService 和 window.SCSAIBomSkill。不要修改它。它的 _ensureSciotMethods() 会在 Sciot.prototype 上补丁 login/getPassword/getLoginName 等方法,前提是 window.Sciot 已定义。
在数字员工平台中集成
推荐目录结构
数字员工平台项目/
├── plm/
│ ├── index.html # PLM 模块入口(含 inline shim)
│ ├── index.js # SCSAIBomService(从 bossagents 复制)
│ ├── utils/
│ │ └── md5.js # 从 bossagents 复制
│ ├── src/
│ │ ├── SCSAI-shim.js # 后备存根
│ │ ├── plm-router.js # PLM 相关路由
│ │ └── views/ # PLM 视图(CustomerManagement 等)
│ └── server/
│ └── SCSAI-proxy.js # /SCSAI-api/ 代理路由
├── digital-staff/ # 你现有的数字员工模块
└── package.json
PLM 功能清单(可复用的 Vue 视图)
| 视图 | SCSAI ItemType | 功能 |
|------|---------------|------|
| CustomerManagement.vue | Customer | 客户 CRUD |
| VendorManagement.vue | Vendor | 供应商 CRUD |
| OrderManagement.vue | Order | 订单 CRUD |
| InventoryManagement.vue | Inventory | 库存管理 |
| ChangeManagement.vue | ECR/ECO | 变更管理 |
| QualityManagement.vue | Quality | 质量管理 |
| ProjectManagement.vue | Project | 项目管理 |
| BomAssistant.vue | Part / BOM | BOM 对比、分析 |
| Dashboard.vue | 多类型 | 聚合看板 |
所有视图统一使用:
const result = await window._bomService._SCSAIApiRequest('ApplyItem', aml);
排错
| 错误 | 原因 | 修复 |
|------|------|------|
| this.validateUser is not a function | SciotStub 未定义 validateUser 或 index.js 先于 shim 加载 | 确保 inline shim 在 index.js 之前 |
| Authentication failed for root | MD5 哈希算法错误或密码错误 | 检查 MD5Util.hash() 输出是否正确 |
| CacheUtil is not a constructor | window.CacheUtil 未定义 | 在 inline shim 中添加空构造器 |
| SOAP Fault / AML 错误 | AML 语法或权限问题 | 检查 SCSAI 服务器日志 |
| _bomService 未定义 | index.js 未加载或加载顺序错误 | 检查 |
性能对比
| 指标 | 原生 SCSAI JS 加载 | Shim 方案 |
|---|---|---|
| HTML script 标签数 | 40 个 | 4 个 |
| JS 传输量 | ~2.1 MB | ~12 KB |
| 首屏阻塞时间 | 500-1500ms(同步 script 阻塞) | 几乎为 0 |
| 构建警告 | 40 条(Vite 无法处理非模块 script) | 0 或极小 |
| 可维护性 | 依赖 SCSAI 版本,升级困难 | 纯 JS 存根,可控 |
BossAgents