fuyuchuan 4 päivää sitten
vanhempi
commit
2fa2a30b18
19 muutettua tiedostoa jossa 425 lisäystä ja 99 poistoa
  1. 0 4
      service-iot/service-iot-api/src/main/java/com/usky/iot/RemoteIotTaskService.java
  2. 0 5
      service-iot/service-iot-api/src/main/java/com/usky/iot/factory/RemoteIotTaskFactory.java
  3. 0 14
      service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/api/ServiceIotTaskApi.java
  4. 1 8
      service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpDeviceInfoServiceImpl.java
  5. 11 0
      service-vpp/service-vpp-biz/pom.xml
  6. 23 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/config/VppSmsProperties.java
  7. 6 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/DrController.java
  8. 16 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppAliyunSmsService.java
  9. 3 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppDrService.java
  10. 87 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppAliyunSmsServiceImpl.java
  11. 1 6
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppDeviceServiceImpl.java
  12. 33 5
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppDrInvitationServiceImpl.java
  13. 57 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppDrServiceImpl.java
  14. 2 1
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/DeviceRequest.java
  15. 2 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/DrStrategyRequest.java
  16. 36 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/DrStrategyVO.java
  17. 48 0
      service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/util/VppSmsTemplateHelper.java
  18. 5 0
      service-vpp/service-vpp-biz/src/main/resources/bootstrap.yml
  19. 94 56
      service-vpp/service-vpp-biz/src/main/resources/sql/vpp_id_auto_increment_migration.sql

+ 0 - 4
service-iot/service-iot-api/src/main/java/com/usky/iot/RemoteIotTaskService.java

@@ -24,10 +24,6 @@ public interface RemoteIotTaskService {
     @GetMapping("/addDeviceInfo")
     void addDeviceInfo(@RequestParam("productCode") String productCode, @RequestParam(value = "deviceUuid") String deviceUuid, @RequestParam(value = "deviceId") String deviceId, @RequestParam(value = "deviceName") String deviceName, @RequestParam(value = "installAddress") String installAddress, @RequestParam(value = "serviceStatus") Integer serviceStatus);
 
-
-    @GetMapping("/addSubsystemDeviceInfo")
-    void addSubsystemDeviceInfo(@RequestParam(value = "deviceUuid") String deviceUuid, @RequestParam(value = "deviceId") String deviceId, @RequestParam(value = "tenantId") Integer tenantId);
-
     @GetMapping("/deleteDeviceInfo")
     void deleteDeviceInfo(@RequestParam(value = "deviceUuid") String deviceUuid);
 }

+ 0 - 5
service-iot/service-iot-api/src/main/java/com/usky/iot/factory/RemoteIotTaskFactory.java

@@ -49,11 +49,6 @@ public class RemoteIotTaskFactory implements FallbackFactory<RemoteIotTaskServic
                 throw new FeignBadRequestException(500,"新增设备信息异常"+throwable.getMessage());
             }
 
