SCIOT 对象创建 — 字段处理实现文档
基于 SCIOT-AML-Basic-Settings-Reference.md + 代码实现 + 数据库模板配置
最后更新: 2026-06-03
目录
1. 字段分类框架
每个业务对象类型的字段分为三类:
| 分类 | 含义 | 数据来源 | 验证规则 |
|------|------|---------|---------|
| llm_fields | LLM 可以生成的字段 | LLM 根据用户描述推断 | 必须经过白名单过滤 + 数据类型清洗 |
| auto_fields | 系统自动填充的字段 | Sequence / 默认值 / SCSAI server 回调 | 不参与 LLM 生成,但前端会补充默认值 |
| system_fields | 系统元字段 | SCSAI 自动管理 | 完全从前端逻辑排除 |
分类算法(batch-import-templates.js classifyFields)
优先级从高到低:
- 系统字段 → auto(SYSTEM_FIELDS 硬编码列表)
- **keyed 且
*_number→ auto(自动编号,如item_number) - keyed 但非
*_number→ llm(用户提供,如name) - readonly=1 → auto
- item/foreign/sequence 数据类型 → auto(如
wbs_id、default_currency) - 特殊模式** → auto(
_id,percent_,has_change_pending,hc_copied_*) - 其余字段 → llm
对应代码位置
- 分类算法:
scripts/batch-import-templates.js:172-229 - 前端白名单:
src/views/StaffCapabilities.vue:1603-1613 - auto 字段补充默认值:
src/views/StaffCapabilities.vue:1616-1638
2. 系统字段清单
以下字段永远属于 auto_fields,不由 LLM 生成:
SCSAI 元字段
id, config_id, created_by_id, created_on, modified_by_id, modified_on
permission_id, keyed_name, current_state, state
major_rev, minor_rev, generation, new_version
is_current, is_released, locked_by_id, team_id
managed_by_id, owned_by_id
classification, css, not_lockable
from_project_id, from_template
编号字段(从 is_keyed 自动识别)
item_number — Part, Document, CAD, ECR, ECN, PR, Manufacturer Part, Product
project_number — Project
login_name — User
pop_po_no — Purchase Order
pop_invoice_no — Bill Received
sop_order_no — Sales Order
sop_invoice_no — Tax Invoice, Commercial Invoice
stk_code — Stock
...(所有以 _number 结尾的 keyed 字段)
特殊字段
// 前端硬编码系统字段(src/views/StaffCapabilities.vue:1194-1201)
const systemFields = [
'id','config_id','created_by_id','created_on','modified_by_id','modified_on',
'permission_id','keyed_name','current_state','state',
'major_rev','minor_rev','generation','new_version',
'is_current','is_released','locked_by_id','team_id',
'classification','css','not_lockable',
'managed_by_id','owned_by_id','llm_configuration','from_project_id','from_template',
// 计算字段(只读,不能写入)
'rollup_percent_compl','rollup_cost','rollup_hours','effort','duration',
'wbs_number','wbs_short_name'
]
3. 编号字段(Sequence)处理
3.1 SCSAI Sequence 配置
参考 SCIOT-AML-Basic-Settings-Reference.md §3.6:
| 序列名称 | 类型 | prefix | initial_value | step | pad_to | suffix |
|---------|------|--------|---------------|------|--------|--------|
| Default Part | Part | - | 100000 | 1 | - | -001 |
| Default Document | Document | - | 100000 | 1 | - | - |
| CAD Document | CAD | CAD- | 0 | 1 | 8 | - |
| ECR | ECR | - | 1 | 1 | - | - |
| ECN | ECN | - | 1 | 1 | - | - |
| PR | Problem Report | - | 1 | 1 | - | - |
| Project Number | Project | - | 1 | 1 | - | - |
3.2 前端 Sequence 获取逻辑
位置: src/views/StaffCapabilities.vue:1506-1545
1. 对每个 keyedField:
a. 从 generation_rules.sequence_field 取配置的 Sequence 名
b. 无配置时从字段名推断(item_number → "{ItemType} Number")
c. GET Sequence → 读取 current_value
d. current_value + 1 → EDIT Sequence
e. 3 次重试(GET+EDIT 是独立操作,需乐观锁)
2. 成功 → 用 Sequence 值覆盖 LLM 值
3. 失败但 LLM 提供了值 → 保留 LLM 值
4. 失败且字段必填 → 生成 AUTO-{timestamp} 保底值
5. 失败且字段非必填 → 删除该字段
3.3 无 Sequence 配置时的处理
configuredSeqField只在generation_rules.sequence_name存在时才匹配keyed_field- 如果无
sequence_name,name等用户提供的 keyed 字段不会被误判为 Sequence 字段 - 字段值直接保留 LLM/用户提供的值(不会被删除)
4. 数据类型清洗规则
位置: src/utils/rule-validator.js:filterAndSanitize
| SCSAI 类型 | 清洗规则 | 无效值处理 |
|-----------|---------|-----------|
| string / text / ml_string | 保留原值 | - |
| integer | parseInt() | → 0 |
| decimal | parseFloat() | 非数值 → 0 |
| float | parseFloat() | 非数值 → 0 |
| boolean | Yes/No/true/false/1/0 | → '1' 或 '0' |
| date | 保留 ISO 格式 | 保留原值 |
| list | 保留字符串(值与可选值列表匹配最佳) | 保留原值 |
| color list | 同上 | 同上 |
| item / foreign | 特殊处理(见 item_properties) | 移出 properties |
| sequence | 特殊处理 | 移出 properties |
对应代码
// src/utils/rule-validator.js:185-225
function sanitizeProperties(props, propDefs) {
for (const [key, value] of Object.entries(props)) {
const def = propDefs.find(p => p.name === key)
if (!def) continue
switch (def.data_type) {
case 'integer':
sanitized[key] = parseInt(value, 10) || 0
break
case 'decimal': case 'float':
const num = parseFloat(value)
sanitized[key] = isNaN(num) ? 0 : num
break
case 'boolean':
if (['yes','y','true','1',1,true].includes(value)) sanitized[key] = '1'
else sanitized[key] = '0'
break
default:
sanitized[key] = value
}
}
}
5. 关系对象处理
5.1 关系格式标准化
LLM 可能返回三种格式:
// 格式 A(标准数组)
{"relationships": [{"relationship_type": "Part BOM", "related_items": [...]}]}
// 格式 B(对象键名)
{"relationships": {"Part BOM": {"related_items": [...]}}}
// 格式 C(related_id 包装)
{"relationships": [{"relationship_type": "Part BOM", "related_id": {"id": "..."}}]}
代码统一在 StaffCapabilities.vue:1976-1991 标准化为格式 A。
5.2 关系类型名解析
LLM 可能使用完整的关系显示名(如 "ECR Affected Item → Affected Item (Affected Items)"),
代码提取 → 前的名称与 relTypes 匹配。
5.3 related_item_type 覆盖
LLM 经常把 related_item_type 写成关系名(如 "Part BOM"),
代码从 relTypes 查找到正确的目标类型(如 "Part")并覆盖。
5.4 子对象字段处理
对于关系中的每个子对象:
- WBS Element → 预创建后通过 ID 引用(不能 inline 创建)
- 所有类型 → 基于
subTypeTemplates的 schema:
- 移除目标类型不存在的字段
- 为必填 keyed 字段生成保底值(
AUTO-{ts}-{rand}) - 补充 hidden 字段的默认值
6. 各类型模板配置
6.1 Part (零件)
| 配置项 | 值 |
|---|---|
| keyed_field | item_number |
| sequence_field | item_number |
| sequence_name | Part Number |
| llm_fields | name, description, cost, make_buy, unit, weight, weight_basis, cost_basis, related_projects, indexed_on (10 个) |
| auto_fields | item_number, major_rev, classification, state, superseeded_date, external_, thumbnail, variant_, has_change_pending, hc_copied_from, allow_team_change_logic (12 个) |
6.2 Document (文档)
| 配置项 | 值 |
|---|---|
| keyed_field | item_number |
| sequence_field | item_number |
| sequence_name | Document Number |
| llm_fields | name, description, is_template, related_projects, authoring_tool_version, drawing_size, scale, specification_type (8 个) |
| auto_fields | item_number, major_rev, has_files, has_files_icon, classification, state, superseeded_date, has_change_pending, allow_team_change_logic, external_*, from_template, thumbnail (14 个) |
6.3 ECR (工程变更请求)
| 配置项 | 值 |
|---|---|
| keyed_field | item_number |
| sequence_field | item_number |
| sequence_name | ECR Number |
| llm_fields | title, description, basis, proposed_solution, fast_track, release_date, priority, change_type, requested_by, source, change_admin, technical_review, problem_status, solution, routing, implementation_timing, implementation_priority, ecr_comments (18 个) |
| auto_fields | item_number, state, low_nonrecurring_cost, nonrecurring_cost, recurring_cost, recurring_cost_direction (6 个) |
6.4 Project (项目)
| 配置项 | 值 |
|---|---|
| keyed_field | project_number |
| sequence_field | project_number |
| sequence_name | Project Number |
| default_properties | scheduling_type=Forward, scheduling_mode=1, project_update_mode=1, update_method=Actual |
| llm_fields | name, description, goals, scheduling_type, comments, owned_by_id (6 个) |
| auto_fields | project_number, date_, state, status_, percent_compl_*, wbs_id, owned_by_id, scheduling_method, update_method, scheduling_mode, project_update_mode, from_project_id, from_template, llm_configuration, rollup_percent_compl (33 个) |
6.5 Vendor (供应商)
| 配置项 | 值 |
|--------|-----|
| keyed_field | name |
| llm_fields | name, description, contact_name, main_phone, main_fax, address, city, address_state, zip_code, country, web_site (11 个) |
| auto_fields | state, default_currency (2 个) |
注意:Vendor 的 name 同时是 keyed_field 和 llm_field。因为 title 不是 *_number,脚本不会把它归为 auto。
6.6 Contact (联系人)
| 配置项 | 值 |
|---|---|
| llm_fields | first_name, last_name, title, company, main_phone, email, cell_num, fax_num, address_1, address_2, city, zip_code, country, notes, job_role (15 个) |
| auto_fields | state_location (1 个) |
6.7 Manufacturer Part (制造商零件)
| 配置项 | 值 |
|---|---|
| keyed_field | item_number |
| sequence_field | item_number |
| sequence_name | Manufacturer Part Number |
| llm_fields | name, description, manufacturer, unit_price, unit (5 个) |
| auto_fields | item_number, state, has_files (3 个) |
6.8 CAD (CAD文档)
| 配置项 | 值 |
|---|---|
| keyed_field | item_number |
| sequence_field | item_number |
| sequence_name | CAD Document |
| llm_fields | description, name, is_standard, allow_team_change_logic, authoring_tool_version, external_owner, external_type, related_projects, thumbnail, x_max, x_min, y_max, y_min, z_max, z_min, superseeded_date (17 个) |
| auto_fields | external_id, from_template, has_change_pending, monolithic_model_file, native_file, shattered_model_file, view_file, viewable_file, item_number, classification, created_by_id, created_on, current_state, generation, locked_by_id, major_rev, managed_by_id, modified_by_id, modified_on, owned_by_id, state (21 个) |
6.9 Product (产品)
| 配置项 | 值 |
|---|---|
| keyed_field | item_number |
| sequence_field | item_number |
| sequence_name | Product Number |
| llm_fields | description, item_number, name (3 个) |
| auto_fields | (无) |
6.10 Manufacturer (制造商)
| 配置项 | 值 |
|---|---|
| keyed_field | name |
| llm_fields | name, description, email, account_no, account_no_icon, address, address_state, city, contact_name, country, field, has_files, has_files_icon, main_fax, main_phone, remarks, web_site, zip_code (18 个) |
| auto_fields | item_folder_template_id, top_item_folder_id, state (3 个) |
6.11 Customer (客户)
| 配置项 | 值 |
|---|---|
| llm_fields | address, address_state, city, contact_name, country, description, email, is_credit, main_fax, main_phone, web_site, zip_code, name (13 个) |
| auto_fields | default_currency (1 个) |
6.12 WBS Element (WBS 节点)
| 配置项 | 值 |
|---|---|
| llm_fields | cpi, spi, earned_value, planned_value, rollup_work_est, rollup_actual_work, rollup_work_est_curr, deliv_required, is_top, name, prev_item, proj_num, rpn, wbs_index (14 个) |
| auto_fields | rollup_date_sched_due, rollup_date_sched_start, rollup_duration, rollup_percent_compl, rollup_status (5 个) |
6.13 Activity2 (项目活动)
| 配置项 | 值 |
|---|---|
| llm_fields | actual_work, cpi, date_, deliv_required, Deliverable, description, earned_value, expected_duration, is_critical, is_required, lead_role, message, name, orig_duration, planned_value, prev_item, proj_index, proj_num, rollup_, signoff_required, spi, work_est, work_est_curr, x, y (37 个) |
| auto_fields | date_activated, date_due_original, date_ef, date_es, date_lf, date_ls, is_milestone, percent_compl, status, managed_by_id, owned_by_id (11 个) |
7. 前端代码字段处理流程
完整流程(按执行顺序):
1. 获取 Schema(/api/aml/unified/schema/:itemType)
├─ properties: 所有字段定义(含 data_type, is_keyed, is_required, is_hidden, default_value)
├─ llmFields: LLM 可生成字段
├─ autoFields: 系统自动填充字段
├─ rules: 验证规则
└─ template: 模板配置(generation_rules, keyed_field)
2. 构建 Prompt → 发送给 LLM
├─ 只包含 llmFields 中的字段
├─ 包含字段名称、类型、可选值(list 值)
└─ 包含 relationship_types
3. 解析 LLM 响应
├─ 提取 JSON payload
├─ 标准化 relationships 格式
└─ 构建 mainValues + relationships
4. 编号字段处理(keyedFields 循环)
├─ 有 Sequence 配置 → 获取 Sequence 值
├─ 无 Sequence 但 LLM 有值 → 保留 LLM 值
├─ 无 Sequence 且字段必填 → 生成 AUTO 保底
└─ 无 Sequence 且字段非必填 → 跳过
5. 字段过滤 + 数据类型清洗(filterAndSanitize)
├─ 只保留 validPropNames 中的字段
├─ 清洗 integer/decimal/float/boolean
└─ 移除 null/undefined/空字符串
6. 补充 auto 字段默认值
├─ 有 default_value 且 LLM 未生成 → 补充
└─ generation_rules.default_properties → 补充
7. 安全网:必填 keyed 字段缺失 → 生成 AUTO 保底
8. 处理 item_properties(Item 类型字段)
└─ 需要预创建的嵌套 Item(如 wbs_id)
9. 关系处理(每个子对象)
├─ WBS Element → 预创建 + ID 引用
├─ 移除无关字段(基于子类型 schema)
├─ 必填 keyed 字段 → AUTO 保底
└─ hidden 字段 → 补充默认值
10. 规则验证(rules)
└─ required / pattern / min / max
11. 构建 AML → 提交 SCSAI
12. AI 自动纠错重试(最多 3 次)
└─ 解析错误 → 发给 LLM 修正 → 重试
8. 脚本自动生成规则
scripts/batch-import-templates.js 自动处理 16 个核心业务类型:
Part, Product, Document, ECR, ECN,
Manufacturer Part, Manufacturer, Vendor, Customer, CAD,
Change Controlled Item, Project, Activity2,
WBS Element, Deliverable, Program
生成步骤
1. 从 SCIOT/SCIOT/{module}/Import/ItemType/{name}.xml 提取属性
2. classifyFields() → 按优先级分类 llm / auto
3. buildGenerationRules() → 检测 keyed *_number 生成 sequence 配置
4. extractLifecycleStartState() → 从 Life Cycle Map XML 提取初始状态
5. 写入 sciot_templates 表(UPDATE 或 INSERT)
防止覆盖
脚本 UPDATE 时覆盖 llm_fields、auto_fields、generation_rules、keyed_field。
手工修改 sciot_import.db 后如果重新运行脚本会覆盖。解决方案:
- 已实现: 脚本的
classifyFields和buildGenerationRules已修正,自动生成正确的值 - 备份:
sciot_import.db.backup_20260603包含手工调整后的完整数据 - 通过 API 保存: 前端有
/api/aml/sciot/update-template-fields端点可以持久化
9. 常见问题与陷阱
9.1 name 字段被删除
原因: name 是 keyed 字段(is_keyed=1),旧脚本归类为 auto_fields。在代码中进入 Sequence 处理分支。
由于无 Sequence 配置,进入 else 分支被删除。
修复要点:
- 脚本: 只把
*_number的 keyed 字段归为 auto(batch-import-templates.js:191-194) - 代码:
configuredSeqField无sequence_name时不匹配 keyed_field(StaffCapabilities.vue:1493) - 代码: 无 Sequence 的 keyed 字段保留 LLM 值(
StaffCapabilities.vue:1583-1585)
9.2 item_number 为 NULL(sub-item Part)
原因: 子 Part 是 inline 创建(通过 Part BOM 关系),代码没有为其生成 item_number。
修复: 子对象处理循环中,基于 subTypeTemplates 为所有必填 keyed 字段生成保底值。
9.3 cost: "High" 导致 PropertyValueFormatException
原因: cost 是 decimal 类型,LLM 生成字符串 "High"。
修复: sanitizeProperties 对 decimal/float 做 parseFloat + isNaN 检查,非数值 → 0。
9.4 ID: undefined
原因: parseSCSAIResponse 将 result.Item 设为数组,但代码访问 result.Item.id。
修复: 将 result.Item 改为单对象(items[0]),同时保留 result.items 数组。
9.5 LLM 关系格式不一致
原因: LLM 可能返回数组、对象、或 related_id 包装的格式。
修复: 关系标准化器处理所有三种格式(StaffCapabilities.vue:1976-1991)。
9.6 LLM 把 related_item_type 写成关系名
原因: LLM 不理解 related_item_type 和 relationship_type 的区别。
修复: 代码从 relTypes 查找关系配置,用正确的目标类型覆盖 LLM 的值。
附录
A. 数据库备份
sciot_import.db → sciot_import.db.backup_20260603 (22.8MB)
B. 相关文件清单
| 文件 | 用途 |
|------|------|
| src/views/StaffCapabilities.vue | 主创建流程(字段处理、关系处理、Sequence) |
| src/utils/rule-validator.js | 数据类型清洗、规则验证 |
| src/utils/SCSAI.js | SCSAI API 请求、XML 解析 |
| src/utils/AmlBuilder.js | AML 生成 |
| src/utils/PromptBuilder.js | LLM Prompt 构建 |
| scripts/batch-import-templates.js | 模板批量导入 |
| server/routes/aml.js | 后端 API(模板查询/更新) |
| server/routes/unified-aml.js | 统一 Schema API |
| server/core/unified-schema.js | Schema Builder |
| server/data/sciot_import.db | SQLite 数据库(模板 + 属性 + 关系) |
C. 参考文档
docs/SCIOT-AML-Basic-Settings-Reference.md— SCSAI 基础设置完整参考
BossAgents