Bläddra i källkod

Merge branch 'fyc-vpp' of uskycloud/usky-modules into feature/service-vpp-20260701

fuyuchuan 3 dagar sedan
förälder
incheckning
528790a66b
15 ändrade filer med 310 tillägg och 39 borttagningar
  1. 3 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/ContractController.java
  2. 10 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/CustomerController.java
  3. 26 2
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/SettlementController.java
  4. 1 1
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/domain/VppContract.java
  5. 1 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/domain/VppCustomer.java
  6. 5 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/domain/VppEnergyReadingMonthly.java
  7. 1 1
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/job/VppUnPollScheduler.java
  8. 5 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppCustomerService.java
  9. 3 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppSettlementService.java
  10. 4 2
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppArchiveServiceImpl.java
  11. 13 8
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppContractServiceImpl.java
  12. 70 25
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppCustomerServiceImpl.java
  13. 71 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppSettlementServiceImpl.java
  14. 5 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/CustomerAccessRequestVO.java
  15. 92 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/util/VppContractStatusHelper.java

+ 3 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/ContractController.java

@@ -86,6 +86,7 @@ public class ContractController {
 
     /**
      * 新增合同
+     * <p>合同状态根据生效/到期日期自动计算,无需手动传入生命周期状态。</p>
      */
     @PostMapping
     public ApiResult<Boolean> create(@RequestBody VppContractRequestVO vo) {
@@ -94,6 +95,8 @@ public class ContractController {
 
     /**
      * 修改合同
+     * <p>合同状态根据生效/到期日期自动计算:未到生效时间为待生效,已过生效时间为已生效,已过到期时间为已到期;
+     * 草稿、审核中、已驳回、已终止状态不受日期影响。</p>
      */
     @PutMapping
     public ApiResult<Boolean> update(@RequestBody VppContractRequestVO vo) {

+ 10 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/CustomerController.java

@@ -81,6 +81,16 @@ public class CustomerController {
         return ApiResult.success();
     }
 
+    /**
+     * 修改准入申请(仅已驳回状态可修改,修改后重新进入待审核)
+     */
+    @PutMapping("/access")
+    public ApiResult<Boolean> updateAccess(@RequestBody CustomerAccessRequestVO vo) {
+        return vppCustomerService.updateAccess(vo)
+                ? ApiResult.success(true)
+                : ApiResult.error("修改准入申请失败,请重试!");
+    }
+
     /**
      * 删除准入申请(软删除)
      */

+ 26 - 2
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/SettlementController.java

@@ -1,6 +1,8 @@
 package com.usky.vpp.controller.web;
 
 import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.vpp.domain.VppEnergyReadingMonthly;
 import com.usky.vpp.service.VppSettlementService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -16,34 +18,56 @@ public class SettlementController {
     @Autowired
     private VppSettlementService vppSettlementService;
 
+    /**
+     * 分页查询powermeter数据
+     * <ul>
+     *   <li>id           主键ID 精确匹配</li>
+     *   <li>customerName 客户名称 模糊匹配</li>
+     *   <li>calcCycle    计算周期 模糊匹配</li>
+     *   <li>current      页码</li>
+     *   <li>size         页大小</li>
+     * </ul>
+     */
     @GetMapping(value = "/reading")
-    public ApiResult<Object> pageReading(@RequestParam(required = false) java.util.Map<String, Object> params) {
-        return ApiResult.success(null);
+    public ApiResult<CommonPage<VppEnergyReadingMonthly>> pageReading(
+            @RequestParam(value = "id", required = false) Long id,
+            @RequestParam(value = "customerName", required = false) String customerName,
+            @RequestParam(value = "calcCycle", required = false) String calcCycle,
+            @RequestParam(value = "current", required = false, defaultValue = "1") Integer current,
+            @RequestParam(value = "size", required = false, defaultValue = "20") Integer size) {
+        return ApiResult.success(vppSettlementService.pageReading(id, customerName, calcCycle, current, size));
     }
+
     @PostMapping(value = "/reading/calculate")
     public ApiResult<Void> calculateReading(@RequestBody(required = false) Object body) {
         return ApiResult.success();
     }
+
     @GetMapping(value = "/bill")
     public ApiResult<Object> pageBill(@RequestParam(required = false) java.util.Map<String, Object> params) {
         return ApiResult.success(null);
     }
+
     @PostMapping(value = "/bill")
     public ApiResult<Object> generateBill(@RequestBody(required = false) Object body) {
         return ApiResult.success(null);
     }
+
     @GetMapping(value = "/bill/{id}")
     public ApiResult<Object> getBill(@PathVariable("id") Long id, @RequestParam(required = false) java.util.Map<String, Object> params) {
         return ApiResult.success(null);
     }
+
     @GetMapping(value = "/bill/{id}/download")
     public ApiResult<Object> downloadBill(@PathVariable("id") Long id) {
         return ApiResult.success(null);
     }
+
     @GetMapping(value = "/payment")
     public ApiResult<Object> pagePayment(@RequestParam(required = false) java.util.Map<String, Object> params) {
         return ApiResult.success(null);
     }
+
     @PostMapping(value = "/payment")
     public ApiResult<Object> recordPayment(@RequestBody(required = false) Object body) {
         return ApiResult.success(null);

+ 1 - 1
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/domain/VppContract.java

@@ -52,7 +52,7 @@ public class VppContract implements Serializable {
     private String contractName;
 
     /**
-     * 0草稿 1审核中 2已生效 3已到期 4已终止
+     * 0草稿 1审核中 2待生效 3已生效 4已驳回 5已到期 6已终止
      */
     @NotNull(message = "合同状态不能为空!")
     @TableField("contract_status")

+ 1 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/domain/VppCustomer.java

@@ -104,6 +104,7 @@ public class VppCustomer implements Serializable {
     @TableField("delete_flag")
     private Integer deleteFlag;
     @TableField("deleted_at")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private LocalDateTime deletedAt;
 
     /**

+ 5 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/domain/VppEnergyReadingMonthly.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
@@ -24,6 +25,10 @@ public class VppEnergyReadingMonthly implements Serializable {
     private Long id;
     @TableField("customer_id")
     private Long customerId;
+
+    @TableField(exist = false)
+    private String customerName;
+
     @TableField("resource_id")
     private Long resourceId;
     @TableField("settle_year")

+ 1 - 1
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/job/VppUnPollScheduler.java

@@ -22,7 +22,7 @@ public class VppUnPollScheduler {
     @Autowired
     private VppUnIntegrationService integrationService;
 
-    @Scheduled(fixedDelayString = "#{${vpp.un.poll-interval-sec:10} * 1000}")
+    //@Scheduled(fixedDelayString = "#{${vpp.un.poll-interval-sec:10} * 1000}")
     public void pollUn() {
         if (!properties.isPollActive()) {
             return;

+ 5 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppCustomerService.java

@@ -40,6 +40,11 @@ public interface VppCustomerService {
      */
     void auditAccess(CustomerAccessAuditRequest request);
 
+    /**
+     * 修改已驳回的准入申请(修改后重新进入待审核)
+     */
+    Boolean updateAccess(CustomerAccessRequestVO request);
+
     /**
      * 删除准入申请(软删除)
      */

+ 3 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppSettlementService.java

@@ -1,6 +1,7 @@
 package com.usky.vpp.service;
 
 import com.usky.common.core.bean.CommonPage;
+import com.usky.vpp.domain.VppEnergyReadingMonthly;
 
 import java.util.Map;
 
@@ -12,4 +13,6 @@ public interface VppSettlementService {
     default Object stub(String action, Map<String, Object> params) {
         return null;
     }
+
+    CommonPage<VppEnergyReadingMonthly> pageReading(Long id, String customerName, String calcCycle, Integer current, Integer size);
 }

+ 4 - 2
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppArchiveServiceImpl.java

@@ -11,6 +11,7 @@ import com.usky.common.security.utils.SecurityUtils;
 import com.usky.vpp.domain.VppFileArchive;
 import com.usky.vpp.mapper.VppFileArchiveMapper;
 import com.usky.vpp.service.VppArchiveService;
+import com.usky.vpp.service.VppSiteService;
 import com.usky.vpp.service.vo.VppFileArchiveRequestVO;
 import com.usky.vpp.service.vo.VppFileArchiveResponseVO;
 import org.apache.commons.lang3.StringUtils;
@@ -57,6 +58,8 @@ public class VppArchiveServiceImpl implements VppArchiveService {
     private FilesMapper filesMapper;
     @Autowired
     private VppFileArchiveMapper vppFileArchiveMapper;
+    @Autowired
+    private VppSiteService vppSiteService;
 
     /**
      * 连接池化的 RestTemplate,避免每次创建新连接
@@ -157,8 +160,7 @@ public class VppArchiveServiceImpl implements VppArchiveService {
             responseVO.setUpdatedBy(entity.getUpdatedBy());
             responseVO.setVersion(entity.getVersion());
             responseVO.setTenantId(entity.getTenantId());
-            // TODO 查询站点名称
-            // responseVO.setSiteName();
+            responseVO.setSiteName(vppSiteService.getSite(entity.getSiteId()).getSiteName());
             return responseVO;
         }).collect(java.util.stream.Collectors.toList());
 

+ 13 - 8
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppContractServiceImpl.java

@@ -15,6 +15,7 @@ import com.usky.vpp.service.VppContractService;
 import com.usky.vpp.service.vo.VppContractRequestVO;
 import com.usky.vpp.service.vo.VppContractResponseVO;
 import com.usky.vpp.util.VppAuditHelper;
+import com.usky.vpp.util.VppContractStatusHelper;
 import com.usky.vpp.util.VppFieldValidator;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -73,7 +74,8 @@ public class VppContractServiceImpl implements VppContractService {
         contract.setTemplateId(vo.getTemplateId());
         contract.setContractType(vo.getContractType());
         contract.setContractName(vo.getContractName());
-        contract.setContractStatus(vo.getContractStatus());
+        contract.setContractStatus(VppContractStatusHelper.resolveForPersist(
+                vo.getContractStatus(), vo.getEffectiveDate(), vo.getExpireDate()));
         contract.setSignDate(vo.getSignDate());
         contract.setEffectiveDate(vo.getEffectiveDate());
         contract.setExpireDate(vo.getExpireDate());
@@ -117,9 +119,6 @@ public class VppContractServiceImpl implements VppContractService {
         if (StringUtils.isNotBlank(vo.getContractName())) {
             existingRecord.setContractName(vo.getContractName());
         }
-        if (vo.getContractStatus() != null) {
-            existingRecord.setContractStatus(vo.getContractStatus());
-        }
         if (vo.getSignDate() != null) {
             existingRecord.setSignDate(vo.getSignDate());
         }
@@ -145,6 +144,11 @@ public class VppContractServiceImpl implements VppContractService {
             existingRecord.setRemark(vo.getRemark());
         }
 
+        Integer requestedStatus = vo.getContractStatus() != null
+                ? vo.getContractStatus() : existingRecord.getContractStatus();
+        existingRecord.setContractStatus(VppContractStatusHelper.resolveForPersist(
+                requestedStatus, existingRecord.getEffectiveDate(), existingRecord.getExpireDate()));
+
         VppAuditHelper.fillUpdate(existingRecord);
 
         int result = vppContractMapper.updateById(existingRecord);
@@ -164,9 +168,9 @@ public class VppContractServiceImpl implements VppContractService {
                 .le(signDateEnd != null, VppContract::getSignDate, signDateEnd)
                 .eq(templateId != null, VppContract::getTemplateId, templateId)
                 .eq(contractType != null, VppContract::getContractType, contractType)
-                .eq(customerId != null, VppContract::getCustomerId, customerId)
-                .eq(contractStatus != null, VppContract::getContractStatus, contractStatus)
-                .orderByDesc(VppContract::getCreateTime);
+                .eq(customerId != null, VppContract::getCustomerId, customerId);
+        VppContractStatusHelper.applyStatusFilter(queryWrapper, contractStatus);
+        queryWrapper.orderByDesc(VppContract::getCreateTime);
         page = vppContractMapper.selectPage(page, queryWrapper);
 
         List<VppContract> records = page.getRecords();
@@ -197,7 +201,8 @@ public class VppContractServiceImpl implements VppContractService {
             vo.setTemplateName(templateNameMap.get(entity.getTemplateId()));
             vo.setContractType(entity.getContractType());
             vo.setContractName(entity.getContractName());
-            vo.setContractStatus(entity.getContractStatus());
+            vo.setContractStatus(VppContractStatusHelper.resolve(
+                    entity.getContractStatus(), entity.getEffectiveDate(), entity.getExpireDate()));
             vo.setSignDate(entity.getSignDate());
             vo.setEffectiveDate(entity.getEffectiveDate());
             vo.setExpireDate(entity.getExpireDate());

+ 70 - 25
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppCustomerServiceImpl.java

@@ -15,6 +15,7 @@ import com.usky.vpp.mapper.VppCustomerAccessMapper;
 import com.usky.vpp.mapper.VppCustomerContactMapper;
 import com.usky.vpp.mapper.VppCustomerMapper;
 import com.usky.vpp.service.VppCustomerService;
+import com.usky.vpp.service.VppSiteService;
 import com.usky.vpp.service.vo.CustomerAccessAuditRequest;
 import com.usky.vpp.service.vo.CustomerAccessRequestVO;
 import com.usky.vpp.service.vo.CustomerAccessResponseVO;
@@ -22,6 +23,7 @@ import com.usky.vpp.service.vo.CustomerContactRequest;
 import com.usky.vpp.service.vo.CustomerRequestVO;
 import com.usky.vpp.service.vo.CustomerResponseVO;
 import com.usky.vpp.util.VppAuditHelper;
+import com.usky.vpp.util.VppContractStatusHelper;
 import com.usky.vpp.util.VppFieldValidator;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -104,7 +106,7 @@ public class VppCustomerServiceImpl implements VppCustomerService {
         access.setContactName(request.getContactName());
         access.setContactPhone(request.getContactPhone());
         access.setContactEmail(request.getContactEmail());
-        access.setSigningDate(request.getSigningDate());
+        // access.setSigningDate(request.getSigningDate());
         VppAuditHelper.fillCreate(access);
 
         int insert = accessMapper.insert(access);
@@ -200,6 +202,48 @@ public class VppCustomerServiceImpl implements VppCustomerService {
         accessMapper.updateById(access);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateAccess(CustomerAccessRequestVO request) {
+        if (request.getId() == null) {
+            throw new BusinessException("准入申请ID不能为空!");
+        }
+        validateAccessRequest(request);
+
+        VppCustomerAccess access = findAccessById(request.getId());
+        if (access.getAccessStatus() != ACCESS_REJECTED) {
+            throw new BusinessException("仅已驳回的准入申请允许修改!");
+        }
+
+        LambdaQueryWrapper<VppCustomerAccess> dupWrapper = new LambdaQueryWrapper<>();
+        dupWrapper.eq(VppCustomerAccess::getAccountNo, request.getAccountNo())
+                .eq(VppCustomerAccess::getTenantId, SecurityUtils.getTenantId())
+                .eq(VppCustomerAccess::getDeleteFlag, VppAuditHelper.NOT_DELETED)
+                .ne(VppCustomerAccess::getId, request.getId());
+        Integer accessCount = accessMapper.selectCount(dupWrapper);
+        if (accessCount != null && accessCount > 0) {
+            throw new BusinessException("该电力户号已存在准入申请,请勿重复提交!");
+        }
+
+        access.setAccountNo(request.getAccountNo());
+        access.setCustomerName(request.getCustomerName());
+        access.setCustomerType(request.getCustomerType());
+        access.setPowerCompany(request.getPowerCompany());
+        access.setContractCapacity(request.getContractCapacity());
+        access.setBusinessLicenseUrl(request.getBusinessLicenseUrl());
+        access.setCreditStatus(request.getCreditStatus());
+        access.setContactName(request.getContactName());
+        access.setContactPhone(request.getContactPhone());
+        access.setContactEmail(request.getContactEmail());
+        access.setAccessStatus(ACCESS_PENDING);
+        access.setAuditOpinion(null);
+        access.setAuditAt(null);
+        access.setApplyAt(LocalDateTime.now());
+
+        VppAuditHelper.fillUpdate(access);
+        return accessMapper.updateById(access) > 0;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean deleteAccess(Long id) {
@@ -370,17 +414,8 @@ public class VppCustomerServiceImpl implements VppCustomerService {
             throw new BusinessException("用电容量不能为空!");
         }
 
-        // 同租户下 accountNo 和 customerName 唯一校验
-        Integer tenantId = SecurityUtils.getTenantId();
-        LambdaQueryWrapper<VppCustomer> dupWrapper = new LambdaQueryWrapper<>();
-        dupWrapper.eq(VppCustomer::getTenantId, tenantId)
-                .eq(VppCustomer::getDeleteFlag, VppAuditHelper.NOT_DELETED)
-                .and(w -> w.eq(VppCustomer::getAccountNo, vo.getAccountNo())
-                        .or().eq(VppCustomer::getCustomerName, vo.getCustomerName()));
-        Integer dupCount = customerMapper.selectCount(dupWrapper);
-        if (dupCount != null && dupCount > 0) {
-            throw new BusinessException("同租户下已存在相同电力户号或客户名称的客户!");
-        }
+        // 电力户号全局唯一校验
+        checkAccountNoUnique(vo.getAccountNo(), null);
 
         // 构建客户
         VppCustomer customer = new VppCustomer();
@@ -554,18 +589,13 @@ public class VppCustomerServiceImpl implements VppCustomerService {
         VppCustomer existing = findCustomerById(id);
 
         // 仅更新非空字段
-        if (StringUtils.isNotBlank(vo.getCustomerName())) {
-            if (!vo.getCustomerName().equals(existing.getCustomerName())) {
-                // 校验同租户下客户名称唯一
-                LambdaQueryWrapper<VppCustomer> uniqueWrapper = new LambdaQueryWrapper<>();
-                uniqueWrapper.eq(VppCustomer::getTenantId, SecurityUtils.getTenantId())
-                        .eq(VppCustomer::getCustomerName, vo.getCustomerName())
-                        .eq(VppCustomer::getDeleteFlag, VppAuditHelper.NOT_DELETED);
-                Integer count = customerMapper.selectCount(uniqueWrapper);
-                if (count != null && count > 0) {
-                    throw new BusinessException("客户名称已存在,请更换!");
-                }
+        if (StringUtils.isNotBlank(vo.getAccountNo())) {
+            if (!vo.getAccountNo().equals(existing.getAccountNo())) {
+                checkAccountNoUnique(vo.getAccountNo(), id);
             }
+            existing.setAccountNo(vo.getAccountNo());
+        }
+        if (StringUtils.isNotBlank(vo.getCustomerName())) {
             existing.setCustomerName(vo.getCustomerName());
         }
         if (vo.getCustomerType() != null) {
@@ -942,7 +972,7 @@ public class VppCustomerServiceImpl implements VppCustomerService {
         customer.setBusinessLicenseUrl(access.getBusinessLicenseUrl());
         customer.setLifecycleStatus(LIFECYCLE_ADMITTED);
         customer.setDrNotifyMinutes(30);
-        customer.setSigningDate(access.getSigningDate());
+        customer.setSigningDate(LocalDateTime.now());
         return customer;
     }
 
@@ -952,7 +982,8 @@ public class VppCustomerServiceImpl implements VppCustomerService {
         brief.setContractNo(contract.getContractNo());
         brief.setContractName(contract.getContractName());
         brief.setContractType(contract.getContractType());
-        brief.setContractStatus(contract.getContractStatus());
+        brief.setContractStatus(VppContractStatusHelper.resolve(
+                contract.getContractStatus(), contract.getEffectiveDate(), contract.getExpireDate()));
         brief.setSignDate(contract.getSignDate());
         brief.setEffectiveDate(contract.getEffectiveDate());
         brief.setExpireDate(contract.getExpireDate());
@@ -999,6 +1030,20 @@ public class VppCustomerServiceImpl implements VppCustomerService {
         return contact;
     }
 
+    /**
+     * 电力户号全局唯一校验(不限租户)
+     */
+    private void checkAccountNoUnique(String accountNo, Long excludeId) {
+        LambdaQueryWrapper<VppCustomer> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(VppCustomer::getAccountNo, accountNo)
+                .eq(VppCustomer::getDeleteFlag, VppAuditHelper.NOT_DELETED)
+                .ne(excludeId != null, VppCustomer::getId, excludeId);
+        Integer count = customerMapper.selectCount(wrapper);
+        if (count != null && count > 0) {
+            throw new BusinessException("电力户号已存在,请更换!");
+        }
+    }
+
     private void validateAccessRequest(CustomerAccessRequestVO request) {
         if (request == null || StringUtils.isBlank(request.getAccountNo())) {
             throw new BusinessException("电力户号不能为空!");

+ 71 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppSettlementServiceImpl.java

@@ -1,11 +1,82 @@
 package com.usky.vpp.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.common.security.utils.SecurityUtils;
+import com.usky.vpp.domain.VppCustomer;
+import com.usky.vpp.domain.VppEnergyReadingMonthly;
+import com.usky.vpp.mapper.VppCustomerMapper;
+import com.usky.vpp.mapper.VppEnergyReadingMonthlyMapper;
 import com.usky.vpp.service.VppSettlementService;
+import com.usky.vpp.util.VppAuditHelper;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
 /**
  * VppSettlementService 默认实现(待按业务完善)
  */
 @Service
 public class VppSettlementServiceImpl implements VppSettlementService {
+
+    @Autowired
+    private VppCustomerMapper vppCustomerMapper;
+    @Autowired
+    private VppEnergyReadingMonthlyMapper energyReadingMonthlyMapper;
+
+
+    @Override
+    public CommonPage<VppEnergyReadingMonthly> pageReading(Long id, String customerName, String calcCycle, Integer current, Integer size) {
+        IPage<VppEnergyReadingMonthly> page = new Page<>(current, size);
+        Integer tenantId = SecurityUtils.getTenantId();
+
+        LambdaQueryWrapper<VppCustomer> customerQueryWrapper = new LambdaQueryWrapper<VppCustomer>();
+        customerQueryWrapper.eq(VppCustomer::getTenantId, tenantId)
+                .eq(VppCustomer::getDeleteFlag, VppAuditHelper.NOT_DELETED)
+                .like(StringUtils.isNotBlank(customerName), VppCustomer::getCustomerName, customerName);
+        Map<Long, String> customerNameMap = vppCustomerMapper.selectList(customerQueryWrapper)
+                .stream()
+                .collect(Collectors.toMap(VppCustomer::getId, VppCustomer::getCustomerName));
+
+        LambdaQueryWrapper<VppEnergyReadingMonthly> energyReadingQueryWrapper = new LambdaQueryWrapper<VppEnergyReadingMonthly>();
+        energyReadingQueryWrapper.eq(VppEnergyReadingMonthly::getTenantId, tenantId)
+                .eq(VppEnergyReadingMonthly::getDeleteFlag, VppAuditHelper.NOT_DELETED)
+                .eq(id != null, VppEnergyReadingMonthly::getCustomerId, id)
+                .eq(StringUtils.isNotBlank(calcCycle), VppEnergyReadingMonthly::getSettleYear, resolveCalcCycle(calcCycle).get("settleYear"))
+                .eq(StringUtils.isNotBlank(calcCycle), VppEnergyReadingMonthly::getSettleMonth, resolveCalcCycle(calcCycle).get("settleMonth"))
+                .orderByDesc(VppEnergyReadingMonthly::getSettleYear);
+        page = energyReadingMonthlyMapper.selectPage(page, energyReadingQueryWrapper);
+
+        List<VppEnergyReadingMonthly> energyReadingMonthlyList = page.getRecords();
+        energyReadingMonthlyList.forEach(energyReadingMonthly -> {
+            energyReadingMonthly.setCustomerName(customerNameMap.get(energyReadingMonthly.getCustomerId()));
+        });
+
+        return new CommonPage<>(energyReadingMonthlyList, page.getTotal(), size, current);
+    }
+
+    /**
+     * 解析核算周期,年-月
+     * @param calcCycle
+     * @return
+     */
+    private Map<String, Object> resolveCalcCycle(String calcCycle) {
+        Map<String, Object> calcCycleMap = new HashMap<>();
+        String[] split = calcCycle.split("-");
+        try {
+            calcCycleMap.put("settleYear", split[0]);
+            calcCycleMap.put("settleMonth", split[1]);
+        } catch (Exception e) {
+            throw new BusinessException("解析核算周期失败!请核对参数!");
+        }
+        return calcCycleMap;
+    }
 }

+ 5 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/CustomerAccessRequestVO.java

@@ -16,6 +16,11 @@ import java.time.LocalDateTime;
 @Data
 public class CustomerAccessRequestVO {
 
+    /**
+     * 主键(修改已驳回准入申请时必传)
+     */
+    private Long id;
+
     /**
      * 电力户号
      */

+ 92 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/util/VppContractStatusHelper.java

@@ -0,0 +1,92 @@
+package com.usky.vpp.util;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.usky.vpp.domain.VppContract;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 合同状态工具:根据生效/到期日期自动解析生命周期状态
+ */
+public final class VppContractStatusHelper {
+
+    public static final int DRAFT = 0;
+    public static final int AUDITING = 1;
+    public static final int PENDING = 2;
+    public static final int EFFECTIVE = 3;
+    public static final int REJECTED = 4;
+    public static final int EXPIRED = 5;
+    public static final int TERMINATED = 6;
+
+    private static final Set<Integer> MANUAL_STATUSES = new HashSet<>(Arrays.asList(
+            DRAFT, AUDITING, REJECTED, TERMINATED
+    ));
+
+    private VppContractStatusHelper() {
+    }
+
+    /**
+     * 根据生效/到期日期解析合同状态;草稿、审核中、已驳回、已终止保持原状态不变。
+     */
+    public static Integer resolve(Integer storedStatus, LocalDate effectiveDate, LocalDate expireDate) {
+        if (storedStatus != null && MANUAL_STATUSES.contains(storedStatus)) {
+            return storedStatus;
+        }
+        return resolveByDates(effectiveDate, expireDate, storedStatus);
+    }
+
+    /**
+     * 创建/更新时根据日期计算应写入的状态;未提供日期时回退为待生效。
+     */
+    public static Integer resolveForPersist(Integer requestedStatus, LocalDate effectiveDate, LocalDate expireDate) {
+        if (requestedStatus != null && MANUAL_STATUSES.contains(requestedStatus)) {
+            return requestedStatus;
+        }
+        Integer resolved = resolveByDates(effectiveDate, expireDate, requestedStatus);
+        return resolved != null ? resolved : PENDING;
+    }
+
+    private static Integer resolveByDates(LocalDate effectiveDate, LocalDate expireDate, Integer fallback) {
+        LocalDate today = LocalDate.now();
+        if (expireDate != null && today.isAfter(expireDate)) {
+            return EXPIRED;
+        }
+        if (effectiveDate != null) {
+            return today.isBefore(effectiveDate) ? PENDING : EFFECTIVE;
+        }
+        return fallback;
+    }
+
+    /**
+     * 分页筛选:将生命周期状态(待生效/已生效/已到期)转换为日期条件。
+     */
+    public static void applyStatusFilter(LambdaQueryWrapper<VppContract> wrapper, Integer contractStatus) {
+        if (contractStatus == null) {
+            return;
+        }
+        LocalDate today = LocalDate.now();
+        if (contractStatus == PENDING) {
+            wrapper.and(w -> w.in(VppContract::getContractStatus, PENDING, EFFECTIVE, EXPIRED)
+                    .gt(VppContract::getEffectiveDate, today)
+                    .and(inner -> inner.isNull(VppContract::getExpireDate)
+                            .or().ge(VppContract::getExpireDate, today)));
+            return;
+        }
+        if (contractStatus == EFFECTIVE) {
+            wrapper.and(w -> w.in(VppContract::getContractStatus, PENDING, EFFECTIVE, EXPIRED)
+                    .le(VppContract::getEffectiveDate, today)
+                    .and(inner -> inner.isNull(VppContract::getExpireDate)
+                            .or().ge(VppContract::getExpireDate, today)));
+            return;
+        }
+        if (contractStatus == EXPIRED) {
+            wrapper.and(w -> w.in(VppContract::getContractStatus, PENDING, EFFECTIVE, EXPIRED)
+                    .lt(VppContract::getExpireDate, today));
+            return;
+        }
+        wrapper.eq(VppContract::getContractStatus, contractStatus);
+    }
+}