From 1574e8e0597dfe5f81a01b016640fc250ad7f72a Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期一, 13 七月 2026 21:41:30 +0800
Subject: [PATCH] feat(chargingPile): 新增批量建桩功能和站点预约设置功能

---
 ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml                           |    6 
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java           |    2 
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java  |   20 +++
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java          |    4 
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java             |   30 +++++
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java    |   30 +++-
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildResultDTO.java   |   14 ++
 ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml                   |   14 ++
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildDTO.java         |   30 +++++
 ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java                 |    9 +
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java     |   45 +++++++
 ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java |  102 ++++++++++++++--
 12 files changed, 277 insertions(+), 29 deletions(-)

diff --git a/ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java b/ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java
index 51dd56f..27ea4ee 100644
--- a/ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TChargingGunVO.java
+++ b/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;
 }
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java
index fbe7360..cd4108a 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java
+++ b/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)
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java
index 517893c..46724b5 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java
+++ b/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;
     /**
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
index 4dc385b..4494a6a 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingPileController.java
+++ b/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}")
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildDTO.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildDTO.java
new file mode 100644
index 0000000..d03ae1b
--- /dev/null
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildDTO.java
@@ -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;
+}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildResultDTO.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildResultDTO.java
new file mode 100644
index 0000000..1afae5f
--- /dev/null
+++ b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/dto/ChargingPileBatchBuildResultDTO.java
@@ -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;
+}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java
index 5bfe152..61cb4a6 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingGunService.java
+++ b/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);
     
     /**
      * 添加充电枪
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
index ad313c3..e792284 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileService.java
+++ b/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);
 	
 	
 	/**
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java
index 2853840..5991884 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingGunServiceImpl.java
+++ b/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;
 
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java b/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
index 6b94846..a685641 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileServiceImpl.java
+++ b/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()){
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml b/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
index 09a2874..84c1971 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/SiteMapper.xml
+++ b/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">
diff --git a/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml b/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml
index 650eaa7..16505c5 100644
--- a/ruoyi-service/ruoyi-chargingPile/src/main/resources/mapper/chargingPile/TChargingGunMapper.xml
+++ b/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>

--
Gitblit v1.7.1