Skill: 2656255594/bom-sop-check (version 2.1.2)

--- name: bom-sop-check version: 2.1.2 description: BOM与SOP对比校对技能。支持多个BOM文件合并后与SOP对比，检测名称规格、位号、数量差异，在SOP文件中标注差异、追加BOM数据并生成报告。校对报告包含：SOP独有物料、BOM独有物料、数量差异明细三个表格。触发场景：用户发送BOM和SOP文件要求对比校对。 --- # BOM 与 SOP 校对技能 ## 功能说明 1. 解析 BOM 表提取物料信息（编码、名称、规格、数量、位号） 2. 解析 SOP 表 AN-BQ 列范围提取物料信息 3. 按物料编码匹配，对比名称规格、位号、数量 4. 在 SOP 文件中标注差异单元格（红色/黄色） 5. 将 BOM 数据追加到 SOP 新列（BS/BT/BU） 6. **新增**：生成校对报告工作表 7. 生成差异报告并发送标注后的文件 ## v1.10.0 功能特性 ### 核心功能 - **BOM 数据追加**：将 BOM 的名称规格、数量、位号写入 SOP 新列 - BS 列：BOM 名称规格 - BT 列：BOM 数量 - BU 列：BOM 位号 ### 表头样式 - 第154行添加 BOM 表头 - 表头样式：加粗 + 浅蓝背景 + 边框 - 数据单元格：细边框表格效果 ### 合并单元格支持 - 自动识别 SOP 中的合并单元格 - BOM 数据列与 SOP 格式保持一致 - 仅给有差异的物料添加 BOM 信息 ### 校对报告工作表（v1.10 新增） - 新增"校对报告"工作表 - 包含 BOM 独有物料列表（BOM有但SOP没有） - 包含 SOP 独有物料列表（SOP有但BOM没有） - 表格格式：类型、物料编码、物料名称、名称规格、数量、位号 ### 版本历史 - **v1.0**：核心对比功能 + 简单标注（红/黄） - **v1.9**：新增 BS/BT/BU 列、表头样式、边框、合并单元格支持 - **v1.10**：新增校对报告工作表 ## 稳定性保障 ### 文件验证 - ✅ 文件存在性检查 - ✅ 文件格式验证（必须是 .xlsx） - ✅ 文件大小限制（≤100MB） - ✅ Excel 格式有效性验证（ZIP 结构检查） ### 数据处理 - ✅ 最大行数限制（10000 行） - ✅ 字符串长度限制（500 字符） - ✅ 物料编码格式验证（`\d{5}-\d{3}-\d{3}`） - ✅ 空值保护（None → 空字符串） - ✅ 除零保护（分母为 0 时默认为 1） ### 对比逻辑 - ✅ 规范化比较（去除多余空格） - ✅ 数量浮点误差容忍（±0.001） - ✅ 位号分隔符兼容（逗号、中文逗号、空格） ### 错误处理 - ✅ 异常捕获与日志记录 - ✅ 友好错误消息 - ✅ 详细模式（`--verbose`） ## 文件格式支持 - `.xlsx` - 直接处理 - `.zip` - 自动解压后处理（支持多个文件或单个文件压缩） ### 压缩文件处理 当用户发送 `.zip` 文件时： 1. 自动解压到临时目录 2. 识别其中的 BOM 和 SOP 文件（根据文件名和内容） 3. 执行对比校对 4. 清理临时文件 ### 文件识别规则 **BOM 文件特征**: - 文件名包含 "BOM" 或 "物料清单" - 列 I 含物料编码格式 `XXXXX-XXX-XXX` - 有父项/子项结构 **SOP 文件特征**: - 文件名包含 "SOP" 或 "作业指导书" - AN-BQ 列范围存在物料编码 ## 文件接收处理 ### 文件缓存目录 - **缓存路径**: `/root/.openclaw/workspace-text-1-feishu-6/skills/bom-sop-check/cache/` - **状态文件**: `cache/status.json` - 记录已接收的文件信息 ### 场景处理流程 #### 场景1：同时发送多个文件 1. 接收所有文件，保存到缓存目录 2. 逐一识别文件类型（BOM/SOP） 3. 全部识别完成后开始对比 4. 完成后清理缓存 #### 场景2：先后发送文件 1. 接收第一个文件，识别类型并保存到缓存 2. 更新 status.json 记录已接收文件 3. 告知用户已接收 X 文件，等待 Y 文件 4. 接收到第二个文件后自动开始对比 5. 完成后清理缓存 #### 场景3：单个文件包含多个工作表 1. 解析所有工作表 2. 自动识别哪个 sheet 是 BOM，哪个是 SOP 3. 开始对比 4. 完成后清理缓存 ### 文件类型识别规则 **BOM 文件特征**: - 列 I 含 "物料编码" 或数据格式为 XXXXX-XXX-XXX - 列 J 含 "物料名称" 或 "子项物料名称" - 列 K 含 "规格型号" 或 "子项规格型号" - 有父项/子项结构（列 D 有父项物料编码） **SOP 文件特征**: - AN-BQ 列范围存在数据 - 列 AQ (或对应列) 含物料编码格式 XXXXX-XXX-XXX - 通常是作业指导书格式 ## 文件格式 ### BOM 文件 | 列 | 字段 | 说明 | |----|------|------| | I | 物料编码 | 格式：XXXXX-XXX-XXX | | J | 物料名称 | 子项物料名称 | | K | 规格型号 | 子项规格型号 | | N | 用量分子 | 用于计算数量 | | O | 用量分母 | 用于计算数量 | | P | 备注 | 包含位号信息 | **数量计算**：实际用量 = 分子(N) ÷ 分母(O)，分母为空或0时默认为1 ### SOP 文件（作业指导书） 提取物料信息（按用户指定映射）： | 列范围 | 字段 | 实际取值 | |--------|------|----------| | AQ-AW | 物料编码 | AQ 列 | | AX-BH | 名称规格 | AX 列 | | BI-BN | 位号 | BI 列 | | BO-BQ | 数量 | BO 列 | ## 校对逻辑 ### 对比流程 1. **物料编码匹配**：BOM 列 I ↔ SOP 列 AQ 2. **名称规格对比**：BOM 列 J+K ↔ SOP 列 AX 3. **位号对比**：BOM 列 P ↔ SOP 列 BI 4. **数量对比**：BOM 列 N÷O ↔ SOP 列 BO ### 差异定义 - **名称规格差异**：名称或规格型号不一致 - **位号差异**：位号信息不匹配 - **数量差异**：数量值不一致 ## 输出说明 ### 1. 差异报告 | 物料编码 | 名称 | 差异类型 | BOM内容 | SOP内容 | |----------|------|----------|---------|---------| **差异类型**：名称规格、位号、数量 ### 2. 标注文件 **标注颜色**： | 颜色 | 含义 | 应用列 | |------|------|--------| | 🔴 红色 | 名称规格/位号/数量差异 | AX, BI, BO | | 🟡 黄色 | 仅 SOP 中存在的物料 | AX, BI, BO | **注意**：物料编码列（AQ）不标注颜色 ### 3. BOM 数据追加（v1.1 新增） 在 SOP 文件右侧新增三列，写入对应的 BOM 数据： | 新列 | 内容 | 说明 | |------|------|------| | BS | BOM 名称规格 | 方便对比名称差异 | | BT | BOM 数量 | 方便对比数量差异 | | BU | BOM 位号 | 方便对比位号差异 | **标注样式**： - 差异物料的 BS/BT/BU 列会标注为红色 - 仅 SOP 存在的物料不追加 BOM 数据 ## 使用方法 ### 步骤1：接收文件并缓存 ``` 检查 cache/status.json 状态 保存文件到 cache/ 目录 更新 status.json ``` ### 步骤2：识别文件类型 根据"文件类型识别规则"判断每个文件是 BOM 还是 SOP。 ### 步骤3：判断是否可以开始对比 **情况A：单个 BOM + 单个 SOP** - BOM 和 SOP 都已收到 → 直接开始对比 **情况B：多个 BOM + 单个 SOP（多 BOM 合并）** - 收到多个 BOM 文件时，**先询问用户确认**： ``` 检测到多个 BOM 文件： 1. bom1.xlsx 2. bom2.xlsx 3. bom3.xlsx 是否要将这些 BOM 文件合并后与 SOP 进行校对？ - 合并规则：同一物料编码累加数量、合并位号 - 请回复"确认"开始校对，或告诉我如何处理 ``` - 用户确认后再执行合并校对 - **防止误上传**：不自动合并，必须用户明确确认 ### 步骤4：执行对比校对 1. 解析 BOM 提取 I/J/K/N/O/P 列 2. 解析 SOP 提取 AN-BQ 范围内的 AQ/AX/BI/BO 列 3. 按物料编码匹配并对比各字段 4. 在 SOP 文件 AN-BQ 列范围内标注差异单元格 5. 生成差异报告 6. 发送报告和标注后的 SOP 文件 ### 步骤5：清理缓存 - **SOP 物料数据**：对比完成后立即删除 `sop_materials.json`，不保留 - **BOM 物料数据**：保留在 `bom_materials.json`，每周提醒用户手动清理一次 - **status.json**：对比完成后重置 ## 缓存清理策略 | 文件 | 清理时机 | |------|----------| | sop_materials.json | 对比完成后立即删除 | | bom_materials.json | 每周提醒用户清理 | | compare_result.json | 对比完成后保留（作为历史记录） | | status.json | 对比完成后重置 | ## 文件发送方案 ### 优先方案：使用飞书 API 直接发送 当 `message` 工具或 `lightclaw_upload_file` 不可用时，使用飞书 API： ```bash # 1. 获取 tenant_access_token TENANT_TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \ -H "Content-Type: application/json" \ -d '{"app_id":"<APP_ID>","app_secret":"<APP_SECRET>"}' | jq -r '.tenant_access_token') # 2. 上传文件 FILE_KEY=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/files" \ -H "Authorization: Bearer $TENANT_TOKEN" \ -F "file_type=xlsx" \ -F "file_name=<文件名>.xlsx" \ -F "file=@<本地文件路径>" | jq -r '.data.file_key') # 3. 发送文件消息 curl -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \ -H "Authorization: Bearer $TENANT_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"receive_id\":\"<用户open_id>\",\"msg_type\":\"file\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\"}\"}" ``` ### 备用方案：使用 message 工具 ```json { "action": "send", "channel": "feishu", "filePath": "/path/to/file.xlsx", "message": "文件说明" } ``` ## 并发处理方案（v1.11 新增） ### 问题背景 当多个用户同时请求校对时，单进程会导致排队等待。 ### 解决方案：Sub-Agent 并行处理 使用 `sessions_spawn` 为每个校对任务启动独立子代理： ``` 用户A请求 ──► spawn sub-agent A ──► 独立进程处理 ──► 完成通知 用户B请求 ──► spawn sub-agent B ──► 独立进程处理 ──► 完成通知 用户C请求 ──► spawn sub-agent C ──► 独立进程处理 ──► 完成通知 ``` ### 使用方法 当收到用户的 BOM 和 SOP 文件后，使用以下流程： 1. **保存文件到缓存目录** 2. **启动 sub-agent 处理**： ```python # 使用 sessions_spawn 启动后台任务 sessions_spawn( task=f"执行 BOM/SOP 校对任务。BOM文件: {bom_path}, SOP文件: {sop_path}。运行命令: python3 {script_dir}/background_compare.py {bom_path} {sop_path}", runtime="subagent", mode="run", timeout_seconds=300 # 5分钟超时 ) ``` 3. **立即回复用户**："任务已提交，正在后台处理，完成后会通知您" 4. **sub-agent 完成后**：自动发送结果给用户 ### 并发能力 | 用户数 | 处理方式 | 预期效果 | |--------|----------|----------| | 1-2 人 | 主进程处理 | 即时响应 | | 3-5 人 | Sub-Agent 并行 | 每人独立处理，互不阻塞 | | 5+ 人 | Sub-Agent + 任务队列 | 建议增加任务队列管理 | ### 后台处理脚本 `scripts/background_compare.py` - 独立运行的校对脚本，无需依赖主进程上下文。 --- ## 注意事项 1. **标注范围限制**：仅在 AN-BQ 列范围内标注，不影响其他列 2. **数量精度**：分子÷分母结果为整数显示整数，否则保留两位小数 3. **防除零**：分母为空或0时默认为1 4. **文件名保持**：输出文件名与原始 SOP 文件名一致 5. **大文件上传**：超过 20MB 的文件可能上传超时，需设置足够超时时间（--max-time 120） 6. **并发处理**：多用户同时使用时，自动使用 Sub-Agent 并行处理 ## v1.15.0 脚本精简 ### 删除的脚本 - `sop_xml_marker.py` - 字符级标注版本（已删除） - `sop_char_marker*.py` - 测试版本（已删除） - `char_diff_marker.py` - 测试版本（已删除） ### 保留的脚本 - `compare_bom_sop.py` - 主对比脚本（单元格颜色标注） - `background_compare.py` - 后台处理脚本 - `task_queue.py` - 任务队列管理 ### 技术实现 1. 使用 `difflib.SequenceMatcher` 进行字符级对比 2. 生成 Excel 富文本 XML（`<r>` + `<rPr>` 标签） 3. 直接操作 xlsx 内部 XML，避免文件膨胀 ## v1.16.0 更新说明 - 忽略名称规格中冒号差异（全角`：`、半角`:`、竖线`|`视为等价） - 减少因分隔符不同导致的误报 ## v1.17.0 更新说明 - **忽略空格差异**：名称规格比较时移除所有空格 - **智能工作表检测**：自动检测包含物料数据的 sheet - 支持物料编码直接在单元格中 - 支持物料编码在共享字符串中 - 修复不同 SOP 文件格式兼容性问题 ## v1.18.0 更新说明 - **修复样式索引问题**：原 styles.xml 中 cellXfs count 属性与实际 xf 标签数不一致，导致颜色标注无法显示 - **改进样式索引计算**：通过遍历查找 fillId 匹配的样式索引，而不是依赖 count 属性 - **修复工作表选择**：改为自动选择包含最多物料编码的工作表（之前硬编码优先选择 sheet2.xml） - **复用已有填充**：检测并复用文件中已有的红色/黄色填充（Fill 7/8），避免重复添加 ## v1.18.1 更新说明 - **修复自闭合标签处理**：正确处理 `<c r="XX"/>` 自闭合标签的样式添加 - **完整遍历校对**：确保所有物料信息遍历完成后再进行对比校对 ## v1.19.0 更新说明 - **修复 quotePrefix 问题**：新添加的 BS/BT/BU 列不再显示单引号前缀 - **修复样式索引计算**：使用实际 xf 标签数量而非 count 属性 - **数量累加和位号合并**：同一物料编码在多行时，自动累加数量、合并位号后再对比 - **忽略标点符号**：对比时忽略所有标点符号（中英文）、全角半角差异 - **智能对比**：仅对比实质内容差异，减少误报 ## v1.19.1 更新说明 - **位号排序比较**：位号分割后排序再比较，忽略顺序差异 - **忽略括号内容**：位号对比时忽略括号内的备注信息（如 `(V06及以上版本PCB...)`） ## v1.19.2 更新说明 - **校对报告增强**：新增"数量差异明细"表格 - 显示数量差异的物料编码 - 显示 BOM 数量和 SOP 数量 - 计算并显示差异数量（正数表示 BOM 多，负数表示 SOP 多） ## v1.19.3 更新说明 - **位号去重**：位号对比时先去重再排序，避免 SOP 中同一物料编码多行导致位号重复而误报 ## v2.1.0 更新说明 - **多 BOM 文件合并**：支持多个 BOM 文件作为标准校对一个 SOP - 命令行语法：`compare_bom_sop.py bom1.xlsx bom2.xlsx --sop sop.xlsx` - 合并规则：同一物料编码累加数量、合并位号（去重） - 用途：多个产品的 BOM 表合并后校对一个 SOP ## v2.1.1 更新说明 - **用户确认流程**：多个 BOM 文件时需用户确认才执行合并 - 防止误上传导致意外合并 - 明确告知用户合并规则 - 用户回复"确认"后才执行


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)