shinnosuke
2026-07-13 1574e8e0597dfe5f81a01b016640fc250ad7f72a
feat(chargingPile): 新增批量建桩功能和站点预约设置功能

- 添加ChargingPileBatchBuildDTO和ChargingPileBatchBuildResultDTO数据传输对象
- 实现批量建桩功能,支持根据模板批量创建充电桩和接口
- 添加站点预约设置的获取和保存接口
- 优化充电桩查询接口,增加站点和合作商信息关联查询
- 实现接口二维码批量导出功能
- 修复导入充电桩时的错误信息显示问题
- 优化充电桩导入验证逻辑和错误处理机制
2个文件已添加
10个文件已修改
306 ■■■■■ 已修改文件
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildDTO.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildResultDTO.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java
@@ -30,4 +30,13 @@
    @ApiModelProperty(value = "结束充电权限")
    private boolean authEndCharge = true;
    @ApiModelProperty(value = "siteName")
    private String siteName;
    @ApiModelProperty(value = "partnerName")
    private String partnerName;
    @ApiModelProperty(value = "chargingPileCode")
    private String chargingPileCode;
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java
@@ -558,8 +558,38 @@
    
    
    
        @RequiresPermissions(value = {"/site/update"}, logical = Logical.OR)
    @ResponseBody
    @PostMapping("/getReservationSetting/{id}")
    @ApiOperation(value = "获取站点预约设置", tags = {"管理后台-站点管理"})
    public AjaxResult<Site> getReservationSetting(@PathVariable Integer id){
        Site site = siteService.lambdaQuery()
                .select(Site::getId, Site::getName, Site::getSupportOrder, Site::getReservationStartTime, Site::getReservationEndTime)
                .eq(Site::getId, id)
                .eq(Site::getDelFlag, 0)
                .one();
        return AjaxResult.success(site);
    }
    @RequiresPermissions(value = {"/site/update"}, logical = Logical.OR)
    @ResponseBody
    @PostMapping("/saveReservationSetting")
    @ApiOperation(value = "保存站点预约设置", tags = {"管理后台-站点管理"})
    public AjaxResult saveReservationSetting(@RequestBody Site site){
        if (site == null || site.getId() == null) {
            return AjaxResult.error("站点id不能为空");
        }
        boolean success = siteService.lambdaUpdate()
                .eq(Site::getId, site.getId())
                .eq(Site::getDelFlag, 0)
                .set(Site::getSupportOrder, site.getSupportOrder())
                .set(Site::getReservationStartTime, site.getReservationStartTime())
                .set(Site::getReservationEndTime, site.getReservationEndTime())
                .update();
        return success ? AjaxResult.success() : AjaxResult.error("保存预约设置失败");
    }
