From 93de43267e1663031fe5dc2f5ae40d128a182a76 Mon Sep 17 00:00:00 2001
From: doum <doum>
Date: 星期四, 18 六月 2026 17:24:51 +0800
Subject: [PATCH] 新增智能电表、空调管理

---
 server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java |  409 ++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 312 insertions(+), 97 deletions(-)

diff --git a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java
index 8cfe1f1..2e5321f 100644
--- a/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java
+++ b/server/visits/dmvisit_service/src/main/java/com/doumee/service/business/impl/YwCustomerRechargeBizServiceImpl.java
@@ -24,9 +24,11 @@
 import com.doumee.dao.business.dto.*;
 import com.doumee.dao.business.model.*;
 import com.doumee.service.business.ConditionerBizService;
+import com.doumee.service.business.YwCustomerDeviceAutoBindService;
 import com.doumee.service.business.YwCustomerRechargeBizService;
 import com.doumee.service.business.YwElectricalBizService;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -40,14 +42,13 @@
 import java.util.stream.Collectors;
 
 @Service
+@Slf4j
 public class YwCustomerRechargeBizServiceImpl implements YwCustomerRechargeBizService {
 
     private static final String ONLINE_TEXT = "鍦ㄧ嚎";
 
     @Autowired
     private YwCustomerMapper ywCustomerMapper;
-    @Autowired
-    private MemberMapper memberMapper;
     @Autowired
     private YwCustomerGsMapper ywCustomerGsMapper;
     @Autowired
@@ -56,6 +57,10 @@
     private YwCustomerConditionerMapper ywCustomerConditionerMapper;
     @Autowired
     private YwElectricalMapper ywElectricalMapper;
+    @Autowired
+    private YwElectricalRoomMapper ywElectricalRoomMapper;
+    @Autowired
+    private YwRoomMapper ywRoomMapper;
     @Autowired
     private YwConditionerMapper ywConditionerMapper;
     @Autowired
@@ -66,17 +71,21 @@
     private YwElectricalBizService ywElectricalBizService;
     @Autowired
     private ConditionerBizService conditionerBizService;
+    @Autowired
+    private YwCustomerDeviceAutoBindService ywCustomerDeviceAutoBindService;
+    @Autowired
+    private MemberMapper memberMapper;
 
     @Override
     public PageData<YwCustomerRechargeMerchantVO> findMerchantPage(PageWrap<YwCustomerRechargeQueryDTO> pageWrap) {
+        if (pageWrap == null) {
+            pageWrap = new PageWrap<>();
+        }
         YwCustomerRechargeQueryDTO query = pageWrap.getModel() != null ? pageWrap.getModel() : new YwCustomerRechargeQueryDTO();
         boolean hasDeviceFilter = query.getElectricalStatusFilter() != null || query.getConditionerStatusFilter() != null;
 
         if (hasDeviceFilter) {
-            List<YwCustomer> all = ywCustomerMapper.selectList(new QueryWrapper<YwCustomer>().lambda()
-                    .eq(YwCustomer::getIsdeleted, Constants.ZERO)
-                    .like(StringUtils.isNotBlank(query.getNameKeyword()), YwCustomer::getName, query.getNameKeyword())
-                    .orderByDesc(YwCustomer::getCreateDate));
+            List<YwCustomer> all = ywCustomerMapper.selectJoinList(YwCustomer.class, buildMerchantCustomerWrapper(query));
             List<YwCustomerRechargeMerchantVO> enriched = enrichMerchantList(all);
             List<YwCustomerRechargeMerchantVO> filtered = enriched.stream()
                     .filter(vo -> matchDeviceFilter(vo, query))
@@ -85,10 +94,7 @@
         }
 
         IPage<YwCustomer> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
-        IPage<YwCustomer> result = ywCustomerMapper.selectPage(page, new QueryWrapper<YwCustomer>().lambda()
-                .eq(YwCustomer::getIsdeleted, Constants.ZERO)
-                .like(StringUtils.isNotBlank(query.getNameKeyword()), YwCustomer::getName, query.getNameKeyword())
-                .orderByDesc(YwCustomer::getCreateDate));
+        IPage<YwCustomer> result = ywCustomerMapper.selectJoinPage(page, YwCustomer.class, buildMerchantCustomerWrapper(query));
         List<YwCustomerRechargeMerchantVO> list = enrichMerchantList(result.getRecords());
         PageData<YwCustomerRechargeMerchantVO> data = new PageData<>();
         data.setRecords(list);
@@ -96,6 +102,17 @@
         data.setPage(result.getCurrent());
         data.setCapacity(result.getSize());
         return data;
+    }
+
+    private MPJLambdaWrapper<YwCustomer> buildMerchantCustomerWrapper(YwCustomerRechargeQueryDTO query) {
+        return new MPJLambdaWrapper<YwCustomer>()
+                .selectAll(YwCustomer.class)
+                .selectAs(Member::getName, YwCustomer::getMemberName)
+                .selectAs(Member::getPhone, YwCustomer::getMemberPhone)
+                .leftJoin(Member.class, Member::getId, YwCustomer::getMemberId)
+                .eq(YwCustomer::getIsdeleted, Constants.ZERO)
+                .like(StringUtils.isNotBlank(query.getNameKeyword()), YwCustomer::getName, query.getNameKeyword())
+                .orderByDesc(YwCustomer::getCreateDate);
     }
 
     private PageData<YwCustomerRechargeMerchantVO> manualPage(List<YwCustomerRechargeMerchantVO> list, long page, long capacity) {
@@ -146,45 +163,20 @@
         }
         List<Integer> customerIds = customers.stream().map(YwCustomer::getId).collect(Collectors.toList());
 
-        Map<Integer, YwCustomerGs> gsMap = ywCustomerGsMapper.selectList(new QueryWrapper<YwCustomerGs>().lambda()
-                        .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
-                        .in(YwCustomerGs::getCustomerId, customerIds))
-                .stream().collect(Collectors.toMap(YwCustomerGs::getCustomerId, g -> g, (a, b) -> a));
+        Map<Integer, YwCustomerGs> gsMap = loadGsMap(customerIds);
 
-        List<YwCustomerElectrical> relE = ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
-                .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO)
-                .in(YwCustomerElectrical::getCustomerId, customerIds));
-        Map<Integer, List<Integer>> customerElectricalIds = relE.stream()
-                .collect(Collectors.groupingBy(YwCustomerElectrical::getCustomerId,
-                        Collectors.mapping(YwCustomerElectrical::getElectricalId, Collectors.toList())));
+        Map<Integer, List<Integer>> customerElectricalIds = ywCustomerDeviceAutoBindService
+                .batchListElectricalIdsByActiveContracts(customerIds);
+        Map<Integer, List<Integer>> customerConditionerIds = ywCustomerDeviceAutoBindService
+                .batchListConditionerIdsByActiveContracts(customerIds);
 