-            @Override
-            public void addSubsystemDeviceInfo(String deviceUuid, String deviceId, Integer tenantId) {
-                throw new FeignBadRequestException(500,"新增子系统设备信息异常"+throwable.getMessage());
-            }
-
             @Override
             public void deleteDeviceInfo(String deviceUuid) {
                 throw new FeignBadRequestException(500,"删除设备信息异常"+throwable.getMessage());

+ 0 - 14
service-iot/service-iot-biz/src/main/java/com/usky/iot/controller/api/ServiceIotTaskApi.java

@@ -61,20 +61,6 @@ public class ServiceIotTaskApi implements RemoteIotTaskService {
         dmpDeviceInfoService.add(dmpDeviceInfo);
     }
 
-    @Override
-    public void addSubsystemDeviceInfo(String deviceUuid, String deviceId, Integer tenantId){
-        DmpDeviceInfo dmpDeviceInfo = new DmpDeviceInfo();
-        dmpDeviceInfo.setProductCode("");
-        dmpDeviceInfo.setDeviceUuid(deviceUuid);
-        dmpDeviceInfo.setDeviceId(deviceId);
-        dmpDeviceInfo.setDeviceName("");
-        dmpDeviceInfo.setInstallAddress("");
-        dmpDeviceInfo.setServiceStatus(1);
-        dmpDeviceInfo.setTenantId(tenantId);
-
-        dmpDeviceInfoService.add(dmpDeviceInfo);
-    }
-
     @Override
     public void deleteDeviceInfo(String deviceUuid){
         LambdaQueryWrapper<DmpDeviceInfo> deviceQueryWrapper = Wrappers.lambdaQuery();

+ 1 - 8
service-iot/service-iot-biz/src/main/java/com/usky/iot/service/impl/DmpDeviceInfoServiceImpl.java

@@ -546,9 +546,7 @@ public class DmpDeviceInfoServiceImpl extends AbstractCrudService<DmpDeviceInfoM
             dmpDeviceInfo.setProductId(list.get(0).getId());
             dmpDeviceInfo.setCreatedBy(SecurityUtils.getUsername());
             dmpDeviceInfo.setCreatedTime(LocalDateTime.now());
-            if(dmpDeviceInfo.getTenantId() == null) {
-                dmpDeviceInfo.setTenantId(SecurityUtils.getTenantId());
-            }
+            dmpDeviceInfo.setTenantId(SecurityUtils.getTenantId());
 
             dmpDeviceInfo.setServiceStatus(1);
             if (StringUtils.isBlank(dmpDeviceInfo.getDeviceUuid())) {
@@ -580,11 +578,6 @@ public class DmpDeviceInfoServiceImpl extends AbstractCrudService<DmpDeviceInfoM
         }
         this.updateById(dmpDeviceInfo);
 
-        LambdaUpdateWrapper<DmpDeviceStatus> updateWrapper = Wrappers.lambdaUpdate();
-        updateWrapper.set(DmpDeviceStatus::getProductId,dmpDeviceInfo.getProductId())
-                .set(DmpDeviceStatus::getProductCode,dmpDeviceInfo.getProductCode())
-                .eq(DmpDeviceStatus::getDeviceId, dmpDeviceInfo.getDeviceId());
-
     }
 
     @Override

+ 11 - 0
service-vpp/service-vpp-biz/pom.xml

@@ -103,6 +103,17 @@
             <artifactId>poi-ooxml</artifactId>
             <version>4.1.2</version>
         </dependency>
+        <!-- 阿里云短信(需求响应邀约通知) -->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.5.16</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
+            <version>1.1.0</version>
+        </dependency>
     </dependencies>
 
     <build>

+ 23 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/config/VppSmsProperties.java

@@ -0,0 +1,23 @@
+package com.usky.vpp.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 虚拟电厂阿里云短信配置
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "vpp.sms")
+public class VppSmsProperties {
+
+    /** 是否启用短信发送 */
+    private Boolean enabled = true;
+
+    /** 短信签名(阿里云控制台申请) */
+    private String signName;
+
+    /** 需求响应邀约默认模板 CODE */
+    private String invitationTemplateCode;
+}

+ 6 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/controller/web/DrController.java

@@ -16,6 +16,7 @@ import com.usky.vpp.service.vo.DrInvitationRequest;
 import com.usky.vpp.service.vo.DrInvitationVO;
 import com.usky.vpp.service.vo.DrParticipateRequest;
 import com.usky.vpp.service.vo.DrStrategyRequest;
+import com.usky.vpp.service.vo.DrStrategyVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -111,6 +112,11 @@ public class DrController {
         return ApiResult.success(vppDrService.pageStrategy(params));
     }
 
