ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/VinManagementQueryDTO.java
@@ -13,4 +13,6 @@ private Integer status; /** 所属公司ID(额度分配弹窗按公司筛选使用) */ private Integer companyId; /** 所属车队ID(车队管理-查看车队抽屉按车队筛选VIN码车辆使用) */ private Integer fleetId; } ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/factory/VinManagementFallbackFactory.java
@@ -1,5 +1,7 @@ package com.ruoyi.account.api.factory; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.account.api.dto.VinManagementQueryDTO; import com.ruoyi.account.api.feignClient.VinManagementClient; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.common.core.domain.R; @@ -35,6 +37,11 @@ public R<List<TVinManagement>> getVinByIds(List<Long> ids) { return R.fail("根据ID批量查询VIN记录失败:" + throwable.getMessage()); } @Override public R<Page<TVinManagement>> getVinPageByFleet(VinManagementQueryDTO query) { return R.fail("按车队分页查询VIN记录失败:" + throwable.getMessage()); } }; } } ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/feignClient/VinManagementClient.java
@@ -1,5 +1,7 @@ package com.ruoyi.account.api.feignClient; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.account.api.dto.VinManagementQueryDTO; import com.ruoyi.account.api.factory.VinManagementFallbackFactory; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.common.core.constant.ServiceNameConstants; @@ -33,4 +35,10 @@ */ @PostMapping("/t-vin-management/inner/list-by-ids") R<List<TVinManagement>> getVinByIds(@RequestBody List<Long> ids); /** * 按车队分页查询VIN码车辆(车队管理-查看车队抽屉使用,query.fleetId 必须传入) */ @PostMapping("/t-vin-management/inner/page-by-fleet") R<Page<TVinManagement>> getVinPageByFleet(@RequestBody VinManagementQueryDTO query); } ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TVinManagementController.java
@@ -104,4 +104,12 @@ List<Long> distinctIds = ids.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()); return R.ok(distinctIds.isEmpty() ? new ArrayList<>() : service.listByIds(distinctIds)); } /** * 内部接口:按车队分页查询VIN码车辆(车队管理-查看车队抽屉使用,含车队名称回填) */ @PostMapping("/inner/page-by-fleet") public R<IPage<TVinManagement>> pageByFleet(@RequestBody VinManagementQueryDTO query) { return R.ok(service.selectPageList(query)); } } ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TVinManagementMapper.xml
@@ -9,6 +9,7 @@ <if test="query != null and query.phone != null and query.phone != ''">AND phone LIKE CONCAT('%', #{query.phone}, '%')</if> <if test="query != null and query.status != null">AND status = #{query.status}</if> <if test="query != null and query.companyId != null">AND company_id = #{query.companyId}</if> <if test="query != null and query.fleetId != null">AND fleet_id = #{query.fleetId}</if> ORDER BY create_time DESC, id DESC </select> <select id="selectExportList" resultType="com.ruoyi.account.api.dto.VinManagementExcelDTO"> ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TFleetController.java
@@ -1,5 +1,7 @@ package com.ruoyi.other.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.utils.poi.ExcelUtil; import com.ruoyi.common.core.web.domain.AjaxResult; @@ -213,6 +215,18 @@ } /** * 分页查询车队下的VIN码车辆(查看车队抽屉使用) */ @RequiresPermissions(value = {"/fleet/list"}, logical = Logical.OR) @GetMapping("/vin-page") @ApiOperation(value = "分页查询车队下VIN码车辆", tags = {"管理后台-车队管理"}) public AjaxResult<Page<TVinManagement>> vinPage(@RequestParam("id") Integer id, @RequestParam(value = "current", defaultValue = "1") Integer current, @RequestParam(value = "size", defaultValue = "10") Integer size) { return AjaxResult.success(fleetService.selectVinPage(id, current, size)); } /** * 按公司ID批量回填公司名称 */ private void fillCompanyName(List<TFleet> records) { ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TFleetService.java
@@ -1,6 +1,8 @@ package com.ruoyi.other.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.other.api.domain.TFleet; import com.ruoyi.other.api.dto.FleetExportDTO; import com.ruoyi.other.api.dto.FleetImportDTO; @@ -34,4 +36,14 @@ */ List<FleetExportDTO> selectExportList(FleetQueryDTO query); /** * 分页查询车队下的VIN码车辆(远程调用VIN管理服务,含VIN码、车牌号、手机号、初始分配额度、启用状态) * * @param fleetId 车队ID * @param current 当前页码 * @param size 每页数量 * @return VIN码车辆分页数据 */ Page<TVinManagement> selectVinPage(Integer fleetId, Integer current, Integer size); } ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TFleetServiceImpl.java
@@ -1,6 +1,11 @@ package com.ruoyi.other.service.impl; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.api.dto.VinManagementQueryDTO; import com.ruoyi.account.api.feignClient.VinManagementClient; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.other.api.domain.TFleet; import com.ruoyi.other.api.domain.TGroupCompany; @@ -42,6 +47,28 @@ @Resource private TGroupCompanyService groupCompanyService; @Resource private VinManagementClient vinManagementClient; @Override public Page<TVinManagement> selectVinPage(Integer fleetId, Integer current, Integer size) { if (fleetId == null) { throw new ServiceException("车队ID不能为空"); } if (getById(fleetId) == null) { throw new ServiceException("车队不存在或已删除"); } VinManagementQueryDTO query = new VinManagementQueryDTO(); query.setFleetId(fleetId); query.setPageCurr(current == null || current < 1 ? 1 : current); query.setPageSize(size == null || size < 1 ? 10 : size); R<Page<TVinManagement>> response = vinManagementClient.getVinPageByFleet(query); if (response == null || !R.isSuccess(response) || response.getData() == null) { throw new ServiceException("VIN码车辆查询失败:" + (response == null ? "服务无响应" : response.getMsg())); } return response.getData(); } @Override @Transactional(rollbackFor = Exception.class) public String importFleets(List<FleetImportDTO> items) { ruoyi-service/ruoyi-other/src/test/java/com/ruoyi/other/service/impl/TFleetServiceImplTest.java
New file @@ -0,0 +1,126 @@ package com.ruoyi.other.service.impl; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.account.api.dto.VinManagementQueryDTO; import com.ruoyi.account.api.feignClient.VinManagementClient; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.other.api.domain.TFleet; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; /** * 车队下VIN码车辆分页查询逻辑单测(VIN管理远程服务以 Mock 替代,不依赖 Spring 容器与数据库)。 */ class TFleetServiceImplTest { @Test void passesFleetIdAndPagingToVinService() { VinManagementClient client = Mockito.mock(VinManagementClient.class); Page<TVinManagement> expected = new Page<>(1, 10); expected.setTotal(1); expected.setRecords(Collections.singletonList(vehicle())); Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(R.ok(expected)); Page<TVinManagement> actual = buildService(fleet(4), client).selectVinPage(4, 1, 10); assertSame(expected, actual); ArgumentCaptor<VinManagementQueryDTO> captor = ArgumentCaptor.forClass(VinManagementQueryDTO.class); Mockito.verify(client).getVinPageByFleet(captor.capture()); assertEquals(4, captor.getValue().getFleetId()); assertEquals(1, captor.getValue().getPageCurr()); assertEquals(10, captor.getValue().getPageSize()); } @Test void fallsBackToDefaultPagingWhenParamsInvalid() { VinManagementClient client = Mockito.mock(VinManagementClient.class); Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(R.ok(new Page<>(1, 10))); buildService(fleet(5), client).selectVinPage(5, null, 0); ArgumentCaptor<VinManagementQueryDTO> captor = ArgumentCaptor.forClass(VinManagementQueryDTO.class); Mockito.verify(client).getVinPageByFleet(captor.capture()); assertEquals(1, captor.getValue().getPageCurr()); assertEquals(10, captor.getValue().getPageSize()); } @Test void rejectsMissingFleetId() { VinManagementClient client = Mockito.mock(VinManagementClient.class); TFleetServiceImpl service = buildService(null, client); ServiceException ex = assertThrows(ServiceException.class, () -> service.selectVinPage(null, 1, 10)); assertTrue(ex.getMessage().contains("车队ID不能为空"), ex.getMessage()); Mockito.verifyNoInteractions(client); } @Test void rejectsUnknownFleet() { VinManagementClient client = Mockito.mock(VinManagementClient.class); TFleetServiceImpl service = buildService(null, client); ServiceException ex = assertThrows(ServiceException.class, () -> service.selectVinPage(9, 1, 10)); assertTrue(ex.getMessage().contains("车队不存在"), ex.getMessage()); Mockito.verifyNoInteractions(client); } @Test void failsWhenRemoteReturnsError() { VinManagementClient client = Mockito.mock(VinManagementClient.class); Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(R.fail("VIN 管理服务调用失败")); ServiceException ex = assertThrows(ServiceException.class, () -> buildService(fleet(4), client).selectVinPage(4, 1, 10)); assertTrue(ex.getMessage().contains("VIN码车辆查询失败"), ex.getMessage()); } @Test void failsWhenRemoteReturnsNullData() { VinManagementClient client = Mockito.mock(VinManagementClient.class); Mockito.when(client.getVinPageByFleet(Mockito.any())).thenReturn(null); ServiceException ex = assertThrows(ServiceException.class, () -> buildService(fleet(4), client).selectVinPage(4, 1, 10)); assertTrue(ex.getMessage().contains("服务无响应"), ex.getMessage()); } private TFleetServiceImpl buildService(TFleet fleet, VinManagementClient client) { TFleetServiceImpl service = Mockito.spy(new TFleetServiceImpl()); Mockito.doReturn(fleet).when(service).getById(Mockito.any()); ReflectionTestUtils.setField(service, "vinManagementClient", client); return service; } private TFleet fleet(Integer id) { TFleet fleet = new TFleet(); fleet.setId(id); return fleet; } private TVinManagement vehicle() { TVinManagement item = new TVinManagement(); item.setId(1L); item.setVin("12345678900000000"); item.setPlateNumber("川A123456"); item.setFleetId(4); item.setInitQuota(new BigDecimal("30.00")); item.setStatus(1); return item; } }