Files
BIPMaterialManager/docs/user-override-match-feature.md
Misaka_Company 77311edce0 feat: add user override match for material validation in cleaner page
Add Priority 3 matching logic that allows User type users to override
material assignments with their own typeKeywords from MaterialsTypeToBeDeleted.

Changes:
- Add session manager integration to get current user context
- Implement Priority 3: User Override Match (only for non-admin users)
- Filter typeKeywords by current username and force override on match
- Maintain existing Priority 1 (exact match) and Priority 2 (type match) behavior
- Admin users bypass override logic and see original matching results
- Update cleaner-validation-flow.md with new matching algorithm flow

This ensures User users see materials assigned to themselves first when
their configured typeKeywords match, while Admin users maintain full visibility.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-03 10:45:25 +08:00

7.7 KiB
Raw Blame History

物料匹配算法增强 - 用户覆盖匹配功能

实施日期: 2026-03-03 功能版本: 1.0 修改文件: src/main/ipc/validation-handler.ts


功能概述

User 用户类型 在物料清理界面增加了 优先级3用户覆盖匹配 功能,确保 User 用户能够优先看到并管理与自己关键词匹配的物料。


实现的更改

1. 获取当前用户信息

位置: validation-handler.ts:218-239

// Get current user info
const sessionManager = (
  await import('../services/user/session-manager')
).SessionManager.getInstance()

const userInfo = sessionManager.getUserInfo()
if (!userInfo) {
  return {
    success: false,
    error: '用户未登录',
    stats: {
      totalRecords: 0,
      matchedCount: 0,
      markedCount: 0
    }
  }
}

const isAdmin = userInfo.userType === 'Admin'
const username = userInfo.username

log.info('Starting validation', { mode: request.mode, user: username, isAdmin })

说明:

  • validation:validate handler 开始时获取当前登录用户信息
  • 提取 isAdminusername 用于后续匹配逻辑
  • 如果用户未登录,返回错误响应

2. 新增优先级3用户覆盖匹配

位置: validation-handler.ts:359-370

// Priority 3: User Override Match (only for non-admin users)
// Override with current user's typeKeyword if available
if (!isAdmin && username) {
  const userKeywords = typeKeywords.filter((tk) => tk.managerName === username)
  for (const userKeyword of userKeywords) {
    if (userKeyword.materialName && materialName.includes(userKeyword.materialName)) {
      matchedTypeKeyword = userKeyword.materialName
      managerName = userKeyword.managerName
      break // Force override with first match
    }
  }
}

匹配逻辑:

  1. 适用范围: 仅对 isAdmin === false 的 User 用户生效
  2. 筛选关键词: 从 typeKeywords 中筛选 managerName === username 的记录
  3. 匹配规则: 使用 materialName.includes(userKeyword.materialName) 包含关系匹配
  4. 强制覆盖: 只要匹配成功,立即覆盖原有的 managerNamematchedTypeKeyword
  5. 无匹配时: 保持优先级2的匹配结果不变

匹配优先级(更新后)

flowchart TB
    Start([物料数据]) --> P1{优先级1<br/>MaterialsToBeDeleted<br/>精确匹配?}
    P1 -->|MaterialCode匹配| M1[✅ 已标记删除<br/>isMarkedForDeletion=true]
    P1 -->|未匹配| P2{优先级2<br/>MaterialsTypeToBeDeleted<br/>包含匹配?}

    P2 -->|匹配到| M2[⚠️ 类型匹配<br/>managerName=其他用户]
    P2 -->|未匹配| M3[❌ 未匹配<br/>managerName='']

    M1 --> Check{用户类型?}
    M2 --> Check
    M3 --> Check

    Check -->|Admin| Skip[跳过覆盖]
    Check -->|User| P3{优先级3<br/>用户覆盖匹配?}

    P3 -->|匹配成功| Override[✅ 覆为当前用户<br/>managerName=当前用户]
    P3 -->|未匹配| Keep[保持原结果]

    Skip --> End([返回结果])
    Override --> End
    Keep --> End

测试场景

场景1: User 用户匹配到自己的 typeKeyword

输入:

  • 当前用户: user1
  • 物料名称: 螺丝 M6
  • MaterialsTypeToBeDeleted: { materialName: "螺丝", managerName: "user1" }

预期输出:

{
  "materialName": "螺丝 M6",
  "managerName": "user1",
  "matchedTypeKeyword": "螺丝",
  "isMarkedForDeletion": false
}