-        List<YwCustomerConditioner> relC = ywCustomerConditionerMapper.selectList(new QueryWrapper<YwCustomerConditioner>().lambda()
-                .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO)
-                .in(YwCustomerConditioner::getCustomerId, customerIds));
-        Map<Integer, List<Integer>> customerConditionerIds = relC.stream()
-                .collect(Collectors.groupingBy(YwCustomerConditioner::getCustomerId,
-                        Collectors.mapping(YwCustomerConditioner::getConditionerId, Collectors.toList())));
+        Set<Integer> allElectricalIds = customerElectricalIds.values().stream()
+                .flatMap(List::stream).collect(Collectors.toSet());
+        Map<Integer, YwElectrical> electricalMap = loadElectricalMap(allElectricalIds);
 
-        Set<Integer> allElectricalIds = relE.stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toSet());
-        Map<Integer, YwElectrical> electricalMap = allElectricalIds.isEmpty() ? Collections.emptyMap()
-                : ywElectricalMapper.selectBatchIds(allElectricalIds).stream()
-                .filter(e -> !Objects.equals(e.getIsdeleted(), Constants.ONE))
-                .collect(Collectors.toMap(YwElectrical::getId, e -> e, (a, b) -> a));
-
-        Set<Integer> allConditionerIds = relC.stream().map(YwCustomerConditioner::getConditionerId).collect(Collectors.toSet());
-        Map<Integer, YwConditioner> conditionerMap = allConditionerIds.isEmpty() ? Collections.emptyMap()
-                : ywConditionerMapper.selectBatchIds(allConditionerIds).stream()
-                .filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE))
-                .collect(Collectors.toMap(YwConditioner::getId, c -> c, (a, b) -> a));
-
-        Set<Integer> memberIds = customers.stream()
-                .map(YwCustomer::getMemberId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, Member> memberMap = memberIds.isEmpty() ? Collections.emptyMap()
-                : memberMapper.selectBatchIds(memberIds).stream()
-                .filter(m -> !Objects.equals(m.getIsdeleted(), Constants.ONE))
-                .collect(Collectors.toMap(Member::getId, m -> m, (a, b) -> a));
+        Set<Integer> allConditionerIds = customerConditionerIds.values().stream()
+                .flatMap(List::stream).collect(Collectors.toSet());
+        Map<Integer, YwConditioner> conditionerMap = loadConditionerMap(allConditionerIds);
 
         List<YwCustomerRechargeMerchantVO> list = new ArrayList<>();
         for (YwCustomer c : customers) {
@@ -194,11 +186,8 @@
             vo.setName(c.getName());
             vo.setPhone(c.getPhone());
             vo.setCreateDate(c.getCreateDate());
-            Member member = c.getMemberId() != null ? memberMap.get(c.getMemberId()) : null;
-            if (member != null) {
-                vo.setMemberName(member.getName());
-                vo.setMemberPhone(member.getPhone());
-            }
+            vo.setMemberName(c.getMemberName());
+            vo.setMemberPhone(StringUtils.defaultIfBlank(c.getMemberPhone(), c.getPhone()));
 
             List<Integer> eIds = customerElectricalIds.getOrDefault(c.getId(), Collections.emptyList());
             vo.setElectricalCount(eIds.size());
@@ -260,9 +249,60 @@
         return list;
     }
 
+    private Map<Integer, YwCustomerGs> loadGsMap(List<Integer> customerIds) {
+        if (CollectionUtils.isEmpty(customerIds)) {
+            return Collections.emptyMap();
+        }
+        try {
+            return ywCustomerGsMapper.selectList(new QueryWrapper<YwCustomerGs>().lambda()
+                            .select(YwCustomerGs::getId, YwCustomerGs::getCustomerId,
+                                    YwCustomerGs::getLeftMoney, YwCustomerGs::getSyncDate, YwCustomerGs::getPlatformGsId)
+                            .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
+                            .in(YwCustomerGs::getCustomerId, customerIds))
+                    .stream().collect(Collectors.toMap(YwCustomerGs::getCustomerId, g -> g, (a, b) -> a));
+        } catch (Exception e) {
+            log.warn("load yw_customer_gs failed, skip gs stats: {}", e.getMessage());
+            return Collections.emptyMap();
+        }
+    }
+
+    private Map<Integer, YwElectrical> loadElectricalMap(Set<Integer> electricalIds) {
+        if (CollectionUtils.isEmpty(electricalIds)) {
+            return Collections.emptyMap();
+        }
+        try {
+            return ywElectricalMapper.selectList(new QueryWrapper<YwElectrical>().lambda()
+                            .select(YwElectrical::getId, YwElectrical::getName, YwElectrical::getAddress,
+                                    YwElectrical::getBalance, YwElectrical::getOnline, YwElectrical::getIsdeleted)
+                            .in(YwElectrical::getId, electricalIds)
+                            .eq(YwElectrical::getIsdeleted, Constants.ZERO))
+                    .stream().collect(Collectors.toMap(YwElectrical::getId, e -> e, (a, b) -> a));
+        } catch (Exception e) {
+            log.warn("load electrical for merchant page failed: {}", e.getMessage());
+            return Collections.emptyMap();
+        }
+    }
+
+    private Map<Integer, YwConditioner> loadConditionerMap(Set<Integer> conditionerIds) {
+        if (CollectionUtils.isEmpty(conditionerIds)) {
+            return Collections.emptyMap();
+        }
+        try {
+            return ywConditionerMapper.selectList(new QueryWrapper<YwConditioner>().lambda()
+                            .select(YwConditioner::getId, YwConditioner::getOnline, YwConditioner::getIsdeleted)
+                            .in(YwConditioner::getId, conditionerIds)
+                            .eq(YwConditioner::getIsdeleted, Constants.ZERO))
+                    .stream().collect(Collectors.toMap(YwConditioner::getId, c -> c, (a, b) -> a));
+        } catch (Exception e) {
+            log.warn("load conditioner for merchant page failed: {}", e.getMessage());
+            return Collections.emptyMap();
+        }
+    }
+
     @Override
     public YwCustomerRechargeDetailVO getDetail(Integer customerId) {
         YwCustomer customer = requireCustomer(customerId);
+        ywCustomerDeviceAutoBindService.refreshCustomerDevices(customerId, systemUser());
         YwCustomerRechargeDetailVO vo = new YwCustomerRechargeDetailVO();
         vo.setCustomerId(customer.getId());
         vo.setCustomerName(customer.getName());
@@ -276,6 +316,7 @@
     @Override
     public PageData<YwElectrical> listCustomerElectrical(PageWrap<YwElectrical> pageWrap, Integer customerId) {
         requireCustomer(customerId);
+        ywCustomerDeviceAutoBindService.refreshCustomerDevices(customerId, systemUser());
         List<Integer> ids = listBoundElectricalIds(customerId);
         if (ids.isEmpty()) {
             return emptyPage(pageWrap);
@@ -349,6 +390,7 @@
     @Override
     public PageData<YwConditioner> listCustomerConditioner(PageWrap<YwConditioner> pageWrap, Integer customerId) {
         requireCustomer(customerId);
+        ywCustomerDeviceAutoBindService.refreshCustomerDevices(customerId, systemUser());
         List<YwConditioner> list = loadCustomerConditionerList(customerId);
         if (CollectionUtils.isEmpty(list)) {
             return emptyPage(pageWrap);
@@ -367,19 +409,30 @@
 
     @Override
     public YwCustomerGs getCustomerGsConfig(Integer customerId) {
-        return ywCustomerGsMapper.selectOne(new QueryWrapper<YwCustomerGs>().lambda()
-                .eq(YwCustomerGs::getCustomerId, customerId)
-                .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
-                .last("limit 1"));
+        try {
+            return ywCustomerGsMapper.selectOne(new QueryWrapper<YwCustomerGs>().lambda()
+                    .eq(YwCustomerGs::getCustomerId, customerId)
+                    .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
+                    .last("limit 1"));
+        } catch (Exception e) {
+            log.warn("load yw_customer_gs failed, retry without stop_money: {}", e.getMessage());
+            return ywCustomerGsMapper.selectOne(new QueryWrapper<YwCustomerGs>().lambda()
+                    .select(YwCustomerGs::getId, YwCustomerGs::getCustomerId, YwCustomerGs::getPlatformGsId,
+                            YwCustomerGs::getIsPwr, YwCustomerGs::getIsRestStop, YwCustomerGs::getGsBz,
+                            YwCustomerGs::getLeftMoney, YwCustomerGs::getSyncDate,
+                            YwCustomerGs::getCreator, YwCustomerGs::getCreateDate,
+                            YwCustomerGs::getEditor, YwCustomerGs::getEditDate, YwCustomerGs::getIsdeleted)
+                    .eq(YwCustomerGs::getCustomerId, customerId)
+                    .eq(YwCustomerGs::getIsdeleted, Constants.ZERO)
+                    .last("limit 1"));
+        }
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void saveCustomerGsConfig(YwCustomerGsConfigDTO dto, LoginUserInfo user) {
         YwCustomer customer = requireCustomer(dto.getCustomerId());
-        if (CollectionUtils.isEmpty(dto.getConditioners())) {
-            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇疯嚦灏戝叧鑱斾竴鍙扮┖璋冨唴鏈�");
-        }
+        validateGsConfigRequired(dto);
         conditionerBizService.ensureLogin();
 
         List<Integer> conditionerIds = dto.getConditioners().stream()
@@ -413,10 +466,10 @@
         }
         gs.setEditor(user.getId());
         gs.setEditDate(new Date());
-        gs.setIsPwr(dto.getIsPwr() != null ? dto.getIsPwr() : Constants.ONE);
-        gs.setIsRestStop(dto.getIsRestStop() != null ? dto.getIsRestStop() : Constants.ZERO);
+        gs.setIsPwr(dto.getIsPwr());
+        gs.setIsRestStop(dto.getIsRestStop());
         gs.setGsBz(StringUtils.defaultString(dto.getGsBz()));
-        gs.setStopMoney(dto.getStopMoney() != null ? dto.getStopMoney() : BigDecimal.ZERO);
+        gs.setStopMoney(dto.getStopMoney());
 
         if (StringUtils.isBlank(customer.getName())) {
             throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "瀹㈡埛鍚嶇О涓嶈兘涓虹┖");
@@ -432,6 +485,8 @@
         companyReq.setIs_rest_stop(gs.getIsRestStop());
         companyReq.setGs_bz(gs.getGsBz());
         companyReq.setStop_money(gs.getStopMoney());
+        companyReq.setLi_dev(liDev);
+        companyReq.setD_dev(dDev);
 
         if (gs.getPlatformGsId() == null) {
             ConditionerBaseResponse<Object> addResp = ConditionerUtil.addGs(companyReq);
@@ -464,29 +519,88 @@
 
         refreshGsLeftMoney(gs);
         if (gs.getId() == null) {
-            ywCustomerGsMapper.insert(gs);
+            try {
+                ywCustomerGsMapper.insert(gs);
+            } catch (Exception e) {
+                if (gs.getStopMoney() != null) {
+                    log.warn("insert yw_customer_gs with stop_money failed, retry without stop_money: {}", e.getMessage());
+                    gs.setStopMoney(null);
+                    ywCustomerGsMapper.insert(gs);
+                } else {
+                    throw e;
+                }
+            }
         } else {
-            ywCustomerGsMapper.updateById(gs);
+            try {
+                ywCustomerGsMapper.updateById(gs);
+            } catch (Exception e) {
+                if (gs.getStopMoney() != null) {
+                    log.warn("update yw_customer_gs with stop_money failed, retry without stop_money: {}", e.getMessage());
+                    BigDecimal stopMoney = gs.getStopMoney();
+                    gs.setStopMoney(null);
+                    ywCustomerGsMapper.updateById(gs);
+                    gs.setStopMoney(stopMoney);
+                } else {
+                    throw e;
+                }
+            }
         }
 
-        ywCustomerConditionerMapper.update(null, new UpdateWrapper<YwCustomerConditioner>().lambda()
-                .set(YwCustomerConditioner::getIsdeleted, Constants.ONE)
-                .set(YwCustomerConditioner::getEditDate, new Date())
-                .set(YwCustomerConditioner::getEditor, user.getId())
-                .eq(YwCustomerConditioner::getCustomerId, dto.getCustomerId())
-                .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO));
+        saveCustomerConditionerRels(dto, user);
+    }
+
+    /**
+     * 鍏宠仈鍐呮満 upsert锛氳〃涓婃湁 uk(customer_id, conditioner_id)锛屼笉鑳借蒋鍒犲悗閲嶅 insert銆�
+     */
+    private void saveCustomerConditionerRels(YwCustomerGsConfigDTO dto, LoginUserInfo user) {
+        List<YwCustomerConditioner> existingRels = ywCustomerConditionerMapper.selectList(
+                new QueryWrapper<YwCustomerConditioner>().lambda()
+                        .eq(YwCustomerConditioner::getCustomerId, dto.getCustomerId()));
+        Map<Integer, YwCustomerConditioner> relByCondId = existingRels.stream()
+                .collect(Collectors.toMap(YwCustomerConditioner::getConditionerId, r -> r, (a, b) -> a));
+
+        Set<Integer> targetIds = dto.getConditioners().stream()
+                .map(YwCustomerGsConfigDTO.ConditionerItem::getConditionerId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+
+        Date now = new Date();
+        for (YwCustomerConditioner rel : existingRels) {
+            if (!targetIds.contains(rel.getConditionerId())
+                    && Objects.equals(rel.getIsdeleted(), Constants.ZERO)) {
+                ywCustomerConditionerMapper.update(null, new UpdateWrapper<YwCustomerConditioner>().lambda()
+                        .set(YwCustomerConditioner::getIsdeleted, Constants.ONE)
+                        .set(YwCustomerConditioner::getEditDate, now)
+                        .set(YwCustomerConditioner::getEditor, user.getId())
+                        .eq(YwCustomerConditioner::getId, rel.getId()));
+            }
+        }
 
         for (YwCustomerGsConfigDTO.ConditionerItem item : dto.getConditioners()) {
-            YwCustomerConditioner rel = new YwCustomerConditioner();
-            rel.setCreator(user.getId());
-            rel.setCreateDate(new Date());
-            rel.setEditor(user.getId());
-            rel.setEditDate(new Date());
-            rel.setIsdeleted(Constants.ZERO);
-            rel.setCustomerId(dto.getCustomerId());
-            rel.setConditionerId(item.getConditionerId());
-            rel.setDevRatio(item.getDevRatio() != null ? item.getDevRatio() : 100);
-            ywCustomerConditionerMapper.insert(rel);
+            if (item.getConditionerId() == null) {
+                continue;
+            }
+            int ratio = item.getDevRatio() != null ? item.getDevRatio() : 100;
+            YwCustomerConditioner rel = relByCondId.get(item.getConditionerId());
+            if (rel != null) {
+                rel.setIsdeleted(Constants.ZERO);
+                rel.setDevRatio(ratio);
+                rel.setEditor(user.getId());
+                rel.setEditDate(now);
+                ywCustomerConditionerMapper.updateById(rel);
+            } else {
+                YwCustomerConditioner created = new YwCustomerConditioner();
+                created.setCreator(user.getId());
+                created.setCreateDate(now);
+                created.setEditor(user.getId());
+                created.setEditDate(now);
+                created.setIsdeleted(Constants.ZERO);
+                created.setCustomerId(dto.getCustomerId());
+                created.setConditionerId(item.getConditionerId());
+                created.setDevRatio(ratio);
+                ywCustomerConditionerMapper.insert(created);
+                relByCondId.put(item.getConditionerId(), created);
+            }
         }
     }
 
@@ -616,6 +730,7 @@
                 .eq(YwElectricalCharge::getIsdeleted, Constants.ZERO)
                 .eq(query.getType() != null, YwElectricalCharge::getType, query.getType())
                 .eq(query.getStatus() != null, YwElectricalCharge::getStatus, query.getStatus())
+                .eq(query.getCustomerId() != null, YwElectricalCharge::getCustomerId, query.getCustomerId())
                 .like(StringUtils.isNotBlank(query.getCustomerName()), YwCustomer::getName, query.getCustomerName())
                 .ge(query.getCreateTimeBegin() != null, YwElectricalCharge::getCreateDate, query.getCreateTimeBegin())
                 .le(query.getCreateTimeEnd() != null, YwElectricalCharge::getCreateDate, query.getCreateTimeEnd())
@@ -762,7 +877,38 @@
         charge.setStatusTime(new Date());
         charge.setStatusInfo("鍏呭�间腑");
         charge.setDeviceInfo("GS-" + gs.getPlatformGsId() + " " + customer.getName());
+        applyRechargeOperator(charge, user);
         return charge;
+    }
+
+    private void applyRechargeOperator(YwElectricalCharge charge, LoginUserInfo user) {
+        if (charge == null || user == null) {
+            return;
+        }
+        if (user.getMemberId() != null) {
+            charge.setMemberId(user.getMemberId());
+        }
+        String operatorName = resolveRechargeUserName(user);
+        if (StringUtils.isNotBlank(operatorName)) {
+            charge.setRechargeUserName(operatorName);
+        }
+    }
+
+    private String resolveRechargeUserName(LoginUserInfo user) {
+        if (user == null) {
+            return null;
+        }
+        if (StringUtils.isNotBlank(user.getMemberName())) {
+            return user.getMemberName();
+        }
+        if (Constants.equalsInteger(user.getH5UserType(), LoginUserInfo.H5_USER_CUSTOMER)
+                && StringUtils.isNotBlank(user.getDisplayName())) {
+            int idx = user.getDisplayName().lastIndexOf('-');
+            if (idx >= 0 && idx < user.getDisplayName().length() - 1) {
+                return user.getDisplayName().substring(idx + 1).trim();
+            }
+        }
+        return StringUtils.trimToNull(user.getRealname());
     }
 
     private void fillRecordText(YwCustomerRechargeRecordVO vo) {
@@ -771,7 +917,13 @@
                 vo.setDeviceInfo(StringUtils.defaultString(vo.getAddress()) + " " + StringUtils.defaultString(vo.getName()));
             }
         }
-        vo.setTypeText(Objects.equals(vo.getType(), Constants.ONE) ? "绌鸿皟" : "鐢佃〃");
+        vo.setTypeText(Objects.equals(vo.getType(), Constants.ONE) ? "绌鸿皟鍏呭��" : "鐢佃〃鍏呭��");
+        if (StringUtils.isBlank(vo.getRechargeUserName()) && vo.getMemberId() != null) {
+            Member member = memberMapper.selectById(vo.getMemberId());
+            if (member != null && StringUtils.isNotBlank(member.getName())) {
+                vo.setRechargeUserName(member.getName());
+            }
+        }
         if (Objects.equals(vo.getStatus(), Constants.ZERO)) {
             vo.setStatusText("鍏呭�间腑");
         } else if (Objects.equals(vo.getStatus(), Constants.ONE)) {
@@ -838,6 +990,24 @@
         }
     }
 
+    private void validateGsConfigRequired(YwCustomerGsConfigDTO dto) {
+        if (dto.getStopMoney() == null) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "娆犺垂棰濆害涓嶈兘涓虹┖");
+        }
+        if (dto.getStopMoney().compareTo(BigDecimal.ZERO) < 0) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "娆犺垂棰濆害涓嶈兘灏忎簬0");
+        }
+        if (dto.getIsPwr() == null) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璁¤垂寮�鍏充笉鑳戒负绌�");
+        }
+        if (dto.getIsRestStop() == null) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鏄惁鍋滄満涓嶈兘涓虹┖");
+        }
+        if (CollectionUtils.isEmpty(dto.getConditioners())) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "璇疯嚦灏戝叧鑱斾竴鍙扮┖璋冨唴鏈�");
+        }
+    }
+
     private String apiMsg(ConditionerBaseResponse<?> resp, String def) {
         return resp != null && StringUtils.isNotBlank(resp.getMessage()) ? resp.getMessage() : def;
     }