+    @GetMapping(value = "/strategy/{id}")
+    public ApiResult<DrStrategyVO> getStrategy(@PathVariable("id") Long id) {
+        return ApiResult.success(vppDrService.getStrategy(id));
+    }
+
     @PostMapping(value = "/strategy")
     public ApiResult<VppDrStrategy> createStrategy(@RequestBody DrStrategyRequest body) {
         return ApiResult.success(vppDrService.createStrategy(body));

+ 16 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/VppAliyunSmsService.java

@@ -0,0 +1,16 @@
+package com.usky.vpp.service;
+
+/**
+ * 阿里云短信发送
+ */
+public interface VppAliyunSmsService {
+
+    /**
+     * 发送模板短信
+     *
+     * @param phone        手机号
+     * @param templateCode 模板 CODE
+     * @param templateParam JSON 模板变量,如 {"name":"张三","event":"EVE_001"}
+     */
+    void sendTemplateSms(String phone, String templateCode, String templateParam);
+}

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

@@ -9,6 +9,7 @@ import com.usky.vpp.service.vo.DrEventRequest;
 import com.usky.vpp.service.vo.DrInterveneRequest;
 import com.usky.vpp.service.vo.DrParticipateRequest;
 import com.usky.vpp.service.vo.DrStrategyRequest;
+import com.usky.vpp.service.vo.DrStrategyVO;
 
 import java.util.Map;
 
@@ -45,6 +46,8 @@ public interface VppDrService {
 
     CommonPage<VppDrStrategy> pageStrategy(Map<String, Object> params);
 
+    DrStrategyVO getStrategy(Long id);
+
     VppDrStrategy createStrategy(DrStrategyRequest request);
 
     void updateStrategy(Long id, DrStrategyRequest request);

+ 87 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppAliyunSmsServiceImpl.java

@@ -0,0 +1,87 @@
+package com.usky.vpp.service.impl;
+
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
+import com.aliyuncs.profile.DefaultProfile;
+import com.usky.common.core.exception.BusinessException;
+import com.usky.vpp.config.VppSmsProperties;
+import com.usky.vpp.service.VppAliyunSmsService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+/**
+ * 阿里云短信服务实现
+ */
+@Service
+public class VppAliyunSmsServiceImpl implements VppAliyunSmsService {
+
+    private static final Logger log = LoggerFactory.getLogger(VppAliyunSmsServiceImpl.class);
+
+    @Value("${sms.ali.region-id:}")
+    private String regionId;
+
+    @Value("${sms.ali.access-key-id:}")
+    private String accessKeyId;
+
+    @Value("${sms.ali.access-key-secret:}")
+    private String accessKeySecret;
+
+    @Autowired
+    private VppSmsProperties smsProperties;
+
+    @Override
+    public void sendTemplateSms(String phone, String templateCode, String templateParam) {
+        if (!Boolean.TRUE.equals(smsProperties.getEnabled())) {
+            throw new BusinessException("短信服务未启用");
+        }
+        if (!StringUtils.hasText(phone)) {
+            throw new BusinessException("手机号不能为空");
+        }
+        if (!StringUtils.hasText(templateCode)) {
+            throw new BusinessException("短信模板不能为空");
+        }
+        if (!StringUtils.hasText(smsProperties.getSignName())) {
+            throw new BusinessException("短信签名未配置,请设置 vpp.sms.sign-name");
+        }
+        ensureCredentialsConfigured();
+
+        try {
+            DefaultProfile profile = DefaultProfile.getProfile(regionId.trim(), accessKeyId.trim(), accessKeySecret.trim());
+            IAcsClient client = new DefaultAcsClient(profile);
+
+            SendSmsRequest request = new SendSmsRequest();
+            request.setPhoneNumbers(phone.trim());
+            request.setSignName(smsProperties.getSignName().trim());
+            request.setTemplateCode(templateCode.trim());
+            if (StringUtils.hasText(templateParam)) {
+                request.setTemplateParam(templateParam);
+            }
+
+            SendSmsResponse response = client.getAcsResponse(request);
+            if (response == null || !"OK".equalsIgnoreCase(response.getCode())) {
+                String message = response != null ? response.getMessage() : "无响应";
+                log.warn("阿里云短信发送失败 phone={} template={} code={} message={}",
+                        phone, templateCode, response != null ? response.getCode() : null, message);
+                throw new BusinessException("短信发送失败: " + message);
+            }
+            log.info("阿里云短信发送成功 phone={} template={} bizId={}", phone, templateCode, response.getBizId());
+        } catch (BusinessException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            log.warn("阿里云短信发送异常 phone={} template={}: {}", phone, templateCode, ex.getMessage());
+            throw new BusinessException("短信发送失败: " + ex.getMessage());
+        }
+    }
+
+    private void ensureCredentialsConfigured() {
+        if (!StringUtils.hasText(regionId) || !StringUtils.hasText(accessKeyId) || !StringUtils.hasText(accessKeySecret)) {
+            throw new BusinessException("阿里云短信密钥未配置,请在 Nacos 配置 sms.ali.region-id / access-key-id / access-key-secret");
+        }
+    }
+}

+ 1 - 6
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppDeviceServiceImpl.java

@@ -93,7 +93,7 @@ public class VppDeviceServiceImpl implements VppDeviceService {
         VppAuditHelper.fillCreate(device);
         deviceMapper.insert(device);
 
-        remoteIotTaskService.addSubsystemDeviceInfo(device.getDeviceUuid(),device.getDeviceCode(),device.getTenantId());
+        remoteIotTaskService.addDeviceInfo(request.getProductCode(),device.getDeviceUuid(),device.getDeviceCode(),device.getDeviceName(),"",2);
         return device;
     }
 
@@ -152,9 +152,6 @@ public class VppDeviceServiceImpl implements VppDeviceService {
         if (request == null || !StringUtils.hasText(request.getDeviceCode())) {
             throw new BusinessException("设备编号不能为空");
         }
-        if (!StringUtils.hasText(request.getDeviceUuid())) {
-            throw new BusinessException("设备uuid不能为空");
-        }
         if (!StringUtils.hasText(request.getDeviceName())) {
             throw new BusinessException("设备名称不能为空");
         }
@@ -162,7 +159,6 @@ public class VppDeviceServiceImpl implements VppDeviceService {
             throw new BusinessException("设备类型不能为空");
         }
         ensureUniqueField(VppDevice::getDeviceCode, request.getDeviceCode(), excludeId, "设备编号已存在");
-        ensureUniqueField(VppDevice::getDeviceUuid, request.getDeviceUuid(), excludeId, "设备uuid已存在");
     }
 
     private void ensureUniqueField(com.baomidou.mybatisplus.core.toolkit.support.SFunction<VppDevice, ?> field,
@@ -180,7 +176,6 @@ public class VppDeviceServiceImpl implements VppDeviceService {
 
     private void applyRequest(VppDevice device, DeviceRequest request) {
         device.setDeviceCode(request.getDeviceCode());
-        device.setDeviceUuid(request.getDeviceUuid());
         device.setDeviceName(request.getDeviceName());
         device.setDeviceType(request.getDeviceType());
         device.setManufacturer(request.getManufacturer());

+ 33 - 5
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppDrInvitationServiceImpl.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 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.vpp.config.VppSmsProperties;
 import com.usky.vpp.domain.VppCustomer;
 import com.usky.vpp.domain.VppCustomerContact;
 import com.usky.vpp.domain.VppDrEvent;
@@ -14,6 +15,7 @@ import com.usky.vpp.mapper.VppCustomerMapper;
 import com.usky.vpp.mapper.VppDrEventMapper;
 import com.usky.vpp.mapper.VppDrInvitationMapper;
 import com.usky.vpp.mapper.VppDrParticipationMapper;
+import com.usky.vpp.service.VppAliyunSmsService;
 import com.usky.vpp.service.VppDrInvitationService;
 import com.usky.vpp.service.VppUnIntegrationService;
 import com.usky.vpp.service.vo.DrInvitationNotifyRequest;
@@ -22,6 +24,7 @@ import com.usky.vpp.service.vo.DrInvitationRequest;
 import com.usky.vpp.service.vo.DrInvitationVO;
 import com.usky.vpp.util.VppAuditHelper;
 import com.usky.vpp.util.VppPageHelper;
+import com.usky.vpp.util.VppSmsTemplateHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -74,6 +77,10 @@ public class VppDrInvitationServiceImpl implements VppDrInvitationService {
     private VppDrParticipationMapper participationMapper;
     @Autowired
     private VppUnIntegrationService unIntegrationService;
+    @Autowired
+    private VppAliyunSmsService aliyunSmsService;
+    @Autowired
+    private VppSmsProperties smsProperties;
 
     @Override
     public CommonPage<DrInvitationVO> pageInvitation(Map<String, Object> params) {
@@ -200,18 +207,29 @@ public class VppDrInvitationServiceImpl implements VppDrInvitationService {
             invitation.setSmsContactId(contactId);
         }
         VppCustomerContact contact = requireContact(contactId, invitation.getCustomerId());
-        String templateCode = request != null && StringUtils.hasText(request.getTemplateCode())
-                ? request.getTemplateCode()
-                : "vpp_dr_invitation";
+        if (!StringUtils.hasText(contact.getContactPhone())) {
+            throw new BusinessException("联系人手机号为空,无法发送短信");
+        }
+
+        VppDrEvent event = requireEvent(invitation.getDrEventId());
+        VppCustomer customer = requireCustomer(invitation.getCustomerId());
+        String templateCode = resolveTemplateCode(request);
+        String templateParam = VppSmsTemplateHelper.buildInvitationParam(invitation, event, customer, contact);
 
         try {
-            log.info("发送邀约短信 invitationNo={} contact={} phone={} template={}",
-                    invitation.getInvitationNo(), contact.getContactName(), contact.getContactPhone(), templateCode);
+            aliyunSmsService.sendTemplateSms(contact.getContactPhone(), templateCode, templateParam);
             invitation.setSmsNotifyStatus(SMS_SENT);
             invitation.setSmsNotifyAt(LocalDateTime.now());
+        } catch (BusinessException ex) {
+            invitation.setSmsNotifyStatus(SMS_FAILED);
+            VppAuditHelper.fillUpdate(invitation);
+            invitationMapper.updateById(invitation);
+            throw ex;
         } catch (Exception ex) {
             log.warn("邀约短信发送失败 invitationId={}: {}", id, ex.getMessage());
             invitation.setSmsNotifyStatus(SMS_FAILED);
+            VppAuditHelper.fillUpdate(invitation);
+            invitationMapper.updateById(invitation);
             throw new BusinessException("短信发送失败: " + ex.getMessage());
         }
 
@@ -483,4 +501,14 @@ public class VppDrInvitationServiceImpl implements VppDrInvitationService {
         }
         return vo;
     }
+
+    private String resolveTemplateCode(DrInvitationNotifyRequest request) {
+        if (request != null && StringUtils.hasText(request.getTemplateCode())) {
+            return request.getTemplateCode().trim();
+        }
+        if (StringUtils.hasText(smsProperties.getInvitationTemplateCode())) {
+            return smsProperties.getInvitationTemplateCode().trim();
+        }
+        throw new BusinessException("短信模板未配置,请设置 vpp.sms.invitation-template-code 或在请求中传入 templateCode");
+    }
 }

+ 57 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/impl/VppDrServiceImpl.java

@@ -25,6 +25,7 @@ import com.usky.vpp.service.vo.DrEventRequest;
 import com.usky.vpp.service.vo.DrInterveneRequest;
 import com.usky.vpp.service.vo.DrParticipateRequest;
 import com.usky.vpp.service.vo.DrStrategyRequest;
+import com.usky.vpp.service.vo.DrStrategyVO;
 import com.usky.vpp.util.VppAuditHelper;
 import com.usky.vpp.util.VppPageHelper;
 import com.usky.vpp.util.VppSiteResourceHelper;
@@ -634,6 +635,15 @@ public class VppDrServiceImpl implements VppDrService {
         return new CommonPage<>(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
     }
 
+    @Override
+    public DrStrategyVO getStrategy(Long id) {
+        VppDrStrategy strategy = strategyMapper.selectById(id);
+        if (strategy == null || VppAuditHelper.isDeleted(strategy.getDeleteFlag())) {
+            throw new BusinessException("策略不存在");
+        }
+        return toStrategyVo(strategy);
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public VppDrStrategy createStrategy(DrStrategyRequest request) {
@@ -817,6 +827,53 @@ public class VppDrServiceImpl implements VppDrService {
                         .eq(VppDrEvaluation::getDeleteFlag, VppAuditHelper.NOT_DELETED)) > 0;
     }
 
+    private DrStrategyVO toStrategyVo(VppDrStrategy strategy) {
+        DrStrategyVO vo = new DrStrategyVO();
+        vo.setId(strategy.getId());
+        vo.setStrategyCode(strategy.getStrategyCode());
+        vo.setStrategyName(strategy.getStrategyName());
+        vo.setResponseType(strategy.getResponseType());
+        vo.setAdjustStepKw(strategy.getAdjustStepKw());
+        vo.setExecuteMode(strategy.getExecuteMode());
+        vo.setStrategyConfig(strategy.getStrategyConfig());
+        vo.setIsDefault(strategy.getIsDefault());
+        vo.setIsEnabled(strategy.getIsEnabled());
+        vo.setTenantId(strategy.getTenantId());
+        vo.setCreateTime(strategy.getCreateTime());
+        vo.setCreatedBy(strategy.getCreatedBy());
+
+        List<VppDrStrategyResource> strategyResources = strategyResourceMapper.selectList(
+                new LambdaQueryWrapper<VppDrStrategyResource>()
+                        .eq(VppDrStrategyResource::getStrategyId, strategy.getId())
+                        .orderByAsc(VppDrStrategyResource::getPriority)
+        );
+        if (strategyResources.isEmpty()) {
+            vo.setResources(Collections.emptyList());
+            return vo;
+        }
+
+        Set<Long> resourceIds = strategyResources.stream()
+                .map(VppDrStrategyResource::getResourceId)
+                .collect(Collectors.toSet());
+        Map<Long, VppResourcePoint> resourceMap = resourcePointMapper.selectBatchIds(resourceIds).stream()
+                .filter(rp -> !VppAuditHelper.isDeleted(rp.getDeleteFlag()))
+                .collect(Collectors.toMap(VppResourcePoint::getId, rp -> rp, (a, b) -> a));
+
+        List<DrStrategyVO.DrStrategyResourceVO> resources = strategyResources.stream().map(sr -> {
+            DrStrategyVO.DrStrategyResourceVO item = new DrStrategyVO.DrStrategyResourceVO();
+            item.setResourceId(sr.getResourceId());
+            item.setPriority(sr.getPriority());
+            item.setMaxAdjustKw(sr.getMaxAdjustKw());
+            VppResourcePoint resourcePoint = resourceMap.get(sr.getResourceId());
+            if (resourcePoint != null) {
+                item.setResourceName(resourcePoint.getResourceName());
+            }
+            return item;
+        }).collect(Collectors.toList());
+        vo.setResources(resources);
+        return vo;
+    }
+
     private void validateStrategyRequest(DrStrategyRequest request) {
         if (request == null) {
             throw new BusinessException("请求不能为空");

+ 2 - 1
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/DeviceRequest.java

@@ -11,7 +11,6 @@ import java.math.BigDecimal;
 public class DeviceRequest {
 
     private String deviceCode;
-    private String deviceUuid;
     private String deviceName;
     private String deviceType;
     private String manufacturer;
@@ -22,4 +21,6 @@ public class DeviceRequest {
     private String firmwareVersion;
     private String gatewayId;
     private String remark;
+
+    private String productCode;
 }

+ 2 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/DrStrategyRequest.java

@@ -1,5 +1,6 @@
 package com.usky.vpp.service.vo;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.JsonNode;
 import lombok.Data;
@@ -27,6 +28,7 @@ public class DrStrategyRequest {
     /**
      * 策略扩展配置 JSON 字符串(兼容对象或字符串入参)
      */
+    @JsonIgnore
     public String getStrategyConfig() {
         if (strategyConfigJson == null || strategyConfigJson.isNull()) {
             return null;

+ 36 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/service/vo/DrStrategyVO.java

@@ -0,0 +1,36 @@
+package com.usky.vpp.service.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 需求响应策略详情
+ */
+@Data
+public class DrStrategyVO {
+
+    private Long id;
+    private String strategyCode;
+    private String strategyName;
+    private Integer responseType;
+    private BigDecimal adjustStepKw;
+    private Integer executeMode;
+    private String strategyConfig;
+    private Integer isDefault;
+    private Integer isEnabled;
+    private Integer tenantId;
+    private LocalDateTime createTime;
+    private String createdBy;
+    private List<DrStrategyResourceVO> resources;
+
+    @Data
+    public static class DrStrategyResourceVO {
+        private Long resourceId;
+        private String resourceName;
+        private Integer priority;
+        private BigDecimal maxAdjustKw;
+    }
+}

+ 48 - 0
service-vpp/service-vpp-biz/src/main/java/com/usky/vpp/util/VppSmsTemplateHelper.java

@@ -0,0 +1,48 @@
+package com.usky.vpp.util;
+
+import com.usky.vpp.domain.VppCustomer;
+import com.usky.vpp.domain.VppCustomerContact;
+import com.usky.vpp.domain.VppDrEvent;
+import com.usky.vpp.domain.VppDrInvitation;
+
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 邀约短信模板参数构建
+ * <p>
+ * 阿里云模板变量需与控制台一致,默认使用:name、event、capacity、deadline
+ */
+public final class VppSmsTemplateHelper {
+
+    private static final DateTimeFormatter DEADLINE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+
+    private VppSmsTemplateHelper() {
+    }
+
+    public static String buildInvitationParam(VppDrInvitation invitation,
+                                            VppDrEvent event,
+                                            VppCustomer customer,
+                                            VppCustomerContact contact) {
+        String name = contact != null && contact.getContactName() != null
+                ? contact.getContactName()
+                : (customer != null ? customer.getCustomerName() : "");
+        String eventCode = event != null ? event.getEventId() : "";
+        String capacity = invitation.getDemandCapacityKw() != null
+                ? invitation.getDemandCapacityKw().stripTrailingZeros().toPlainString()
+                : "";
+        String deadline = invitation.getReplyDeadline() != null
+                ? DEADLINE_FORMAT.format(invitation.getReplyDeadline())
+                : "";
+        return "{\"name\":\"" + escapeJson(name)
+                + "\",\"event\":\"" + escapeJson(eventCode)
+                + "\",\"capacity\":\"" + escapeJson(capacity)
+                + "\",\"deadline\":\"" + escapeJson(deadline) + "\"}";
+    }
+
+    private static String escapeJson(String value) {
+        if (value == null) {
+            return "";
+        }
+        return value.replace("\\", "\\\\").replace("\"", "\\\"");
+    }
+}

+ 5 - 0
service-vpp/service-vpp-biz/src/main/resources/bootstrap.yml

@@ -31,3 +31,8 @@ vpp:
     token-ttl-minutes: 25
     auto-ack-clearing: false
     auto-register-on-startup: false
+  # 阿里云短信(密钥复用 Nacos 共享配置 sms.ali.*)
+  sms:
+    enabled: true
+    sign-name: 上海永天科技股份有限公司
+    invitation-template-code: SMS_xxxxxx

+ 94 - 56
service-vpp/service-vpp-biz/src/main/resources/sql/vpp_id_auto_increment_migration.sql

@@ -1,51 +1,58 @@
 -- VPP 主键自增迁移(已有库执行,可重复执行)
 -- 将各表 id 列改为 BIGINT AUTO_INCREMENT,与 MyBatis-Plus IdType.AUTO 对齐
+-- 表不存在时自动跳过,适用于部分表尚未创建的库
 
 -- vpp_customer
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_customer' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_customer') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_customer' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_customer` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_customer.id already auto_increment'''
+    'SELECT ''skip: vpp_customer.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_customer_access
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_customer_access' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_customer_access') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_customer_access' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_customer_access` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_customer_access.id already auto_increment'''
+    'SELECT ''skip: vpp_customer_access.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_customer_contact
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_customer_contact' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_customer_contact') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_customer_contact' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_customer_contact` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_customer_contact.id already auto_increment'''
+    'SELECT ''skip: vpp_customer_contact.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_contract
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_contract' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_contract') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_contract' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_contract` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_contract.id already auto_increment'''
+    'SELECT ''skip: vpp_contract.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_contract_template
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_contract_template' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_contract_template') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_contract_template' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_contract_template` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_contract_template.id already auto_increment'''
+    'SELECT ''skip: vpp_contract_template.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_contract_audit_log
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_contract_audit_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_contract_audit_log') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_contract_audit_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_contract_audit_log` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_contract_audit_log.id already auto_increment'''
+    'SELECT ''skip: vpp_contract_audit_log.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
@@ -69,177 +76,208 @@ PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_resource_point
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_resource_point' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_resource_point') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_resource_point' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_resource_point` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_resource_point.id already auto_increment'''
+    'SELECT ''skip: vpp_resource_point.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_resource_point_config
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_resource_point_config' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_resource_point_config') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_resource_point_config' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_resource_point_config` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_resource_point_config.id already auto_increment'''
+    'SELECT ''skip: vpp_resource_point_config.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_device
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_device' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_device') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_device' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_device` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_device.id already auto_increment'''
+    'SELECT ''skip: vpp_device.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_device_control_log
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_device_control_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_device_control_log') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_device_control_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_device_control_log` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_device_control_log.id already auto_increment'''
+    'SELECT ''skip: vpp_device_control_log.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_energy_reading_monthly
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_energy_reading_monthly' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_energy_reading_monthly') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_energy_reading_monthly' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_energy_reading_monthly` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_energy_reading_monthly.id already auto_increment'''
+    'SELECT ''skip: vpp_energy_reading_monthly.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_energy_summary_daily
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_energy_summary_daily' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_energy_summary_daily') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_energy_summary_daily' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_energy_summary_daily` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_energy_summary_daily.id already auto_increment'''
+    'SELECT ''skip: vpp_energy_summary_daily.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_settlement_bill
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_settlement_bill' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_settlement_bill') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_settlement_bill' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_settlement_bill` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_settlement_bill.id already auto_increment'''
+    'SELECT ''skip: vpp_settlement_bill.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_settlement_bill_detail
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_settlement_bill_detail' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_settlement_bill_detail') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_settlement_bill_detail' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_settlement_bill_detail` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_settlement_bill_detail.id already auto_increment'''
+    'SELECT ''skip: vpp_settlement_bill_detail.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_payment_record
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_payment_record' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_payment_record') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_payment_record' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_payment_record` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_payment_record.id already auto_increment'''
+    'SELECT ''skip: vpp_payment_record.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_report_task
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_task' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_report_task') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_task' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_report_task` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_report_task.id already auto_increment'''
+    'SELECT ''skip: vpp_report_task.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_report_record
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_record' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_report_record') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_record' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_report_record` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_report_record.id already auto_increment'''
+    'SELECT ''skip: vpp_report_record.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_report_data
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_data' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_report_data') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_data' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_report_data` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_report_data.id already auto_increment'''
+    'SELECT ''skip: vpp_report_data.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_report_audit_log
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_audit_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_report_audit_log') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_audit_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_report_audit_log` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_report_audit_log.id already auto_increment'''
+    'SELECT ''skip: vpp_report_audit_log.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_dr_event
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_event' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_event') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_event' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_dr_event` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_dr_event.id already auto_increment'''
+    'SELECT ''skip: vpp_dr_event.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_dr_participation
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_participation' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_participation') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_participation' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_dr_participation` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_dr_participation.id already auto_increment'''
+    'SELECT ''skip: vpp_dr_participation.id already auto_increment or table missing'''
+);
+PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
+
+-- vpp_dr_invitation
+SET @sql = IF(
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_invitation') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_invitation' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    'ALTER TABLE `vpp_dr_invitation` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
+    'SELECT ''skip: vpp_dr_invitation.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_dr_strategy
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_strategy' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_strategy') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_strategy' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_dr_strategy` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_dr_strategy.id already auto_increment'''
+    'SELECT ''skip: vpp_dr_strategy.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_dr_strategy_resource
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_strategy_resource' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_strategy_resource') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_strategy_resource' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_dr_strategy_resource` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_dr_strategy_resource.id already auto_increment'''
+    'SELECT ''skip: vpp_dr_strategy_resource.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_dr_execution
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_execution' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_execution') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_execution' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_dr_execution` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_dr_execution.id already auto_increment'''
+    'SELECT ''skip: vpp_dr_execution.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_dr_evaluation
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_evaluation' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_evaluation') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_dr_evaluation' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_dr_evaluation` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_dr_evaluation.id already auto_increment'''
+    'SELECT ''skip: vpp_dr_evaluation.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_registration
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_registration' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_registration') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_registration' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_registration` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_registration.id already auto_increment'''
+    'SELECT ''skip: vpp_registration.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_report_log
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_report_log') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_report_log' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_report_log` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_report_log.id already auto_increment'''
+    'SELECT ''skip: vpp_report_log.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
 
 -- vpp_file_archive
 SET @sql = IF(
-    (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_file_archive' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
+    (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'vpp_file_archive') > 0
+    AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vpp_file_archive' AND column_name = 'id' AND EXTRA LIKE '%auto_increment%') = 0,
     'ALTER TABLE `vpp_file_archive` MODIFY COLUMN `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT ''主键''',
-    'SELECT ''skip: vpp_file_archive.id already auto_increment'''
+    'SELECT ''skip: vpp_file_archive.id already auto_increment or table missing'''
 );
 PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;