场景2: User 用户覆盖其他用户的匹配

输入:

  • 当前用户: user1
  • 物料名称: 螺丝 M6
  • MaterialsTypeToBeDeleted:
    • { materialName: "螺丝", managerName: "user2" }
    • { materialName: "螺丝", managerName: "user1" }

优先级2结果: managerName = "user2" 优先级3结果: managerName = "user1" 强制覆盖

场景3: User 用户无匹配关键词

输入:

  • 当前用户: user1
  • 物料名称: 螺丝 M6
  • MaterialsTypeToBeDeleted:
    • { materialName: "螺丝", managerName: "user2" }

预期输出:

{
  "materialName": "螺丝 M6",
  "managerName": "user2",
  "matchedTypeKeyword": "螺丝",
  "isMarkedForDeletion": false
}

说明: 保持优先级2的匹配结果

场景4: Admin 用户不执行覆盖

输入:

  • 当前用户: admin (isAdmin=true)
  • 物料名称: 螺丝 M6
  • MaterialsTypeToBeDeleted:
    • { materialName: "螺丝", managerName: "user1" }
    • { materialName: "螺丝", managerName: "admin" }

预期输出:

{
  "materialName": "螺丝 M6",
  "managerName": "user1",
  "matchedTypeKeyword": "螺丝",
  "isMarkedForDeletion": false
}

说明: Admin 不执行优先级3保持原有匹配行为

场景5: 优先级1匹配不受影响

输入:

  • 当前用户: user1
  • 物料代码: MAT001
  • MaterialsToBeDeleted: { materialCode: "MAT001", managerName: "user2" }

预期输出:

{
  "materialCode": "MAT001",
  "managerName": "user2",
  "isMarkedForDeletion": true,
  "matchedTypeKeyword": undefined
}

说明: 优先级1的精确匹配不受覆盖影响


数据库配置示例

MaterialsTypeToBeDeleted 表数据

MaterialName ManagerName 说明
螺丝 user1 user1 负责所有包含"螺丝"的物料
螺母 user2 user2 负责所有包含"螺母"的物料
垫圈 user1 user1 也负责"垫圈"类物料
电缆 admin admin 负责电缆类物料

匹配结果示例

物料名称 当前用户 原匹配 (优先级2) 覆盖后 (优先级3)
螺丝 M6 user1 user2 user1
螺母 M8 user1 user2 user2 (无匹配)
垫圈 φ10 user1 user2 user1
电缆 5m user1 admin user1 (无匹配)
螺丝 M6 admin user2 user2 (Admin跳过)

与前端协同

前端过滤器逻辑 (CleanerPage.tsx) 保持不变:

const filteredResults = React.useMemo(() => {
  let results = validationResults
  if (!isAdmin && currentUsername) {
    // User 只看到自己的物料 + 未分配的物料
    results = results.filter((r) => r.managerName === currentUsername || !r.managerName)
  }
  return results
}, [validationResults, isAdmin, currentUsername, managers, selectedManagers, hiddenItems])

协同效果:

  1. 后端匹配算法确保 User 用户的物料优先分配给自己
  2. 前端过滤器只显示属于当前用户或未分配的物料
  3. Admin 用户可以看到所有物料并切换查看不同负责人

代码审查检查点

  • User 信息获取正确使用 SessionManager
  • 只对 !isAdmin 的用户执行覆盖逻辑
  • 使用相同的包含匹配规则 materialName.includes(typeKeyword.materialName)
  • 优先级1精确匹配不受覆盖影响
  • 无匹配时保持原有结果
  • 日志记录包含用户信息 { user: username, isAdmin }
  • 未登录时返回明确的错误信息

潜在改进方向

  1. 性能优化: 如果 typeKeywords 数量很大,可以预先构建 Map<username, typeKeyword[]> 索引
  2. 日志增强: 添加覆盖匹配的统计信息(覆盖了多少条记录)
  3. 配置开关: 允许 Admin 用户通过配置启用/禁用覆盖功能
  4. UI 反馈: 在前端显示哪些物料是通过覆盖匹配分配的

相关文件

  • 实现文件: src/main/ipc/validation-handler.ts (Lines 218-239, 359-370)
  • 前端页面: src/renderer/src/pages/CleanerPage.tsx
  • 会话管理: src/main/services/user/session-manager.ts
  • 类型定义: src/main/types/validation.types.ts

文档结束