# 部门编码同步功能实现说明 ## 功能概述 在部门同步过程中,自动从SQL Server的dictionary表读取服务单编码和调度单编码,并根据分公司名称中的地名自动匹配到对应的编码。 ## 数据库变更 ### 1. 新增字段 在`sys_dept`表中添加两个字段: ```sql -- 服务单编码(对应旧系统OrderClass vType=1) ALTER TABLE sys_dept ADD COLUMN service_order_class VARCHAR(20) NULL COMMENT '服务单编码(对应旧系统OrderClass vType=1)' AFTER department_id; -- 调度单编码(对应旧系统OrderClass vType=2) ALTER TABLE sys_dept ADD COLUMN dispatch_order_class VARCHAR(20) NULL COMMENT '调度单编码(对应旧系统OrderClass vType=2)' AFTER service_order_class; -- 添加索引 ALTER TABLE sys_dept ADD INDEX idx_service_order_class (service_order_class); ALTER TABLE sys_dept ADD INDEX idx_dispatch_order_class (dispatch_order_class); ``` **脚本位置**:`sql/add_dept_order_class_fields.sql` ## 代码实现 ### 2. 新增文件 #### 2.1 OrderClassDTO.java **路径**:`ruoyi-system/src/main/java/com/ruoyi/system/domain/OrderClassDTO.java` **作用**:订单编码数据传输对象,映射SQL Server的dictionary表 **字段**: - `vtext` - 编码文本(如:中山服务单) - `vOrder2` - 编码值(如:JA) - `vType` - 编码类型(1-服务单,2-调度单) #### 2.2 OrderClassMapper.java **路径**:`ruoyi-system/src/main/java/com/ruoyi/system/mapper/OrderClassMapper.java` **作用**:从SQL Server查询编码数据的Mapper接口 **方法**: - `selectServiceOrderClass()` - 查询服务单编码列表 - `selectDispatchOrderClass()` - 查询调度单编码列表 **注解**:`@DataSource(DataSourceType.SQLSERVER)` - 使用SQL Server数据源 #### 2.3 OrderClassMapper.xml **路径**:`ruoyi-system/src/main/resources/mapper/system/OrderClassMapper.xml` **SQL查询**: ```xml SELECT vtext, vOrder2, vType FROM dictionary WHERE vtitle = 'OrderClass' AND vType = 1 ORDER BY vOrder2 SELECT vtext, vOrder2, vType FROM dictionary WHERE vtitle = 'OrderClass' AND vType = 2 ORDER BY vOrder2 ``` #### 2.4 IOrderClassDataService.java **路径**:`ruoyi-system/src/main/java/com/ruoyi/system/service/IOrderClassDataService.java` **作用**:订单编码数据服务接口 #### 2.5 OrderClassDataServiceImpl.java **路径**:`ruoyi-system/src/main/java/com/ruoyi/system/service/impl/OrderClassDataServiceImpl.java` **作用**:订单编码数据服务实现类,专门负责从SQL Server查询编码数据 **注解**:`@DataSource(DataSourceType.SQLSERVER)` - 整个服务使用SQL Server数据源 ### 3. 修改文件 #### 3.1 SysDept.java **新增字段**: ```java /** 服务单编码(对应旧系统OrderClass vType=1) */ private String serviceOrderClass; /** 调度单编码(对应旧系统OrderClass vType=2) */ private String dispatchOrderClass; ``` #### 3.2 SysDeptMapper.xml **更新内容**: - 在`resultMap`中添加新字段映射 - 在`selectDeptVo`中添加新字段查询 - 在`insertDept`中添加新字段插入 - 在`updateDept`中添加新字段更新 #### 3.3 DepartmentSyncServiceImpl.java **新增依赖**: ```java @Autowired private IOrderClassDataService orderClassDataService; ``` **核心逻辑更新**: 在创建分公司时,自动调用`syncOrderClassCodes()`方法同步编码: ```java // 创建新的分公司 SysDept newBranch = new SysDept(); newBranch.setParentId(100L); newBranch.setDeptName(branchName); // ... 其他属性设置 ... // 自动匹配并设置服务单和调度单编码 syncOrderClassCodes(newBranch, parts[0].trim()); sysDeptMapper.insertDept(newBranch); ``` **新增辅助方法**: 1. `syncOrderClassCodes(SysDept dept, String cityName)` - 同步订单编码(服务单和调度单编码) - 参数:部门对象、城市名称(如:中山、广州) 2. `matchCityNameToCode(String cityName, List orderClassList)` - 根据城市名称匹配编码 - 匹配规则:如果vtext中包含城市名称,则返回对应的vOrder2编码 - 示例:cityName="中山", vtext="中山服务单", vOrder2="JA" → 返回"JA" ## 工作流程 ### 同步流程 ``` 1. 部门同步开始 ↓ 2. 解析部门名称 湛江--护士 → 分公司:湛江,部门:护士 ↓ 3. 创建/更新分公司 ↓ 4. 查询SQL Server编码数据 ├─ 查询服务单编码 (vType=1) └─ 查询调度单编码 (vType=2) ↓ 5. 地名匹配 ├─ 提取城市名称:湛江 ├─ 遍历服务单编码列表,匹配"湛江" ├─ 遍历调度单编码列表,匹配"湛江" └─ 返回匹配的编码值 ↓ 6. 更新部门对象 ├─ setServiceOrderClass("ZJ") └─ setDispatchOrderClass("ZJ01") ↓ 7. 保存到MySQL数据库 ↓ 8. 同步完成 ``` ## 数据示例 ### SQL Server dictionary表数据 | vtext | vOrder2 | vType | |-------|---------|-------| | 中山服务单 | JA | 1 | | 广州服务单 | GZ | 1 | | 湛江服务单 | ZJ | 1 | | 中山调度单 | JA01 | 2 | | 广州调度单 | GZ01 | 2 | | 湛江调度单 | ZJ01 | 2 | ### MySQL sys_dept表数据(同步后) | dept_id | dept_name | parent_id | service_order_class | dispatch_order_class | |---------|-----------|-----------|---------------------|---------------------| | 200 | 中山分公司 | 100 | JA | JA01 | | 201 | 广州分公司 | 100 | GZ | GZ01 | | 202 | 湛江分公司 | 100 | ZJ | ZJ01 | ## 匹配逻辑 ### 地名匹配算法 ```java private String matchCityNameToCode(String cityName, List orderClassList) { // 1. 检查参数有效性 if (StringUtils.isEmpty(cityName) || orderClassList == null) { return null; } // 2. 遍历编码列表,查找包含城市名称的项 for (OrderClassDTO dto : orderClassList) { if (dto.getVtext() != null && dto.getVtext().contains(cityName)) { // 3. 匹配成功,返回编码值 return dto.getVOrder2(); } } // 4. 未匹配到,返回null return null; } ``` ### 匹配示例 | 分公司名称 | 提取城市名 | vtext(SQL Server) | 匹配结果(vOrder2) | |-----------|-----------|-------------------|------------------| | 湛江--护士 | 湛江 | 湛江服务单 | ZJ | | 中山--车队 | 中山 | 中山服务单 | JA | | 广州--客服 | 广州 | 广州服务单 | GZ | ## 日志输出 ### 成功匹配日志 ``` 2025-10-19 10:00:00 INFO DepartmentSyncServiceImpl - 开始从 SQL Server 查询服务单编码数据... 2025-10-19 10:00:00 INFO OrderClassDataServiceImpl - 成功查询到 10 条服务单编码数据 2025-10-19 10:00:00 INFO DepartmentSyncServiceImpl - 匹配到服务单编码 - 城市: 中山, 编码: JA 2025-10-19 10:00:00 INFO DepartmentSyncServiceImpl - 匹配到调度单编码 - 城市: 中山, 编码: JA01 2025-10-19 10:00:00 INFO DepartmentSyncServiceImpl - 创建新分公司: 中山分公司, ID: 200, 服务单编码: JA, 调度单编码: JA01 ``` ### 未匹配日志 ``` 2025-10-19 10:00:00 WARN DepartmentSyncServiceImpl - 未找到匹配的服务单编码 - 城市: 深圳 2025-10-19 10:00:00 WARN DepartmentSyncServiceImpl - 未找到匹配的调度单编码 - 城市: 深圳 2025-10-19 10:00:00 INFO DepartmentSyncServiceImpl - 创建新分公司: 深圳分公司, ID: 203, 服务单编码: null, 调度单编码: null ``` ## 使用说明 ### 1. 执行数据库脚本 ```bash mysql -u root -p ry-vue < sql/add_dept_order_class_fields.sql ``` ### 2. 重新编译项目 ```bash mvn clean package -DskipTests ``` ### 3. 重启服务 ```bash cd ruoyi-admin java -jar target/ruoyi-admin.jar ``` ### 4. 调用同步接口 ```bash POST http://localhost:8080/system/dept/sync/branch Headers: Authorization: Bearer {token} ``` ### 5. 验证结果 ```sql -- 查看同步的分公司及其编码 SELECT dept_id, dept_name, service_order_class, dispatch_order_class FROM sys_dept WHERE parent_id = 100 AND dept_name LIKE '%分公司' ORDER BY dept_name; ``` ## 注意事项 1. **数据源切换**:`OrderClassMapper`和`OrderClassDataServiceImpl`都使用`@DataSource(DataSourceType.SQLSERVER)`注解,确保从SQL Server查询数据 2. **匹配规则**:使用`contains()`方法进行模糊匹配,如果SQL Server中的vtext包含城市名称即可匹配 3. **未匹配处理**:如果未匹配到编码,字段值为null,不影响部门同步流程 4. **编码更新**:对于已存在的分公司,也会自动更新编码(如果之前为空) 5. **兼容性**:该功能完全向下兼容,不影响原有的部门同步逻辑 ## 扩展建议 ### 1. 精确匹配优化 如果需要更精确的匹配规则,可以修改`matchCityNameToCode`方法: ```java // 完全匹配优先 for (OrderClassDTO dto : orderClassList) { String vtext = dto.getVtext(); if (vtext != null) { // 完全匹配:中山 == 中山服务单(去除"服务单"/"调度单"后缀) String baseName = vtext.replace("服务单", "").replace("调度单", "").trim(); if (baseName.equals(cityName)) { return dto.getVOrder2(); } } } ``` ### 2. 缓存优化 为避免每次同步都查询SQL Server,可以添加缓存: ```java @Cacheable(value = "orderClass", key = "'service'") public List getServiceOrderClass() { // ... } ``` ### 3. 手动配置接口 可以添加一个手动配置编码的接口,用于处理自动匹配失败的情况。 ## 版本历史 - **v1.0** (2025-10-19) - 初始实现 - 支持自动匹配服务单和调度单编码 - 支持在部门同步时自动更新编码 ## 相关文档 - [部门同步功能说明](./部门同步功能说明.md) - [OA数据同步多数据源架构说明](./OA数据同步多数据源架构说明.md) - [部门同步服务重构说明](./部门同步服务重构说明.md)