ThirdPartyChargingServiceImpl.java 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. package com.zsElectric.boot.business.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  5. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  6. import com.fasterxml.jackson.core.JsonProcessingException;
  7. import com.fasterxml.jackson.databind.ObjectMapper;
  8. import com.zsElectric.boot.charging.entity.*;
  9. import com.zsElectric.boot.business.mapper.FirmInfoMapper;
  10. import com.zsElectric.boot.business.mapper.ThirdPartyEquipmentInfoMapper;
  11. import com.zsElectric.boot.business.mapper.ThirdPartyInfoMapper;
  12. import com.zsElectric.boot.business.mapper.ThirdPartyStationInfoMapper;
  13. import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper;
  14. import com.zsElectric.boot.charging.mapper.ThirdPartyEquipmentPricePolicyMapper;
  15. import com.zsElectric.boot.charging.mapper.ThirdPartyPolicyInfoMapper;
  16. import com.zsElectric.boot.business.model.entity.FirmInfo;
  17. import com.zsElectric.boot.business.model.entity.ThirdPartyInfo;
  18. import com.zsElectric.boot.business.model.query.ThirdPartyEquipmentInfoQuery;
  19. import com.zsElectric.boot.business.model.query.ThirdPartyStationInfoQuery;
  20. import com.zsElectric.boot.business.model.vo.PartyStationInfoVO;
  21. import com.zsElectric.boot.business.model.vo.ThirdPartyEquipmentInfoVO;
  22. import com.zsElectric.boot.business.model.vo.ThirdPartyStationInfoVO;
  23. import com.zsElectric.boot.business.service.ThirdPartyChargingService;
  24. import com.zsElectric.boot.charging.vo.ChargingPricePolicyVO;
  25. import com.zsElectric.boot.charging.vo.QueryStationsInfoVO;
  26. import lombok.RequiredArgsConstructor;
  27. import lombok.extern.slf4j.Slf4j;
  28. import org.springframework.stereotype.Service;
  29. import org.springframework.transaction.annotation.Transactional;
  30. import org.springframework.util.CollectionUtils;
  31. import java.math.BigDecimal;
  32. import java.time.LocalDateTime;
  33. import java.util.Comparator;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.Objects;
  37. import java.util.stream.Collectors;
  38. /**
  39. * 第三方充电站/充电桩/价格策略统一服务实现
  40. *
  41. * @author system
  42. * @since 2025-12-15
  43. */
  44. @Slf4j
  45. @Service
  46. @RequiredArgsConstructor
  47. public class ThirdPartyChargingServiceImpl implements ThirdPartyChargingService {
  48. private final ThirdPartyStationInfoMapper stationInfoMapper;
  49. private final ThirdPartyEquipmentInfoMapper equipmentInfoMapper;
  50. private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
  51. private final ThirdPartyEquipmentPricePolicyMapper pricePolicyMapper;
  52. private final ThirdPartyPolicyInfoMapper policyInfoMapper;
  53. private final FirmInfoMapper firmInfoMapper;
  54. private final ThirdPartyInfoMapper thirdPartyInfoMapper;
  55. private final ObjectMapper objectMapper;
  56. // ==================== 充电站信息查询 ====================
  57. @Override
  58. public IPage<ThirdPartyStationInfoVO> getStationInfoPage(ThirdPartyStationInfoQuery queryParams) {
  59. // 构建分页
  60. Page<ThirdPartyStationInfoVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
  61. // 调用Mapper联表查询
  62. return stationInfoMapper.selectStationInfoPage(page, queryParams);
  63. }
  64. // ==================== 充电桩信息查询 ====================
  65. @Override
  66. public IPage<ThirdPartyEquipmentInfoVO> getEquipmentInfoPage(ThirdPartyEquipmentInfoQuery queryParams) {
  67. // 构建分页
  68. Page<ThirdPartyEquipmentInfoVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
  69. // 调用Mapper联表查询
  70. return equipmentInfoMapper.selectEquipmentInfoPage(page, queryParams);
  71. }
  72. @Override
  73. public List<PartyStationInfoVO> getPartyStationInfo() {
  74. // 查询所有设备信息
  75. List<ThirdPartyEquipmentInfo> equipmentInfos = equipmentInfoMapper.selectList(null);
  76. // 获取所有不重复的充电站ID
  77. List<String> stationIds = equipmentInfos.stream()
  78. .map(ThirdPartyEquipmentInfo::getStationId)
  79. .distinct()
  80. .collect(Collectors.toList());
  81. if (stationIds.isEmpty()) {
  82. return List.of();
  83. }
  84. // 查询充电站信息
  85. List<ThirdPartyStationInfo> stationInfos = stationInfoMapper.selectList(
  86. new LambdaQueryWrapper<ThirdPartyStationInfo>()
  87. .in(ThirdPartyStationInfo::getStationId, stationIds)
  88. );
  89. // 转换为VO
  90. return stationInfos.stream()
  91. .map(station -> {
  92. PartyStationInfoVO vo = new PartyStationInfoVO();
  93. vo.setId(station.getId());
  94. vo.setStationName(station.getStationName());
  95. return vo;
  96. })
  97. .collect(Collectors.toList());
  98. }
  99. // ==================== 充电站数据保存 ====================
  100. @Override
  101. @Transactional(rollbackFor = Exception.class)
  102. public void saveStationsInfo(QueryStationsInfoVO queryStationsInfoVO) {
  103. if (queryStationsInfoVO == null || CollectionUtils.isEmpty(queryStationsInfoVO.getStationInfos())) {
  104. log.warn("充电站信息为空,跳过存储");
  105. return;
  106. }
  107. List<StationInfo> stationInfos = queryStationsInfoVO.getStationInfos();
  108. log.info("开始保存充电站信息,总数: {}", stationInfos.size());
  109. for (StationInfo stationInfo : stationInfos) {
  110. try {
  111. // 保存充电站信息
  112. saveStationInfo(stationInfo);
  113. // 保存设备信息
  114. if (!CollectionUtils.isEmpty(stationInfo.getEquipmentInfos())) {
  115. for (EquipmentInfo equipmentInfo : stationInfo.getEquipmentInfos()) {
  116. saveEquipmentInfo(equipmentInfo, stationInfo.getStationID());
  117. // 保存接口信息
  118. if (!CollectionUtils.isEmpty(equipmentInfo.getConnectorInfos())) {
  119. for (ConnectorInfo connectorInfo : equipmentInfo.getConnectorInfos()) {
  120. saveConnectorInfo(connectorInfo, equipmentInfo.getEquipmentID(), stationInfo.getStationID());
  121. }
  122. }
  123. }
  124. }
  125. } catch (Exception e) {
  126. log.error("保存充电站信息失败, stationId: {}", stationInfo.getStationID(), e);
  127. throw new RuntimeException("保存充电站信息失败: " + stationInfo.getStationID(), e);
  128. }
  129. }
  130. log.info("充电站信息保存完成");
  131. }
  132. /**
  133. * 保存充电站信息
  134. */
  135. private void saveStationInfo(StationInfo stationInfo) {
  136. // 查询是否已存在
  137. ThirdPartyStationInfo existingStation = stationInfoMapper.selectOne(
  138. new LambdaQueryWrapper<ThirdPartyStationInfo>()
  139. .eq(ThirdPartyStationInfo::getStationId, stationInfo.getStationID())
  140. );
  141. ThirdPartyStationInfo entity = buildStationEntity(stationInfo, existingStation);
  142. if (existingStation == null) {
  143. // 不存在,执行新增
  144. stationInfoMapper.insert(entity);
  145. log.debug("充电站信息新增成功 - stationId: {}", stationInfo.getStationID());
  146. } else if (!isStationSame(existingStation, entity)) {
  147. // 存在且数据变化,执行更新
  148. stationInfoMapper.updateById(entity);
  149. log.debug("充电站信息更新成功 - stationId: {}", stationInfo.getStationID());
  150. } else {
  151. log.debug("充电站信息未变化,跳过保存 - stationId: {}", stationInfo.getStationID());
  152. }
  153. }
  154. /**
  155. * 构建充电站实体
  156. */
  157. private ThirdPartyStationInfo buildStationEntity(StationInfo stationInfo, ThirdPartyStationInfo existingStation) {
  158. ThirdPartyStationInfo entity = new ThirdPartyStationInfo();
  159. if (existingStation != null) {
  160. entity.setId(existingStation.getId());
  161. // 保留原有的配置状态
  162. entity.setPolicyConfigured(existingStation.getPolicyConfigured());
  163. }
  164. // 设置字段值
  165. entity.setStationId(stationInfo.getStationID());
  166. entity.setOperatorId(stationInfo.getOperatorID());
  167. entity.setEquipmentOwnerId(stationInfo.getEquipmentOwnerID());
  168. entity.setStationName(stationInfo.getStationName());
  169. entity.setCountryCode(stationInfo.getCountryCode());
  170. entity.setAreaCode(stationInfo.getAreaCode());
  171. entity.setAddress(stationInfo.getAddress());
  172. entity.setStationTel(stationInfo.getStationTel());
  173. entity.setServiceTel(stationInfo.getServiceTel());
  174. entity.setStationType(stationInfo.getStationType());
  175. entity.setStationStatus(stationInfo.getStationStatus());
  176. entity.setParkNums(stationInfo.getParkNums());
  177. // 处理经纬度
  178. if (stationInfo.getStationLng() != null) {
  179. entity.setStationLng(BigDecimal.valueOf(stationInfo.getStationLng()));
  180. }
  181. if (stationInfo.getStationLat() != null) {
  182. entity.setStationLat(BigDecimal.valueOf(stationInfo.getStationLat()));
  183. }
  184. entity.setSiteGuide(stationInfo.getSiteGuide());
  185. entity.setConstruction(stationInfo.getConstruction());
  186. // 处理图片列表(转JSON)
  187. if (!CollectionUtils.isEmpty(stationInfo.getPictures())) {
  188. try {
  189. entity.setPictures(objectMapper.writeValueAsString(stationInfo.getPictures()));
  190. } catch (JsonProcessingException e) {
  191. log.warn("图片列表转JSON失败", e);
  192. }
  193. }
  194. entity.setBusineHours(stationInfo.getBusineHours());
  195. // 处理费用(字符串转BigDecimal)
  196. if (stationInfo.getElectricityFee() != null) {
  197. try {
  198. entity.setElectricityFee(new BigDecimal(stationInfo.getElectricityFee()));
  199. } catch (NumberFormatException e) {
  200. log.warn("电费转换失败: {}", stationInfo.getElectricityFee(), e);
  201. }
  202. }
  203. if (stationInfo.getServiceFee() != null) {
  204. try {
  205. entity.setServiceFee(new BigDecimal(stationInfo.getServiceFee()));
  206. } catch (NumberFormatException e) {
  207. log.warn("服务费转换失败: {}", stationInfo.getServiceFee(), e);
  208. }
  209. }
  210. entity.setParkFee(stationInfo.getParkFee());
  211. entity.setPayment(stationInfo.getPayment());
  212. entity.setSupportOrder(stationInfo.getSupportOrder());
  213. entity.setRemark(stationInfo.getRemark());
  214. return entity;
  215. }
  216. /**
  217. * 判断充电站信息是否相同
  218. */
  219. private boolean isStationSame(ThirdPartyStationInfo existing, ThirdPartyStationInfo newEntity) {
  220. return Objects.equals(existing.getOperatorId(), newEntity.getOperatorId()) &&
  221. Objects.equals(existing.getEquipmentOwnerId(), newEntity.getEquipmentOwnerId()) &&
  222. Objects.equals(existing.getStationName(), newEntity.getStationName()) &&
  223. Objects.equals(existing.getCountryCode(), newEntity.getCountryCode()) &&
  224. Objects.equals(existing.getAreaCode(), newEntity.getAreaCode()) &&
  225. Objects.equals(existing.getAddress(), newEntity.getAddress()) &&
  226. Objects.equals(existing.getStationTel(), newEntity.getStationTel()) &&
  227. Objects.equals(existing.getServiceTel(), newEntity.getServiceTel()) &&
  228. Objects.equals(existing.getStationType(), newEntity.getStationType()) &&
  229. Objects.equals(existing.getStationStatus(), newEntity.getStationStatus()) &&
  230. Objects.equals(existing.getParkNums(), newEntity.getParkNums()) &&
  231. isBigDecimalEqual(existing.getStationLng(), newEntity.getStationLng()) &&
  232. isBigDecimalEqual(existing.getStationLat(), newEntity.getStationLat()) &&
  233. Objects.equals(existing.getSiteGuide(), newEntity.getSiteGuide()) &&
  234. Objects.equals(existing.getConstruction(), newEntity.getConstruction()) &&
  235. Objects.equals(existing.getPictures(), newEntity.getPictures()) &&
  236. Objects.equals(existing.getBusineHours(), newEntity.getBusineHours()) &&
  237. isBigDecimalEqual(existing.getElectricityFee(), newEntity.getElectricityFee()) &&
  238. isBigDecimalEqual(existing.getServiceFee(), newEntity.getServiceFee()) &&
  239. Objects.equals(existing.getParkFee(), newEntity.getParkFee()) &&
  240. Objects.equals(existing.getPayment(), newEntity.getPayment()) &&
  241. Objects.equals(existing.getSupportOrder(), newEntity.getSupportOrder()) &&
  242. Objects.equals(existing.getRemark(), newEntity.getRemark());
  243. }
  244. /**
  245. * 保存充电设备信息
  246. */
  247. private void saveEquipmentInfo(EquipmentInfo equipmentInfo, String stationId) {
  248. // 查询是否已存在
  249. ThirdPartyEquipmentInfo existingEquipment = equipmentInfoMapper.selectOne(
  250. new LambdaQueryWrapper<ThirdPartyEquipmentInfo>()
  251. .eq(ThirdPartyEquipmentInfo::getEquipmentId, equipmentInfo.getEquipmentID())
  252. );
  253. ThirdPartyEquipmentInfo entity = buildEquipmentEntity(equipmentInfo, stationId, existingEquipment);
  254. if (existingEquipment == null) {
  255. // 不存在,执行新增
  256. equipmentInfoMapper.insert(entity);
  257. log.debug("充电设备信息新增成功 - equipmentId: {}", equipmentInfo.getEquipmentID());
  258. } else if (!isEquipmentSame(existingEquipment, entity)) {
  259. // 存在且数据变化,执行更新
  260. equipmentInfoMapper.updateById(entity);
  261. log.debug("充电设备信息更新成功 - equipmentId: {}", equipmentInfo.getEquipmentID());
  262. } else {
  263. log.debug("充电设备信息未变化,跳过保存 - equipmentId: {}", equipmentInfo.getEquipmentID());
  264. }
  265. }
  266. /**
  267. * 构建充电设备实体
  268. */
  269. private ThirdPartyEquipmentInfo buildEquipmentEntity(EquipmentInfo equipmentInfo, String stationId, ThirdPartyEquipmentInfo existingEquipment) {
  270. ThirdPartyEquipmentInfo entity = new ThirdPartyEquipmentInfo();
  271. if (existingEquipment != null) {
  272. entity.setId(existingEquipment.getId());
  273. }
  274. // 设置字段值
  275. entity.setEquipmentId(equipmentInfo.getEquipmentID());
  276. entity.setStationId(stationId);
  277. entity.setManufacturerId(equipmentInfo.getManufacturerID());
  278. entity.setManufacturerName(equipmentInfo.getManufacturerName());
  279. entity.setEquipmentModel(equipmentInfo.getEquipmentModel());
  280. entity.setProductionDate(equipmentInfo.getProductionDate());
  281. entity.setEquipmentType(equipmentInfo.getEquipmentType());
  282. // 处理经纬度
  283. if (equipmentInfo.getEquipmentLng() != null) {
  284. entity.setEquipmentLng(BigDecimal.valueOf(equipmentInfo.getEquipmentLng()));
  285. }
  286. if (equipmentInfo.getEquipmentLat() != null) {
  287. entity.setEquipmentLat(BigDecimal.valueOf(equipmentInfo.getEquipmentLat()));
  288. }
  289. // 处理功率
  290. if (equipmentInfo.getPower() != null) {
  291. entity.setPower(BigDecimal.valueOf(equipmentInfo.getPower()));
  292. }
  293. entity.setEquipmentName(equipmentInfo.getEquipmentName());
  294. return entity;
  295. }
  296. /**
  297. * 判断充电设备信息是否相同
  298. */
  299. private boolean isEquipmentSame(ThirdPartyEquipmentInfo existing, ThirdPartyEquipmentInfo newEntity) {
  300. return Objects.equals(existing.getStationId(), newEntity.getStationId()) &&
  301. Objects.equals(existing.getManufacturerId(), newEntity.getManufacturerId()) &&
  302. Objects.equals(existing.getManufacturerName(), newEntity.getManufacturerName()) &&
  303. Objects.equals(existing.getEquipmentModel(), newEntity.getEquipmentModel()) &&
  304. Objects.equals(existing.getProductionDate(), newEntity.getProductionDate()) &&
  305. Objects.equals(existing.getEquipmentType(), newEntity.getEquipmentType()) &&
  306. isBigDecimalEqual(existing.getEquipmentLng(), newEntity.getEquipmentLng()) &&
  307. isBigDecimalEqual(existing.getEquipmentLat(), newEntity.getEquipmentLat()) &&
  308. isBigDecimalEqual(existing.getPower(), newEntity.getPower()) &&
  309. Objects.equals(existing.getEquipmentName(), newEntity.getEquipmentName());
  310. }
  311. /**
  312. * 保存充电接口信息
  313. */
  314. private void saveConnectorInfo(ConnectorInfo connectorInfo, String equipmentId, String stationId) {
  315. // 查询是否已存在
  316. ThirdPartyConnectorInfo existingConnector = connectorInfoMapper.selectOne(
  317. new LambdaQueryWrapper<ThirdPartyConnectorInfo>()
  318. .eq(ThirdPartyConnectorInfo::getConnectorId, connectorInfo.getConnectorID())
  319. );
  320. ThirdPartyConnectorInfo entity = buildConnectorEntity(connectorInfo, equipmentId, stationId, existingConnector);
  321. if (existingConnector == null) {
  322. // 不存在,执行新增
  323. connectorInfoMapper.insert(entity);
  324. log.debug("充电接口信息新增成功 - connectorId: {}", connectorInfo.getConnectorID());
  325. } else if (!isConnectorSame(existingConnector, entity)) {
  326. // 存在且数据变化,执行更新
  327. connectorInfoMapper.updateById(entity);
  328. log.debug("充电接口信息更新成功 - connectorId: {}", connectorInfo.getConnectorID());
  329. } else {
  330. log.debug("充电接口信息未变化,跳过保存 - connectorId: {}", connectorInfo.getConnectorID());
  331. }
  332. }
  333. /**
  334. * 构建充电接口实体
  335. */
  336. private ThirdPartyConnectorInfo buildConnectorEntity(ConnectorInfo connectorInfo, String equipmentId, String stationId, ThirdPartyConnectorInfo existingConnector) {
  337. ThirdPartyConnectorInfo entity = new ThirdPartyConnectorInfo();
  338. if (existingConnector != null) {
  339. entity.setId(existingConnector.getId());
  340. }
  341. // 设置字段值
  342. entity.setConnectorId(connectorInfo.getConnectorID());
  343. entity.setEquipmentId(equipmentId);
  344. entity.setStationId(stationId);
  345. entity.setConnectorName(connectorInfo.getConnectorName());
  346. entity.setConnectorType(connectorInfo.getConnectorType());
  347. entity.setVoltageUpperLimits(connectorInfo.getVoltageUpperLimits());
  348. entity.setVoltageLowerLimits(connectorInfo.getVoltageLowerLimits());
  349. entity.setCurrent(connectorInfo.getCurrent());
  350. // 处理功率
  351. if (connectorInfo.getPower() != null) {
  352. entity.setPower(BigDecimal.valueOf(connectorInfo.getPower()));
  353. }
  354. entity.setParkNo(connectorInfo.getParkNo());
  355. entity.setNationalStandard(connectorInfo.getNationalStandard());
  356. return entity;
  357. }
  358. /**
  359. * 判断充电接口信息是否相同
  360. */
  361. private boolean isConnectorSame(ThirdPartyConnectorInfo existing, ThirdPartyConnectorInfo newEntity) {
  362. return Objects.equals(existing.getEquipmentId(), newEntity.getEquipmentId()) &&
  363. Objects.equals(existing.getStationId(), newEntity.getStationId()) &&
  364. Objects.equals(existing.getConnectorName(), newEntity.getConnectorName()) &&
  365. Objects.equals(existing.getConnectorType(), newEntity.getConnectorType()) &&
  366. Objects.equals(existing.getVoltageUpperLimits(), newEntity.getVoltageUpperLimits()) &&
  367. Objects.equals(existing.getVoltageLowerLimits(), newEntity.getVoltageLowerLimits()) &&
  368. Objects.equals(existing.getCurrent(), newEntity.getCurrent()) &&
  369. isBigDecimalEqual(existing.getPower(), newEntity.getPower()) &&
  370. Objects.equals(existing.getParkNo(), newEntity.getParkNo()) &&
  371. Objects.equals(existing.getNationalStandard(), newEntity.getNationalStandard());
  372. }
  373. // ==================== 价格策略数据保存 ====================
  374. @Override
  375. @Transactional(rollbackFor = Exception.class)
  376. public void savePricePolicyInfo(ChargingPricePolicyVO pricePolicyVO) {
  377. if (pricePolicyVO == null) {
  378. log.warn("价格策略信息为空,跳过存储");
  379. return;
  380. }
  381. try {
  382. // 查询最新的价格策略记录
  383. ThirdPartyEquipmentPricePolicy latestPolicy = getLatestPricePolicy(
  384. pricePolicyVO.getEquipBizSeq(),
  385. pricePolicyVO.getConnectorID()
  386. );
  387. // 如果数据完全相同,不做任何操作
  388. if (latestPolicy != null && isPolicySame(latestPolicy, pricePolicyVO)) {
  389. log.info("价格策略数据未发生变化,跳过保存 - equipBizSeq: {}, connectorId: {}",
  390. pricePolicyVO.getEquipBizSeq(), pricePolicyVO.getConnectorID());
  391. return;
  392. }
  393. // 数据发生变化
  394. Long policyId;
  395. if (latestPolicy != null) {
  396. // 已存在记录,执行更新
  397. policyId = updatePricePolicy(latestPolicy, pricePolicyVO);
  398. log.info("价格策略信息保存成功(更新记录) - equipBizSeq: {}, connectorId: {}, policyId: {}",
  399. pricePolicyVO.getEquipBizSeq(), pricePolicyVO.getConnectorID(), policyId);
  400. } else {
  401. // 不存在记录,执行新增
  402. policyId = insertNewPricePolicy(pricePolicyVO);
  403. log.info("价格策略信息保存成功(新增记录) - equipBizSeq: {}, connectorId: {}, policyId: {}",
  404. pricePolicyVO.getEquipBizSeq(), pricePolicyVO.getConnectorID(), policyId);
  405. }
  406. // 保存价格策略明细(对比后更新或新增,不做删除操作)
  407. if (!CollectionUtils.isEmpty(pricePolicyVO.getPolicyInfos())) {
  408. savePolicyInfoDetails(pricePolicyVO.getPolicyInfos(), policyId);
  409. }
  410. } catch (Exception e) {
  411. log.error("保存价格策略信息失败 - equipBizSeq: {}, connectorId: {}",
  412. pricePolicyVO.getEquipBizSeq(), pricePolicyVO.getConnectorID(), e);
  413. throw new RuntimeException("保存价格策略信息失败", e);
  414. }
  415. }
  416. @Override
  417. public IPage<ThirdPartyStationInfoVO> getStationInfoPageByEquipment(ThirdPartyStationInfoQuery queryParams) {
  418. // 构建分页
  419. Page<ThirdPartyStationInfoVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
  420. // 调用Mapper联表查询(固定设备所属方MA6DP6BE7)
  421. IPage<ThirdPartyStationInfoVO> resultPage = stationInfoMapper.selectStationInfoPageByEquipment(page, queryParams);
  422. // 填充单位名称
  423. for (ThirdPartyStationInfoVO vo : resultPage.getRecords()) {
  424. if (vo.getSalesType() != null) {
  425. if (vo.getSalesType() == 1 && vo.getFirmId() != null) {
  426. // 企业类型,查询企业名称
  427. FirmInfo firmInfo = firmInfoMapper.selectById(vo.getFirmId());
  428. if (firmInfo != null) {
  429. vo.setUnitName(firmInfo.getName());
  430. }
  431. } else if (vo.getSalesType() == 2 && vo.getThirdPartyId() != null) {
  432. // 渠道方类型,查询渠道方名称
  433. ThirdPartyInfo thirdPartyInfo = thirdPartyInfoMapper.selectById(vo.getThirdPartyId());
  434. if (thirdPartyInfo != null) {
  435. vo.setUnitName(thirdPartyInfo.getEcName());
  436. }
  437. }
  438. }
  439. }
  440. return resultPage;
  441. }
  442. /**
  443. * 获取最新的价格策略记录
  444. */
  445. private ThirdPartyEquipmentPricePolicy getLatestPricePolicy(String equipBizSeq, String connectorId) {
  446. List<ThirdPartyEquipmentPricePolicy> policies = pricePolicyMapper.selectList(
  447. Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
  448. .eq(ThirdPartyEquipmentPricePolicy::getEquipBizSeq, equipBizSeq)
  449. .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, connectorId)
  450. .orderByDesc(ThirdPartyEquipmentPricePolicy::getCreateTime)
  451. .last("LIMIT 1")
  452. );
  453. return CollectionUtils.isEmpty(policies) ? null : policies.get(0);
  454. }
  455. /**
  456. * 判断价格策略是否相同(比较主表和明细表)
  457. */
  458. private boolean isPolicySame(ThirdPartyEquipmentPricePolicy latestPolicy, ChargingPricePolicyVO newPolicy) {
  459. // 比较主表字段
  460. if (!Objects.equals(latestPolicy.getSuccStat(), newPolicy.getSuccStat()) ||
  461. !Objects.equals(latestPolicy.getFailReason(), newPolicy.getFailReason()) ||
  462. !Objects.equals(latestPolicy.getSumPeriod(), newPolicy.getSumPeriod())) {
  463. return false;
  464. }
  465. // 查询明细表数据
  466. List<ThirdPartyPolicyInfo> existingDetails = policyInfoMapper.selectList(
  467. Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
  468. .eq(ThirdPartyPolicyInfo::getPricePolicyId, latestPolicy.getId())
  469. .orderBy(true, true, ThirdPartyPolicyInfo::getStartTime)
  470. );
  471. // 比较明细表
  472. return isPolicyDetailsSame(existingDetails, newPolicy.getPolicyInfos());
  473. }
  474. /**
  475. * 比较价格策略明细是否相同
  476. */
  477. private boolean isPolicyDetailsSame(List<ThirdPartyPolicyInfo> existingDetails,
  478. List<ChargingPricePolicyVO.PolicyInfo> newDetails) {
  479. if (CollectionUtils.isEmpty(existingDetails) && CollectionUtils.isEmpty(newDetails)) {
  480. return true;
  481. }
  482. if (CollectionUtils.isEmpty(existingDetails) || CollectionUtils.isEmpty(newDetails)) {
  483. return false;
  484. }
  485. if (existingDetails.size() != newDetails.size()) {
  486. return false;
  487. }
  488. // 按 StartTime 排序后比较
  489. List<ChargingPricePolicyVO.PolicyInfo> sortedNewDetails = newDetails.stream()
  490. .sorted(Comparator.comparing(ChargingPricePolicyVO.PolicyInfo::getStartTime))
  491. .collect(Collectors.toList());
  492. for (int i = 0; i < existingDetails.size(); i++) {
  493. ThirdPartyPolicyInfo existing = existingDetails.get(i);
  494. ChargingPricePolicyVO.PolicyInfo newDetail = sortedNewDetails.get(i);
  495. if (!Objects.equals(existing.getStartTime(), newDetail.getStartTime()) ||
  496. !isBigDecimalEqual(existing.getElecPrice(), newDetail.getElecPrice()) ||
  497. !isBigDecimalEqual(existing.getServicePrice(), newDetail.getServicePrice()) ||
  498. !Objects.equals(existing.getPeriodFlag(), newDetail.getPeriodFlag())) {
  499. return false;
  500. }
  501. }
  502. return true;
  503. }
  504. /**
  505. * 比较 BigDecimal 是否相等(处理 null 情况)
  506. */
  507. private boolean isBigDecimalEqual(BigDecimal a, BigDecimal b) {
  508. if (a == null && b == null) {
  509. return true;
  510. }
  511. if (a == null || b == null) {
  512. return false;
  513. }
  514. return a.compareTo(b) == 0;
  515. }
  516. /**
  517. * 插入新的价格策略记录
  518. */
  519. private Long insertNewPricePolicy(ChargingPricePolicyVO pricePolicyVO) {
  520. ThirdPartyEquipmentPricePolicy entity = new ThirdPartyEquipmentPricePolicy();
  521. // 设置字段值
  522. entity.setEquipBizSeq(pricePolicyVO.getEquipBizSeq());
  523. entity.setConnectorId(pricePolicyVO.getConnectorID());
  524. entity.setSuccStat(pricePolicyVO.getSuccStat());
  525. entity.setFailReason(pricePolicyVO.getFailReason());
  526. entity.setSumPeriod(pricePolicyVO.getSumPeriod());
  527. entity.setCreateTime(LocalDateTime.now());
  528. // 插入新记录
  529. pricePolicyMapper.insert(entity);
  530. return entity.getId();
  531. }
  532. /**
  533. * 更新价格策略记录
  534. */
  535. private Long updatePricePolicy(ThirdPartyEquipmentPricePolicy existingPolicy, ChargingPricePolicyVO pricePolicyVO) {
  536. existingPolicy.setSuccStat(pricePolicyVO.getSuccStat());
  537. existingPolicy.setFailReason(pricePolicyVO.getFailReason());
  538. existingPolicy.setSumPeriod(pricePolicyVO.getSumPeriod());
  539. pricePolicyMapper.updateById(existingPolicy);
  540. return existingPolicy.getId();
  541. }
  542. /**
  543. * 保存价格策略明细(对比后更新或新增)
  544. */
  545. private void savePolicyInfoDetails(List<ChargingPricePolicyVO.PolicyInfo> policyInfos, Long policyId) {
  546. // 查询已存在的明细记录,以 startTime 为 key
  547. Map<String, ThirdPartyPolicyInfo> existingMap = policyInfoMapper.selectList(
  548. Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
  549. .eq(ThirdPartyPolicyInfo::getPricePolicyId, policyId))
  550. .stream()
  551. .collect(Collectors.toMap(ThirdPartyPolicyInfo::getStartTime, info -> info, (v1, v2) -> v1));
  552. for (ChargingPricePolicyVO.PolicyInfo policyInfo : policyInfos) {
  553. ThirdPartyPolicyInfo existing = existingMap.get(policyInfo.getStartTime());
  554. if (existing == null) {
  555. // 不存在,执行新增
  556. savePolicyInfoDetail(policyInfo, policyId);
  557. log.debug("价格策略明细新增成功 - policyId: {}, startTime: {}", policyId, policyInfo.getStartTime());
  558. } else if (!isPolicyInfoSame(existing, policyInfo)) {
  559. // 存在且数据变化,执行更新
  560. updatePolicyInfoDetail(existing, policyInfo);
  561. log.debug("价格策略明细更新成功 - policyId: {}, startTime: {}", policyId, policyInfo.getStartTime());
  562. } else {
  563. log.debug("价格策略明细未变化,跳过保存 - policyId: {}, startTime: {}", policyId, policyInfo.getStartTime());
  564. }
  565. }
  566. }
  567. /**
  568. * 判断价格策略明细是否相同
  569. */
  570. private boolean isPolicyInfoSame(ThirdPartyPolicyInfo existing, ChargingPricePolicyVO.PolicyInfo newInfo) {
  571. return isBigDecimalEqual(existing.getElecPrice(), newInfo.getElecPrice()) &&
  572. isBigDecimalEqual(existing.getServicePrice(), newInfo.getServicePrice()) &&
  573. Objects.equals(existing.getPeriodFlag(), newInfo.getPeriodFlag());
  574. }
  575. /**
  576. * 更新价格策略明细
  577. */
  578. private void updatePolicyInfoDetail(ThirdPartyPolicyInfo existing, ChargingPricePolicyVO.PolicyInfo policyInfo) {
  579. existing.setElecPrice(policyInfo.getElecPrice());
  580. existing.setServicePrice(policyInfo.getServicePrice());
  581. existing.setPeriodFlag(policyInfo.getPeriodFlag());
  582. policyInfoMapper.updateById(existing);
  583. }
  584. /**
  585. * 保存价格策略明细
  586. */
  587. private void savePolicyInfoDetail(ChargingPricePolicyVO.PolicyInfo policyInfo, Long policyId) {
  588. ThirdPartyPolicyInfo entity = new ThirdPartyPolicyInfo();
  589. entity.setPricePolicyId(policyId);
  590. entity.setStartTime(policyInfo.getStartTime());
  591. entity.setElecPrice(policyInfo.getElecPrice());
  592. entity.setServicePrice(policyInfo.getServicePrice());
  593. entity.setPeriodFlag(policyInfo.getPeriodFlag());
  594. entity.setCreateTime(LocalDateTime.now());
  595. policyInfoMapper.insert(entity);
  596. }
  597. @Override
  598. public boolean updateStationTips(Long stationId, String stationTips) {
  599. return stationInfoMapper.update(null, Wrappers.<ThirdPartyStationInfo>lambdaUpdate()
  600. .eq(ThirdPartyStationInfo::getId, stationId)
  601. .set(ThirdPartyStationInfo::getStationTips, stationTips)) > 0;
  602. }
  603. }