@@ -859,20 +1029,14 @@
     }
 
     private void assertElectricalBound(Integer customerId, Integer electricalId) {
-        Long cnt = ywCustomerElectricalMapper.selectCount(new QueryWrapper<YwCustomerElectrical>().lambda()
-                .eq(YwCustomerElectrical::getCustomerId, customerId)
-                .eq(YwCustomerElectrical::getElectricalId, electricalId)
-                .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO));
-        if (cnt == null || cnt == 0) {
-            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鐢佃〃鏈叧鑱旇鍟嗘埛");
+        List<Integer> boundIds = ywCustomerDeviceAutoBindService.listElectricalIdsByActiveContracts(customerId);
+        if (!boundIds.contains(electricalId)) {
+            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "鐢佃〃鏈叧鑱旇鍟嗘埛鏈夋晥鍚堝悓鎴挎簮");
         }
     }
 
     private List<Integer> listBoundElectricalIds(Integer customerId) {
-        return ywCustomerElectricalMapper.selectList(new QueryWrapper<YwCustomerElectrical>().lambda()
-                        .eq(YwCustomerElectrical::getCustomerId, customerId)
-                        .eq(YwCustomerElectrical::getIsdeleted, Constants.ZERO))
-                .stream().map(YwCustomerElectrical::getElectricalId).collect(Collectors.toList());
+        return ywCustomerDeviceAutoBindService.listElectricalIdsByActiveContracts(customerId);
     }
 
     private Set<Integer> listAllBoundElectricalIds() {
@@ -900,22 +1064,73 @@
     }
 
     private List<YwConditioner> loadCustomerConditionerList(Integer customerId) {
-        List<YwCustomerConditioner> rels = ywCustomerConditionerMapper.selectList(new QueryWrapper<YwCustomerConditioner>().lambda()
-                .eq(YwCustomerConditioner::getCustomerId, customerId)
-                .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO));
-        if (rels.isEmpty()) {
+        List<Integer> conditionerIds = ywCustomerDeviceAutoBindService.listConditionerIdsByActiveContracts(customerId);
+        if (conditionerIds.isEmpty()) {
             return Collections.emptyList();
         }
-        Map<Integer, Integer> ratioMap = rels.stream()
+        Map<Integer, Integer> ratioMap = ywCustomerConditionerMapper.selectList(new QueryWrapper<YwCustomerConditioner>().lambda()
+                        .eq(YwCustomerConditioner::getCustomerId, customerId)
+                        .eq(YwCustomerConditioner::getIsdeleted, Constants.ZERO))
+                .stream()
                 .collect(Collectors.toMap(YwCustomerConditioner::getConditionerId, YwCustomerConditioner::getDevRatio, (a, b) -> a));
-        List<YwConditioner> list = ywConditionerMapper.selectBatchIds(ratioMap.keySet());
+        List<YwConditioner> list = ywConditionerMapper.selectBatchIds(conditionerIds);
         list = list.stream().filter(c -> !Objects.equals(c.getIsdeleted(), Constants.ONE)).collect(Collectors.toList());
+        enrichConditionerRoomNames(list, customerId);
         for (YwConditioner c : list) {
-            c.setDevRatio(ratioMap.get(c.getId()));
+            c.setDevRatio(ratioMap.getOrDefault(c.getId(), 100));
         }
         return list;
     }
 
