# 车辆查询部门自动匹配功能说明 ## 功能概述 在车辆查询时,无论用户传入的是分公司ID还是子部门ID(如技术部、业务部),系统都会自动查找其所属的分公司,并返回该分公司的车辆。 ## 业务背景 ### 部门层级结构 ``` 100 (总公司) ├── 101 (深圳分公司) ← 车辆归属于分公司 │ ├── 201 (技术部) ← 用户可能属于子部门 │ ├── 202 (业务部) │ └── 203 (财务部) ├── 102 (广州分公司) │ ├── 204 (技术部) │ ├── 205 (业务部) │ └── 206 (财务部) └── 103 (北京分公司) ├── 207 (技术部) └── 208 (业务部) ``` ### 问题场景 **原有逻辑**: - 用户A(技术部,deptId=201)查询车辆 - 系统查询:`WHERE dept_id = 201` - 结果:❌ 查不到车辆(因为车辆的dept_id=101,不是201) **期望逻辑**: - 用户A(技术部,deptId=201)查询车辆 - 系统自动找到分公司:201 → 101(深圳分公司) - 系统查询:`WHERE dept_id = 101` - 结果:✅ 查到深圳分公司的所有车辆 ## 实现方案 ### SQL查询逻辑 **文件**:[`VehicleInfoMapper.xml`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\ruoyi-system\src\main\resources\mapper\system\VehicleInfoMapper.xml) ```xml and v.dept_id = ( select case when exists(select 1 from sys_dept where dept_id = #{deptId} and parent_id = 100) then #{deptId} else ( select d.dept_id from sys_dept d where d.parent_id = 100 and FIND_IN_SET(d.dept_id, ( select ancestors from sys_dept where dept_id = #{deptId} )) limit 1 ) end ) ``` ### 查询逻辑说明 #### 步骤1:判断传入的deptId是否为分公司 ```sql when exists(select 1 from sys_dept where dept_id = #{deptId} and parent_id = 100) ``` - 如果传入的 `deptId` 的 `parent_id = 100`,说明传入的就是分公司 - 直接使用该 `deptId` 查询 #### 步骤2:如果不是分公司,从ancestors中查找 ```sql select d.dept_id from sys_dept d where d.parent_id = 100 and FIND_IN_SET(d.dept_id, ( select ancestors from sys_dept where dept_id = #{deptId} )) ``` **原理**: - 每个部门的 `ancestors` 字段存储了所有上级部门ID(用逗号分隔) - 例如:技术部(201)的 `ancestors` 可能是 `"100,101,201"` - 使用 `FIND_IN_SET` 在 ancestors 中查找 `parent_id=100` 的部门 - 找到的就是分公司ID ## 使用示例 ### 示例1:传入分公司ID **输入**: ```javascript deptId: 101 // 深圳分公司 ``` **SQL执行**: ```sql -- 检查:101 的 parent_id = 100 ✅ -- 直接使用:dept_id = 101 WHERE v.dept_id = 101 ``` **结果**:✅ 返回深圳分公司的所有车辆 ### 示例2:传入子部门ID **输入**: ```javascript deptId: 201 // 深圳分公司-技术部 ``` **数据**: ```sql -- sys_dept 表数据 dept_id | parent_id | ancestors 101 | 100 | 100,101 201 | 101 | 100,101,201 ``` **SQL执行**: ```sql -- 1. 检查:201 的 parent_id = 100 ❌ -- 2. 查询 ancestors:select ancestors from sys_dept where dept_id = 201 -- 结果:"100,101,201" -- 3. 在 ancestors 中查找 parent_id=100 的部门 -- FIND_IN_SET(d.dept_id, "100,101,201") and d.parent_id = 100 -- 找到:101 -- 4. 使用:dept_id = 101 WHERE v.dept_id = 101 ``` **结果**:✅ 返回深圳分公司的所有车辆 ### 示例3:传入孙部门ID **输入**: ```javascript deptId: 301 // 深圳分公司-技术部-开发组 ``` **数据**: ```sql -- sys_dept 表数据 dept_id | parent_id | ancestors 101 | 100 | 100,101 201 | 101 | 100,101,201 301 | 201 | 100,101,201,301 ``` **SQL执行**: ```sql -- 1. 检查:301 的 parent_id = 100 ❌ -- 2. 查询 ancestors:"100,101,201,301" -- 3. 在 ancestors 中查找 parent_id=100 的部门 -- 找到:101 -- 4. 使用:dept_id = 101 WHERE v.dept_id = 101 ``` **结果**:✅ 返回深圳分公司的所有车辆 ## 应用场景 ### 场景1:绑定车辆 **用户**:技术部员工(deptId=201) ```javascript // 前端调用 listAvailableVehicles(201, 'GENERAL') // 后端查询 SELECT * FROM tb_vehicle_info v WHERE v.dept_id = ( -- 自动找到分公司:201 → 101 ... ) ``` **结果**:显示深圳分公司的所有车辆 ### 场景2:创建任务 **用户**:业务部员工(deptId=202) ```javascript // 前端调用 listAvailableVehicles(202, 'EMERGENCY') // 后端查询 SELECT * FROM tb_vehicle_info v WHERE v.dept_id = ( -- 自动找到分公司:202 → 101 ... ) ``` **结果**:显示深圳分公司的所有车辆 ## 数据流程图 ```mermaid sequenceDiagram participant User as 用户(技术部) participant Page as 前端页面 participant API as 后端API participant DB as 数据库 User->>Page: 打开绑定车辆页面 Page->>Page: 获取用户部门ID: 201 Page->>API: listAvailableVehicles(201, 'GENERAL') API->>DB: SELECT dept_id FROM sys_dept WHERE dept_id=201 DB-->>API: parent_id=101 (不是100) API->>DB: SELECT ancestors FROM sys_dept WHERE dept_id=201 DB-->>API: "100,101,201" API->>DB: FIND_IN_SET in ancestors WHERE parent_id=100 DB-->>API: 找到分公司ID: 101 API->>DB: SELECT * FROM tb_vehicle_info WHERE dept_id=101 DB-->>API: 深圳分公司的车辆列表 API-->>Page: 返回车辆数据 Page-->>User: 显示深圳分公司的车辆 ``` ## 兼容性 ### ✅ 支持的场景 | 输入deptId | 部门类型 | 查询结果 | |-----------|---------|---------| | 101 | 分公司 | 101的车辆 ✅ | | 201 | 子部门 | 101的车辆 ✅ | | 301 | 孙部门 | 101的车辆 ✅ | | 401 | 曾孙部门 | 101的车辆 ✅ | ### ⚠️ 特殊情况 | 输入deptId | 说明 | 查询结果 | |-----------|------|---------| | 100 | 总公司 | ❌ 查不到(车辆必须归属于分公司) | | null | 空值 | ❌ 不执行部门过滤 | ## 性能优化 ### 索引建议 为了提高查询性能,建议在 `sys_dept` 表添加索引: ```sql -- 部门表索引 CREATE INDEX idx_parent_id ON sys_dept(parent_id); CREATE INDEX idx_ancestors ON sys_dept(ancestors(100)); -- 车辆表索引(已存在) CREATE INDEX idx_dept_id ON tb_vehicle_info(dept_id); ``` ### 查询优化 - ✅ 使用 `CASE WHEN` 减少子查询次数 - ✅ 使用 `LIMIT 1` 限制结果集 - ✅ `FIND_IN_SET` 利用索引查询 ## 测试验证 ### 测试场景1:分公司用户 ```sql -- 模拟输入:deptId = 101 SELECT * FROM tb_vehicle_info v WHERE v.dept_id = ( select case when exists(select 1 from sys_dept where dept_id = 101 and parent_id = 100) then 101 else (...) end ) -- 结果:dept_id = 101 ``` ### 测试场景2:子部门用户 ```sql -- 模拟输入:deptId = 201 SELECT * FROM tb_vehicle_info v WHERE v.dept_id = ( select case when exists(select 1 from sys_dept where dept_id = 201 and parent_id = 100) then 201 else ( select d.dept_id from sys_dept d where d.parent_id = 100 and FIND_IN_SET(d.dept_id, ( select ancestors from sys_dept where dept_id = 201 )) limit 1 ) end ) -- 结果:dept_id = 101 ``` ## 影响范围 ### 修改的文件 - [`VehicleInfoMapper.xml`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\ruoyi-system\src\main\resources\mapper\system\VehicleInfoMapper.xml) - 车辆查询Mapper ### 影响的功能 1. ✅ 绑定车辆 - 自动显示分公司车辆 2. ✅ 创建任务 - 自动显示分公司车辆 3. ✅ 车辆管理 - 自动按分公司过滤 4. ✅ 所有调用 `selectVehicleInfoList` 的地方 ### 向后兼容 - ✅ 传入分公司ID仍然正常工作 - ✅ 传入子部门ID自动转换为分公司ID - ✅ 不影响其他查询条件 ## 总结 ### ✅ 优势 1. **自动匹配** - 无论用户在哪个层级的部门,都能看到分公司的车辆 2. **用户友好** - 用户不需要关心自己是在哪个子部门 3. **数据隔离** - 依然保持分公司之间的数据隔离 4. **向后兼容** - 不影响现有功能 ### 📝 注意事项 1. **ancestors字段** - 依赖 `sys_dept` 表的 `ancestors` 字段正确维护 2. **性能** - 建议添加索引以提高查询性能 3. **总公司** - 传入总公司ID(100)不会返回车辆 --- **更新时间**: 2025-10-25 **版本**: v1.0 **状态**: ✅ 已实现