SCSAI 对象 CRUD 操作指南
基于 server/utils/SCSAI-client.js 代码整理
适用对象:Part、Vendor、Manufacturer Part、Part BOM、Part AML 等所有 SCSAI ItemType
一、初始化 SCSAIClient
const { SCSAIClient } = require('./server/utils/SCSAI-client');
const SCSAI = new SCSAIClient({
serverUrl: 'https://ylxt.chat/scplm',
database: 'SCPLM',
username: 'root',
password: 'gyc123456;', // 注意:密码末尾有分号
timeout: 30000
});
关键说明:
- 密码必须经过 MD5 哈希后放在
AUTHPASSWORD请求头(内部自动处理) - MD5 哈希结果必须为 大写
password字段原样传入,内部调用_md5()处理
二、查找对象(Query / 查询)
方法1:queryItems()(推荐,简单查询)
// 查所有 Vendor(最多100条)
const res = await SCSAI.queryItems('Vendor', {
select: 'id,name,contact_email,overall_rating',
maxRecords: 50
});
if (res.success) {
const vendors = res.items; // Array<Object>
vendors.forEach(v => console.log(v.id, v.name, v.contact_email));
}
方法2:queryItems() 带条件
// 查 approved 状态的 Vendor
const res = await SCSAI.queryItems('Vendor', {
select: 'id,name,status,contact_email',
where: '<status>approved</status>',
maxRecords: 50
});
方法3:sendAML()(高级,支持复杂查询)
// 查 contact_email 不为空的 Vendor
const aml = `<AML>
<Item type="Vendor" action="get" maxRecords="50" select="id,name,contact_email">
<contact_email condition="is not null"></contact_email>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
const vendors = res.items;
方法4:查关系对象(如 Part BOM)
// 查某个 Part 的 BOM(子件)
const parentId = 'D4F2F90F01D34399B07A0BEFEEBDCB86';
const aml = `<AML>
<Item type="Part BOM" action="get" maxRecords="100" select="source_id,related_id,quantity">
<source_id>${parentId}</source_id>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
// res.items 中每个元素:
// source_id = 父件 ID(或对象)
// related_id = 子件 ID(或对象)
// quantity = 用量
响应结构
{
success: true,
items: [ { id: '...', name: '...', ... } ],
fault: null,
rawXml: '...',
count: 3
}
items 中字段的两种形态:
- 普通字段:
name: 'Clamp'(直接是值) - 引用字段:
source_id: 'D4F2F...'(只是 ID 字符串) - 如果要展开引用对象,AML 中用
select="source_id(keyed_name,item_number)"
三、添加对象(Create / 创建)
方法1:createItem()(推荐)
const res = await SCSAI.createItem('Vendor', {
name: '测试供应商有限公司',
vendor_number: 'V-2026-0099',
contact_email: 'tuan_zhang@sina.com',
contact_name: '张经理',
type: 'manufacturer',
status: 'approved',
overall_rating: '90',
country: '中国',
province: '广东',
city: '深圳'
});
if (res.success) {
const newId = res.items[0].id;
console.log('创建成功,ID =', newId);
} else {
console.error('创建失败:', res.fault);
}
方法2:sendAML()(高级,支持更多控制)
const aml = `<AML>
<Item type="Vendor" action="add">
<name>测试供应商有限公司</name>
<vendor_number>V-2026-0099</vendor_number>
<contact_email>tuan_zhang@sina.com</contact_email>
<contact_name>张经理</contact_name>
<type>manufacturer</type>
<status>approved</status>
<overall_rating>90</overall_rating>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
创建关系对象(如 Part BOM)
// 创建 BOM 行:父件 → 子件
const aml = `<AML>
<Item type="Part BOM" action="add">
<source_id type="Part">D4F2F90F01D34399B07A0BEFEEBDCB86</source_id>
<related_id type="Part">2C1DE8449A7F4B5ABC9315C770874C3A</related_id>
<quantity>2</quantity>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
关键: 引用字段(source_id、related_id)必须用 type="Part" 指定目标 ItemType。
四、修改对象(Update / 编辑)
方法1:updateItem()(推荐)
const vendorId = 'V-001'; // 要修改的 Item ID
const res = await SCSAI.updateItem('Vendor', vendorId, {
contact_email: 'tuan_zhang@sina.com',
overall_rating: '95',
status: 'strategic'
});
if (res.success) {
console.log('修改成功');
} else {
console.error('修改失败:', res.fault);
}
方法2:sendAML()(高级)
const vendorId = 'V-001';
const aml = `<AML>
<Item type="Vendor" action="edit" id="${vendorId}">
<contact_email>tuan_zhang@sina.com</contact_email>
<overall_rating>95</overall_rating>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
批量修改
// SCSAI 不支持真正的批量 update,需要逐条发送
for (const v of vendors) {
await SCSAI.updateItem('Vendor', v.id, { status: 'approved' });
}
五、删除对象(Delete / 删除)
方法1:deleteItem()(推荐)
const vendorId = 'V-001';
const res = await SCSAI.deleteItem('Vendor', vendorId);
if (res.success) {
console.log('删除成功');
} else {
console.error('删除失败:', res.fault);
}
方法2:sendAML()
const aml = `<AML>
<Item type="Vendor" action="delete" id="V-001" />
</AML>`;
const res = await SCSAI.sendAML(aml);
警告:
- 删除是物理删除(SCSAI 默认不进回收站,取决于 ItemType 配置)
- 有级联引用的对象可能无法删除(会报 SOAP Fault)
六、添加对象属性(Property / 字段)
如果 ItemType 缺少某个字段(如 Vendor 缺少 contact_email),需要先在 SCSAI 中创建 Property 定义,然后才能写入数据。
通过 AML 创建 Property(给 ItemType 加字段)
// 给 Vendor 对象类型添加 contact_email 字段
const aml = `<AML>
<Item type="Property" action="add">
<name>contact_email</name>
<label xml:lang="en">Contact Email</label>
<data_type>string</data_type>
<stored_length>128</stored_length>
<is_required>0</is_required>
<is_hidden>0</is_hidden>
<is_indexed>0</is_indexed>
<source_id type="ItemType">9F23A02D1E464F44A3A93A1EFB732B5C</source_id>
<sort_order>1544</sort_order>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
注意: source_id 的 value 是 Vendor 的 ItemType ID,需要从 SCSAI 中先查到。
七、常见错误与排查
错误1:ValidateUser 失败(ItemNotFoundException)
原因: ValidateUser 不是标准的 SCSAI AML Item 操作,需要用 User 的 get 操作代替:
// ❌ 错误写法
const aml = `<Item type="User" action="ValidateUser">...</Item>`;
// ✅ 正确写法:直接查 User
const aml = `<AML>
<Item type="User" action="get">
<login_name>root</login_name>
</Item>
</AML>`;
const res = await SCSAI.sendAML(aml);
错误2:密码 MD5 哈希大小写问题
// ❌ 错误:SCSAI 要求大写
const hash = crypto.createHash('md5').update(pwd).digest('hex');
// 结果:a1b2c3d4...
// ✅ 正确
const hash = crypto.createHash('md5').update(pwd).digest('hex').toUpperCase();
// 结果:A1B2C3D4...
SCSAI-client.js 第67行已完成此修复。
错误3:XML 中有特殊字符未转义
// ❌ 错误:密码中有 & < > " ' 会破坏 XML
const aml = `<name>${v.name}</name>`; // 如果 v.name 含 & 会报错
// ✅ 正确:用 _escapeXml() 处理
const safeName = SCSAI._escapeXml(v.name);
const aml = `<name>${safeName}</name>`;
错误4:AML 标签未正确闭合
// ❌ 错误
const aml = `<AML><Item type="Part" action="get"></AML>`;
// 缺少 </Item>
// ✅ 正确
const aml = `<AML><Item type="Part" action="get"></Item></AML>`;
八、完整示例:给 Vendor 添加 contact_email 并写入数据
const { SCSAIClient } = require('./server/utils/SCSAI-client');
const SCSAI = new SCSAIClient({
serverUrl: 'https://ylxt.chat/scplm',
database: 'SCPLM',
username: 'root',
password: 'gyc123456;',
timeout: 30000
});
async function main() {
// 1. 查现有 Vendor
console.log('=== Step1: 查询现有 Vendor ===');
let res = await SCSAI.queryItems('Vendor', {
select: 'id,name,contact_email',
maxRecords: 5
});
console.log('现有 Vendor:', JSON.stringify(res.items, null, 2));
// 2. 创建新 Vendor(带 contact_email)
console.log('\n=== Step2: 创建新 Vendor ===');
res = await SCSAI.createItem('Vendor', {
name: '演示供应商有限公司',
vendor_number: 'V-2026-DEMO',
contact_email: 'tuan_zhang@sina.com',
contact_name: '演示联系人',
type: 'manufacturer',
status: 'approved',
overall_rating: '88',
country: '中国',
province: '北京',
city: '北京'
});
console.log('创建结果:', JSON.stringify(res, null, 2));
if (res.success) {
const newId = res.items[0].id;
// 3. 修改刚创建的 Vendor
console.log('\n=== Step3: 修改 Vendor ===');
res = await SCSAI.updateItem('Vendor', newId, {
overall_rating: '95',
contact_email: 'tuan_zhang@sina.com'
});
console.log('修改结果:', JSON.stringify(res, null, 2));
// 4. 删除测试数据
console.log('\n=== Step4: 删除测试 Vendor ===');
res = await SCSAI.deleteItem('Vendor', newId);
console.log('删除结果:', JSON.stringify(res, null, 2));
}
}
main().catch(e => console.error('错误:', e.message));
九、常用 ItemType 速查表
| ItemType | 关键字段 | 关系 |
|-----------|-----------|------|
| Part | item_number, name, cost, unit | → Part BOM, → Part AML |
| Vendor | name, vendor_number, contact_email, overall_rating | — |
| Manufacturer Part | item_number, name, unit_price, manufacturer | ← Part AML |
| Part BOM (关系) | source_id(父Part), related_id(子Part), quantity | — |
| Part AML (关系) | source_id(Part), related_id(Manufacturer Part) | — |
| ECR | item_number, title, status, priority | — |
| Change Request | item_number, title, state | — |
十、注意事项总结
- 密码末尾有分号:
gyc123456;(分号是密码的一部分) - MD5 哈希必须大写:已修复在
SCSAI-client.js第67行 - AML 必须闭合所有标签:
必须有,必须有 - 引用字段要指定 type:
ID select里展开引用:select="source_id(keyed_name,item_number)"- SCSAI 连接测试:先
queryItems('Part', { maxRecords:1 })验证连通性
BossAgents