+    private void enrichConditionerRoomNames(List<YwConditioner> list, Integer customerId) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        List<Integer> contractRoomIds = ywCustomerDeviceAutoBindService.listActiveContractRoomIds(customerId);
+        Map<Integer, Integer> conditionerRoomMap = new HashMap<>();
+        if (!CollectionUtils.isEmpty(contractRoomIds)) {
+            ywElectricalRoomMapper.selectList(new QueryWrapper<YwElectricalRoom>().lambda()
+                            .in(YwElectricalRoom::getRoomId, contractRoomIds)
+                            .eq(YwElectricalRoom::getType, Constants.ONE)
+                            .eq(YwElectricalRoom::getIsdeleted, Constants.ZERO))
+                    .forEach(rel -> {
+                        if (rel.getObjId() != null && rel.getRoomId() != null) {
+                            conditionerRoomMap.putIfAbsent(rel.getObjId(), rel.getRoomId());
+                        }
+                    });
+        }
+        Set<Integer> roomIds = new HashSet<>(contractRoomIds);
+        for (YwConditioner conditioner : list) {
+            Integer roomId = conditionerRoomMap.getOrDefault(conditioner.getId(), conditioner.getRoomId());
+            if (roomId != null) {
+                roomIds.add(roomId);
+            }
+        }
+        if (roomIds.isEmpty()) {
+            return;
+        }
+        Map<Integer, YwRoom> roomMap = ywRoomMapper.selectBatchIds(roomIds).stream()
+                .filter(r -> !Objects.equals(r.getIsdeleted(), Constants.ONE))
+                .collect(Collectors.toMap(YwRoom::getId, r -> r, (a, b) -> a));
+        for (YwConditioner conditioner : list) {
+            if (StringUtils.isNotBlank(conditioner.getRoomName())) {
+                continue;
+            }
+            Integer roomId = conditionerRoomMap.getOrDefault(conditioner.getId(), conditioner.getRoomId());
+            YwRoom room = roomId != null ? roomMap.get(roomId) : null;
+            if (room != null) {
+                conditioner.setRoomName(StringUtils.defaultString(room.getRoomNum()));
+            }
+        }
+    }
+
+    private LoginUserInfo systemUser() {
+        LoginUserInfo user = new LoginUserInfo();
+        user.setId(1);
+        user.setRealname("system");
+        return user;
+    }
+
     private PageData<YwElectrical> pageElectricalByIds(PageWrap<YwElectrical> pageWrap, List<Integer> ids) {
         IPage<YwElectrical> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
         YwElectrical model = pageWrap.getModel();

--
Gitblit v1.9.3