@RequiresPermissions(value = {"/site/update"}, logical = Logical.OR)
    @ResponseBody
    @PostMapping("/editSite")
    @ApiOperation(value = "编辑站点", tags = {"管理后台-站点管理"})
    @Log(title = "【站点管理】编辑站点", businessType = BusinessType.UPDATE)
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java
@@ -41,6 +41,8 @@
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * <p>
@@ -226,6 +228,49 @@
            e.printStackTrace();
        }
    }
    @RequiresPermissions(value = {"/chargingGun/download_qr_code"}, logical = Logical.OR)
    @ApiOperation(tags = {"管理后台-接口信息"}, value = "批量导出接口二维码")
    @PutMapping(value = "/exportQRCodeZip")
    @Log(title = "【接口信息】批量导出接口二维码", businessType = BusinessType.EXPORT, operatorType = OperatorType.MANAGE)
    public void exportQRCodeZip(@RequestBody TChargingGunQuery query, HttpServletResponse response) {
        try {
            List<TChargingGunVO> list = chargingGunService.exportQRCodeList(query == null ? new TChargingGunQuery() : query);
            String zipName = URLEncoder.encode("接口二维码.zip", "UTF-8");
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment;filename=" + zipName);
            List<String> names = new ArrayList<>();
            try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
                for (TChargingGunVO gun : list) {
                    String code = StringUtils.isNotEmpty(gun.getFullNumber()) ? gun.getFullNumber() : gun.getChargingPileCode() + gun.getCode();
                    if (StringUtils.isEmpty(code)) {
                        continue;
                    }
                    String baseName = sanitizeFileName((StringUtils.isNotEmpty(gun.getSiteName()) ? gun.getSiteName() : "电站")
                            + (StringUtils.isNotEmpty(gun.getName()) ? gun.getName() : code));
                    String entryName = baseName + ".jpg";
                    int index = 1;
                    while (names.contains(entryName)) {
                        entryName = baseName + "(" + index++ + ").jpg";
                    }
                    names.add(entryName);
                    zipOut.putNextEntry(new ZipEntry(entryName));
                    QRCodeUtils.encode("https://mxcd.zhinenganguan.com?No=" + code, zipOut);
                    zipOut.closeEntry();
                }
                zipOut.finish();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private String sanitizeFileName(String name) {
        if (StringUtils.isEmpty(name)) {
            return "qrcode";
        }
        return name.replaceAll("[\\\\/:*?\\\"<>|]", "_");
    }
    @Resource
    private TokenService tokenService;
    /**
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
@@ -18,6 +18,7 @@
import com.ruoyi.chargingPile.dto.ChargingGunCountMonitoring;
import com.ruoyi.chargingPile.dto.ChargingGunMonitoring;
import com.ruoyi.chargingPile.dto.GetChargingGunMonitoring;
import com.ruoyi.chargingPile.dto.ChargingPileBatchBuildDTO;
import com.ruoyi.chargingPile.dto.ChargingPileImportDTO;
import com.ruoyi.chargingPile.dto.ChargingPileImportResultDTO;
import com.ruoyi.chargingPile.export.ChargingPileExport;
@@ -182,8 +183,8 @@
    @RequiresPermissions(value = {"/chargingPile/export", "/chargingPile"}, logical = Logical.OR)
    @ResponseBody
    @PutMapping("/export")
    @Log(title = "??????????????", businessType = BusinessType.EXPORT,operatorType = OperatorType.MANAGE)
    @ApiOperation(value = "???????", tags = {"????-?????"})
    @Log(title = "【充电桩信息】导出充电桩数据", businessType = BusinessType.EXPORT,operatorType = OperatorType.MANAGE)
    @ApiOperation(value = "导出充电桩数据", tags = {"管理后台-充电桩信息"})
    public void export(@RequestBody PageChargingPileList page, HttpServletResponse response){
        List<PageChargingPileListDTO> records = chargingPileService.listChargingPileForExport(page);
        List<ChargingPileExport> exports = records.stream().map(record -> {
@@ -192,36 +193,45 @@
            return export;
        }).collect(Collectors.toList());
        ExcelUtil<ChargingPileExport> util = new ExcelUtil<>(ChargingPileExport.class);
        util.exportExcel(response, exports, "?????");
        util.exportExcel(response, exports, "充电桩数据");
    }
    @RequiresPermissions(value = {"/chargingPile/add"}, logical = Logical.OR)
    @ResponseBody
    @GetMapping("/importTemplate")
    @ApiOperation(value = "?????????", tags = {"????-?????"})
    @ApiOperation(value = "下载充电桩导入模板", tags = {"管理后台-充电桩信息"})
    public void importTemplate(HttpServletResponse response){
        ExcelUtil<ChargingPileImportDTO> util = new ExcelUtil<>(ChargingPileImportDTO.class);
        util.importTemplateExcel(response, "???????");
        util.importTemplateExcel(response, "充电桩导入模板");
    }
    @RequiresPermissions(value = {"/chargingPile/add"}, logical = Logical.OR)
    @ResponseBody
    @PostMapping("/import")
    @Log(title = "??????????????", businessType = BusinessType.IMPORT,operatorType = OperatorType.MANAGE)
    @ApiOperation(value = "???????", tags = {"????-?????"})
    @Log(title = "【充电桩信息】批量导入充电桩", businessType = BusinessType.IMPORT,operatorType = OperatorType.MANAGE)
    @ApiOperation(value = "批量导入充电桩", tags = {"管理后台-充电桩信息"})
    public AjaxResult importChargingPile(@RequestParam("file") MultipartFile file,
            @RequestParam(value = "cover", defaultValue = "false") Boolean cover) throws Exception{
        ChargingPileImportResultDTO result = chargingPileService.importChargingPile(file, cover);
        if(Boolean.TRUE.equals(result.getNeedConfirm())){
            return AjaxResult.warn("????????????", result);
            return AjaxResult.warn("检测到重复设备编码,是否覆盖?", result);
        }
        if(result.getErrorCount() != null && result.getErrorCount() > 0){
            return AjaxResult.error("????????????", result);
            return AjaxResult.error("导入失败,请检查错误信息", result);
        }
        return AjaxResult.success("????", result);
        return AjaxResult.success("导入成功", result);
    }
    
    @RequiresPermissions(value = {"/chargingPile/add"}, logical = Logical.OR)
    @ResponseBody
    @PostMapping("/batchBuild")
    @Log(title = "【充电桩信息】批量建桩", businessType = BusinessType.INSERT,operatorType = OperatorType.MANAGE)
    @ApiOperation(value = "批量建桩", tags = {"管理后台-充电桩信息"})
    public AjaxResult batchBuild(@RequestBody ChargingPileBatchBuildDTO dto){
        return AjaxResult.success("批量建桩成功", chargingPileService.batchBuildChargingPile(dto));
    }
    @RequiresPermissions(value = {"/chargingPile/select", "/chargingPile/update"}, logical = Logical.OR)
    @ResponseBody
    @GetMapping("/getChargingPile/{id}")
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildDTO.java
New file
@@ -0,0 +1,30 @@
package com.ruoyi.chargingPile.dto;
import com.ruoyi.chargingPile.api.dto.TChargingGunDTO;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class ChargingPileBatchBuildDTO {
    @ApiModelProperty("充电桩模板信息")
    private TChargingPile chargingPile;
    @ApiModelProperty("接口模板信息")
    private TChargingGunDTO chargingGun;
    @ApiModelProperty("设备编码列表")
    private List<String> codes;
    @ApiModelProperty("设备名称固定内容")
    private String namePrefix;
    @ApiModelProperty("桩号起始值")
    private Integer numberStart;
    @ApiModelProperty("单桩接口数")
    private Integer gunCount;
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildResultDTO.java
New file
@@ -0,0 +1,14 @@
package com.ruoyi.chargingPile.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class ChargingPileBatchBuildResultDTO {
    @ApiModelProperty("新建充电桩数量")
    private Integer pileCount = 0;
    @ApiModelProperty("新建接口数量")
    private Integer gunCount = 0;
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java
@@ -30,6 +30,8 @@
     * @return
     */
    PageInfo<TChargingGunVO> pageList(TChargingGunQuery query);
    List<TChargingGunVO> exportQRCodeList(TChargingGunQuery query);
    
    /**
     * 添加充电枪
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
@@ -10,6 +10,8 @@
import com.ruoyi.chargingPile.dto.ChargingGunCountMonitoring;
import com.ruoyi.chargingPile.dto.ChargingGunMonitoring;
import com.ruoyi.chargingPile.dto.GetChargingGunMonitoring;
import com.ruoyi.chargingPile.dto.ChargingPileBatchBuildDTO;
import com.ruoyi.chargingPile.dto.ChargingPileBatchBuildResultDTO;
import com.ruoyi.chargingPile.dto.ChargingPileImportResultDTO;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
@@ -48,6 +50,8 @@
    AjaxResult addChargingPile(TChargingPile chargingPile);
    ChargingPileImportResultDTO importChargingPile(MultipartFile file, Boolean cover) throws Exception;
    ChargingPileBatchBuildResultDTO batchBuildChargingPile(ChargingPileBatchBuildDTO dto);
    
    
    /**
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java
@@ -127,6 +127,26 @@
        return pageInfo;
    }
    @Override
    public List<TChargingGunVO> exportQRCodeList(TChargingGunQuery query) {
        Set<Integer> siteIds = null;
        SysUser sysUser = sysUserClient.getSysUser(tokenService.getLoginUser().getUserid()).getData();
        Integer roleType = sysUser.getRoleType();
        Integer objectId = sysUser.getObjectId();
        if (roleType == 2) {
            siteIds = partnerService.authSite(objectId, SiteMenu.CHARGING_GUN);
        } else {
            if (!SecurityUtils.isAdmin(tokenService.getLoginUser().getUserid())) {
                List<Integer> data = userSiteClient.getSiteIds(sysUser.getUserId()).getData();
                List<SysUserRoleVo> data2 = sysUserRoleClient.getRoleByUserId(sysUser.getUserId()).getData();
                List<Integer> data1 = roleSiteClient.getSiteIds(data2.get(0).getRoleId()).getData();
                data.addAll(data1);
                siteIds = new HashSet<>(data);
            }
        }
        PageInfo<TChargingGunVO> pageInfo = new PageInfo<>(1, 100000);
        return this.baseMapper.pageList(query, pageInfo, siteIds);
    }
    @Autowired
    private SiteMapper siteMapper;
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
@@ -7,6 +7,7 @@
import com.ruoyi.account.api.feignClient.AppUserCarClient;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.account.api.model.TAppUserCar;
import com.ruoyi.chargingPile.api.dto.TChargingGunDTO;
import com.ruoyi.chargingPile.api.dto.PageChargingPileListDTO;
import com.ruoyi.chargingPile.api.model.*;
import com.ruoyi.chargingPile.api.query.BatchSetAccountingStrategy;
@@ -17,6 +18,8 @@
import com.ruoyi.chargingPile.dto.ChargingGunCountMonitoring;
import com.ruoyi.chargingPile.dto.ChargingGunMonitoring;
import com.ruoyi.chargingPile.dto.GetChargingGunMonitoring;
import com.ruoyi.chargingPile.dto.ChargingPileBatchBuildDTO;
import com.ruoyi.chargingPile.dto.ChargingPileBatchBuildResultDTO;
import com.ruoyi.chargingPile.dto.ChargingPileImportDTO;
import com.ruoyi.chargingPile.dto.ChargingPileImportErrorDTO;
import com.ruoyi.chargingPile.dto.ChargingPileImportResultDTO;
@@ -49,6 +52,7 @@
import com.ruoyi.system.api.feignClient.SysUserRoleClient;
import com.ruoyi.system.api.model.SysUserRoleVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -204,12 +208,12 @@
    @Transactional(rollbackFor = Exception.class)
    public ChargingPileImportResultDTO importChargingPile(MultipartFile file, Boolean cover) throws Exception {
        if (file == null || file.isEmpty()) {
            throw new ServiceException("????????");
            throw new ServiceException("请选择要导入的Excel文件");
        }
        ExcelUtil<ChargingPileImportDTO> util = new ExcelUtil<>(ChargingPileImportDTO.class);
        List<ChargingPileImportDTO> rows = util.importExcel(file.getInputStream(), 0);
        if (rows == null || rows.isEmpty()) {
            throw new ServiceException("????????");
            throw new ServiceException("导入文件没有数据");
        }
        SysUser sysUser = sysUserClient.getSysUser(tokenService.getLoginUser().getUserid()).getData();
@@ -234,7 +238,7 @@
            List<String> errors = validateImportRow(row, siteMap, partnerNameMap, roleType, objectId, visibleSiteIds, fileCodes);
            String code = row == null ? null : normalizeImportValue(row.getCode());
            if (!errors.isEmpty()) {
                result.getErrorMessage().add(new ChargingPileImportErrorDTO(rowNum, code, String.join("?", errors)));
                result.getErrorMessage().add(new ChargingPileImportErrorDTO(rowNum, code, String.join(";", errors)));
                continue;
            }
            TChargingPile chargingPile = buildImportChargingPile(row, siteMap, partnerNameMap, roleType, objectId);
@@ -279,7 +283,7 @@
            Set<Integer> visibleSiteIds, Set<String> fileCodes) {
        List<String> errors = new ArrayList<>();
        if (row == null) {
            errors.add("??");
            errors.add("数据为空");
            return errors;
        }
        String siteCode = normalizeImportValue(row.getSiteCode());
@@ -287,37 +291,37 @@
        String name = normalizeImportValue(row.getName());
        String partnerName = normalizeImportValue(row.getPartnerName());
        if (StringUtils.isEmpty(siteCode)) {
            errors.add("????????");
            errors.add("归属电站编码不能为空");
        } else if (!siteMap.containsKey(siteCode)) {
            errors.add("???????");
            errors.add("归属电站不存在");
        }
        if (StringUtils.isEmpty(code)) {
            errors.add("????????");
            errors.add("设备编码不能为空");
        } else if (!fileCodes.add(code)) {
            errors.add("???????????");
            errors.add("导入文件内设备编码重复");
        }
        if (StringUtils.isEmpty(name)) {
            errors.add("??????????");
            errors.add("充电设备名称不能为空");
        }
        if (row.getNumber() == null) {
            errors.add("??????");
            errors.add("桩号不能为空");
        }
        if (row.getType() == null) {
            errors.add("????????");
            errors.add("设备类型不能为空");
        }
        if (row.getRatedPower() == null) {
            errors.add("????????");
            errors.add("额定功率不能为空");
        }
        Site site = siteMap.get(siteCode);
        if (site != null) {
            if (visibleSiteIds != null && !visibleSiteIds.contains(site.getId())) {
                errors.add("??????????");
                errors.add("无权操作该电站");
            }
            Integer partnerId = resolveImportPartnerId(partnerName, site, partnerNameMap, roleType, objectId);
            if (partnerId == null) {
                errors.add("????????");
                errors.add("归属合作商不存在");
            } else if (Objects.equals(roleType, 2) && !Objects.equals(partnerId, objectId)) {
                errors.add("???????????????");
                errors.add("无权导入其他合作商设备");
            }
        }
        return errors;
@@ -390,6 +394,74 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChargingPileBatchBuildResultDTO batchBuildChargingPile(ChargingPileBatchBuildDTO dto) {
        if (dto == null || dto.getChargingPile() == null || dto.getChargingGun() == null) {
            throw new ServiceException("批量建桩参数不能为空");
        }
        if (dto.getCodes() == null || dto.getCodes().isEmpty()) {
            throw new ServiceException("设备编码不能为空");
        }
        if (dto.getNumberStart() == null) {
            throw new ServiceException("桩号起始值不能为空");
        }
        if (dto.getGunCount() == null || dto.getGunCount() <= 0) {
            throw new ServiceException("单桩接口数必须大于0");
        }
        List<String> codes = dto.getCodes().stream()
                .filter(StringUtils::isNotEmpty)
                .map(String::trim)
                .collect(Collectors.toList());
        if (codes.isEmpty()) {
            throw new ServiceException("设备编码不能为空");
        }
        Set<String> distinctCodes = new LinkedHashSet<>(codes);
        if (distinctCodes.size() != codes.size()) {
            throw new ServiceException("设备编码存在重复");
        }
        ChargingPileBatchBuildResultDTO result = new ChargingPileBatchBuildResultDTO();
        TChargingPile pileTemplate = dto.getChargingPile();
        TChargingGunDTO gunTemplate = dto.getChargingGun();
        String namePrefix = StringUtils.isEmpty(dto.getNamePrefix()) ? "" : dto.getNamePrefix().trim();
        for (int i = 0; i < codes.size(); i++) {
            TChargingPile chargingPile = new TChargingPile();
            BeanUtils.copyProperties(pileTemplate, chargingPile);
            chargingPile.setId(null);
            chargingPile.setCode(codes.get(i));
            chargingPile.setNumber(dto.getNumberStart() + i);
            chargingPile.setName(namePrefix + chargingPile.getNumber() + "号桩");
            AjaxResult pileResult = addChargingPile(chargingPile);
            if (pileResult.isError()) {
                throw new ServiceException("设备" + chargingPile.getCode() + "创建失败:" + getAjaxMessage(pileResult));
            }
            result.setPileCount(result.getPileCount() + 1);
            for (int j = 1; j <= dto.getGunCount(); j++) {
                TChargingGunDTO chargingGun = new TChargingGunDTO();
                BeanUtils.copyProperties(gunTemplate, chargingGun);
                String gunCode = String.format("%02d", j);
                chargingGun.setId(null);
                chargingGun.setCode(gunCode);
                chargingGun.setName(chargingPile.getName() + gunCode + "枪");
                chargingGun.setChargingPileId(chargingPile.getId());
                chargingGun.setSiteId(chargingPile.getSiteId());
                chargingGun.setPartnerId(chargingPile.getPartnerId());
                AjaxResult gunResult = chargingGunService.add(chargingGun);
                if (gunResult.isError()) {
                    throw new ServiceException("设备" + chargingPile.getCode() + "接口" + gunCode + "创建失败:" + getAjaxMessage(gunResult));
                }
                result.setGunCount(result.getGunCount() + 1);
            }
        }
        return result;
    }
    private String getAjaxMessage(AjaxResult ajaxResult) {
        Object msg = ajaxResult.get("msg");
        return msg == null ? "未知错误" : msg.toString();
    }
    @Override
    public AjaxResult addChargingPile(TChargingPile chargingPile) {
        AjaxResult ajaxResult = addChargingPileVerify(chargingPile);
        if(ajaxResult.isError()){
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.chargingPile.mapper.SiteMapper">
    
@@ -250,8 +250,8 @@
            AND ts.del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()}
        </where>
    </select>
    <select id="getSiteListGun" resultType="com.ruoyi.chargingPile.api.model.Site">
        select <include refid="Base_Column_List"></include>
        <select id="getSiteListGun" resultType="com.ruoyi.chargingPile.api.model.Site">
        select id, `name`, partner_id
        from t_site
        <where>
            <if test="null != ids and ids.size()>0">
ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml
@@ -35,13 +35,25 @@
    <select id="pageList" resultType="com.ruoyi.chargingPile.api.vo.TChargingGunVO">
        SELECT
            tcg.*,
        tas.name AS strategyName
            tas.name AS strategyName,
            ts.name AS siteName,
            tp.name AS partnerName,
            tcp.code AS chargingPileCode
        FROM t_charging_gun tcg
        LEFT JOIN t_accounting_strategy tas ON tas.id = tcg.accounting_strategy_id
        LEFT JOIN t_site ts ON ts.id = tcg.site_id
        LEFT JOIN t_partner tp ON tp.id = tcg.partner_id
        LEFT JOIN t_charging_pile tcp ON tcp.id = tcg.charging_pile_id
        <where>
            <if test="query.siteId != null">
                AND tcg.site_id = #{query.siteId}
            </if>
            <if test="query.partnerId != null">
                AND tcg.partner_id = #{query.partnerId}
            </if>
            <if test="query.siteType != null">
                AND ts.site_type = #{query.siteType}
            </if>
            <if test="query.chargingPileId != null">
                AND tcg.charging_pile_id = #{query.chargingPileId}
            </if>